ML Temelleri · Modül 4 · 24 dakika

Normalizasyon ve düzenlileştirme

Derin bir ağda her layer bir öncekinin çıktısını işler. Aktivasyonların ölçeği layer’dan layer’a büyüyebilir ya da küçülebilir. Eğitim bu yüzden yavaşlar ya da hiç başlamaz.

Bir de ters sorun vardır. Model eğitim verisini ezberler, yeni veride kötü çalışır. Buna aşırı öğrenme (overfitting)aşırı öğrenme (overfitting): Modelin eğitim verisini gürültüsüyle birlikte ezberleyip yeni veride kötü çalışması; eğitim loss'u düşerken validation loss'u yükselir. (overfitting) denir. Overfitting’i azaltan yöntemlerin ortak adı düzenlileştirme (regularization)düzenlileştirme (regularization): Aşırı öğrenmeyi azaltmak için modeli kısıtlayan yöntemlerin ortak adı; L2 penalty, dropout ve early stopping örnekleridir.’dir (regularization).

Bu derste şunları yapacaksın:

  • Aktivasyonların derinlikle nasıl kaydığını ölçeceksin.
  • Batch normalization ve layer normalization’ı kodla yazacaksın.
  • Overfitting’i eğitim loss’u ile doğrulama kümesi (validation set)doğrulama kümesi (validation set): Eğitimde kullanılmayan, hiperparametreleri seçmek ve aşırı öğrenmeyi görmek için ayrılmış örnek kümesi. (validation set) loss’u arasındaki farkta göreceksin.
  • L2 cezasını (L2 penalty) ve gradyanını yazacaksın.
  • Dropout’u ters ölçekleme (inverted scaling) ile yazacaksın.

Aktivasyonlar kayarken

Normalizasyon (normalization), her layer’ın çıktısını kullanışlı bir aralıkta tutar.

Derinlikle büyüyen ya da küçülen ölçek

Sekiz layer’lı bir ağı rastgele weight’lerle kuralım. Her layer bir dense layer ve ardından ReLU’dur. Girdi 256 örnek ve 64 feature’dır; her layer’dan sonra aktivasyonların standart sapmasını ölçeceğiz.

Weight’lerin ölçeğini std belirler. Tek bir sayı farkı sonucu tamamen değiştirir:

import numpy as npdef depth_stds(std, normalize, depth=8):    rng = np.random.default_rng(0)    a = rng.normal(size=(256, 64))     # 256 örnek, 64 feature    stds = []    for _ in range(depth):        W = rng.normal(size=(64, 64)) * std        a = np.maximum(0, a @ W)       # dense layer + ReLU        if normalize:            a = (a - a.mean(axis=0)) / (a.std(axis=0) + 1e-5)        stds.append(a.std())    return np.round(stds, 3)depth_stds(0.1, False)    # → array([0.461, 0.268, 0.152, 0.089, 0.041, 0.021, 0.01 , 0.006])depth_stds(0.25, False)   # → array([1.153, 1.674, 2.376, 3.466, 4.032, 5.073, 6.327, 8.882])

İki satırı karşılaştır:

  • std = 0.1 ise standart sapma her layer’da küçülür ve sekizinci layer’da 0,006 olur. Sinyal sönmüştür.
  • std = 0.25 ise standart sapma her layer’da büyür ve 8,9’a çıkar.

Ölçek her layer’da yaklaşık aynı çarpanla değişir, bu yüzden ölçekteki kayma layer sayısıyla üstel büyür. Küçük aktivasyonlar küçük gradyan, büyük aktivasyonlar büyük gradyan ve kararsız adımlar demektir.

Normalizasyon ölçeği sabitler

Çözüm basittir: her layer’ın çıktısını yeniden ölçekle.

Önceki derslerde girdileri standartlaştırmıştık (standardization): ortalamayı çıkar, standart sapmaya böl. Aynı işlemi ara layer’lara da uygularız.

Yukarıdaki kodda normalize=True yapınca her layer’ın çıktısı standartlaştırılır:

# önceki bloktaki np ve depth_stds iledepth_stds(0.25, True)    # → array([1., 1., 1., 1., 1., 1., 1., 1.])

Weight std’yi 0,25 yap, “Layer ekle” ile layer sayısını 8’e çıkar, sonra normalizasyonu yok, batchnorm ve layernorm arasında değiştir:

