Yığın Normalleştirme (Batch Normalization)

Yığın Normalleştirme Nedir ? Neden Kullanılır ?

Yığın normalleştirme methodu görece yeni bir yöntem. 2015 yılında şu makaleyle yayınlandı. Yığın normalleştirme derin sinir ağlarındaki herhangi bir katmana 0’a ortalanmış ve 1 ile 0 arasında değerlere sahip veriler vermemizi sağlar.

Mini-Yığınlar, Kaydırma ve Ölçekleme

Tabii sadece bu kadarla kalmıyor. Yığın normalleştirmeyi günümüz sinir ağlarında tercih edilen bir metod yapan birkaç şey daha var. Gelin yığın normalleştirme algoritmasına bir göz atalım:

Sırasıyla :

  • Mini-yığındaki girdilerin hepsi toplanıp toplam girdi sayısına bölünerek ortalama değer bulunuyor.

  • Mini-yığındaki her girdiden ortalama değer çıkarılıp karesi alınıyor ve hepsi toplanıyor. Sonrasında yine mini-yığındaki toplam girdi sayısına bölünüyor. Buna mini-yığının varyansı denir. Yani verilerin genellikle hangi aralıklarda bulunduğunun bir ölçütü.

  • Veriler normalize ediliyor.

  • Normalize edilmiş veri gamma(ölçekleme parametresi) ve beta(kaydırma parametresi) ile çarpılıyor.

Şimdi son kısma dikkatinizi çekmek istiyorum. Burada normalize edilmiş veriyi gamma ve beta parametreleriyle çarpıyoruz ve elimizde öğrenilebilir bir lineer denklem oluyor. Yani gamma ve beta hiper parametreler. Bu, onların eğitim sırasında optimize edileceği anlamına geliyor. Bu parametreler yığın normalleştirme katmanının veri üzerinde ne kadar işlem yapacağı üstüne bir kontrol kazanmasını sağlıyor. Dikkat ederseniz bu parametrelere gamma = sqrt(var(x)) ve beta = mean(x) değerleri atanırsa veri üstünde herhangi bir normalizasyon gerçekleşmeyecek. Yani basitçe eğitim sırasında bu katman verinin üstünde ne kadar oynama yapmak gerektiğine kendi karar veriyor.

Modelleme, İleri-İşlem ve Geri-İşlem

Modellemeler algoritmaları görselleştirip daha kolay anlaşılmalarını sağlar. Özellikle derin sinir ağlarında, ağdaki işlemlerin modellemelerini çıkarıp ileri ve geri işlemleri bu grafik benzeri modellerde izlememiz gerekir. Dolayısıyla, biz de yığın normalleştirme için oluşturulmuş bir modelin üstünden gideceğiz.

Derin ağların ve hesaplama modellemelerinin nasıl çalıştığı hakkında basit bir bilgiye sahip olduğunuzu varsayarak, yığın-normalleştirmenin ileri işlem safhasını direkt koda dökeceğim. Zaten grafikteki işlemlerin dışında farklı bir şey yapmayacağız.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def batchnorm_forward(x, gamma, beta, eps):

N, D = x.shape

#adım1 : ortalama değer hesabı
mu = 1./N * np.sum(x, axis = 0)

#adım2: ortalama değer vektörünün her x değerinden çıkarılması
xmu = x - mu

#adım3: Aşağıya kıvrılan dalı takip ederek - xmu'nün karesi
sq = xmu ** 2

#adım4: varyansın hesaplanması
var = 1./N * np.sum(sq, axis = 0)

#adım5: nümerik stabilite için eps ekliyoruz ve sonra karekök alıyoruz
sqrtvar = np.sqrt(var + eps)

#adım6: tersini alıyoruz
ivar = 1./sqrtvar

#adım7: normalizasyon için son adım
xhat = xmu * ivar

#adım8: gamma(scaling) parametresiyle çarpalım
gammax = gamma * xhat

#adım9: beta(shift) parametresiyle toplayalım.
out = gammax + beta

#geri işlem için gerekecek değerleri cache'te tutuyoruz.
cache = (xhat,gamma,xmu,ivar,sqrtvar,var,eps)

return out, cache

Geri İşlem

Şimdi işin zorlayıcı kısmına geldik. Geri-işlem sırasında grafiğimizdeki nodları adım adım geriye doğru izleyeceğiz. Bir öndeki noddan gelen gradyan değeriyle şimdiki nodumuzun gradyanını çarparak, kayıp fonksiyonumuz üstündeki etkisini bulmak istediğimiz değişkenlere kadar ilerleyeceğiz.

Adım 9




Hatırlarsanız f = x + y şeklinde bir fonksiyonun iki değişkene göre türevi de 1 olurdu. Dolayısıyla burada lokal nodumuzun iki değişkene göre de gradyanı 1, üstten gelen gradyan akımımız ise dout değeri. Üstelik bu nodda beta yani kaydırma parametremize giden gradyanı direkt bulmuş olduk. beta (D,) boyutlarında bir vektördü. Üstten gelen dout gradyanı ise (N,D) boyutlarına sahip dolayısıyla betanın gradyan değerinin kendi boyutlarıyla uyuşması için her bir d ∈ D değeri için N değeri topluyoruz.

