Ana içeriğe geç

Orta13 dkA — Sinir Ağı Temelleri

Kaybolan gradyan problemi

Önkoşul:Geri yayılım

Kanca

  1. derste 2 katmanlı bir ağda geri yayılımı elle doğruladık. Peki 15 katmanlı bir ağda ne olur? Zincir kuralı hâlâ matematiksel olarak doğru — ama pratikte BÜYÜK bir sorun ortaya çıkabilir: gradyan, ağın başına ulaşana kadar yok olabilir.

Sezgi

Kaybolan gradyan, geri yayılım zinciri uzadıkça (katman sayısı arttıkça) gradyanların katlanarak küçülüp neredeyse SIFIRA inmesi problemidir. Sebebi basit: her katmanda gradyan, o katmanın aktivasyon türeviyle ÇARPILIR. Sigmoid’in türevi her zaman 0.25’ten küçüktür — bu küçük sayıları art arda 15 kez çarparsan, sonuç akıl almaz derecede küçülür.

0246810-15-10-50Katman (0 = girdiye en yakın, sonuncu = çıktı)log10(gradyan büyüklüğü)

Girdiye en yakın katmanın gradyan büyüklüğü: 1.84e-7 (çıktıdaki büyüklük: 6.59e-1) -- sigmoid'in türevi her zaman ≤0.25 olduğu için, katman sayısı arttıkça gradyan katlanarak KÜÇÜLÜYOR.

Katman sayısını artır ve Sigmoid ile ReLU arasında geçiş yap: Sigmoid’de çubuklar, girdiye yaklaştıkça (soldan) HIZLA küçülüyor (log ölçekte bile bariz). ReLU’da ise çubuklar sabit kalıyor — hiç sönümlenme yok.

Mekanizma

Bu kategoride ilk kez PyTorch’u kullanalım — autograd, 4. derste elle yaptığımız zincir kuralı türetmesini otomatikleştiriyor:

İlk PyTorch ağı: autograd

# Bu kategoride İLK KEZ PyTorch kullanıyoruz. autograd, 4. dersteki elle türettiğimiz
# zincir kuralını OTOMATİK uygular -- .backward() çağrısı yeter.
katman = nn.Linear(1, 1, bias=False)
katman.weight.data.fill_(1.0)
girdi = torch.tensor([[1.0]], requires_grad=False)
cikti = torch.sigmoid(katman(girdi))
kayip = 0.5 * (cikti - 0) ** 2
kayip.backward()
print(f"Tek katmanlı ağ: çıktı={cikti.item():.4f}, ağırlık gradyanı={katman.weight.grad.item():.4f}")
print("Elle hiçbir türev almadan, PyTorch bu gradyanı OTOMATİK hesapladı (autograd).")
Tek katmanlı ağ: çıktı=0.7311, ağırlık gradyanı=0.1437
Elle hiçbir türev almadan, PyTorch bu gradyanı OTOMATİK hesapladı (autograd).

Tek satır .backward() çağrısı, tüm zincir kuralını arka planda uyguluyor. Şimdi 15 katmanlı, hepsi sigmoid olan derin bir ağ kuralım:

15 katmanlı sigmoid ağ

# Şimdi 15 katmanlı, HER katmanı sigmoid olan derin bir ağ kuralım.
def derin_ag_olustur(katman_sayisi, aktivasyon):
    katmanlar = []
    for _ in range(katman_sayisi):
        lin = nn.Linear(1, 1, bias=False)
        lin.weight.data.fill_(1.0)  # tüm ağırlıklar TAM OLARAK 1 -- sönümlenme SADECE aktivasyondan gelsin
        katmanlar.append(lin)
        katmanlar.append(aktivasyon())
    return nn.Sequential(*katmanlar)

ag_sigmoid = derin_ag_olustur(15, nn.Sigmoid)
x = torch.tensor([[1.0]])
y_tahmin = ag_sigmoid(x)
kayip = 0.5 * (y_tahmin - 0) ** 2
kayip.backward()

gradyan_buyuklukleri_sigmoid = [
    katman.weight.grad.abs().item() for katman in ag_sigmoid if isinstance(katman, nn.Linear)
]
print(f"\n15 katmanlı SİGMOİD ağda, çıktıya en yakın katmanın gradyanı: {gradyan_buyuklukleri_sigmoid[-1]:.2e}")
print(f"Girdiye en yakın (1.) katmanın gradyanı: {gradyan_buyuklukleri_sigmoid[0]:.2e}")
print(f"Oran (çıktı/girdi): {gradyan_buyuklukleri_sigmoid[-1] / gradyan_buyuklukleri_sigmoid[0]:.2e} kat büyük")

15 katmanlı SİGMOİD ağda, çıktıya en yakın katmanın gradyanı: 9.76e-02
Girdiye en yakın (1.) katmanın gradyanı: 1.05e-10
Oran (çıktı/girdi): 9.28e+08 kat büyük