normalization_viz · layers

256 örnek · 64 nöron · ReLU · W = N(0, 1) · std · her satır bir layer'ın dağılımı

−404812161std 1,1532std 1,6743std 2,3764std 3,4665678aktivasyon değeri · ReLU'dan sonra

layer 4 · std 3,466 · ortalama 2,05 · eksen dışı %1 ağırlıklar büyük: her layer ölçeği büyütüyor

Şunları dene:

  • Normalizasyon yokken son layer’ın std’si 8,882’dir. Batchnorm’a geçince her layer 1’e iner.
  • Weight std’yi 0,1’e al: bu kez std 0,006’ya kadar küçülür. Normalizasyon bunu da 1’e çeker.

Weight ölçeği artık sonucu etkilemez. Her layer’ın çıktısı aynı ölçekle bir sonrakine girer.

Bunun neden eğitimi iyileştirdiği hâlâ tartışmalıdır. Sık duyulan “internal covariate shift” açıklaması kesin değildir. Kesin olan şudur: normalizasyon aktivasyonları sabit bir ölçekte tutar ve eğitimi çoğu ağda hızlandırır ve kararlı kılar.

Kısa soruWeight'ler çok büyük seçilmiş sekiz layer'lı bir ağda aktivasyonların standart sapması layer'dan layer'a büyüyor. Normalizasyon bunu nasıl düzeltir?

Cevabı göster

Her layer'ın çıktısını ortalaması 0 ve standart sapması 1 olacak şekilde yeniden ölçekler, böylece ölçek birikmez. Normalizasyon her layer'dan sonra ölçeği sıfırlar. Weight'ler büyük olsa da bir sonraki layer 1 ölçeğinde girdi görür.

Batch normalization

Batch normalization, her feature’ı batch üzerinden standartlaştırır.

Feature başına normalize et

X∈RN×dX \in \mathbb{R}^{N \times d} bir layer’ın çıktısıdır: satırlar örnek, sütunlar feature’dır. Her sütun için batch’teki ortalamayı ve varyansı hesaplarız:

μj=1N∑i=1NXij,σj2=1N∑i=1N(Xij−μj)2\mu_j = \frac{1}{N}\sum_{i=1}^{N} X_{ij}, \qquad \sigma_j^2 = \frac{1}{N}\sum_{i=1}^{N} (X_{ij} - \mu_j)^2

Sonra her değeri standartlaştırırız:

X^ij=Xij−μjσj2+ϵ\hat{X}_{ij} = \frac{X_{ij} - \mu_j}{\sqrt{\sigma_j^2 + \epsilon}}

ϵ\epsilon küçük bir sabittir; varyans 0 olursa sıfıra bölmeyi önler. Formül her feature’ı batch içinde ortalaması 0, standart sapması 1 olan bir sütuna çevirir.

Üç örnek ve iki feature ile deneyelim. İkinci sütun birinciden on kat büyük değerler taşır:

X = np.array([[1.0, 10.0],              [2.0, 20.0],              [3.0, 60.0]])mu = X.mean(axis=0)       # her sütunun ortalamasıvar = X.var(axis=0)       # her sütunun varyansıX_hat = (X - mu) / np.sqrt(var + 1e-5)mu                        # → array([ 2., 30.])var                       # → array([  0.66666667, 466.66666667])X_hat.round(3)            # → array([[-1.225, -0.926],                          #          [ 0.   , -0.463],                          #          [ 1.225,  1.389]])X_hat.mean(axis=0).round(6)  # → array([0., 0.])X_hat.std(axis=0).round(3)   # → array([1., 1.])

axis=0 örnekler boyunca ortalama alır, yani sütun başına bir sayı verir. Normalizasyondan sonra iki sütun aynı ölçeğe gelir.

γ\gamma ve β\beta

Her feature’ı zorla 0 ortalama ve 1 standart sapmaya bağlamak ağı kısıtlar. Bu yüzden batch norm iki öğrenilebilir parametre ekler: ölçek γ\gamma ve kayma β\beta. Her feature’ın kendi γj\gamma_j ve βj\beta_j değeri vardır.

Yij=γjX^ij+βjY_{ij} = \gamma_j \hat{X}_{ij} + \beta_j

