Processing math: 100%

dersblog



Yapay Sinir Ağları (Neural Networks)

YSA'ları anlamak için onların temel taşı olan tek nöron'u görmemiz lazım.

Üstteki resimde üç girdisi ve tek çıktısı olan bir nöron görüyoruz. Girdi olarak x1,x2,x3 ve çıktı olarak bir fonksiyon hesabı. Literatürde üstteki yapıya perseptron (perceptron) ismi de veriliyor. Eğer 0/1, evet/hayır türünde çıktıları modellemek istersek bu fonksiyon çoğunlukla sigmoid fonksiyonu olarak seçilir. Yani

h(x)=f(wTx)=f(3i=1wixi+b)

ve

f(z)=11+exp(z)

ki w ağırlık değerlerinin taşıyan bir vektördür. Sigmoid seçiminin bir diğer sebebi türevinin rahat alınabilmesi. Alternatif fonksiyonlar tanh olabilirdi, ya da düzeltilmiş lineer ünite (rectified linear unit -ReLu-) fonksiyonları. ReLu'lar YSA'ların uzantısı Derin Öğrenim'de oldukca popüler oldu, tanımı

f(z)=max(0,z)

Şimdi tek nörondan çok katmanlı bir YSA nasıl oluşturulur görelim,

Bu yapıda her xi'in her nörona gittiğini görüyoruz, bu katmanlara bu sebeple tamamen bağlanmış katman (fully-connected layer), ya da yoğun (dense) katman deniyor. Her türlü girdi / nöron kombinasyonu çarpıldığı için ağırlıklar bir matris içinde tutulur, ve aktivasyondan önceki vektör basit bir matris çarpımı haline gelir, mesela 2. katman aktivasyonu f2 olsun, 1. gizli katman çıktısı

f2(W1x+b)

Girdi 4×1, ağırlık W1 boyutu 3×4, o zaman çarpım 3×1 olacak, f2 uygulanınca boyut değişmez (her öge üzerinde aynı fonksiyon işletiliyor) sonuç 3×1, bu da zaten 2. katmana giren (sonra oradan sonraki katmana çıkan) hesap. Üstteki diyagramda yanlılık (bias) ayrı bir nöron olarak eklenmiş (bazen bu yapılmayabiliyor).

İki gizli seviyesi (hidden layer) olan bir YSA,

Görüldüğü gibi çok seviyeli durumda bir seviyenin çıktısı bir diğer seviyenin girdisi haline geliyor. YSA'lar denetimli (supervised) şekilde eğitilirler. Elde xi,yi veri noktaları vardır, ve her bir ya da çok boyutlu xi yine bir ya da çok boyutlu yi ile eşlidir. Aynen regresyonda olduğu gibi bu veri çiftlerini alırız ve onları en iyi temsil eden YSA'yı eğitmek için kullanırız. Eğitim tamamlandığında i katmanındaki Wi ağırlıkları belli değerlere sahip olurlar, ve eldeki "model" bu ağırlıklardır. Yeni bir veri noktası verildiğinde o veri noktası ağırlıklar her katmanın Wi'sı ile çarpılıp, toplanıp, aktivasyon fonksiyonlarına geçilip, tüm katmanlardan bu şekilde geçirildikten sonra en sondaki çıktı değerine erişilir.

Yanlılık taşımayan şekilde ağ yapısı görelim ve matris çarpımı ile tüm girdileri / çıktıları gösterelim,

Girdi=x0

x1=f1(W1x0)

x2=f2(W2x1)

Çıktı=f3(W3x2)

Aktivasyon için f1,f2,f3 ReLu ya da sigmoid seçilebilir.

İki gizli seviyesi olan (ve yeterince sayıda nöron içeren) YSA'nın evrensel yaklaşıklayıcı (universal approximator) olduğu iddia edilir, yani üstteki gibi yeterince çetrefil bir YSA her türlü fonksiyonu yaklaşık olarak temsil edebilir. İşin tarihine gidersek, ilk başta tek seviyeli YSA vardı, fakat XOR fonksiyonunu başarılı şekilde temsil edemedi. Gizli (tek) seviyeli olan bunu başardı.

