Ana içeriğe geç

Orta11 dkA — Sinir Ağı Temelleri

SGD, batch, momentum

Önkoşul:Optimizasyona giriş

Kanca

  1. derste öğrenme oranını inceledik ama şu ana kadar hep TÜM veriyle (full batch) gradyan hesapladık. Gerçek eğitimde veri setleri milyonlarca örnek içerebilir — her adımda TÜMÜNÜ kullanmak çok yavaş olur. Bu dersin konusu: SGD, mini-batch, ve bunun getirdiği “gürültü” sorununu çözen momentum.

Sezgi

Stochastic Gradient Descent (SGD), gradyanı TÜM veri yerine KÜÇÜK bir rastgele örneklemle (mini-batch) tahmin eder. Bu daha hızlıdır ama her tahmin, gerçek gradyandan biraz SAPAR — bu sapmaya “gradyan gürültüsü” denir. Momentum, bu gürültüyü yumuşatan bir teknik.

Önce optimizer’ların bir “vadi” yüzeyinde nasıl yarıştığını izle — SGD’nin zigzag çizdiğine, momentumun bu salınımı nasıl düzelttiğine dikkat et.

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

Gürültü sorununu somutlaştıralım: aynı ağırlıkta (w=1.0), farklı büyüklükte rastgele örneklemlerle gradyanı defalarca tahmin edelim.

Tam veriyle 'gerçek' gradyan

# y = 3x + gürültü. w=1.0'da (henüz eğitilmemiş) GERÇEK gradyanı (TÜM veriyle) hesaplayalım.
N = 50
xs = rng.uniform(-2, 2, N)
ys = 3 * xs + rng.uniform(-0.25, 0.25, N)

def gradyan_orneklem(w, indeksler):
    hatalar = w * xs[indeksler] - ys[indeksler]
    return np.mean(2 * hatalar * xs[indeksler])

w_sabit = 1.0
gercek_gradyan = gradyan_orneklem(w_sabit, np.arange(N))
print(f"Tam batch (n=50) gradyanı: {gercek_gradyan:.4f}  -- TÜM veriyle hesaplanan, 'gerçek' gradyan")
Tam batch (n=50) gradyanı: -5.0398  -- TÜM veriyle hesaplanan, 'gerçek' gradyan

Batch boyutu ve gradyan gürültüsü

# Şimdi KÜÇÜK rastgele örneklemlerle (mini-batch) aynı w'de gradyanı tahmin edelim.
# Her tahmin, gerçek gradyandan biraz SAPACAK -- bu sapmaya "gradyan gürültüsü" denir.
rng2 = np.random.default_rng(99)
print(f"\n{'Batch boyutu':<14} {'8 tahmin örneği':<50} {'std (300 tekrar)':<10}")
for batch_boyutu in [1, 4, 8, 16, 32]:
    tahminler_8 = [gradyan_orneklem(w_sabit, rng2.integers(0, N, batch_boyutu)) for _ in range(8)]
    tahminler_300 = [gradyan_orneklem(w_sabit, rng2.integers(0, N, batch_boyutu)) for _ in range(300)]
    std_deger = np.std(tahminler_300)
    ornek_str = ", ".join(f"{v:.2f}" for v in tahminler_8)
    print(f"{batch_boyutu:<14} {ornek_str:<50} {std_deger:<10.3f}")

print(f"\nbatch=1 (saf SGD) gradyanı ÇOK gürültülü; batch=32 gerçek gradyana ({gercek_gradyan:.2f}) çok daha yakın kümeleniyor.")

Batch boyutu   8 tahmin örneği                                    std (300 tekrar)
1              -3.22, -6.23, -0.04, -7.57, -9.39, -6.23, -3.22, -1.85 4.282     
4              -2.77, -6.96, -4.22, -4.39, -5.69, -7.89, -6.41, -3.14 1.931     
8              -7.24, -7.95, -6.87, -4.42, -4.09, -4.75, -5.72, -4.86 1.540     
16             -7.00, -5.48, -3.63, -4.15, -4.21, -6.82, -5.51, -5.11 1.057     
32             -4.87, -5.52, -5.13, -3.82, -4.40, -4.62, -5.61, -5.29 0.728     

batch=1 (saf SGD) gradyanı ÇOK gürültülü; batch=32 gerçek gradyana (-5.04) çok daha yakın kümeleniyor.