Adım 8




Bu sefer elimizde f = x * y tarzında bir fonksiyon var. Bu tür bir fonksiyonda ise iki değişkenden birine göre türev alındığında diğerini verir. Dolayısıyla bu adımda ileri işlemde cache değişkenin tuttuğumz değerlerden bazılarına ihtiyacımız olacak. Gamma yani ölçekleme paratmetremiz için üstten gelen gradyan ile normalize edilmiş x değerini çarpıp ( bu arada matris iç çarpımı yapmıyoruz, iki matrisin ilişkili her elemanını birbiriyle çarpıyoruz.), gamma (D,) boyutlarına sahip bir vektör olduğu için az önceki gibi her d ∈ D değeri için N değeri topluyoruz. Artık elimizde gamma parametremize giden gradyan da var. Geriye sadece x’e giden gradyanı takip etmek kaldı.

Adım 7




Artık mantığı anladığımıza göre uzun uzun anlatmadan devam edebiliriz. Şimdi ise cache değerinden bize gereken değerler xmu ve ivar.

Adım 6




Bu nodda girdi değerinin çarpmaya göre tersi alınıyor. f = 1 / x türünde bir fonksiyonun x’e göre türevi 1 / x^2’dir. Dolayısıyla lokal gradyanımız da 1 / sqrtvar^2’e eşit, zira ileri işlem sırasında bu fonksiyona girdi olarak verilen değişken sqrtvar idi.(sqrtvar değişkenini de cache’te depolamıştık.)

Adım 5




Gerekli değişkenlerimiz var ve eps. Yine karekök içerisindeki terimi (x + eps)^-1/2 olarak alıp üstel türev işlemi yapalım.

Adım 4




İlk bakışta bu adımdaki gradyanın hesabı gözünüze karmaşık gelebilir. Aslında yapacağımız işlem oldukça basit. Hatırlıyosak + (toplama) nodlarında üstten gelen gradyan değişmeden direkt (adım 9’a bakın) aktarılıyordu. Bu sefer ise üstten gelen (D,) boyutlu gradyanı (N,D) boyutlu matrise dönüştürmek için her sütunda gradyanı N ayrı satıra eşit olarak dağıtacağız. Sonuç olarak ileri işlemde bu nodun girdisi olan sq değişkeninin boyutlarında 1’lerden oluşan bir matris oluşturuyoruz, her elemanı 1/N ile çarpıyoruz, sonrasında ise üstten gelen gradyan ile çarpıyoruz.

Adım 3




Bu nodda da yapılacak oldukça basit. İleri işlem sırasında kare üs alıyorsak, geri işlem sırasında da 2x şekline dönüştürüyoruz.

Adım 2




Buradaki püf nokta ise eğer bir noda üstten 2 yada daha fazla gradyan geliyorsa, işlemlerin gradyanların toplanarak yapılacağını bilmeniz. Gerisi toplama nodlarındakiyle aynı mantıkla işliyor. Gördüğünüz gibi mu değişkeni için yine (D,) boyutuna indirmek amacıyla matrisi topluyoruz.

Adım 1




Bu nodda yapacağımız şey adım 4’tekiyle tamamen aynı.

Adım 0 (Girdi Gradyanı)




Sonuç olarak x girdi verilerine gelen gradyanı böyle buluyoruz. Ayrıca burda elde ettiğimiz dx değeri bir önceki katmana vereceğimiz dout değeri olacak.

Geri İşlem Uygulaması

Şimdi de yaptığımız işlemleri koda dökelim :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def batchnorm_backward(dout, cache):

#cache verilerini çıkaralım
xhat,gamma,xmu,ivar,sqrtvar,var,eps = cache

#girdi/çıktının boyutlarını belirleyelim
N,D = dout.shape

#adım9
dbeta = np.sum(dout, axis=0)
dgammax = dout #not necessary, but more understandable

#adım8
dgamma = np.sum(dgammax*xhat, axis=0)
dxhat = dgammax * gamma

#adım7
divar = np.sum(dxhat*xmu, axis=0)
dxmu1 = dxhat * ivar

#adım6
dsqrtvar = -1. /(sqrtvar**2) * divar

#adım5
dvar = 0.5 * 1. /np.sqrt(var+eps) * dsqrtvar

#adım4
dsq = 1. /N * np.ones((N,D)) * dvar

#adım3
dxmu2 = 2 * xmu * dsq

#adım2
dx1 = (dxmu1 + dxmu2)
dmu = -1 * np.sum(dxmu1+dxmu2, axis=0)

#adım1
dx2 = 1. /N * np.ones((N,D)) * dmu

#adım0
dx = dx1 + dx2

return dx, dgamma, dbeta

KAYNAKÇA

Paylaş Yorumlar