YSA'lar imaj tanıma alanında bolca kullanılmıştır. Bir imajda, mesela sayı tanıma uygulamasında, alttaki gibi pek çok resimler olabilir,

Bir imaj nihayetinde o resmi temsil eden gri değerlerin olduğu bir matristen ibarettir. YSA'ya girdi olması için matris genelde düzleştirilir, ve tek bir vektör olarak verilir, 8x8 matris 64x1 vektörü olur, girdi 64 boyutlu bir xi çıktı ise tek boyutlu 0,1,2,..,9 gibi etiketler.. Çoğunlukla bu tür kategorik çıktılar ikisel olarak modellenir, 0,..,9 yerine 10 öğeli bir ikisel vektör alınır, 9. öğesi 1 diğerleri 0 yapılır.

YSA'lar nasıl eğitilir? Eldeki xi,yi çiftleri YSA'ya verilir, her xi önce tahmin için kullanılır, ve bir YSA'nın tahmin ettiğine, bir de gerçek veriye bakılır. Bu fark, hata, YSA'nın düzeltilmesi / iyileştirilmesi için kullanılır, burada geriye yayılım (backpropagation -backprop-) adlı bir teknik var. YSA içinde, üstte gördüğümüz gibi, sol seviyeden başlayarak sağa gidecek şekilde, fonksiyonlar, fonksiyonların fonksiyonları şeklinde çetrefil bir yapı var. Backprop elde hatayı alıp YSA'daki tüm nöronların ağırlıklarını bu hataya göre düzeltilmesini, düzelmenin "yayılmasını" sağlar [1,2]. Bu işlem ardı ardına, farklı her döngüde tekrarlanır, bir süre sonra YSA eldeki veriyi en iyi temsil eden ideal bir hale yaklaşacaktır.

Formüller ve Kod

Backprop'un genel bir resmi üstte: a) Eğitim verisi ileri yönde (soldan sağa) YSA'ya veriliyor, ve bu veri her nokta için, o anda sahip olunan ağırlıklara göre bir tahmin üretiyor. b) Eğitim verisindeki beklenen ve tahmin edilen değerler arasındaki hata hesaplanıyor c) Hata YSA'ya "geri yönde" veriliyor, her ağırlık wi'dan Ewi büyüklüğünün bir kısmı çıkartılıyor, bu düzeltmenin ne oranda yapıldığı dışarıdan, önceden kararlaştırılan bir sabit η'e oranda yapılıyor.

Daha detaylı bir resimde gösterelim,

Tek bir gizli katman var, girdi katmanı ai'den gelen sinyaller wij ağırlıkları ile çarpılıyor, daha önce gördüğümüz gibi bu tamamen bağlanmış katman, çünkü tüm girdi sinyalleri her gizli katman düğümüne hep beraber giriş yapıyorlar (tabii farklı ağırlıklar üzerinden). Devam edelim, ağırlıklar sonrası bir de yanlılık (bias) eklenecek (resimde atlandı), ve elde edilen zi=bj+iaiwij. Bu 3. katmandaki aktivasyon önceki son hal. Gizli katmandan çıkan sinyal aj, bu sinyaller son katmanda bu sefer wjk ağırlıkları ile çarpılıp toplanacak, bk yanlılığı eklenecek, ve sonuç gk aktivasyon fonksiyonundan geçirilip çıktı ak haline getirilecek.

Bir YSA'yı eğitmek demek öyle bir parametre demeti θ=(W,b) bulmaktır ki ağın hatası en minimal seviyede olsun. Çoğunlukla bu hata hedef (eğitim) çıktısı tk ile ağın en son ağırlıklara göre kendi hesapladığı ak fark karelerinin toplamı üzerinden hesaplanır.

E=12k(aktk)2

Çıktı katmanının hata fonksiyonu üzerinde direk etkisi olduğu için bu parametreler için gradyanı hesaplamak oldukca kolay,

Ewjk=12k(attk)2

=(aktk)wjk(aktk)