Ağ isterse γ=σ2+ϵ\gamma = \sqrt{\sigma^2 + \epsilon} ve β=μ\beta = \mu öğrenerek normalizasyonu tamamen geri alabilir. γ\gamma ve β\beta ağa ölçeği ve ortalamayı kendi seçme özgürlüğü verir. Başlangıçta γ=1\gamma = 1 ve β=0\beta = 0 alınır.

Şimdi tüm ileri geçişi bir fonksiyona koyalım. Önceki bloktaki X ile:

def batchnorm_forward(X, gamma, beta, eps=1e-5):    mu = X.mean(axis=0)    var = X.var(axis=0)    X_hat = (X - mu) / np.sqrt(var + eps)    return gamma * X_hat + betagamma = np.array([2.0, 1.0])beta = np.array([0.0, 5.0])Y = batchnorm_forward(X, gamma, beta)Y.round(3)                # → array([[-2.449,  4.074],                          #          [ 0.   ,  4.537],                          #          [ 2.449,  6.389]])Y.mean(axis=0).round(3)   # → array([0., 5.])Y.std(axis=0).round(3)    # → array([2., 1.])

Çıktının ortalaması β\beta, standart sapması γ\gamma olur. Bu fonksiyon Batch norm ileri geçişi problemindeki koddur.

Eğitimde batch, çıkarımda running statistics

Batch norm örneğin çıktısını aynı batch’teki öbür örneklere bağlar. Çıkarımda (inference) çoğu zaman tek bir örnek gelir; batch istatistiği anlamsız olur.

Bu yüzden eğitim sırasında ortalama ve varyansın hareketli ortalamasını tutarız. Bunlara running statistics denir. Çıkarımda batch yerine onları kullanırız:

# önceki bloktaki np, X, mu ve var ilemomentum = 0.9                # eski değerin payı (optimizer momentum'u değil)running_mean = np.zeros(2)running_var = np.ones(2)for _ in range(50):       # 50 eğitim adımı, aynı batch ile    running_mean = momentum * running_mean + (1 - momentum) * mu    running_var = momentum * running_var + (1 - momentum) * varx_new = np.array([[2.5, 30.0]])       # tek bir yeni örnek((x_new - running_mean) / np.sqrt(running_var + 1e-5)).round(3)# → array([[0.624, 0.007]])

Running statistics batch’in gerçek değerlerine yaklaşır (burada [1.99, 29.85]). Tek örnek bu istatistiklerle normalize edilir.

Layer’ın içindeki yeri

Batch norm çoğu zaman dense layer ile aktivasyon fonksiyonunun arasına girer: Z=XW+bZ = XW + \mathbf{b}, sonra normalizasyon, sonra ReLU. Normalizasyon ZZ‘nin ortalamasını zaten çıkardığı için ondan önceki bias gereksiz kalır.

Sıra şöyledir:

  1. Dense layer’ı hesapla: Z = X @ W.
  2. Batch norm uygula: Z_norm = batchnorm_forward(Z, gamma, beta).
  3. Aktivasyonu uygula: A = np.maximum(0, Z_norm).

Önceki bölümün 8 layer’lı ağıyla bu sırayı deneyelim. Weight’ler yine büyük ölçekte seçilmiş:

# önceki bloktaki np ve batchnorm_forward ilerng = np.random.default_rng(0)A = rng.normal(size=(256, 64))gamma, beta = np.ones(64), np.zeros(64)for layer in range(8):    W = rng.normal(size=(64, 64)) * 0.25    Z_norm = batchnorm_forward(A @ W, gamma, beta)   # dense, sonra batch norm    A = np.maximum(0, Z_norm)                        # sonra ReLU    print(layer, A.mean().round(3), A.std().round(3))# → 0 0.398 0.587# → 1 0.397 0.584# → 2 0.396 0.588# → 3 0.391 0.586# → 4 0.391 0.585# → 5 0.388 0.59# → 6 0.385 0.587# → 7 0.383 0.598

ReLU’dan sonra ortalama ve standart sapma her layer’da yaklaşık aynı kalır (0,38–0,40 ve 0,58–0,60). Weight ölçeği buna karışmaz.

Dikkat

Eğitim ve çıkarım modunu karıştırma. Çıkarımda batch istatistiği kullanırsan tek bir örneğin normalize edilmiş değeri 0 olur: ortalaması kendisidir, farkı 0’dır. Çıktı yalnızca β\beta‘dır ve anlamsızlaşır.

