Ana içeriğe geç

Orta10 dkA — Sinir Ağı Temelleri

Dropout

Önkoşul:L1/L2 düzenlileştirme

Kanca

  1. derste ağırlıkların BÜYÜKLÜĞÜNÜ cezalayarak aşırı öğrenmeyi önledik (weight decay). Dropout, tamamen farklı bir strateji izliyor: ağırlıklara dokunmuyor, bunun yerine eğitim sırasında rastgele nöronları GEÇİCİ olarak “kapatıyor”.

Sezgi

Dropout, her eğitim adımında, her nöronu (belirli bir olasılıkla) geçici olarak SIFIRLAR. Bu, ağın tek bir nörona veya küçük bir nöron grubuna aşırı BAĞIMLI hale gelmesini engeller — her nöron, “komşularının her zaman orada olacağını” varsayamaz.

Dropout oranını ve normalizasyon sekmelerini dene — rastgele sıfırlamanın aktivasyon dağılımını nasıl değiştirdiğine bak (BatchNorm ve LayerNorm sekmeleri 23-24. derste işlenecek).

örnek 1, nöron 1: 1.62örnek 1, nöron 2: -1.61örnek 1, nöron 3: -0.24örnek 1, nöron 4: 2.54örnek 1, nöron 5: -2.71örnek 1, nöron 6: 0.491.6-1.6-0.22.5-2.70.5örnek 2, nöron 1: 1.52örnek 2, nöron 2: -4.74örnek 2, nöron 3: -0.70örnek 2, nöron 4: -2.90örnek 2, nöron 5: -1.48örnek 2, nöron 6: 1.811.5-4.7-0.7-2.9-1.51.8örnek 3, nöron 1: 3.05örnek 3, nöron 2: -1.23örnek 3, nöron 3: 1.28örnek 3, nöron 4: 3.72örnek 3, nöron 5: -2.20örnek 3, nöron 6: -1.013.1-1.21.33.7-2.2-1.0örnek 4, nöron 1: 8.08örnek 4, nöron 2: -3.72örnek 4, nöron 3: -2.05örnek 4, nöron 4: 1.54örnek 4, nöron 5: -1.27örnek 4, nöron 6: 0.838.1-3.7-2.11.5-1.30.8örnek 5, nöron 1: 1.58örnek 5, nöron 2: -2.72örnek 5, nöron 3: 0.19örnek 5, nöron 4: 3.33örnek 5, nöron 5: -2.81örnek 5, nöron 6: 0.221.6-2.70.23.3-2.80.2örnek 6, nöron 1: 2.63örnek 6, nöron 2: -1.93örnek 6, nöron 3: 0.74örnek 6, nöron 4: 2.87örnek 6, nöron 5: -2.52örnek 6, nöron 6: 0.112.6-1.90.72.9-2.50.1örnek 7, nöron 1: 3.00örnek 7, nöron 2: 2.61örnek 7, nöron 3: 2.35örnek 7, nöron 4: 0.72örnek 7, nöron 5: -4.93örnek 7, nöron 6: -0.393.02.62.40.7-4.9-0.4örnek 8, nöron 1: 0.22örnek 8, nöron 2: -1.74örnek 8, nöron 3: 0.60örnek 8, nöron 4: 1.51örnek 8, nöron 5: -0.99örnek 8, nöron 6: -0.400.2-1.70.61.5-1.0-0.4-8-6-4-20246800.050.100.15Aktivasyon değeriYoğunluk

Ham aktivasyonlar düzensiz: örnekten örneğe (satır) ve nörondan nörona (sütun) çok farklı büyüklük ve merkezlerde.

Mekanizma

Dropout’un en şaşırtıcı özelliği: AYNI girdi, AYNI ağırlıklarla bile, eğitim modunda HER SEFERİNDE farklı bir çıktı verebilir.

train() vs eval() modunda dropout

