Ana içeriğe geç

Orta10 dkA — Sinir Ağı Temelleri

L1/L2 düzenlileştirme

Önkoşul:Ağırlık ilklendirme

Kanca

Makine Öğrenmesi kategorisinde Ridge/Lasso ile L1/L2 cezalarını klasik regresyon bağlamında görmüştük. Sinir ağlarında bu fikirler AYNI matematikle ama farklı bir isim ve farklı bir amaçla karşımıza çıkıyor: weight decay, aşırı öğrenmeyi önlemenin en temel yollarından biri.

Sezgi

Düzenlileştirme (regularization), kayıp fonksiyonuna ağırlıkların BÜYÜKLÜĞÜNÜ cezalandıran bir terim ekler. Fikir basit: büyük ağırlıklar genelde “ezberlemenin” işaretidir — model, veri setindeki gürültüye bile aşırı hassas hale gelmiştir. Ağırlıkları küçük tutmaya ZORLAMAK, modeli daha “genel” bir çözüme itiyor.

Mekanizma

Önce ML kategorisindeki L1/L2 farkını hızlıca hatırlayalım:

L1 (Lasso) vs L2 (Ridge) hatırlatması

# ML kategorisindeki Ridge/Lasso dersinde L1 (Lasso) ve L2 (Ridge) cezalarını görmüştük.
# Hızlı bir hatırlatma: L1, gereksiz özellikleri TAM SIFIRA çekerken, L2 küçültür ama sıfırlamaz.
np.random.seed(0)
N = 100
X = np.random.randn(N, 5)
gercek_w = np.array([3.0, -2.0, 0.0, 0.0, 0.0])  # sadece ilk 2 özellik GERÇEKTEN önemli
y = X @ gercek_w + np.random.randn(N) * 0.1

lasso = Lasso(alpha=0.1).fit(X, y)
ridge = Ridge(alpha=1.0).fit(X, y)
print("Gerçek ağırlıklar:", gercek_w)
print("Lasso (L1):        ", np.round(lasso.coef_, 4))
print("Ridge (L2):        ", np.round(ridge.coef_, 4))
print("\nLasso, önemsiz 3 özelliği TAM SIFIRA çekiyor -- Ridge küçültüyor ama sıfırlamıyor.")
print("Sinir ağlarında bu tür 'özellik seçimi' nadiren hedeftir -- asıl mesele AŞIRI ÖĞRENMEYİ önlemek.")
Gerçek ağırlıklar: [ 3. -2.  0.  0.  0.]
Lasso (L1):         [ 2.9079 -1.8922  0.     -0.     -0.    ]
Ridge (L2):         [ 2.9741e+00 -1.9724e+00  2.0600e-02 -6.0000e-04 -1.1200e-02]

Lasso, önemsiz 3 özelliği TAM SIFIRA çekiyor -- Ridge küçültüyor ama sıfırlamıyor.
Sinir ağlarında bu tür 'özellik seçimi' nadiren hedeftir -- asıl mesele AŞIRI ÖĞRENMEYİ önlemek.

Lasso (L1), önemsiz özellikleri TAM sıfıra çekiyor; Ridge (L2) küçültüyor ama sıfırlamıyor. Sinir ağlarında ise asıl mesele “hangi özellik önemli” değil — aşırı öğrenmeyi önlemek. Küçük, gürültülü bir veri setinde büyük bir ağ eğitelim:

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

# Sinir ağlarında L2, genelde 'weight decay' olarak optimizer İÇİNDE uygulanır.
# Küçük, gürültülü bir veri setinde büyük bir ağ -- aşırı öğrenmeye MÜKEMMEL bir aday.
torch.manual_seed(0)
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():
    torch.manual_seed(1)
    return nn.Sequential(nn.Linear(1, 64), nn.Tanh(), nn.Linear(64, 64), nn.Tanh(), nn.Linear(64, 1))

def egit(weight_decay, epochs=2000, lr=0.01):
    ag = ag_olustur()
    optimizer = torch.optim.Adam(ag.parameters(), lr=lr, weight_decay=weight_decay)
    for _ in range(epochs):
        optimizer.zero_grad()
        tahmin = ag(x_egitim)
        kayip = torch.mean((tahmin - y_egitim) ** 2)
        kayip.backward()
        optimizer.step()
    egitim_kaybi = torch.mean((ag(x_egitim) - y_egitim) ** 2).item()
    test_kaybi = torch.mean((ag(x_test) - y_test) ** 2).item()
    agirlik_normu = sum(p.abs().sum().item() for p in ag.parameters())
    return egitim_kaybi, test_kaybi, agirlik_normu

