Ana içeriğe geç

Orta9 dkA — Sinir Ağı Temelleri

Patlayan gradyan ve clipping

Önkoşul:Adam

Kanca

  1. derste ağırlık w=1’ken sigmoid’in gradyanının katman katman KAYBOLDUĞUNU gördük. Şimdi aynanın diğer yüzüne bakalım: ağırlık 1’den BÜYÜKSE, gradyan katman katman tam tersi yönde — PATLAR.

Sezgi

Patlayan gradyan, geri yayılımda her katmanda çarpılan değerler 1’den büyükse, gradyanın katman sayısıyla ÜSTEL olarak büyümesidir. Kaybolan gradyanın “sinyal hiç ulaşmıyor” sorunu yerine, burada “sinyal o kadar büyüyor ki güncelleme anlamsızlaşıyor” sorunu var.

Mekanizma

  1. dersteki AYNI deney kurulumunu kullanalım — ama bu kez ağırlığı w=1 yerine w=1.5 yapalım:

w=1.5 ile gradyan patlaması

# 5. derste ağırlık w=1 iken sigmoid'in KAYBOLAN gradyanını görmüştük.
# Şimdi tam TERSİ: ağırlık 1'den BÜYÜKSE (w=1.5), gradyan katman katman PATLAR.
def derin_ag_olustur(katman_sayisi, agirlik):
    katmanlar = []
    for _ in range(katman_sayisi):
        katman = nn.Linear(1, 1, bias=False)
        with torch.no_grad():
            katman.weight.fill_(agirlik)
        katmanlar.append(katman)
    return nn.Sequential(*katmanlar)

print(f"{'Katman sayısı':<16} {'İlk katman gradyanı':<20}")
for katman_sayisi in [1, 5, 10, 15, 20]:
    ag = derin_ag_olustur(katman_sayisi, agirlik=1.5)
    x = torch.tensor([[1.0]], requires_grad=True)
    y = ag(x)
    y.backward()
    print(f"{katman_sayisi:<16} {ag[0].weight.grad.item():<20.4e}")

print("\nw=1.5 (sadece %50 büyük) ile 20 katmanda gradyan 2216 KATINA çıkıyor -- vadi problemi 5. dersin AYNASI.")
Katman sayısı    İlk katman gradyanı 
1                1.0000e+00          
5                5.0625e+00          
10               3.8443e+01          
15               2.9193e+02          
20               2.2168e+03          

w=1.5 (sadece %50 büyük) ile 20 katmanda gradyan 2216 KATINA çıkıyor -- vadi problemi 5. dersin AYNASI.

Sadece %50 büyük bir ağırlıkla (1.5 vs 1.0), 20 katmanlı bir ağda gradyan 2216 KATINA çıkıyor. Çoğu kişi “ağırlıklar 1’e yakınsa sorun olmaz” sanır. Yanlış, çünkü çarpımlar katman sayısıyla ÜSTEL büyür — küçük bir sapma bile devasa bir sonuca dönüşür.

Matematik

Patlayan gradyan ve kırpma (clipping)
Lw(1)wL\left\|\frac{\partial \mathcal{L}}{\partial w^{(1)}}\right\| \approx \|w\|^{L}gkırpılmıs¸=gmin(1,τg)g_{\text{kırpılmış}} = g \cdot \min\left(1, \frac{\tau}{\|g\|}\right)
SembolAnlamı
wL\|w\|^LLL katmanlı bir ağda, gradyanın büyüklüğü yaklaşık olarak ağırlığın LL. kuvvetiyle orantılıdır
τ\tau (tau)Kırpma tavanı — gradyan normunun izin verilen maksimum büyüklüğü
min(1,τ/g)\min(1, \tau/\|g\|)Gradyan normu tavanı AŞARSA küçültme oranı; aşmıyorsa 1 (değişiklik yok)

Kırpma, gradyanın YÖNÜNÜ korur — sadece büyüklüğünü sınırlar. Bu yüzden “hangi yöne gidileceği” bilgisi kaybolmaz, sadece adım boyutu makul kalır.