# Dropout, HER forward pass'te rastgele nöronları (olasılık p ile) SIFIRLAR.
# Bu yüzden aynı girdi bile, train() modunda her seferinde FARKLI bir çıktı verebilir.
torch.manual_seed(0)
ag = nn.Sequential(nn.Linear(4, 4), nn.Dropout(0.5))
x = torch.ones(1, 4)

ag.train()
print("train() modunda AYNI girdiyle 3 farklı forward pass:")
for _ in range(3):
    print(" ", ag(x).detach().numpy().round(3))

ag.eval()
print("\neval() modunda AYNI girdiyle 3 farklı forward pass:")
for _ in range(3):
    print(" ", ag(x).detach().numpy().round(3))

print("\ntrain() modunda çıktı HER SEFERİNDE değişiyor (rastgele maskeleme); eval() modunda SABİT -- dropout kapalı.")
train() modunda AYNI girdiyle 3 farklı forward pass:
  [[-0.635  1.256 -1.001 -0.   ]]
  [[-0.635  1.256 -1.001 -2.428]]
  [[-0.     0.    -1.001 -0.   ]]

eval() modunda AYNI girdiyle 3 farklı forward pass:
  [[-0.317  0.628 -0.5   -1.214]]
  [[-0.317  0.628 -0.5   -1.214]]
  [[-0.317  0.628 -0.5   -1.214]]

train() modunda çıktı HER SEFERİNDE değişiyor (rastgele maskeleme); eval() modunda SABİT -- dropout kapalı.

train() modunda 3 forward pass 3 farklı sonuç veriyor (rastgele hangi nöronların sıfırlandığına bağlı); eval() modunda ise 3’ü de BİREBİR AYNI. Çoğu kişi “model her zaman aynı girdiye aynı çıktıyı verir” sanır. Eğitim sırasında YANLIŞ, çünkü dropout kasıtlı olarak rastgelelik ekliyor — bu da ağın SAĞLAM (dayanıklı) örüntüler öğrenmesini zorluyor.

Matematik

Dropout ve 'inverted dropout' ölçeklemesi
hi=mihi1pmiBernoulli(1p)h'_i = \frac{m_i \cdot h_i}{1-p} \qquad m_i \sim \text{Bernoulli}(1-p)
SembolAnlamı
ppDropout oranı — bir nöronun sıfırlanma OLASILIĞI
mim_iO nöron için rastgele maske: 1p1-p olasılıkla 1, pp olasılıkla 0
1/(1p)1/(1-p)“Inverted dropout” ölçeklemesi — kalan nöronları büyüterek beklenen TOPLAMI korur

Bu ölçekleme olmasaydı, eğitim sırasında (dropout aktifken) ve değerlendirmede (dropout kapalıyken) katmanın ÇIKTI BÜYÜKLÜĞÜ sistematik olarak farklı olurdu.

Kod

  1. dersteki AYNI küçük/gürültülü veri setinde, bu kez dropout’u deneyelim:

Dropout, aşırı öğrenmeyi nasıl önler

# 21. dersteki AYNI küçük/gürültülü veri setinde, weight_decay yerine dropout deneyelim.
N_egitim = 15
x_egitim = torch.linspace(-3, 3, N_egitim).unsqueeze(1)
y_egitim = torch.sin(x_egitim) + torch.randn(N_egitim, 1) * 0.3

N_test = 100
x_test = torch.linspace(-3, 3, N_test).unsqueeze(1)
y_test = torch.sin(x_test)

def ag_olustur(dropout_orani):
    torch.manual_seed(1)
    katmanlar = [nn.Linear(1, 64), nn.Tanh()]
    if dropout_orani > 0:
        katmanlar.append(nn.Dropout(dropout_orani))
    katmanlar += [nn.Linear(64, 64), nn.Tanh()]
    if dropout_orani > 0:
        katmanlar.append(nn.Dropout(dropout_orani))
    katmanlar.append(nn.Linear(64, 1))
    return nn.Sequential(*katmanlar)

