Ana içeriğe geç

Orta10 dkA — Sinir Ağı Temelleri

Adagrad

Önkoşul:SGD, batch, momentum

Kanca

  1. derste momentumun, gürültülü gradyanları YUMUŞATTIĞINI gördük — ama tüm ağırlıklara AYNI öğrenme oranını uyguluyordu. Ya bazı ağırlıklar (örn. nadir kelimelere karşılık gelenler) çok SEYREK, bazıları (yaygın kelimeler) çok SIK güncelleniyorsa? Adagrad, bu soruna cevap veren ilk “uyarlanabilir” (adaptive) optimizer.

Sezgi

Adagrad, HER ağırlık için AYRI bir öğrenme oranı tutar — ve bu oranı, o ağırlığın GEÇMİŞTEKİ gradyanlarının büyüklüğüne göre otomatik küçültür. Sık güncellenen bir ağırlık zamanla “yavaşlar”; seyrek güncellenen bir ağırlık göreli olarak “hızlı” kalır.

Optimizer yarışında Adagrad’ı (yeşil) izle — vadi yüzeyinde diğerlerinden nasıl farklı bir yörünge izliyor?

Yüzey
Optimizerlar

Adım: 0

SGD'nin dar vadide nasıl ZİGZAG çizdiğine, momentumun ise bu salınımı nasıl yumuşatıp hızlandırdığına dikkat et.

Mekanizma

Bunu somutlaştırmak için iki ağırlık düşünelim: w1 HER adımda güncelleniyor (sık bir özellik), w2 sadece 6 adımda bir güncelleniyor (seyrek bir özellik, örn. nadir görülen bir kelime).

Sık vs seyrek özellik

# İki ağırlık: w1 HER adımda güncellenen "sık" bir özelliği, w2 SADECE 6 adımda
# bir güncellenen "seyrek" bir özelliği temsil ediyor (örn. nadir görülen bir kelime).
def egit(adagrad_kullan, adim_sayisi=30, lr=0.4):
    w1, w2 = 5.0, 5.0
    cache1, cache2 = 0.0, 0.0
    yol1, yol2 = [w1], [w2]
    for t in range(adim_sayisi):
        g1 = 1.0
        g2 = 5.0 if t % 6 == 0 else 0.0
        if adagrad_kullan:
            cache1 += g1 ** 2
            cache2 += g2 ** 2
            w1 -= lr * g1 / (np.sqrt(cache1) + 1e-8)
            w2 -= lr * g2 / (np.sqrt(cache2) + 1e-8)
        else:
            w1 -= lr * g1
            w2 -= lr * g2
        yol1.append(w1)
        yol2.append(w2)
    return yol1, yol2

yol1_sgd, yol2_sgd = egit(adagrad_kullan=False)
yol1_ada, yol2_ada = egit(adagrad_kullan=True)

print(f"SGD:     w1(sık)={yol1_sgd[-1]:.3f}, w2(seyrek)={yol2_sgd[-1]:.3f}")
print(f"Adagrad: w1(sık)={yol1_ada[-1]:.3f}, w2(seyrek)={yol2_ada[-1]:.3f}")
print("\nSGD, iki ağırlığı da AYNI sabit öğrenme oranıyla günceller -- hangisinin sık, hangisinin seyrek olduğunu 'bilmez'.")
print("Adagrad ise seyrek güncellenen w2'yi daha AZ küçültüyor (cache'i az büyüdüğü için efektif lr yüksek kalıyor).")
SGD:     w1(sık)=-7.000, w2(seyrek)=-5.000
Adagrad: w1(sık)=1.166, w2(seyrek)=3.707

SGD, iki ağırlığı da AYNI sabit öğrenme oranıyla günceller -- hangisinin sık, hangisinin seyrek olduğunu 'bilmez'.
Adagrad ise seyrek güncellenen w2'yi daha AZ küçültüyor (cache'i az büyüdüğü için efektif lr yüksek kalıyor).

SGD ile ikisi de BENZER şekilde küçülüyor (-7.000 ve -5.000) — SGD hangisinin sık, hangisinin seyrek olduğunu “bilmiyor”. Adagrad ile sonuç çarpıcı şekilde farklı: sık güncellenen w1 sadece 1.166’ya iniyor (küçük efektif adımlarla), seyrek w2 ise 3.707’de kalıyor (hâlâ göreli büyük adımlar alıyor). Çoğu kişi “optimizer sadece hızlandırır” sanır. Eksik, çünkü Adagrad her ağırlığa KENDİ geçmişine göre farklı davranır.