Girdiye en yakın katmanın gradyanı 1.05e-10 — neredeyse sıfır! Şimdi AYNI mimariyi, sadece aktivasyonu ReLU yaparak deneyelim:

15 katmanlı ReLU ağ

ag_relu = derin_ag_olustur(15, nn.ReLU)
y_tahmin_relu = ag_relu(x)
kayip_relu = 0.5 * (y_tahmin_relu - 0) ** 2
kayip_relu.backward()

gradyan_buyuklukleri_relu = [
    katman.weight.grad.abs().item() for katman in ag_relu if isinstance(katman, nn.Linear)
]
print(f"\n15 katmanlı RELU ağda, çıktıya en yakın katmanın gradyanı: {gradyan_buyuklukleri_relu[-1]:.2e}")
print(f"Girdiye en yakın (1.) katmanın gradyanı: {gradyan_buyuklukleri_relu[0]:.2e}")
print("ReLU'da gradyan, 15 katman boyunca neredeyse HİÇ küçülmüyor -- sigmoid'in aksine.")

15 katmanlı RELU ağda, çıktıya en yakın katmanın gradyanı: 1.00e+00
Girdiye en yakın (1.) katmanın gradyanı: 1.00e+00
ReLU'da gradyan, 15 katman boyunca neredeyse HİÇ küçülmüyor -- sigmoid'in aksine.

ReLU’da gradyan, 15 katman boyunca TAM OLARAK 1.00 kalıyor — hiç küçülmüyor! Çoğu kişi “derin ağlar her zaman aynı şekilde eğitilir, katman sayısı sadece kapasiteyi etkiler” sanır. Değil, çünkü aktivasyon fonksiyonunun seçimi, derin bir ağın EĞİTİLEBİLİR olup olmadığını doğrudan belirliyor — bu 928 milyon kat fark, sadece bir sayı değil, “bu ağ hiç öğrenemeyebilir” anlamına geliyor.

Matematik

Neden sigmoid, ReLU değil?
σ(z)=σ(z)(1σ(z))0.25\sigma'(z) = \sigma(z)(1-\sigma(z)) \leq 0.25ReLU(z)={1z>00z0\text{ReLU}'(z) = \begin{cases} 1 & z > 0 \\ 0 & z \leq 0 \end{cases}
FonksiyonTürevin maksimumu15 katman sonra (çarpımsal)
Sigmoid0.25 (sadece z=0z=0‘da)0.25159×1010\leq 0.25^{15} \approx 9 \times 10^{-10} — pratikte SIFIRA yakın
ReLU1 (pozitif bölgede)115=11^{15} = 1 — HİÇ küçülmez

Zincir kuralı, katman katman TÜREVLERİ çarpar (4. dersi hatırla). Sigmoid’in türevi her zaman 1’den küçük olduğu için, bu çarpım katman sayısı arttıkça katlanarak küçülür. ReLU’nun türevi (pozitif bölgede) TAM OLARAK 1 olduğu için, bu çarpım hiç küçülmez.

Kod

Tüm 15 katmanı yan yana karşılaştıralım:

Katman katman karşılaştırma

print(f"\n{'Katman':<10} {'Sigmoid gradyanı':>18} {'ReLU gradyanı':>16}")
for i, (gs, gr) in enumerate(zip(gradyan_buyuklukleri_sigmoid, gradyan_buyuklukleri_relu)):
    print(f"{i + 1:<10} {gs:>18.2e} {gr:>16.2e}")
print("\nSigmoid'in 1. katmanındaki gradyan, ReLU'nunkinden ONLARCA BASAMAK küçük -- bu katman,")
print("gradyan inişiyle GÜNCELLENEMEYECEK kadar küçük bir sinyal alıyor. Bu, 'kaybolan gradyan'.")

Katman       Sigmoid gradyanı    ReLU gradyanı
1                    1.05e-10         1.00e+00
2                    3.91e-10         1.00e+00
3                    1.65e-09         1.00e+00
4                    7.23e-09         1.00e+00
5                    3.21e-08         1.00e+00
6                    1.43e-07         1.00e+00
7                    6.34e-07         1.00e+00
8                    2.82e-06         1.00e+00
9                    1.26e-05         1.00e+00
10                   5.59e-05         1.00e+00
11                   2.49e-04         1.00e+00
12                   1.11e-03         1.00e+00
13                   4.93e-03         1.00e+00
14                   2.19e-02         1.00e+00
15                   9.76e-02         1.00e+00

Sigmoid'in 1. katmanındaki gradyan, ReLU'nunkinden ONLARCA BASAMAK küçük -- bu katman,
gradyan inişiyle GÜNCELLENEMEYECEK kadar küçük bir sinyal alıyor. Bu, 'kaybolan gradyan'.
Katman numarasına karşı gradyan büyüklüğünü logaritmik ölçekte gösteren grafik; sigmoid eğrisi girdiye yaklaştıkça dramatik şekilde düşerken ReLU eğrisi düz kalıyor.
Sigmoid (turuncu), girdiye yaklaştıkça gradyan büyüklüğünde 9 basamaklık bir düşüş gösteriyor. ReLU (mavi) tamamen düz -- hiç sönümlenme yok.