def egit(dropout_orani, epochs=3000, lr=0.01):
    ag = ag_olustur(dropout_orani)
    optimizer = torch.optim.Adam(ag.parameters(), lr=lr)
    for _ in range(epochs):
        ag.train()  # dropout AKTİF
        optimizer.zero_grad()
        tahmin = ag(x_egitim)
        kayip = torch.mean((tahmin - y_egitim) ** 2)
        kayip.backward()
        optimizer.step()
    ag.eval()  # dropout KAPALI -- değerlendirmede rastgelelik istenmez
    with torch.no_grad():
        egitim_kaybi = torch.mean((ag(x_egitim) - y_egitim) ** 2).item()
        test_kaybi = torch.mean((ag(x_test) - y_test) ** 2).item()
    return egitim_kaybi, test_kaybi

print(f"\n{'Dropout oranı':<16} {'Eğitim kaybı':<14} {'Test kaybı':<12}")
sonuclar = {}
for p in [0.0, 0.1, 0.3, 0.5]:
    et, tt = egit(p)
    sonuclar[p] = (et, tt)
    print(f"{p:<16} {et:<14.4f} {tt:<12.4f}")

print("\ndropout=0: eğitim kaybı sıfıra çok yakın (ezber). dropout=0.3: test kaybı EN DÜŞÜK -- 21. dersteki weight_decay'e benzer bir 'tatlı nokta'.")
print("dropout=0.5: eğitim kaybı belirgin arttı -- çok fazla nöron sıfırlanınca ağ yeterince öğrenemiyor.")

Dropout oranı    Eğitim kaybı   Test kaybı  
0.0              0.0002         0.0715      
0.1              0.0175         0.0515      
0.3              0.0398         0.0624      
0.5              0.0813         0.0621      

dropout=0: eğitim kaybı sıfıra çok yakın (ezber). dropout=0.3: test kaybı EN DÜŞÜK -- 21. dersteki weight_decay'e benzer bir 'tatlı nokta'.
dropout=0.5: eğitim kaybı belirgin arttı -- çok fazla nöron sıfırlanınca ağ yeterince öğrenemiyor.

dropout=0’da eğitim kaybı neredeyse sıfır (ezber) ama test kaybı yüksek (0.0715). dropout=0.1’de test kaybı 0.0515’e düşüyor — 21. dersteki weight_decay’e çok benzer bir “tatlı nokta” hikayesi.

Ölçeklemenin doğruluğunu kontrol edelim

# nn.Dropout, kalan (sıfırlanmayan) değerleri 1/(1-p) ile ÖLÇEKLER -- neden?
p = 0.5
katman = nn.Dropout(p)
katman.train()
girdi = torch.ones(10000)  # büyük bir örneklemle ortalamayı test edelim
cikti = katman(girdi)
print(f"\nGirdi ortalaması: {girdi.mean().item():.4f}")
print(f"Dropout(p=0.5) SONRASI çıktı ortalaması: {cikti.mean().item():.4f}")
print("İkisi de ~1.0 -- 'inverted dropout' ölçeklemesi sayesinde ortalama korunuyor.")
print("Bu sayede train() ve eval() arasında modelin çıktı BÜYÜKLÜĞÜ tutarlı kalıyor.")

Girdi ortalaması: 1.0000
Dropout(p=0.5) SONRASI çıktı ortalaması: 0.9964
İkisi de ~1.0 -- 'inverted dropout' ölçeklemesi sayesinde ortalama korunuyor.
Bu sayede train() ve eval() arasında modelin çıktı BÜYÜKLÜĞÜ tutarlı kalıyor.
Dropout oranına karşı eğitim ve test kaybını gösteren grafik; eğitim kaybı sürekli artarken test kaybı önce düşüp sonra tekrar yükseliyor.
Dropout=0'da aşırı öğrenme; orta oranlarda test kaybı en düşük; yüksek oranlarda eğitim kaybı da belirgin artıyor (yetersiz öğrenme).

Nerede işe yarar