batch=1’de (saf SGD) tahminler -9.39’dan -0.04’e kadar SAVRULUYOR (std=4.28); batch=32’de -3.82 ile -5.61 arasına SIKIŞIYOR (std=0.73). Çoğu kişi “küçük batch = kötü gradyan” sanır. Kısmen doğru, çünkü her TEK tahmin gürültülü olsa da, YÖN ortalamada doğrudur — sorun sadece bu gürültünün eğitimi yavaşlatmasıdır.

Matematik

Mini-batch gradyan ve momentum güncellemesi
gt1BiBwLig_t \approx \frac{1}{|B|}\sum_{i \in B} \nabla_w \mathcal{L}_ivt=βvt1ηgtv_t = \beta v_{t-1} - \eta \, g_twt+1=wt+vtw_{t+1} = w_t + v_t
SembolAnlamı
BBMini-batch — veri setinden rastgele seçilen küçük bir alt küme
gtg_ttt. adımdaki (gürültülü) gradyan TAHMİNİ
vtv_t“Hız” — geçmiş gradyanların üstel ortalaması
β\betaMomentum katsayısı (genelde 0.9) — geçmişin ne kadarının hatırlanacağı

Momentum, sadece SON gradyanı değil, GEÇMİŞ gradyanların ağırlıklı ortalamasını kullanır — bu da rastgele gürültüyü birbirine karıştırıp iptal eder (11. derste gördüğümüz “ortalamanın gürültüyü azaltması” fikriyle aynı mantık).

Kod

Momentumun gürültülü mini-batch eğitimindeki etkisini doğrudan ölçelim:

Momentum, zigzag'ı nasıl azaltır

# Momentum, geçmiş adımların bir kısmını "hatırlayarak" bu gürültüyü yumuşatır.
# PyTorch'ta torch.optim.SGD(momentum=...) ile karşılaştıralım.
def egit(momentum, adim_sayisi=30, lr=0.05):
    w = torch.tensor(1.0, requires_grad=True)
    optimizer = torch.optim.SGD([w], lr=lr, momentum=momentum)
    rng_egitim = np.random.default_rng(7)
    gecmis = [w.item()]
    for _ in range(adim_sayisi):
        idx = rng_egitim.integers(0, N, 4)  # küçük mini-batch -- gürültülü gradyan
        optimizer.zero_grad()
        tahmin = w * torch.tensor(xs[idx], dtype=torch.float32)
        kayip = torch.mean((tahmin - torch.tensor(ys[idx], dtype=torch.float32)) ** 2)
        kayip.backward()
        optimizer.step()
        gecmis.append(w.item())
    return gecmis

gecmis_momentumsuz = egit(momentum=0.0)
gecmis_momentumlu = egit(momentum=0.9)

def pürüzlülük(gecmis):
    # ardışık adımlar arası yön değişikliklerinin sayısı -- "zigzag" miktarı
    farklar = np.diff(gecmis)
    isaret_degisimi = np.sum(np.diff(np.sign(farklar)) != 0)
    return isaret_degisimi

print(f"\nMomentumsuz (β=0)  son w={gecmis_momentumsuz[-1]:.3f}, yön değişikliği sayısı={pürüzlülük(gecmis_momentumsuz)}")
print(f"Momentumlu (β=0.9) son w={gecmis_momentumlu[-1]:.3f}, yön değişikliği sayısı={pürüzlülük(gecmis_momentumlu)}")
print("Momentum, gürültülü mini-batch gradyanlarının ortalamasını 'hatırlayarak' yön değişikliklerini AZALTIYOR.")

Momentumsuz (β=0)  son w=2.972, yön değişikliği sayısı=7
Momentumlu (β=0.9) son w=2.678, yön değişikliği sayısı=3
Momentum, gürültülü mini-batch gradyanlarının ortalamasını 'hatırlayarak' yön değişikliklerini AZALTIYOR.

Momentumsuz eğitimde 30 adımda 7 yön değişikliği var; momentumlu eğitimde sadece 3. Momentum, ağırlığı daha AZ salınarak, daha DÜZGÜN bir yolla hedefe taşıyor.