Matematik

Adagrad güncelleme kuralı
ct=ct1+gt2c_t = c_{t-1} + g_t^2wt+1=wtηct+ϵgtw_{t+1} = w_t - \frac{\eta}{\sqrt{c_t} + \epsilon} \, g_t
SembolAnlamı
ctc_tO ağırlığın TÜM geçmiş gradyanlarının kareler toplamı (“cache”)
η/ct\eta / \sqrt{c_t}Efektif öğrenme oranı — ctc_t büyüdükçe KÜÇÜLÜR
ϵ\epsilonSıfıra bölmeyi önleyen küçük bir sabit (örn. 10810^{-8})

ctc_t SADECE artabilir (kareler toplamı) — bu yüzden efektif öğrenme oranı SADECE küçülebilir, asla büyüyemez.

Kod

Bu tek-yönlü küçülmenin somut etkisini görelim, sonra PyTorch’un torch.optim.Adagrad’ı ile doğrulayalım:

Efektif öğrenme oranının çöküşü

# Adagrad'ın "efektif öğrenme oranı" (lr / sqrt(cache)), her güncellemede KÜÇÜLÜR.
cache1 = 0.0
print("\nw1 (her adımda g=1 alan 'sık' ağırlık) için efektif öğrenme oranının çöküşü:")
for t in range(1, 31, 5):
    cache1 = t  # g1=1 sabit olduğu için cache1, adım sayısına eşit büyüyor
    efektif_lr = 0.4 / (np.sqrt(cache1) + 1e-8)
    print(f"  adım {t}: efektif_lr = {efektif_lr:.4f}")

print("\nBu çöküş, Adagrad'ın en büyük ZAYIFLIĞI: uzun eğitimlerde efektif öğrenme oranı o kadar küçülür ki öğrenme neredeyse DURUR.")

w1 (her adımda g=1 alan 'sık' ağırlık) için efektif öğrenme oranının çöküşü:
  adım 1: efektif_lr = 0.4000
  adım 6: efektif_lr = 0.1633
  adım 11: efektif_lr = 0.1206
  adım 16: efektif_lr = 0.1000
  adım 21: efektif_lr = 0.0873
  adım 26: efektif_lr = 0.0784

Bu çöküş, Adagrad'ın en büyük ZAYIFLIĞI: uzun eğitimlerde efektif öğrenme oranı o kadar küçülür ki öğrenme neredeyse DURUR.

PyTorch ile doğrulama

# PyTorch'un torch.optim.Adagrad'ı ile aynı sonucu doğrulayalım.
w1_t = torch.tensor(5.0, requires_grad=True)
w2_t = torch.tensor(5.0, requires_grad=True)
optimizer = torch.optim.Adagrad([w1_t, w2_t], lr=0.4)

for t in range(30):
    optimizer.zero_grad()
    g1 = 1.0
    g2 = 5.0 if t % 6 == 0 else 0.0
    w1_t.grad = torch.tensor(g1)
    w2_t.grad = torch.tensor(g2)
    optimizer.step()

print(f"\nPyTorch Adagrad: w1={w1_t.item():.3f}, w2={w2_t.item():.3f}")
print(f"Elle yazdığımız Adagrad: w1={yol1_ada[-1]:.3f}, w2={yol2_ada[-1]:.3f}  -- neredeyse aynı (küçük farklar epsilon uygulama detayından).")

PyTorch Adagrad: w1=1.166, w2=3.707
Elle yazdığımız Adagrad: w1=1.166, w2=3.707  -- neredeyse aynı (küçük farklar epsilon uygulama detayından).

PyTorch’un sonucu (w1=1.166, w2=3.707) elle yazdığımız versiyonla BİREBİR aynı.

Soldaki grafikte SGD ile iki ağırlığın benzer hızda küçüldüğü, sağdaki grafikte Adagrad ile seyrek ağırlığın çok daha az küçüldüğü gösteriliyor.
SGD (sol), sık ve seyrek ağırlığı ayırt etmiyor. Adagrad (sağ), sık güncellenen ağırlığın öğrenme oranını daha hızlı küçültüyor.

Nerede işe yarar