print(f"\n{'weight_decay':<14} {'Eğitim kaybı':<14} {'Test kaybı':<12} {'Ağırlık normu':<14}")
sonuclar = {}
for wd in [0.0, 0.001, 0.01, 0.1]:
    et, tt, an = egit(wd)
    sonuclar[wd] = (et, tt, an)
    print(f"{wd:<14} {et:<14.4f} {tt:<12.4f} {an:<14.1f}")

print("\nwd=0: eğitim kaybı NEREDEYSE SIFIR (ezberlemiş) ama ağırlık normu devasa (666.1) -- klasik aşırı öğrenme.")
print("wd=0.01: eğitim kaybı biraz arttı ama TEST kaybı en düşük -- bu, düzenlileştirmenin 'tatlı noktası'.")
print("wd=0.1: eğitim kaybı çok arttı (yetersiz öğrenme) -- aşırı düzenlileştirme yeni bir sorun yaratıyor.")

weight_decay   Eğitim kaybı   Test kaybı   Ağırlık normu 
0.0            0.0000         0.0696       666.1         
0.001          0.0106         0.0596       174.0         
0.01           0.0719         0.0165       84.8          
0.1            0.2257         0.0675       31.5          

wd=0: eğitim kaybı NEREDEYSE SIFIR (ezberlemiş) ama ağırlık normu devasa (666.1) -- klasik aşırı öğrenme.
wd=0.01: eğitim kaybı biraz arttı ama TEST kaybı en düşük -- bu, düzenlileştirmenin 'tatlı noktası'.
wd=0.1: eğitim kaybı çok arttı (yetersiz öğrenme) -- aşırı düzenlileştirme yeni bir sorun yaratıyor.

weight_decay=0 iken eğitim kaybı NEREDEYSE SIFIR (ağ, 15 noktayı ezberlemiş) ama ağırlık normu 666.1 — devasa. weight_decay=0.01’de eğitim kaybı biraz artıyor ama TEST kaybı en düşük noktaya (0.0165) iniyor. Çoğu kişi “düzenlileştirme ne kadar güçlü olursa o kadar iyi” sanır. Yanlış, çünkü weight_decay=0.1’de eğitim kaybı da test kaybı da KÖTÜLEŞİYOR — model artık yetersiz öğreniyor.

Matematik

Düzenlileştirilmiş kayıp fonksiyonu
Ldu¨zenli=Lorijinal+λiwiL1\mathcal{L}_{\text{düzenli}} = \mathcal{L}_{\text{orijinal}} + \lambda \underbrace{\sum_i |w_i|}_{\text{L1}}veya\text{veya}Ldu¨zenli=Lorijinal+λiwi2L2\mathcal{L}_{\text{düzenli}} = \mathcal{L}_{\text{orijinal}} + \lambda \underbrace{\sum_i w_i^2}_{\text{L2}}
SembolAnlamı
λ\lambda (lambda)Düzenlileştirme gücü — 0 ise ceza yok, büyüdükçe ağırlıklar daha çok baskılanır
L1 cezasıAğırlıkların MUTLAK DEĞERLERİNİN toplamı — sıfıra çeken (seyreklik) etkisi
L2 cezasıAğırlıkların KARELERİNİN toplamı — büyük ağırlıkları orantısız cezalandırır, ama sıfırlamaz

PyTorch’ta L2, weight_decay parametresiyle optimizer’ın İÇİNDE, ayrı bir loss terimi yazmaya GEREK KALMADAN uygulanır.

Matematik tazelemeVektör işlemleri ve norm

Kod

PyTorch’ta bu ne kadar basit, görelim:

weight_decay tek satır

# PyTorch'ta weight_decay, optimizer'a TEK bir parametreyle eklenir -- L2 cezasını elle
# loss'a eklemeye GEREK YOK, optimizer bunu otomatik yapar.
print("\ntorch.optim.Adam(model.parameters(), lr=0.01, weight_decay=0.01)")
print("Bu satır, her güncellemede ağırlıklara otomatik olarak w -= lr * weight_decay * w ekler.")
print("Elle eklemek isteseydik: kayip = kayip + weight_decay * sum(w**2 for w in agirliklar)")

torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=0.01)
Bu satır, her güncellemede ağırlıklara otomatik olarak w -= lr * weight_decay * w ekler.
Elle eklemek isteseydik: kayip = kayip + weight_decay * sum(w**2 for w in agirliklar)
weight_decay değerine 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.
weight_decay=0'da aşırı öğrenme (düşük eğitim, yüksek test kaybı); orta değerde tatlı nokta; çok yüksek değerde yetersiz öğrenme.