Adım sayısına karşı ağırlık değerini gösteren iki çizgi; momentumsuz çizgi daha çok zigzag yaparken momentumlu çizgi daha düz bir yörünge izliyor.
Aynı gürültülü mini-batch gradyanları, momentum (β=0.9) ile çok daha düzgün bir yörüngeye dönüşüyor.

Nerede işe yarar

Batch boyutu ve momentum, pratikte birlikte ayarlanan hiperparametrelerdir:

  • Büyük veri setlerinde mini-batch SGD standarttır. Tam batch (tüm veri) çoğu zaman belleğe sığmaz ve çok yavaştır.
  • Momentum (genelde β=0.9), neredeyse HER modern optimizer’ın (16-18. derste göreceğimiz Adagrad, RMSprop, Adam) içinde bir şekilde bulunur.
  • Batch boyutu arttıkça gradyan daha az gürültülü ama her adım daha PAHALI olur — pratikte 32-256 arası yaygın bir denge noktasıdır.

Bu 3 hatayı yaparsın:

  1. Çok küçük batch boyutuyla (örn. 1-2) momentum KULLANMADAN eğitmek — gürültü, eğitimi yavaşlatır veya kararsızlaştırır.
  2. “Daha büyük batch her zaman daha iyi” sanmak — büyük batch her adımda daha pahalı olur ve bazen genelleme performansını düşürebilir.
  3. Momentum katsayısını (β) çok yükseğe (örn. 0.99) ayarlayıp ağın “geçmişe fazla bağlı kalarak” yön değiştirmekte zorlanmasına neden olmak.

Kendini test et

1. Notebook'ta batch=1 ile hesaplanan gradyan tahminleri neden bu kadar farklı çıktı (std=4.28)?
  1. Kod hatalıydı
  2. Tek bir rastgele örnek, TÜM verinin ortalama eğilimini temsil etmekte yetersiz kalır -- her örnek kendi gürültüsünü taşır (doğru cevap)
  3. batch=1 her zaman yanlış sonuç verir
  4. Gradyan hesabı deterministik olmalıydı ama olmadı

Neden: Tek bir örnek, verinin genel eğilimini temsil etmek için yetersizdir; her örneğin kendi gürültüsü doğrudan gradyan tahminine yansır, bu yüzden tahminler geniş bir aralıkta dağılır.

2. Momentum, gürültülü mini-batch gradyanlarının etkisini nasıl azaltır?
  1. Gradyanı sıfırlayarak
  2. Sadece SON gradyanı değil, GEÇMİŞ gradyanların üstel ortalamasını kullanarak -- rastgele gürültü ortalamada birbirini iptal eder (doğru cevap)
  3. Öğrenme oranını sıfıra indirerek
  4. Batch boyutunu otomatik büyüterek

Neden: Momentum güncellemesi geçmiş gradyanların ağırlıklı ortalamasını (v_t) biriktirir; rastgele gürültü ortalamada birbirini götürdüğü için sonuç daha düzgün bir yörünge olur.

3. Neden neredeyse hiçbir zaman tam batch (tüm veri seti) ile eğitim yapılmaz?
  1. Tam batch her zaman yanlış sonuç verir
  2. Büyük veri setlerinde tüm veriyi her adımda kullanmak belleğe sığmayabilir ve çok yavaş olur (doğru cevap)
  3. Tam batch gradyan hesaplayamaz
  4. Sadece küçük modellerde tam batch kullanılabilir

Neden: Milyonlarca örnekli veri setlerinde her adımda TÜM veriyi işlemek hem bellek hem de hız açısından pratik değildir -- mini-batch, bu maliyeti azaltırken gradyanı hâlâ makul şekilde tahmin eder.

Özet

Özet

  • SGD, gradyanı tüm veri yerine küçük bir rastgele örneklemle (mini-batch) tahmin eder.
  • Küçük batch boyutu daha hızlı ama daha gürültülü gradyan tahmini üretir.
  • Momentum, geçmiş gradyanların ağırlıklı ortalamasını kullanarak bu gürültüyü yumuşatır.
  • Momentum, sonraki derslerde göreceğimiz Adagrad/RMSprop/Adam gibi optimizer'ların da temel bir bileşenidir.
  • Batch boyutu (32-256 arası yaygın) ve momentum (genelde β=0.9), birlikte ayarlanan pratik hiperparametrelerdir.
Sonraki adım: Adagrad →