Kod

Bu patlamanın PRATİKTE neden tehlikeli olduğunu, sonra PyTorch’un hazır çözümünü görelim:

Tek güncelleme, anlamsız bir ağırlık

# Patlayan gradyan, tek bir kötü güncellemeyle ağırlıkları anlamsız (hatta NaN) değerlere savurabilir.
w = torch.tensor(0.5, requires_grad=True)
ag_20 = derin_ag_olustur(20, agirlik=1.5)
x = torch.tensor([[1.0]])
y = ag_20(x)
y.backward()
gradyan = ag_20[0].weight.grad.item()
ogrenme_orani = 0.01
yeni_agirlik = ag_20[0].weight.item() - ogrenme_orani * gradyan
print(f"\nAğırlık {ag_20[0].weight.item():.3f} idi, TEK bir güncellemeyle {yeni_agirlik:.3f} oldu!")
print("Öğrenme oranı 0.01 gibi KÜÇÜK bir değer olsa bile, gradyan bu kadar büyükse ağırlık anlamsız bir yere savrulabilir.")

Ağırlık 1.500 idi, TEK bir güncellemeyle -20.668 oldu!
Öğrenme oranı 0.01 gibi KÜÇÜK bir değer olsa bile, gradyan bu kadar büyükse ağırlık anlamsız bir yere savrulabilir.

Öğrenme oranı küçük (0.01) olsa bile, ağırlık TEK adımda 1.5’ten -20.668’e savruluyor — bu, modelin o ana kadar öğrendiği her şeyi silebilir.

torch.nn.utils.clip_grad_norm_ ile çözüm

# Çözüm: gradient clipping -- gradyanın NORMUNU (büyüklüğünü) bir tavana sabitlemek.
ag_20_clip = derin_ag_olustur(20, agirlik=1.5)
x = torch.tensor([[1.0]])
y = ag_20_clip(x)
y.backward()

norm_oncesi = torch.nn.utils.get_total_norm([p.grad for p in ag_20_clip.parameters()])
gradyan_normu = torch.nn.utils.clip_grad_norm_(ag_20_clip.parameters(), max_norm=5.0)
norm_sonrasi = torch.nn.utils.get_total_norm([p.grad for p in ag_20_clip.parameters()])

print(f"\nKırpma ÖNCESİ toplam gradyan normu: {norm_oncesi.item():.1f}")
print(f"Kırpma SONRASI toplam gradyan normu: {norm_sonrasi.item():.4f}")
print(f"İlk katmanın gradyanı: {ag_20_clip[0].weight.grad.item():.4f} (kırpmadan önce {ag_20[0].weight.grad.item():.1f} idi)")
print("clip_grad_norm_, TÜM gradyan vektörünü aynı ORANLA küçültür -- yönü korur, sadece büyüklüğü sınırlar.")

Kırpma ÖNCESİ toplam gradyan normu: 9914.0
Kırpma SONRASI toplam gradyan normu: 5.0000
İlk katmanın gradyanı: 1.1180 (kırpmadan önce 2216.8 idi)
clip_grad_norm_, TÜM gradyan vektörünü aynı ORANLA küçültür -- yönü korur, sadece büyüklüğü sınırlar.

Kırpma öncesi toplam gradyan normu 9914.0 iken, kırpma sonrası tam olarak 5.0000 — tavanı aştığı için oranla küçültüldü.

Katman sayısına karşı ilk katmanın gradyanını log ölçekte gösteren grafik; gradyan katman arttıkça üstel olarak büyüyor, kesikli çizgi kırpma tavanını gösteriyor.
w=1.5 ile katman sayısı arttıkça gradyan üstel olarak patlıyor (log eksende düz bir çizgi bu yüzden) -- kırpma tavanı, bu patlamayı pratik bir sınıra sabitler.

Nerede işe yarar