Nerede işe yarar

Weight decay, pratikte en yaygın kullanılan düzenlileştirme tekniklerinden biridir:

  • PyTorch’ta torch.optim.Adam(params, lr=..., weight_decay=...) ile tek parametre. Tipik değerler 1e-5 ile 1e-2 arası.
  • L2 (weight decay), sinir ağlarında L1’den ÇOK daha yaygın kullanılır — ağırlıkları tam sıfırlamak (seyreklik) nadiren hedeftir; amaç sadece büyümelerini sınırlamaktır.
  • 22-24. derste (Dropout, Batch/Layer normalization) başka düzenlileştirme tekniklerini göreceğiz — weight decay bunlarla BİRLİKTE kullanılabilir.

Bu 3 hatayı yaparsın:

  1. weight_decay’i hiç kullanmayıp modelin küçük veri setlerinde ezberlediğini fark etmemek.
  2. weight_decay’i çok yükseğe ayarlayıp modelin yetersiz öğrenmesine (underfitting) neden olmak — notebook’taki wd=0.1 örneği gibi.
  3. Adam ile weight_decay kullanırken “AdamW” adlı düzeltilmiş versiyonun varlığından habersiz olmak — klasik Adam’da weight_decay’in matematiği hafifçe farklı davranır (NLP kategorisinde bu detaya döneceğiz).

Kendini test et

1. Notebook'ta weight_decay=0 iken eğitim kaybı neredeyse sıfırken test kaybının (0.0696) yüksek kalması neyi gösteriyor?
  1. Kod hatası
  2. Model, eğitim verisini EZBERLEMİŞ (aşırı öğrenme) -- eğitim verisinde mükemmel ama görmediği veride kötü performans gösteriyor (doğru cevap)
  3. Model hiç öğrenmedi
  4. Test verisi hatalıydı

Neden: Eğitim kaybının neredeyse sıfır ama test kaybının yüksek olması, klasik aşırı öğrenme belirtisidir -- model, eğitim verisindeki GÜRÜLTÜYE bile uyum sağlamış (büyük ağırlık normu 666.1 bunun kanıtı).

2. weight_decay değerini çok yükseğe (örn. 0.1) ayarlamanın notebook'taki sonucu neydi?
  1. Test kaybı sürekli düşmeye devam etti
  2. Hem eğitim hem test kaybı KÖTÜLEŞTİ -- model artık yetersiz öğreniyor (underfitting) (doğru cevap)
  3. Hiçbir etkisi olmadı
  4. Sadece eğitim hızını etkiledi

Neden: wd=0.1'de eğitim kaybı 0.2257'ye (en yüksek), test kaybı da 0.0675'e çıktı -- aşırı düzenlileştirme, modelin veri deki gerçek örüntüyü bile öğrenmesini engelliyor.

3. Sinir ağlarında L2 (weight decay), L1'den neden daha yaygın kullanılır?
  1. L1 matematiksel olarak yanlıştır
  2. Sinir ağlarında amaç genelde "hangi ağırlık önemsiz, onu tam sıfırla" (seyreklik) değil, sadece ağırlıkların büyümesini sınırlamaktır -- L2 bunun için daha uygundur (doğru cevap)
  3. L2 her zaman daha hızlı hesaplanır
  4. L1, PyTorch'ta desteklenmez

Neden: L1'in seyreklik (bazı ağırlıkları tam sıfırlama) etkisi klasik regresyonda özellik seçimi için değerlidir, ama sinir ağlarında genelde istenen şey sadece ağırlık büyüklüklerini kontrol altında tutmaktır -- bu da L2'nin doğal alanıdır.

Özet

Özet

  • Düzenlileştirme, kayıp fonksiyonuna ağırlık büyüklüğünü cezalandıran bir terim ekleyerek aşırı öğrenmeyi önler.
  • L1 (Lasso), ağırlıkları tam sıfıra çekebilir (seyreklik); L2 (Ridge/weight decay) küçültür ama sıfırlamaz.
  • Sinir ağlarında L2, weight_decay parametresiyle optimizer içinde uygulanır ve L1'den çok daha yaygındır.
  • Düzenlileştirme gücü (λ / weight_decay) bir "tatlı nokta" gerektirir -- çok azı aşırı öğrenmeyi önlemez, çok fazlası yetersiz öğrenmeye yol açar.
  • Bir sonraki derste (Dropout), ağırlık büyüklüğünü değil, ağın YAPISINI hedefleyen farklı bir düzenlileştirme tekniği göreceğiz.
Sonraki adım: Dropout →