Bu türevde Zincirleme Kanununu kullandık. Dikkat edersek toplama operatörü kayboldu, bunun sebebi j'inci düğüme göre türev alıyor olmamız o yüzden j'inci haricinde tüm diğer parametreler türevde sıfırlanıyor, toplamdan geriye tek bir terim kalıyor. tk'in türevi de sıfır çünkü içinde wjk'ye bağlı hiçbir değişken yok (tk dışarıdan verilen eğitim verisi sonuçta, çoğu durum için sabit sayılabilir). Ayrıca ak=g(zk) olduğunu hatırlayalım. O zaman

Ewjk=(aktk)wjkak

=(aktk)wjkgk(zk)

=(aktk)gk(zk)wjkzk(1)

Yine Zincirleme Kanununu kullandık. Şimdi hatırlayalım ki zk=bj+jgj(zj)wjk, yani zkwjk=gj(zj)=aj, demek ki

Ewjk=(aktk)gk(zk)aj

Bu üç terimin çarpımı, birincisi ağ çıktısı "tahmini" ile hedef değerinin farkı, diğeri çıktı katmanının aktivasyon fonksiyonunun türevi. Üçüncüsü gizli katmandaki j'inci düğümün aktivasyon çıktı değeri. Bu üçlü çarpımı kısaltılmış şekilde göstermek için k indisi için δk değişkeni tanımlayabiliriz,

δk=(aktk)gk(zk)

O zaman

Ewjk=δkaj

δk değişkeni hatanın çıktı aktivasyonunden geriye doğru filtrelenmiş hali olarak görülebilir, yani bir tür hata sinyali olarak alınabilir. Kabaca belirtmek gerekirse üstteki formül her wjk'nin nihai hataya ne kadar ek yaptığını belirtir. Bu sebeple, eğitim sırasında, bu hataların tersi yönde gidilmelidir ki hata daha azalsın.

wjkwjkηEwjk

Çıktı Katman Yanlılığı, bk

Yanlılık için wjk'ye benzer bir yaklaşımı takip ediyoruz, tek fark (1)'deki 3. terim şöyle,

bkzk=bk[bk+jgj(zj)]=1

ve sonuç olarak alttaki gradyanı elde ediyoruz,

Ebk(aktk)gk(zk)(1)

=δk

Yani yanlınlık gradyanı sadece çıktı ünitelerinin geriye yayılmış hali. Bu mantıklı aslında çünkü yanlılığın aktivasyon üzerindeki ağırlığı hep 1'e eşit, ileri doğru giden sinyal ne olursa olsun. Bu sebeple yanlılık gradyanı ileri giden sinyalden hiç etkilenmiyor, sadece hatanın kendisinden etkileniyor.

Gizli Katman Ağırlıklarının Gradyanı

Bu katmanın nihai hata üzerinde etkisi dolaylı olduğu için gizli katman ağırlıkları wij için gradyanları hesaplamak biraz daha zor. Fakat hesaba yine aynı şekilde başlıyoruz,

Ewij=12k(aktk)2

=k(aktk)wijak

Dikkat edersek toplam operatörü bu sefer kaybolmadı, çünkü katmanların tam bağlı olması sebebiyle, her gizli katman ünitesinden çıkan sonuç her çıktı katmanındaki üniteyi etkiliyor. Devam edersek, ve ak=gk(zk) olmasından hareketle,

Ewij=k(aktk)wijgk(zk)

=k(aktk)gk(zk)wijzk(2)

Yine Zincirleme Kanununu kullandık. Evet, şimdi işler biraz daha karmaşıklaşacak. Üstteki formüldeki üçüncü terimde olan kısmi türeve bakarsak, bu türev wij'e göre ama türevi alınan zj j indisine bağlı. Şimdi ne yapacağız? zk'yi açınca içinde alt fonksiyonlar olduğunu görüyoruz,

zk=bk+jajwjk

=bk+jgj(zj)wjk

=bk+jgj(bi+iziwij)wjk

Üstteki son denklemdeki son terime göre zk sadece dolaylı olarak wij'ye bağlı. Bu ayrıca demektir ki Zincirleme Kanununu kullanarak zkwij'i hesaplayabiliriz. Türetimin belki de en püf noktalı yeri burası..

zkwij=zkajajwij

=ajajwjkajwij

=wjkajwij

=wjkgj(zj)wij

=wjkgk(zj)zjwij