Kısa soruBatch norm'da ortalamayı ve varyansı sütun başına değil, satır başına hesaplarsan ne elde edersin?

Cevabı göster

Layer norm'u; her örnek kendi feature'ları üzerinden standartlaşır. Satır başına istatistik bir örneğin feature'ları üzerinden alınır. Bu layer norm'un işlemidir; batch norm sütun, yani feature başına istatistik ister.

Layer normalization

Layer normalization, her örneği kendi feature’ları üzerinden standartlaştırır.

Örnek başına normalize et

Layer norm istatistikleri satır başına hesaplar: eksen artık axis=1’dir. Hiçbir örnek batch’teki başkalarına bağlı olmaz.

μi=1d∑j=1dXij,σi2=1d∑j=1d(Xij−μi)2\mu_i = \frac{1}{d}\sum_{j=1}^{d} X_{ij}, \qquad \sigma_i^2 = \frac{1}{d}\sum_{j=1}^{d} (X_{ij} - \mu_i)^2

Standartlaştırma ve γ\gamma, β\beta aynıdır. Yalnızca ortalama ve varyans satırlardan gelir. İki örnek ve üç feature ile deneyelim:

def layernorm_forward(X, gamma, beta, eps=1e-5):    mu = X.mean(axis=1, keepdims=True)    # (N, 1): her örnek için bir ortalama    var = X.var(axis=1, keepdims=True)    X_hat = (X - mu) / np.sqrt(var + eps)    return gamma * X_hat + betaB = np.array([[1.0, 2.0, 3.0],              [10.0, 20.0, 30.0]])layernorm_forward(B, np.ones(3), np.zeros(3)).round(3)# → array([[-1.225,  0.   ,  1.225],#          [-1.225,  0.   ,  1.225]])

İki satır birbirinin 10 katıdır ve aynı çıktıyı verir. keepdims=True ortalamayı (N, 1) şeklinde tutar; böylece X ile yayınlanır (broadcasting). Bu fonksiyon Layer norm ileri geçişi problemindeki koddur.

Batch norm ile layer norm

Tek bir örnek geldiğinde fark en açık görünür:

# önceki bloktaki np, B, batchnorm_forward ve layernorm_forward ileone = B[:1]                                        # tek örnek: [[1., 2., 3.]]batchnorm_forward(one, np.ones(3), np.zeros(3))    # → array([[0., 0., 0.]])layernorm_forward(one, np.ones(3), np.zeros(3)).round(3)# → array([[-1.225,  0.   ,  1.225]])

Matristeki bir hücreye tıkla ve batch norm’un sütunu, layer norm’un satırı kullandığını izle. “1 örnek” düğmesi yukarıdaki bloğu yeniden üretir. Şekildeki matriste 4 satır vardır; ilk ikisi koddaki B’dir:

normalization_viz · axes

x · ham

f1f2f3

x̂ · feature başına

f1f2f3
−1,300
−0,605
−0,494
1,453
1,687
1,729
−0,382
−0,859
−0,576
0,229
−0,223
−0,659

seçili ö2, f3 · grup: f3 sütunu (4 örnek) · μ 9 · σ² 147,5 x̂ = (30 − 9) / √(147,5 + 10⁻⁵) = 1,729 çıktıda aynı grubun ortalaması 0, varyansı 1

Şunları dene:

  • “4 örnek” ile batchnorm seçip bir hücre seç: aynı sütundaki 4 değer birlikte normalize edilir.
  • “1 örnek” ile batchnorm’da çıktı 0 0 0, layernorm’da −1,225 0 1,225 olur.

Batch norm tek örnekte her şeyi 0 yapar. Layer norm örneğin kendi içindeki yapıyı korur. Karşılaştırma şöyledir:

Batch normLayer norm
İstatistikfeature başına, batch üzerindenörnek başına, feature’lar üzerinden
Eksenaxis=0axis=1
Batch boyutuna bağlı mıevethayır
Çıkarımdarunning statistics gerekireğitimle aynı hesap
Tipik kullanımMLP’lertransformer’lar

Transformer’lar layer norm kullanır, çünkü girdi uzunlukları ve batch boyutları değişir ve çıkarımda ek istatistik tutmak istemezler.

