2. ünite / 10
Autograd: hesaplama grafiği ve geri yayılım
requires_grad, grad_fn, dinamik grafik, backward ve zincir kuralı, gradyan birikimi, no_grad, sayısal kontrol.
Bu ünitenin sonunda
- İleri geçişte hesaplama grafiğinin nasıl kurulduğunu açıklamak
- Zincir kuralıyla küçük bir grafikte gradyanları elle hesaplamak ve autograd ile karşılaştırmak
- Gradyan birikimini ve zero_grad'ın neden gerektiğini göstermek
- torch.no_grad ve detach'ın ne zaman kullanılacağını bilmek
Ders notları
Bir sinir ağını eğitmek, kaybı her parametreye göre türevlemek ve parametreyi gradyanın tersi yönünde biraz kaydırmaktır. Milyonlarca parametre için türevi elle yazmak imkânsızdır; PyTorch bunu autograd ile yapar.
Grafik, ileri geçişte kurulur
requires_grad=True olan bir tensörle yapılan her işlem bir düğüm olarak kaydedilir; sonuç tensörünün grad_fn alanı o düğümü gösterir. Grafik dinamiktir: her ileri geçişte yeniden kurulur, Python'daki if ve döngüler olduğu gibi çalışır.
Geri geçiş: zincir kuralı
L.backward(), L'den başlayıp grafiği tersten dolaşır. Her düğüm kendi yerel türevini bilir ve gelen gradyanı onunla çarpıp girdilerine aktarır:
Yaprak tensörlerin (parametrelerin) .grad alanı dolar. Bir değişken birden çok yerde kullanılırsa katkılar toplanır; bu yüzden gradyanlar çağrılar arasında da birikir ve her adımda optimizer.zero_grad() gerekir.
Grafiğin dışında kalmak
Doğrulama ve çıkarımda grafiğe gerek yoktur: with torch.no_grad(): bellek ve zaman kazandırır. .detach() bir tensörü grafikten koparır. Gradyanı doğrulamanın en iyi yolu sayısal türevdir: (L(θ + h) − L(θ − h)) / 2h.
Görselleştirici
Hesaplama grafiği ve geri yayılım, adım adım
Küçük bir ifade (bir nöron: y = tanh(w₁x₁ + w₂x₂ + b), kayıp (y − t)²) grafiğe dönüşür. İleri geçişte değerler, geri geçişte zincir kuralıyla gradyanlar düğüm düğüm dolar. Sonuç sayısal türevle karşılaştırılır.
Kendin dene
Grafik görselleştiricisinde "İleri" ile değerleri doldur, sonra "Geri" ile gradyanların L'den yapraklara doğru nasıl aktığını adım adım izle. w₁'in gradyanını notlardaki formülle elle hesapla ve sağdaki sayısal türevle karşılaştır. "SGD adımı"na 10 kez bas: kayıp nasıl değişti? x₁'i 0 yap: w₁'in gradyanına ne oldu, neden?
Kod
import torch
x1, x2, t = torch.tensor(2.0), torch.tensor(0.5), torch.tensor(0.8)
w1 = torch.tensor(-0.5, requires_grad=True) # yaprak, gradyanı tutulur
w2 = torch.tensor(1.2, requires_grad=True)
b = torch.tensor(0.3, requires_grad=True)
y = torch.tanh(w1 * x1 + w2 * x2 + b) # ileri geçiş grafiği kurar
L = (y - t) ** 2
print(y.grad_fn, L.grad_fn) # TanhBackward0, PowBackward0
L.backward() # zincir kuralı, tersten
print(w1.grad, w2.grad, b.grad)
# sayısal kontrol: merkezî fark
def loss(w):
return ((torch.tanh(w * x1 + w2 * x2 + b) - t) ** 2).item()
h = 1e-4
print('sayısal:', (loss(w1.item() + h) - loss(w1.item() - h)) / (2 * h))
with torch.no_grad(): # güncelleme grafiğe girmesin
for p in (w1, w2, b):
p -= 0.1 * p.grad
p.grad = None # gradyanlar birikir: sıfırlaColab defteri
PyTorch tarayıcıda çalışmaz; gerçek kodu Google Colab'da (ücretsiz GPU ile) çalıştır. Defteri indir, colab.research.google.com adresinde "Dosya → Not defteri yükle" ile aç, "Çalışma zamanı → Çalışma zamanı türünü değiştir → T4 GPU" seç ve hücreleri sırayla çalıştır.
Defteri indir (.ipynb)Sık yapılan hatalar
- optimizer.zero_grad() çağırmayı unutmak: gradyanlar her yığında birikir, adımlar giderek büyür.
- Parametreyi with torch.no_grad() dışında elle güncellemek: güncelleme grafiğe girer ve "a leaf Variable that requires grad is being used in an in-place operation" hatası çıkar.
- Doğrulamada no_grad kullanmamak: bellek gereksiz yere dolar, büyük modelde GPU belleği taşar.
- Kaybı listeye eklerken .item() demeden saklamak: tüm grafikler bellekte kalır.
Yazılım mühendisliği bağlantısı
Gradyan kontrolü (gradient check) yeni bir katman ya da kayıp fonksiyonu yazarken kullanılan klasik bir doğrulama testidir.
torch.autograd.gradcheck, float64 girdilerle analitik ve sayısal türevi karşılaştırır; özel katmanların birim testine ekle.- Tekrarlanabilirlik için tohumu sabitle (
torch.manual_seed) ve testte küçük boyutlar kullan.
Kendini sına
L = (y − t)² ve y = tanh(z) ise ∂L/∂z nedir?
Aynı parametreyle iki kez backward() çağrılır ve arada zero_grad yoksa .grad ne olur?
with torch.no_grad(): bloğunun ana amacı nedir?
z = w·x ise ∂z/∂w nedir?