Adagrad, özellikle SEYREK verilerde (NLP kategorisinde göreceğimiz kelime embedding’leri gibi) faydalıdır:

  • Seyrek özellikli problemlerde (örn. nadir kelimeler) iyi çalışır — nadir görülen özellikler, göreli büyük güncellemeler almaya devam eder.
  • Uzun eğitimlerde efektif öğrenme oranı çok küçülebilir — bu, Adagrad’ın en bilinen ZAYIFLIĞI (bir sonraki derste RMSprop bunu nasıl çözdüğünü göreceğiz).
  • Pratikte RMSprop veya Adam, Adagrad’ın bu zayıflığını gidermiş halleri olarak tercih edilir — ama Adagrad, “uyarlanabilir öğrenme oranı” fikrinin temelini attı.

Bu 3 hatayı yaparsın:

  1. Adagrad’ı çok UZUN eğitimlerde kullanıp öğrenmenin neden durduğunu anlamamak — cache sürekli büyüdüğü için efektif lr sıfıra yaklaşır.
  2. “Uyarlanabilir” kelimesini duyunca öğrenme oranını hiç ayarlamaya gerek olmadığını sanmak — başlangıç η\eta hâlâ önemlidir.
  3. Adagrad’ı YOĞUN (dense, her özelliğin her örnekte göründüğü) verilerde kullanıp RMSprop/Adam’ın daha iyi çalışacağı bir durumu kaçırmak.

Kendini test et

1. Notebook'ta Adagrad ile w2 (seyrek güncellenen ağırlık) neden w1'den (sık güncellenen) çok daha az küçüldü?
  1. Rastgele bir sonuç
  2. w2'nin cache'i (geçmiş gradyanların karesi) çok daha AZ büyüdüğü için efektif öğrenme oranı yüksek kaldı; w1'in cache'i hızla büyüyüp efektif lr'ını küçülttü (doğru cevap)
  3. w2 hiç güncellenmedi
  4. Adagrad sadece sık güncellenen ağırlıkları etkiler

Neden: Adagrad'ın cache'i (c_t), gradyanın karesini biriktirir; sık güncellenen w1'in cache'i hızla büyüyüp efektif öğrenme oranını (η/√c_t) küçültürken, seyrek güncellenen w2'nin cache'i az büyüdüğü için efektif lr yüksek kalır.

2. Adagrad'ın en bilinen zayıflığı nedir?
  1. Hiçbir zaman yakınsamaz
  2. Cache SADECE büyüyebildiği için (kareler toplamı), efektif öğrenme oranı uzun eğitimlerde o kadar küçülür ki öğrenme neredeyse durur (doğru cevap)
  3. Sadece küçük veri setlerinde çalışır
  4. Bellekte çok yer kaplar

Neden: Cache hiç azalmadan sürekli biriktiği için efektif öğrenme oranı (η/√c_t) monoton şekilde küçülür -- uzun eğitimlerde bu, öğrenmeyi neredeyse durma noktasına getirebilir.

3. Adagrad hangi tür problemlerde özellikle faydalıdır?
  1. Sadece görüntü verisinde
  2. Seyrek özellikli problemlerde (örn. nadir kelimeler) -- nadir görülen özellikler göreli büyük güncellemeler almaya devam eder (doğru cevap)
  3. Sadece küçük ağlarda
  4. Hiçbir özel durumda avantajı yoktur

Neden: Adagrad, seyrek (nadir güncellenen) özelliklerin cache'inin yavaş büyümesi sayesinde bu özelliklere göreli olarak daha büyük güncellemeler vermeye devam eder -- bu da onu seyrek veri (örn. NLP'de nadir kelimeler) için uygun kılar.

Özet

Özet

  • Adagrad, her ağırlık için AYRI ve UYARLANABİLİR bir öğrenme oranı tutar.
  • Bu oran, o ağırlığın geçmiş gradyanlarının kareler toplamına (cache) göre otomatik küçülür.
  • Sık güncellenen ağırlıklar zamanla yavaşlar; seyrek güncellenenler göreli hızlı kalır.
  • Cache sadece büyüyebildiği için, efektif öğrenme oranı uzun eğitimlerde çok küçülebilir -- Adagrad'ın temel zayıflığı.
  • Adagrad, seyrek veri (örn. nadir kelimeler) için özellikle faydalıdır; bir sonraki derste bu zayıflığı gideren RMSprop'u göreceğiz.
Sonraki adım: RMSprop ve Adadelta →