Kısa soruBir layer norm layer'ına tek bir örnek veriliyor. Çıktı nasıl olur?

Cevabı göster

Örneğin feature'ları kendi ortalaması 0 ve standart sapması 1 olacak şekilde ölçeklenir. Layer norm istatistiği örneğin kendi feature'larından hesaplar. Batch'te kaç örnek olduğu sonucu değiştirmez.

Overfitting

Overfitting yapan model eğitim verisinde iyi, yeni veride kötüdür.

Eğitim loss’u ile validation loss’u

Modelin yeni veride ne yaptığını görmek için veriyi ikiye ayırırız. Modeli eğitim kümesinde (training set) eğitiriz. Hiç görmediği validation set’te ölçeriz. Yeni veride iyi çalışmaya genelleme (generalization) denir.

Deneyi küçük tutalım. sin⁡(3x)\sin(3x) fonksiyonundan gürültülü 12 training ve 100 validation noktası üretelim. Derecesi 1, 3 ve 9 olan polinomları eğitim noktalarına uyduralım:

rng = np.random.default_rng(1)x_train = np.sort(rng.uniform(-1, 1, 12))x_val = np.sort(rng.uniform(-1, 1, 100))f = lambda x: np.sin(3 * x)y_train = f(x_train) + rng.normal(0, 0.2, 12)y_val = f(x_val) + rng.normal(0, 0.2, 100)def mse(y_hat, y):    return np.mean((y_hat - y) ** 2)for degree in [1, 3, 9]:    coefs = np.polyfit(x_train, y_train, degree)    train_loss = mse(np.polyval(coefs, x_train), y_train)    val_loss = mse(np.polyval(coefs, x_val), y_val)    print(degree, round(train_loss, 3), round(val_loss, 3))# → 1 0.23 0.27# → 3 0.022 0.049# → 9 0.004 2.862

Üç satır üç durumdur:

  • Derece 1: iki loss da yüksek. Model fonksiyonu yakalayamıyor; bu yetersiz öğrenmedir (underfitting).
  • Derece 3: iki loss da düşük ve birbirine yakın.
  • Derece 9: eğitim loss’u en düşük (0,004), validation loss’u en yüksek (2,862). Model gürültüyü de ezberledi.

Eğitim loss’u düşerken validation loss’u yükseliyorsa model overfitting yapıyordur. Eğitim loss’una bakarak bunu asla göremezsin.

Early stopping

En basit regularization, eğitimi erken durdurmaktır (early stopping). Her epoch’ta validation loss’u ölç. Validation loss’u artmaya başlayınca eğitimi durdur ve en iyi epoch’un weight’lerine dön.

Sonraki iki bölüm başka yollar sunar: weight’leri küçük tutmak (L2) ve nöronları rastgele kapatmak (dropout).

Kısa soruBir modelin eğitim loss'u 0,01, validation loss'u 1,5. Ne yapmak mantıklı olur?

Cevabı göster

Regularization eklemek ya da modeli küçültmek; model eğitim verisini ezberliyor. Büyük fark overfitting işaretidir. L2, dropout, early stopping, daha fazla veri ya da daha küçük model generalization'ı iyileştirir.

L2 penalty

L2 penalty, büyük weight’leri loss’a ekleyerek modeli küçük weight’lere iter.

Ceza ve gradyanı

Weight’ler ne kadar büyükse ceza o kadar artar. Ceza, weight’lerin karelerinin toplamıyla orantılıdır; λ\lambda cezanın gücünü seçer:

R(W)=λ2∑i,jWij2,∂R∂W=λWR(W) = \frac{\lambda}{2}\sum_{i,j} W_{ij}^2, \qquad \frac{\partial R}{\partial W} = \lambda W

Toplam loss Lveri+R(W)L_{\text{veri}} + R(W) olur. İkinci denklem cezanın gradyanıdır: kareden gelen 2, baştaki yarım ile sadeleşir. Her weight kendi değeriyle orantılı bir kuvvetle sıfıra çekilir.

Küçük bir matrisle hesaplayalım. Bu fonksiyon L2 cezası problemindeki koddur:

def l2_penalty(W, lam):    penalty = 0.5 * lam * np.sum(W ** 2)    dW = lam * W    return float(penalty), dWW = np.array([[3.0, -4.0],              [0.0, 12.0]])penalty, dW = l2_penalty(W, 0.1)penalty    # → 8.450000000000001   (0.05 * (9 + 16 + 0 + 144))dW         # → array([[ 0.3, -0.4],           #          [ 0. ,  1.2]])