Dropout, özellikle tam bağlantılı (fully-connected) katmanlarda yaygın kullanılır:

  • nn.Dropout(p), genelde aktivasyon fonksiyonundan SONRA eklenir. Tipik oranlar 0.1-0.5 arası.
  • model.train() ve model.eval() çağırmayı UNUTMAMAK kritiktir — eval() olmadan değerlendirme sırasında bile rastgelelik devam eder, bu da tutarsız sonuçlara yol açar.
  • CNN’lerde (bir sonraki bölüm) dropout daha az yaygındır — konvolüsyon katmanlarının kendine has parametre paylaşımı, zaten bir miktar düzenlileştirme sağlar.

Bu 3 hatayı yaparsın:

  1. Değerlendirme (inference) öncesi model.eval() çağırmayı unutmak — bu, üretim ortamında SESSİZCE tutarsız/rastgele tahminlere yol açar.
  2. Dropout oranını çok yükseğe (örn. 0.7-0.8) ayarlayıp ağın yeterince öğrenememesine neden olmak.
  3. Çok küçük ağlarda (az parametre) agresif dropout kullanmak — zaten sınırlı kapasiteyi daha da kısıtlar.

Kendini test et

1. Notebook'ta train() modunda aynı girdiye 3 farklı forward pass neden 3 FARKLI sonuç verdi?
  1. Kod hatalıydı
  2. Dropout, HER forward pass'te rastgele farklı bir nöron alt kümesini sıfırlıyor -- bu yüzden aynı girdi bile farklı bir "etkin ağ" üzerinden geçiyor (doğru cevap)
  3. Ağırlıklar her seferinde değişiyor
  4. PyTorch rastgele hata üretiyor

Neden: Her forward pass'te YENİ bir rastgele maske (m_i) örneklenir; hangi nöronların sıfırlandığı her seferinde değiştiği için, aynı girdi ve aynı ağırlıklarla bile çıktı değişir.

2. 'Inverted dropout' ölçeklemesi (kalan değerleri 1/(1-p) ile çarpmak) neden gereklidir?
  1. Hesaplamayı hızlandırmak için
  2. Nöronların bir kısmı sıfırlandığında toplam aktivasyon büyüklüğü küçülür; bu ölçekleme, beklenen toplamı koruyarak train/eval arasında tutarlılık sağlar (doğru cevap)
  3. Gradyanları büyütmek için
  4. Sadece görselleştirme amaçlı

Neden: Nöronların p oranı sıfırlandığında kalan aktivasyonların toplamı da küçülür; 1/(1-p) ile ölçekleme bu kaybı telafi ederek katmanın beklenen çıktı büyüklüğünü hem train hem eval modunda tutarlı tutar.

3. model.eval() çağırmayı unutmanın pratikte en büyük riski nedir?
  1. Model daha yavaş çalışır
  2. Dropout (ve batch normalization gibi diğer katmanlar) train modunda kalır -- bu da değerlendirme/üretim sırasında SESSİZCE tutarsız, rastgele tahminlere yol açar (doğru cevap)
  3. Bellek hatası oluşur
  4. Hiçbir etkisi yoktur

Neden: eval() çağrılmazsa dropout aktif kalmaya devam eder ve her tahmin farklı bir rastgele maskeyle üretilir -- bu da modelin üretimde GÜVENİLMEZ, tekrarlanamaz sonuçlar vermesine yol açan sessiz bir hatadır.

Özet

Özet

  • Dropout, eğitim sırasında her nöronu belirli bir olasılıkla geçici olarak sıfırlar.
  • "Inverted dropout", kalan nöronları 1/(1-p) ile ölçekleyerek beklenen çıktı büyüklüğünü korur.
  • train() modunda dropout AKTİF (rastgele); eval() modunda KAPALI (deterministik).
  • model.eval() çağırmayı unutmak, üretimde tutarsız tahminlere yol açan yaygın bir hatadır.
  • Dropout oranı da bir "tatlı nokta" gerektirir -- weight decay'deki (21. ders) gibi çok azı yetersiz, çok fazlası zararlıdır.
Sonraki adım: Batch normalization →