Yapay Sinir Ağları ve Derin Öğrenme – 3

Çok Katmanlı Perceptron ve Backpropagation

Bir Çok Katmanlı Perceptron (Multi-Layer Perceptron – MLP), bir giriş katmanı, hidden layer olarak adlandırılan bir yada daha fazla LTU katmanı ve bir çıkış katmanından oluşur (Şekil 1). Çıkış katmanı hariç diğer katmanlar yanlılık nöronu içerir ve diğer katmanlara tamamen bağlıdır (fully connected). Bir YSA, iki yada daha fazla hidden layer içeriyorsa, derin sinir ağı (Deep neural network – DNN) olarak adlandırılır.

 im3-1
Şekil 1. Çok Katmanlı Perceptron

Uzun yıllar boyunca araştırmacılar, MLP’leri eğitmek için bir yol aradılar. 1986 yılında Rumelhart, Hinton ve Williams, Learning Internal Representations by Error Propagation adlı makalelerinde, backpropagation eğitim algoritmasını tanıttılar.

Her bir eğitim verisi için ilk olarak tahmin yapılır (forward pass), hata ölçülür, daha sonra geriye doğru gidilerek nöronlar arasındaki her bir bağlantının hataya ne kadar katkı yaptığı bulunur (reverse pass) ve son olarakta bağlantı ağırlıkları hatayı azaltıcak şekilde yeniden düzenlenir (gradient descent adımı).

Bu algoritmanın düzgün çalışması için, yazarlar MLP’nin mimarisinde bir değişiklik yapmışlardır: adım fonksiyonunu lojistik fonksiyon (\sigma(z)=\frac{1}{1+e^{-z}}) ile değiştirmişlerdir. Bu gereklidir çünkü, adım fonksiyonu düz bölüngelerden oluşmaktadır. Dolayısıyla Gradient Descent çalışmaz. Backpropagation başka aktivasyon fonksiyonları ile de kullanılabilir. Popüler iki aktivasyon fonksiyonu:

  • Hiperbolik tanjant fonksiyonu:
    tanh(z)=2\sigma(2z)-1
  • ReLU fonksiyonu: \text{ReLU}(z)=\text{max}(0,z)

Fonksiyonlar ve türevleri aşağıdaki grafikte verilmiştir (Şekil 2):

 im3-2
Şekil 2. Aktivasyon fonksiyonları ve türevleri

MLP, sıklıkla sınıflandırma için kullanılır. Her bir çıkış farklı bir ikili sınıfa (spam/ham gibi) karşılık gelir. Sınıflar özel ise (sıfırdan dokuza kadar rakam sınıflandırma gibi), çıkış katmanının aktivasyon fonksiyonkarı soft-max fonksiyonu ile değiştirilir (Şekil 3). Böylece herbir nöronun çıkşı karşılık gelen sınıfa ait olma olasılığı olur. Nöronların sinyal akışı tek yönlü olduğundan (girişten çıkışa), bu tip bir ağ ileri beslemeli sinir ağı (feedforward neural network – FNN) olarak adlandırılır.

 im3-3
Şekil 3. Sınıflandırma için bir MLP

Tensorflow ile DNN

MNIST veriseti ile çalışacağız. İlk olarak tensorflow ve numpy kütüphanelerini içeri aktaracağız. Ardından giriş ve çıkış sayısı ve gizlenmiş katmanlarda (hidden layers) ne kadar nöron bulunacağını belirteceğiz:

import numpy as np
import tensorflow as tf

n_inputs = 28*28
n_hidden1 = 300
n_hidden2 = 100
n_outputs = 10

MNIST verisetindeki resimler 28×28 boyutunda olduğundan ve herbir piksele karşılık bir öznitelik karşılık geleceğinden n_{inputs}=28x28 olarak belirledik. İlk gizli katmanda 300 ve ikinci gizli katmanda 100 nöron olacak. Son olarakta 10 çıkışımız olacak. Şimdi, eğitim verimiz ve hedef değerlerimiz için placeholder oluşturacağız. X ‘in şekli kısmen tanımlıdır. 2-boyutlu bir tensör olacağını ve 28×28 öznitelik içereceğini biliyoruz fakat her bir eğitim yığınının kaç tane örnek içereceğini bilmiyoruz. Bu nedenle X‘in şekli (None, n_inputs) olacak. Benzer şekilde, y de 1-boyutlu bir tensör olacak ama yine eğitim yığınının ne kadar örnek içerdiğini bilmediğimizden şekli (None) olacaktır.