Gradient clipping, özellikle RNN’lerde (NLP kategorisinde göreceğiz) ve çok derin ağlarda standart bir güvenlik önlemidir:

  • torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=...), backward() sonrası, optimizer.step() öncesi çağrılır.
  • max_norm tipik olarak 1.0-5.0 arasında seçilir — probleme göre deneysel olarak ayarlanır.
  • Kırpma, patlamayı ÖNLEMEZ, sonucunu SINIRLAR — kök neden (kötü ağırlık ilklendirme, çok yüksek öğrenme oranı) hâlâ ayrıca ele alınmalıdır (20. derste ağırlık ilklendirmeyi göreceğiz).

Bu 3 hatayı yaparsın:

  1. Kaybın aniden NaN olduğunu görüp mimariyi değiştirmeye başlamak — önce gradient clipping eklemeyi dene, çoğu zaman kök neden budur.
  2. Clipping’i optimizer.step()‘TEN SONRA çağırmak — kırpma, backward() ile step() ARASINDA yapılmalıdır.
  3. max_norm’u rastgele çok küçük seçip (örn. 0.01) her adımı aşırı kısıtlamak — bu da öğrenmeyi yavaşlatabilir.

Kendini test et

1. Notebook'ta w=1.5 ile 20 katmanlı bir ağda gradyan neden 2216 katına çıktı?
  1. Kod hatalıydı
  2. Geri yayılımda her katman gradyanı w ile çarpar; w>1 olduğunda bu çarpım katman sayısıyla ÜSTEL olarak büyür (doğru cevap)
  3. PyTorch bir hata yaptı
  4. Öğrenme oranı çok yüksekti

Neden: Zincir kuralı gereği, gradyan her katmanda w ile çarpılır; w=1.5 gibi 1'den büyük bir değer, L katman sonunda yaklaşık w üzeri L kadar büyür -- bu da üstel bir patlamadır.

2. Gradient clipping (gradyan kırpma) tam olarak neyi değiştirir?
  1. Gradyanın yönünü tersine çevirir
  2. Gradyan normu bir tavanı aşarsa, YÖNÜ koruyarak sadece BÜYÜKLÜĞÜNÜ o tavana kadar küçültür (doğru cevap)
  3. Öğrenme oranını sıfırlar
  4. Ağırlıkları rastgele değiştirir

Neden: Kırpma, gradyan vektörünü normu tavanı aşıyorsa aynı yönde ama daha küçük bir büyüklüğe ölçekler -- "hangi yöne gidileceği" bilgisi korunur, sadece adım boyutu sınırlanır.

3. torch.nn.utils.clip_grad_norm_ ne zaman çağrılmalıdır?
  1. optimizer.step()'ten SONRA
  2. loss.backward() ile optimizer.step() ARASINDA (doğru cevap)
  3. Eğitim başlamadan önce, bir kere
  4. Hiç önemli değil, herhangi bir sırada çağrılabilir

Neden: Gradyanlar backward() ile hesaplandıktan SONRA, ama optimizer bu gradyanları kullanarak ağırlıkları güncellemeden (step()) ÖNCE kırpılmalıdır -- aksi halde kırpma hiçbir etki yapmaz.

Özet

Özet

  • Patlayan gradyan, ağırlıklar 1'den büyükken (veya benzer bir çarpan etkisiyle) geri yayılımda gradyanın katman sayısıyla üstel büyümesidir.
  • Bu, kaybolan gradyanın (5. ders) tam tersi problemidir -- ama sonucu aynı derecede yıkıcı olabilir.
  • Tek bir kötü güncelleme, ağırlıkları anlamsız (hatta NaN) değerlere savurabilir.
  • Gradient clipping (clip_grad_norm_), gradyan normunu bir tavana sabitleyerek bu riski kontrol eder.
  • Kırpma, patlamanın SONUCUNU sınırlar; kök nedeni (ağırlık ilklendirme, öğrenme oranı) ayrıca ele almak gerekir.
Sonraki adım: Ağırlık ilklendirme →