Nerede işe yarar

Kaybolan gradyan problemi, derin öğrenmenin tarihinde ciddi bir engeldi ve hâlâ dikkat gerektirir:

  • ReLU’nun (ve türevlerinin) yaygınlaşmasının ana nedeni. 2010’lar öncesi ağlar genelde sigmoid/tanh kullanıyordu ve derinleştikçe eğitilemez hale geliyordu — ReLU bunu büyük ölçüde çözdü.
  • Çok derin ağlarda hâlâ dikkat gerektirir. ReLU bile, çok derin ağlarda (yüzlerce katman) başka mekanizmalarla (artık bağlantılar/residual connections, normalizasyon) desteklenir.
  • Ağırlık ilklendirme ve normalizasyonla birlikte düşünülür. Bu kategorinin ilerleyen derslerinde (ağırlık ilklendirme, batch/layer normalization) bu sorunun diğer çözümlerini göreceğiz.

Bu 3 hatayı yaparsın:

  1. Çok derin bir ağda sigmoid/tanh’ı hiç düşünmeden kullanmak — bu derste gördüğümüz gibi, gradyan pratik olarak sıfırlanabilir.
  2. “Model öğrenmiyor” sorununu her zaman öğrenme oranına bağlamak — bazen kök neden, gradyanın ağın derinliklerine hiç ULAŞAMAMASI.
  3. ReLU’nun “her sorunu çözdüğünü” düşünmek — ReLU’nun kendi sorunu var (ölü ReLU/dying ReLU), bir sonraki bölümde aktivasyon fonksiyonlarını derinlemesine karşılaştıracağız.

Kendini test et

1. Kaybolan gradyan problemi neden özellikle DERİN (çok katmanlı) ağlarda ortaya çıkar?
  1. Derin ağlar daha az veri kullanır
  2. Zincir kuralı, her katmanın aktivasyon türevini ÇARPAR; sigmoid gibi türevi 1'den küçük fonksiyonlarda, bu çarpım katman sayısı arttıkça katlanarak küçülür (doğru cevap)
  3. Derin ağlar daha yavaş çalışır
  4. PyTorch derin ağları desteklemez

Neden: Geri yayılım, her katmanda aktivasyon türevini çarpar; sigmoid'in türevi her zaman ≤0.25 olduğu için, katman sayısı arttıkça bu çarpım katlanarak (üstel olarak) küçülür.

2. Notebook'ta 15 katmanlı ReLU ağında gradyan neden HİÇ küçülmedi (tam olarak 1.00 kaldı)?
  1. Kod hatalıydı
  2. ReLU'nun türevi, pozitif girdilerde TAM OLARAK 1'dir -- bu değer tekrar tekrar çarpılsa bile hiç küçülmez (doğru cevap)
  3. ReLU rastgele sayılar üretiyor
  4. Ağırlıklar sıfırdı

Neden: ReLU'nun türevi pozitif bölgede tam olarak 1 olduğu için, zincir kuralındaki çarpım hiçbir katmanda küçülmez -- 1'i kaç kere çarparsan çarp sonuç yine 1'dir.

3. Girdiye en yakın katmanın gradyanı astronomik derecede küçükse (örn. 1e-10), pratikte ne olur?
  1. Hiçbir etkisi olmaz
  2. O katmanın ağırlıkları, gradyan inişiyle neredeyse HİÇ güncellenmez -- ağ, ilk katmanlarında pratik olarak öğrenmeyi durdurur (doğru cevap)
  3. Model daha hızlı eğitilir
  4. Kayıp fonksiyonu değişir

Neden: Ağırlık güncelleme adımı gradyanla orantılıdır (4. ML dersini hatırla); gradyan neredeyse sıfırsa, güncelleme adımı da neredeyse sıfır olur -- o katman pratikte öğrenmeyi durdurur.

Özet

Özet

  • Kaybolan gradyan, geri yayılım zinciri uzadıkça gradyanların katlanarak küçülüp neredeyse sıfırlanması problemidir.
  • Sebebi, her katmanda aktivasyon türevinin gradyana ÇARPILMASI -- sigmoid'in türevi her zaman ≤0.25'tir.
  • ReLU'nun türevi (pozitif bölgede) tam olarak 1 olduğu için bu sönümlenmeyi yaşamaz.
  • Bu, ReLU'nun modern derin ağlarda sigmoid/tanh'a tercih edilmesinin ana nedenlerinden biridir.
  • Kaybolan gradyan yaşayan bir katman, gradyan inişiyle pratikte ÖĞRENMEYİ durdurur.
Sonraki adım: Sigmoid →