X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
y = tf.placeholder(tf.int64, shape=(None), name="y")

Şimdi sinir ağını oluşturalım. X placeholder’ı giriş katmanı gibi davranıcak; çalışma sırasında, eğitim yığınları ile değiştirilecek. Gizlenmiş katmanları ve çıkış katmanını oluşturmamız gerekiyor. Katman yaratmak için kullanacağımız ve giriş değerlerini, nöron sayısını, aktivasyon fonksiyonunu ve katmanın ismini parametre olarak alan bir fonksiyon oluşturalım:

def neuron_layer(X, n_neurons, name, activation=None):
    with tf.name_scope(name):
        n_inputs = int(X.get_shape()[1])
        stddev = 2 / np.sqrt(n_inputs)
        init = tf.truncated_normal((n_inputs, n_neurons), stddev=stddev)
        W = tf.Variable(init, name="weights")
        b = tf.Variable(tf.zeros([n_neurons]), name="biases")
        z = tf.matmul(X, W) + b
        if activation=="relu":
            return tf.nn.relu(z)
        else:
            return z

Bu kodu adım adım açıklayalım:

  1. İlk olarak katmanın ismi ile bir name scope oluşturduk: name scope sadece bu katmanın hesaplama düğümlerini içericek.
  2. Giriş matrisinin şekline alıp bu matrisin ikinci boyutunu giriş sayısı olarak ayarlıyoruz (ilk boyut örnek sayısı).
  3. W değişkeni tüm bağlantıların ağırlıklarını içericek. Dolayısıyla boyutu (n_inputs, n_neurons) olacaktır. Başlangıçta 2/\sqrt{n_{inputs}} standart sapmasına sahip truncated normal dağılım ile rastgele olarak belirlenicek. Bunu daha detaylı olarak ileride göreceğiz.
  4. b değişkeni yanlılıkları içeriyor.
  5. z=X\cdot W+b hesaplamasını gerçekleştiriyoruz.
  6. Aktivasyon parametresi “relu” ise, fonksiyon relu(z) değerini, değilse z değerini döndürüyor.

Şimdi derin sinir ağımızı oluşturalım. İlk gizlenmiş katmanımız X tensörünü giriş olarak alacak. İkinci gizlenmiş katman, ilkinin çıkışını giriş olarak alacak ve ve son olarak da, çıkış katmanı ikinci gizlenmiş katmanın çıkışını giriş olarak alacak:

with tf.name_scope("dnn"):
    hidden1 = neuron_layer(X, n_hidden1, "hidden1", activation="relu")
    hidden2 = neuron_layer(hidden1, n_hidden2, "hidden2", activation="relu")
    outputs = neuron_layer(hidden2, n_outputs, "outputs")

Not olarak belirtelim, optimizasyon için softmax hesaplamasını daha sonra yapacağız.

Yukarıda kendi yazdığımız katman fonksiyonu yerine, tensorflow’un içinde gelen fully_connected fonksiyonunu da kullanabiliriz. Daha ileride göreceğimiz üzere, fully_connnected fonksiyonu, normalleştirme ve düzenlileştirme parametrelerini de desteklemektedir.

Şimdi eğitim için kullanacağımız maliyet fonksiyonumuzu tanımlayalım. Bunun için sparse_softmax_cross_entropy_with_logits fonksiyonunu kullanacağız: bu, “logits”lere (ağın, softmax uygulanmadan önceki çıktısı) göre cross entropy’i hesaplar ve etiketlerin 0dan (sınıf sayısı – 1)’e kadar tamsayılar olmasını bekler(bizim örneğimizde sıfıran dokuza kadar). Bu bize her örnek için cross entropy’i içeren 1-boyutlu bir tensör verir. Tensorflow’un reduce_mean() fonksiyonu ile de tüm örnekler için ortalama cross entropy’i hesaplayabiliriz.