=wjkgj(zj)wij(bi+iaiwij)

=wjkgj(zj)ai

Eğer üstteki formülü (2)'deki zk'ye koyarsak, Ewij için şunu elde ederiz,

Ewij=k(aktk)gk(zk)wjkgj(zj)ai

gj(zj)aik(aktk)gk(zk)wjk

=aigj(zj)kδkwjk

Gizli katman yanlılığının gradyanı için Zincirleme Kanunu ile zkbi hesabını yapmak lazım.

zkbi=wjkgj(zj)zjbi

=wjkgj(zj)bi(bi+iaiwij)

=wjkgj(zj)(1)

bunun sonucu

Ebi=gj(zj)kδkwjk

=δj

Özet olarak YSA eğitimi için yapılan hesaplar şunlar:

  1. İleri yönde sinyalleri girdiden çıktıya doğru hesapla

  2. Tahmin ak ve hedef tk'ye göre hata E'yi hesapla

  3. Hatayı önceki katmanlardaki ağırlıklar ve aktivasyon fonksiyonlarının gradyanlarına göre geriye doğru yay.

  4. Parametreleri her parametrenin gradyanı için θθηEθ şeklinde güncelle.

Kodlar

Alttaki kod [3] baz alınarak yazıldı. Bu arada hem gizli, hem çıktıdaki aktivasyonlar gk,gj, ya da hata E hesabında farklı seçimler yapılabilir. Mesela [3] üstte belirttiğimiz gibi hata hesaplıyor ama [2]'deki hata

E=1Nniyn,ilogˆyn,i

ile hesaplanıyor. Her iki kod çıktı aktivasyonu için "softmax" denen fonksiyon kullanıyor. Softmax 0/1 kararı yapan lojistik fonksiyonun 2'den fazla çıktı boyutu için genellenmiş halidir, yani iki seçimden biri yerine K seçimden biri için kullanılır, ve

$$ \sigma(z)j = \frac{e^{z_j}}{\sum_{k=1}^{K} e^{z_k}}$$

ile hesaplanır, z vektöründeki herhangi bazı reel değerleri "ezerek" σ(z) vektörü içinde toplamı 1 olacak değerlere çevirir.

Alttaki kod gizli katman aktivasyonu için sigmoid kullanmış.

from numpy import *

class mlp:
    def __init__(self,inputs,targets,nhidden,beta=1,momentum=0.9):
        self.nin = shape(inputs)[1]
        self.nout = shape(targets)[1]
        self.ndata = shape(inputs)[0]
        self.nhidden = nhidden
        self.beta = beta
        self.momentum = momentum
        self.weights1 = (random.rand(self.nin+1,self.nhidden)-0.5)*2/sqrt(self.nin)
        self.weights2 = (random.rand(self.nhidden+1,self.nout)-0.5)*2 / \
                        sqrt(self.nhidden)

    def earlystopping(self,inputs,targets,valid,validtargets,eta,niterations=100):

        valid = concatenate((valid,-ones((shape(valid)[0],1))),axis=1)        
        old_val_error1 = 100002
        old_val_error2 = 100001
        new_val_error = 100000

        count = 0
        while (((old_val_error1 - new_val_error) > 0.001) or \
               ((old_val_error2 - old_val_error1)>0.001)):
            count+=1
            self.mlptrain(inputs,targets,eta,niterations)
            old_val_error2 = old_val_error1
            old_val_error1 = new_val_error
            validout = self.mlpfwd(valid)
            new_val_error = 0.5*sum((validtargets-validout)**2)

        print "Stopped", new_val_error,old_val_error1, old_val_error2
        return new_val_error

    def mlptrain(self,inputs,targets,eta,niterations):
        inputs = concatenate((inputs,-ones((self.ndata,1))),axis=1)
        change = range(self.ndata)    
        updatew1 = zeros((shape(self.weights1)))
        updatew2 = zeros((shape(self.weights2)))
        for n in range(niterations):    
            self.outputs = self.mlpfwd(inputs)
            error = 0.5*sum((targets-self.outputs)**2)
            #if (n % 100) ==0 : print "Iteration: ",n, " Error: ",error    
            deltao = (targets-self.outputs)/self.ndata            
            deltah = self.hidden*(1.0-self.hidden)*\
                     (dot(deltao,transpose(self.weights2)))
            updatew1 = eta*(dot(transpose(inputs),deltah[:,:-1])) + \
                       self.momentum*updatew1
            updatew2 = eta*(dot(transpose(self.hidden),deltao)) + \
                       self.momentum*updatew2
            self.weights1 += updatew1
            self.weights2 += updatew2                

            random.shuffle(change)
            inputs = inputs[change,:]
            targets = targets[change,:]

    def mlpfwd(self,inputs):
        self.hidden = dot(inputs,self.weights1);
        self.hidden = 1.0/(1.0+exp(-self.beta*self.hidden))
        self.hidden = concatenate((self.hidden,-ones((shape(inputs)[0],1))),axis=1)
        outputs = dot(self.hidden,self.weights2);
        normalisers = sum(exp(outputs),axis=1)*ones((1,shape(outputs)[0]))
        return transpose(transpose(exp(outputs))/normalisers)