Gradyanı sayısal olarak da doğrulayabiliriz. W00W_{00}‘ı biraz artır ve azalt:

# önceki bloktaki np, l2_penalty, W ve lam = 0.1 ileeps = 1e-6W_plus, W_minus = W.copy(), W.copy()W_plus[0, 0] += epsW_minus[0, 0] -= eps(l2_penalty(W_plus, 0.1)[0] - l2_penalty(W_minus, 0.1)[0]) / (2 * eps)# → 0.29999999995311555 (dW[0, 0] = 0.3 ile aynı)

Weight decay

Gradient descent adımına cezanın gradyanını eklersek güncelleme şu olur:

W←W−η(∂Lveri∂W+λW)=(1−ηλ) W−η ∂Lveri∂WW \leftarrow W - \eta\left(\frac{\partial L_{\text{veri}}}{\partial W} + \lambda W\right) = (1 - \eta\lambda)\,W - \eta\,\frac{\partial L_{\text{veri}}}{\partial W}

Sağdaki biçim her adımda weight’in (1−ηλ)(1 - \eta\lambda) ile çarpılıp biraz küçüldüğünü gösterir. Bu yüzden L2 penalty’ye ağırlık azaltma (weight decay) da denir.

Veri gradyanının 0 olduğu bir durumda yalnızca küçülmeyi görelim: w=5w = 5, η=0,1\eta = 0{,}1, λ=0,1\lambda = 0{,}1.

# önceki bloktaki np ilelr, lam = 0.1, 0.1w = np.array([5.0])for _ in range(3):    w = w - lr * (0 + lam * w)    # veri gradyanı 0    print(w)# → [4.95]# → [4.9005]# → [4.851495]5 * (1 - lr * lam) ** 3           # → 4.851495

Weight her adımda %1 küçülür. Veri gradyanı weight’i büyütmeye çalışırsa ceza ona direnir.

Overfitting yapan derece 9 polinomuna cezayı uygulayalım. AA, xx‘in 0’dan 9’a kadar kuvvetlerini sütun olarak tutan matristir (np.vander). Kapalı formda çözüm (A⊤A+λI) w=A⊤y(A^\top A + \lambda I)\,\mathbf{w} = A^\top \mathbf{y} denkleminden gelir:

# önceki bloktaki np, mse, x_train, y_train, x_val ve y_val iledef fit_ridge(x, y, degree, lam):    A = np.vander(x, degree + 1)    return np.linalg.solve(A.T @ A + lam * np.eye(degree + 1), A.T @ y)for lam in [0, 1e-3, 1e-1]:    w = fit_ridge(x_train, y_train, 9, lam)    train_loss = mse(np.vander(x_train, 10) @ w, y_train)    val_loss = mse(np.vander(x_val, 10) @ w, y_val)    print(lam, round(np.abs(w).max(), 1), round(train_loss, 3), round(val_loss, 3))# → 0 219.3 0.004 2.862# → 0.001 2.4 0.006 0.118# → 0.1 1.8 0.019 0.098

Aşağıdaki şekilde λ kaydırıcısını sürükleyerek tablodaki üç satırı kendin gör:

overfit_l2
uyumeğitimdoğrulamagerçek−101−101xeğitimdoğrulamaen iyi λ0,0010,010,1110010⁻⁶10⁻⁴10⁻²110MSEλ
Eğitim MSE0,004
Doğrulama MSE2,862
En büyük |w|219,3

kayıp = Σ(ŷ − y)² + λ · Σ wₖ² · λ = 0 ceza yok: 12 noktadan neredeyse tam geçiyor ve eğri uçlarda savruluyor

Şunları dene:

  • λ = 0’da doğrulama MSE’si 2,862’dir. λ’yı 0,001’e getirince 0,118’e düşer.
  • “Doğrulamaya göre en iyi λ’ya git” düğmesi λ = 0,1’e götürür; doğrulama MSE’si 0,098’dir.
  • λ büyüdükçe eğitim MSE’si de artar: 0,004’ten 0,019’a.