with tf.name_scope("loss"):
    xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        labels=y, logits=outputs)
    loss = tf.reduce_mean(xentropy, name="loss")

Sinir ağı modelimizi ve maliyet fonksiyonumuzu oluşturduk. Şimdi model parametrelerini maliyet fonksiyonunu minimum yapacak şekilde değiştirecek fonksiyonu tanımlayacağız:

learning_rate = 0.01

with tf.name_scope("train"):
    optimizer =tf.train.GradientDescentOptimizer(learning_rate)
    training_op = optimizer.minimize(loss)

Son adım ise modelimizi nasıl değerlendireceğimiz. Doğruluk değerini performans ölçütü olarak kullanacağız:

with tf.name_scope("eval"):
    correct = tf.nn.in_top_k(outputs, y, 1)
    accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))

Değişkenlerimizi oluşturmak ve modelimizi kaydetmek için de:

init = tf.global_variables_initializer()
saver = tf.train.Saver()

Modelimizin inşa kısmı bitti! Artık çalıştırma kısmına geçebiliriz.

İlk olarak verisetimizi yükleyelim. Bunun için tensorflow içindeki bir fonksiyondan faydalanacağız:

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data")

Şimdi yığınların boyutunu ve modelimizi verimizin üstünde kaç kere çalıştıracağımızı belirleyeceğiz:

n_epocs = 100
batch_size = 50
 Şimdi modeli eğitelim:
with tf.Session() as sess:
    init.run()
    for epoch in range(n_epocs):
        for iteration in range(mnist.train.num_examples // batch_size):
            X_batch, y_batch = mnist.train.next_batch(batch_size)
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
        acc_train = accuracy.eval(feed_dict={X: X_batch, y: y_batch})
        acc_test = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels})
        print(epoch, "Train accuracy:", acc_train, "Test accuracy:", acc_test)

    save_path = saver.save(sess, "./mnist_model.ckpt")
0 Train accuracy: 0.88 Test accuracy: 0.9089
1 Train accuracy: 0.9 Test accuracy: 0.9297
2 Train accuracy: 0.9 Test accuracy: 0.9384
3 Train accuracy: 0.96 Test accuracy: 0.9452
4 Train accuracy: 0.96 Test accuracy: 0.9478
.
.
.
96 Train accuracy: 1.0 Test accuracy: 0.9799
97 Train accuracy: 1.0 Test accuracy: 0.9797
98 Train accuracy: 1.0 Test accuracy: 0.9799
99 Train accuracy: 1.0 Test accuracy: 0.9799

Bu kod ilk olarak bir TensorFlow oturumu oluşturur ve tüm değişkenleri kullanıma hazırlar. Daha sonra eğitim döngüsünü çalıştırır: her bir adımda, yığınlar üzerinde eğitim işlemini gerçekleştirir. Her bir adımın sonunda, modeli değerlendirir ve sonucu ekrana yazar. En son olarakta model parametrelerini diske kaydeder.

YSA ile tahmin

YSA’yı tahmin için kullanalım. İnşa aşaması yukarıdaki ile aynı fakat çalıştırma aşamasını aşağıdaki gibi değiştirmeliyiz:

with tf.Session() as sess:
    saver.restore(sess, "./mnist_model.ckpt")
    X_new = mnist.train.images[0].reshape(1, 784) # eğitim setinden bir imaj seçtik
    Z = outputs.eval(feed_dict={X: X_new})
    y_pred= np.argmax(Z, axis=1)
    print(y_pred)
Tahmin sonucu:
[7]

Bir sonraki yazımızda sinir ağının hiperparametreleri üzerinde nasıl ince ayarlar yapabileceğimizi inceleyeceğiz. Görüşmek üzere.

Kaynaklar

  1. Geron, A. (2017). Hands-On Machine Learning with Scikit-Learn and TensorFlow Concepts, Tools, and Techniques for Building Intelligent Systems. Sebastopol: OReilly UK Ltd.
Reklamlar

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

w

Connecting to %s