from sklearn.cross_validation import train_test_split
from sklearn import datasets
import mlp

def generate_data():
    np.random.seed(0)
    X, y = datasets.make_moons(200, noise=0.20)
    return X, y

one_hot = lambda x, K : np.array(x[:,None] == np.arange(K)[None, :], dtype=int)

X, y = generate_data()
y2 = one_hot(y, 2)
print X.shape, y2.shape
X_train, X_test, y_train, y_test = train_test_split(X, y2, test_size=0.2,random_state=0)
print X_train.shape, y_train.shape
print X_test.shape, y_test.shape
net = mlp.mlp(X_train,y_train,2)
print net.earlystopping(X_train,y_train,X_test,y_test,0.1)
(200, 2) (200, 2)
(160, 2) (160, 2)
(40, 2) (40, 2)
Stopped 2.86548233378 2.86551829438 2.86620503073
Out[1]: 
2.8654823337797608
def predict(x): 
    inputs2 = np.concatenate((x,-np.ones((np.shape(x)[0],1))),axis=1)
    outputs = net.mlpfwd(inputs2)
    return np.where(outputs>0.5,1,0)

def plot_decision_boundary(XX, yyy):
    # Set min and max values and give it some padding
    x_min, x_max = XX[:, 0].min() - .5, XX[:, 0].max() + .5
    y_min, y_max = XX[:, 1].min() - .5, XX[:, 1].max() + .5
    h = 0.01
    # Generate a grid of points with distance h between them
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    # Predict the function value for the whole gid
    Z = predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.argmax(axis=1)
    Z = Z.reshape(xx.shape)
    # Plot the contour and training examples
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    yyy = yyy.argmax(axis=1)
    XX1 = XX[yyy==0]; XX2 = XX[yyy==1]
    plt.scatter(XX1[:, 0], XX1[:, 1], color='blue')
    plt.hold(True)
    plt.scatter(XX2[:, 0], XX2[:, 1], color='red')

plot_decision_boundary(X, y2)
plt.savefig('mlp_06.png')

Alttaki alternatif bir kod, bu kod [2]'yi baz alıyor, YSA ile 0/1 regresyonu yapacak, gizli katman aktivasyonu için tanh kullanılmış. Karar sınırları grafikleniyor.

import pandas as pd
import numpy as np
from sklearn import datasets, linear_model

class Config:
    nn_input_dim = 2  # input layer dimensionality
    nn_output_dim = 2  # output layer dimensionality
    eta = 0.01  # learning rate for gradient descent
    reg_lambda = 0.01  # regularization strength

def generate_data():
    np.random.seed(0)
    X, y = datasets.make_moons(200, noise=0.20)
    return X, y

def visualize(X, y, model):
    plot_decision_boundary(lambda x:predict(model,x), X, y)

def plot_decision_boundary(pred_func, X, y):
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    h = 0.01
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    Z = pred_func(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)

def calculate_loss(model, X, y):
    num_examples = len(X)  # training set size
    W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
    z1 = X.dot(W1) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
    exp_scores = np.exp(z2)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    corect_logprobs = -np.log(probs[range(num_examples), y])
    data_loss = np.sum(corect_logprobs)
    data_loss += Config.reg_lambda / 2 * (np.sum(np.square(W1)) + \
                 np.sum(np.square(W2)))
    return 1. / num_examples * data_loss