Sütunlar λ\lambda, en büyük weight, eğitim loss’u ve validation loss’udur. Küçük bir ceza en büyük weight’i 219’dan 2,4’e indirir. Eğitim loss’u biraz artar, validation loss’u 2,862’den 0,118’e düşer.

Dikkat

λ\lambda çok büyük olursa weight’ler sıfıra yapışır ve model underfitting yapar. λ\lambda bir hiperparametredir; validation loss’una bakarak seç. Bias’a genellikle ceza uygulanmaz; fit_ridge basitlik için sabit terimi de cezalandırır.

Kısa soruL2 penalty'nin gradyanı lambda çarpı w'dir. w = 10 ve lambda = 0,01 ise bu weight için cezanın gradyanı kaçtır?

Cevabı göster

0,1 0,01 · 10 = 0,1. Ceza her weight'i kendi değeriyle orantılı bir kuvvetle sıfıra çeker.

Dropout

Dropout, eğitimde nöronları rastgele kapatır; ağ tek bir nörona güvenemez.

Rastgele nöronları kapat

Her eğitim adımında her aktivasyon pp olasılıkla 0’a çekilir. pp düşürme olasılığıdır (PyTorch’taki gibi). Her adımda yeni bir maske çekilir, yani her adım başka bir alt ağı eğitir.

Maske, rastgele sayıların pp‘den büyük ya da eşit olduğu yerlerde True olur:

rng = np.random.default_rng(0)a = np.full((1, 10), 2.0)             # 10 aktivasyon, hepsi 2p = 0.5mask = rng.random(a.shape) >= p       # True: nöron açıkmask.astype(int)                      # → array([[1, 0, 0, 0, 1, 1, 1, 1, 1, 1]])a * mask                              # → array([[2., 0., 0., 0., 2., 2., 2., 2., 2., 2.]])

Bu hâliyle toplam aktivasyon ortalamada 1−p1 - p katına iner. Çıkarımda bütün nöronlar açık olacağı için eğitim ve çıkarım farklı ölçeklerde çalışır.

Ters ölçekleme

Ters dropout (inverted dropout) bunu eğitimde düzeltir: açık kalan aktivasyonları 1−p1 - p ile böleriz. Beklenen değer değişmez.

a~=a⊙m1−p\tilde{a} = \frac{a \odot m}{1 - p}

mm maskedir. Çıkarımda hiçbir şey yapılmaz: dropout kapalıdır ve aa aynen geçer. Bu fonksiyon Ters dropout problemindeki koddur:

def dropout(x, p, training, seed=0):    if not training:        return x.copy()                       # çıkarımda dropout kapalı    rng = np.random.default_rng(seed)    mask = rng.random(x.shape) >= p    return x * mask / (1 - p)dropout(a, 0.5, True)    # → array([[4., 0., 0., 0., 4., 4., 4., 4., 4., 4.]])dropout(a, 0.5, False)   # → array([[2., 2., 2., 2., 2., 2., 2., 2., 2., 2.]])

p kaydırıcısını oynat ve “Yeniden örnekle” ile yeni maskeler çek; “×100” ile yüz maske birden çekilir:

dropout_mask

Ters dropout · inverted dropout · a = 2,0 · 10 birim

a · aktivasyonm · maskea · ma · m / (1 − p)ortalama · n = 1 örnek2,012,04,04,002,00××0,002,00××0,002,00××0,002,012,04,04,002,012,04,04,002,012,04,04,002,012,04,04,002,012,04,04,002,012,04,04,00çizgi: a · halka: ölçeksiz ortalama

p = 0,5 · tutma olasılığı 1 − p = 0,5 · bu maskede 3 / 10 birim düştü n = 1 örnek · ölçekli ortalamanın a = 2 değerinden en büyük sapması 2,00 halka = ölçeksiz ortalama, (1 − p)·a = 1,0 değerine iner çıkarımda maske de ölçekleme de yok: çıktı doğrudan a

Şunları dene:

  • p = 0,5’te ilk maske koddaki maskedir: açık kalan değerler 2 yerine 4 olur.
  • “×100” ile çok maske çek: ters ölçeklemeyle ortalama 2’ye yaklaşır. Ölçeklemeyen halka ise (1 − p) · a değerinde, p = 0,5’te 1,0’da kalır.

Açık kalan her değer 2 yerine 4 oldu. seed maskeyi belirler: aynı seed aynı maskeyi verir. Bir eğitim döngüsünde her adıma farklı bir seed verirsin; varsayılan seed=0 her çağrıda aynı maskeyi üretir.

# önceki bloktaki np, a ve dropout ilenp.array_equal(dropout(a, 0.5, True, seed=0), dropout(a, 0.5, True, seed=0))   # → Truenp.array_equal(dropout(a, 0.5, True, seed=0), dropout(a, 0.5, True, seed=1))   # → False

Büyük bir matriste ortalamayı ölçelim:

# önceki bloktaki np ve dropout ilebig = np.ones((1000, 100))out = dropout(big, 0.5, True)out.mean().round(3)           # → 0.998   (1'e yakın: beklenen değer korunur)(out == 0).mean().round(3)    # → 0.501   (yaklaşık yarısı kapalı)naive = big * (np.random.default_rng(0).random(big.shape) >= 0.5)naive.mean().round(3)         # → 0.499   (bölme yok: ortalama yarıya düşer)

Ters ölçekleme eğitimde ortalamayı korur; böylece çıkarımda ekstra bir ölçekleme gerekmez.

Yöntemleri birleştirmek

Bu dersteki yöntemler birbirinin yerine geçmez; bir ağda birlikte kullanılabilir. Her biri başka bir sorunu hedefler:

YöntemNeyi düzeltirNerede çalışır
Batch norm, layer normaktivasyon ölçeğinin kaymasılayer’ların çıktısında
L2 penaltybüyük weight’lerloss’a eklenir
Dropoutnöronlar arası aşırı bağımlılıkeğitimde aktivasyonlarda
Early stoppinggereğinden uzun eğitimeğitim döngüsünde

λ\lambda ve pp birer hiperparametredir. Gücü validation loss’una bakarak seç; eğitim loss’una değil.

Dikkat

Dropout’u çıkarımda açık bırakma. Tahminler rastgele olur ve her çağrıda değişir. Eğitim modunda aç, çıkarım modunda kapat.

Kısa sorup = 0,2 ile ters dropout uygulanıyor. Açık kalan bir aktivasyon neyle çarpılır?

Cevabı göster

1 / 0,8 = 1,25 Aktivasyonların %80'i açık kalır. Bunları 1,25 ile çarpmak beklenen toplamı eski değerine getirir.

Özet

  • Derin bir ağda aktivasyonların ölçeği layer’dan layer’a büyüyebilir ya da küçülebilir. Normalizasyon her layer’ın çıktısını sabit bir ölçekte tutar.
  • Batch norm her feature’ı batch üzerinden standartlaştırır (axis=0), ardından γ\gamma ve β\beta ile ölçekler ve kaydırır. Çıkarımda running statistics kullanılır.
  • Layer norm her örneği kendi feature’ları üzerinden standartlaştırır (axis=1). Batch boyutuna bağlı olmadığı için transformer’larda kullanılır.
  • Overfitting, eğitim loss’u düşerken validation loss’unun yükselmesidir. L2 penalty weight’lerin karelerinin toplamıdır, λ\lambda ile ölçeklenir ve gradyanı λW\lambda W‘dir. Bu ceza weight’leri küçük tutar. Early stopping validation loss’u artınca eğitimi durdurur.
  • Dropout eğitimde aktivasyonları pp olasılıkla 0’lar ve kalanları 1−p1 - p‘ye böler. Çıkarımda dropout kapalıdır.

Terimler

TürkçeEnglish
normalizasyonnormalization
standartlaştırmastandardization
aşırı öğrenmeoverfitting
yetersiz öğrenmeunderfitting
genellemegeneralization
düzenlileştirmeregularization
doğrulama kümesivalidation set
eğitim kümesitraining set
L2 cezasıL2 penalty
ağırlık azaltmaweight decay
erken durdurmaearly stopping
çıkarıminference
ters dropoutinverted dropout

Şimdi sıra sende

  1. Batch norm ileri geçişiZorluk: OrtaBaşla →
  2. Layer norm ileri geçişiZorluk: OrtaBaşla →
  3. Ters dropoutZorluk: KolayBaşla →
  4. L2 cezasıZorluk: KolayBaşla →
İlk problem: Batch norm ileri geçişi →

Notların

Metinden bir bölüm seçip Not al'a basarak da ekleyebilirsin.

Geri bildirim

Tür