def predict(model, x):
    W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
    z1 = x.dot(W1) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
    exp_scores = np.exp(z2)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    return np.argmax(probs, axis=1)

def build_model(X, y, nn_hdim, num_passes=20000, print_loss=False):
    num_examples = len(X)
    np.random.seed(0)
    W1 = np.random.randn(Config.nn_input_dim, nn_hdim) / np.sqrt(Config.nn_input_dim)
    b1 = np.zeros((1, nn_hdim))
    W2 = np.random.randn(nn_hdim, Config.nn_output_dim) / np.sqrt(nn_hdim)
    b2 = np.zeros((1, Config.nn_output_dim))
    model = {}

    for i in range(0, num_passes):
        z1 = X.dot(W1) + b1
        a1 = np.tanh(z1)
        z2 = a1.dot(W2) + b2
        exp_scores = np.exp(z2)
        probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)

        delta3 = probs
        delta3[range(num_examples), y] -= 1
        dW2 = (a1.T).dot(delta3)
        db2 = np.sum(delta3, axis=0, keepdims=True)
        delta2 = delta3.dot(W2.T) * (1 - np.power(a1, 2))
        dW1 = np.dot(X.T, delta2)
        db1 = np.sum(delta2, axis=0)

        dW2 += Config.reg_lambda * W2
        dW1 += Config.reg_lambda * W1

        W1 += -Config.eta * dW1
        b1 += -Config.eta * db1
        W2 += -Config.eta * dW2
        b2 += -Config.eta * db2

        model = {'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2}
        if print_loss and i % 1000 == 0:
            print("Loss after iteration %i: %f" % (i, calculate_loss(model, X, y)))

    return model
import mlp2
X, y = mlp2.generate_data()

model = mlp2.build_model(X, y, 3, print_loss=True)
mlp2.plot_decision_boundary(lambda x:predict(model,x), X, y)
plt.title('YSA')
plt.savefig('mlp_08.png')
Loss after iteration 0: 0.432387
Loss after iteration 1000: 0.068947
Loss after iteration 2000: 0.068883
Loss after iteration 3000: 0.070752
Loss after iteration 4000: 0.070748
Loss after iteration 5000: 0.070751
Loss after iteration 6000: 0.070754
Loss after iteration 7000: 0.070756
Loss after iteration 8000: 0.070757
Loss after iteration 9000: 0.070758
Loss after iteration 10000: 0.070758
Loss after iteration 11000: 0.070758
Loss after iteration 12000: 0.070758
Loss after iteration 13000: 0.070758
Loss after iteration 14000: 0.070758
Loss after iteration 15000: 0.070758
Loss after iteration 16000: 0.070758
Loss after iteration 17000: 0.070758
Loss after iteration 18000: 0.070758
Loss after iteration 19000: 0.070758

Karşılaştırmak için lojistik regresyon kullanalım, ve aynı karar sınırlarını grafikleyelim,

clf = linear_model.LogisticRegressionCV()
clf.fit(X, y)
mlp2.plot_decision_boundary(lambda x: clf.predict(x), X, y)
plt.title('Lojistik Regresyon')
plt.savefig('mlp_09.png')

Görüldüğü gibi karar sınırı daha basit, kıyasla YSA çok daha esnek bir şekilde ayrım yapabiliyor.

Aktivasyon Fonksiyonları

Biraz once ReLu'dan bahsettik, tanh yerine kullanilabilir. Bir diger fonksiyon sigmoid. Bu fonksiyonlarin tipik grafikleri alttadir.

Kaynaklar

[1] Stansbury, Derivation: Error Backpropagation \& Gradient Descent for Neural Networks, https://theclevermachine.wordpress.com/2014/09/06/derivation-error-backpropagation-gradient-descent-for-neural-networks/

[2] Britz, Implementing a Neural Network from Scratch in Python - An Introduction, http://www.wildml.com/2015/09/implementing-a-neural-network-from-scratch/

[3] Marsland, Machine Learning - An Algorithmic Approach


Yukarı