Türev, Gradient ve Matrix Calculus: Backprop'un Matematiği Sıfırdan
Skalerden vektöre, vektörden matrise türev. Jacobian, Hessian, chain rule, numerator vs denominator layout. Softmax + cross-entropy'nin türevinin neden zarif olduğu. Backprop'un manuel hesabıyla PyTorch autograd karşılaştırması.
Şükrü Yusuf KAYA
40 dakikalık okuma
Orta🧮 Backprop'u 'sihir' olmaktan çıkaracağız
Çoğu öğrenci backpropagation'ı 'PyTorch yapıyor' diye geçer. Senior pozisyonlarda bu kabul edilmez — autograd bug'ı debug ettiğinde, custom backward yazdığında, FlashAttention kerneli düşündüğünde matematiği bilmeden geçilmez. 40 dakika sonra zincir kuralının matris versiyonunu kendi başına yazabileceksin.
Ders Haritası#
- Skaler türev refresher
- Kısmi türev ve gradient (skaler → vektör)
- Jacobian (vektör → vektör)
- Hessian (skaler → matris)
- Zincir kuralı matris versiyonu
- Numerator vs denominator layout — büyük tuzak
- NN'de yaygın türevler: sigmoid, softmax, cross-entropy
- Softmax + Cross-entropy zarif türevi
- Manuel backprop — küçük bir ağda adım adım
- PyTorch autograd ile karşılaştırma
1. Skaler Türev — Refresher#
Bir fonksiyon . Türev:
f: ℝ → ℝGeometrik: tanjant doğrusunun eğimi. Fiziksel: değişim hızı.
Önemli türevler:
d/dx [x^n] = n x^{n-1}d/dx [e^x] = e^xd/dx [ln(x)] = 1/xd/dx [sin(x)] = cos(x)
Çarpım kuralı:
Bölüm kuralı:
Zincir kuralı:
(fg)' = f'g + fg'(f/g)' = (f'g - fg') / g²(f(g(x)))' = f'(g(x)) · g'(x)2. Kısmi Türev ve Gradient#
Çok değişkenli fonksiyon için her bir değişkene göre ayrı türev alabiliriz. Buna partial derivative (kısmi türev) denir.
f: ℝ^n → ℝx_iGradient#
Tüm kısmi türevlerin bir vektörde toplanmış haline gradient denir:
Sezgi: Gradient, fonksiyonun en hızlı arttığı yönü gösteren bir vektördür. Büyüklüğü = artış hızı.
LLM'de:#
Loss ∈ ℝ. Weight ∈ ℝ^{d_out × d_in}. ∈ ℝ^{d_out × d_in} — her bir weight için gradient. Bunu loss'un weight'e göre türevi diye okuruz. ile gradient descent yaparız.
LW∂L/∂WW ← W - η ∇Lpython
import torch # f(x, y) = x^2 + 3*x*y + y^2# ∂f/∂x = 2x + 3y# ∂f/∂y = 3x + 2y# Gradient: (2x+3y, 3x+2y) x = torch.tensor(1.0, requires_grad=True)y = torch.tensor(2.0, requires_grad=True)f = x**2 + 3*x*y + y**2 # PyTorch autogradf.backward()print("∂f/∂x =", x.grad.item()) # 2*1 + 3*2 = 8print("∂f/∂y =", y.grad.item()) # 3*1 + 2*2 = 7 # Manuel doğrulama:# Gradient'in büyüklüğü: ||∇f|| = √(8² + 7²) = √113 ≈ 10.63# En hızlı artış yönü: (8/10.63, 7/10.63)PyTorch autograd ile gradient hesabı + manuel doğrulama.
3. Jacobian — Vektör Çıktılı Fonksiyonlar#
Şimdi (vektör → vektör). Türevi nedir?
f: ℝ^n → ℝ^mCevap: Jacobian matrisi. m × n matris:
Her satır = output bileşeninin gradient'i.
Her sütun = input bileşenine göre output'un nasıl değiştiği.
Sezgi#
f(x + dx) ≈ f(x) + J · dxYani Jacobian = "fonksiyonun lokal linearleştirilmesi". Lineer cebirin türeve karışmış hali.
NN'de Jacobian#
Bir Linear layer: . Jacobian: . Her zaman.
Sigmoid: element-wise. Jacobian diagonal: .
Softmax: Jacobian dense (köşegen değil) — birazdan göreceğiz.
y = Wx + b∂y/∂x = Wy = σ(x)diag(σ(x) * (1 - σ(x)))4. Hessian — İkinci Türev Matrisi#
f: ℝ^n → ℝn × n simetrik matris (Schwarz teoremi: ).
∂²/∂x∂y = ∂²/∂y∂xNiye önemli?#
- Convexity testi: Hessian pozitif tanımlı → fonksiyon konveks (yerel minimum globaldir)
- Newton method: — daha hızlı convergence
x_{k+1} = x_k - H^{-1} ∇f - Loss landscape analysis: Hessian eigenvalue'ları → flat vs sharp minima
- LLM training: Adam ailesi Hessian'a yaklaşım yapıyor
Pratik#
Tam Hessian'ı saklamak imkânsız (modelin 10B parametresi → Hessian 10B × 10B = 10^20 element). Bunun yerine diagonal Hessian ya da Hessian-vector products kullanılır (Modül 17'de detayda).
5. Zincir Kuralı — Backpropagation'ın Kalbi#
Skaler versiyonu: .
(f(g(x)))' = f'(g(x)) · g'(x)Matris versiyonu (genel): , x → g → z → f → y.
y = f(g(x))İki Jacobian'ın matris çarpımı.
NN bağlamı#
Bir 3-katmanlı ağ:
x → [Layer 1] → h1 → [Layer 2] → h2 → [Layer 3] → y → L
Loss'un Layer 1'in weight'ine göre gradient'i:
Backprop, bu çarpımı sağdan sola (output'tan input'a) yapar — çünkü her seferinde sadece bir Jacobian × vektör (gradient) çarpımı gerekiyor, tam matris saklamaya gerek yok.
💡 Backprop = Zincir kuralı + dinamik programlama
Backprop'un sırrı: aynı ara hesabı tekrarlamamak. Forward pass'te kaydedilen ara çıkışları kullanarak, gradient'leri tek geçişte hesapla. Brüt zincir kuralı her gradient için ayrı zincir çarpsa, exponansiyel zaman alırdı. Backprop = O(n).
6. Numerator vs Denominator Layout — Büyük Tuzak#
Matrix calculus'ta türev tanımı için iki konvansiyon var:
Numerator layout (Jacobian convention)#
∂y/∂x — y'nin shape'i satır olarak gelir
Eğer ∈ ℝ^m, ∈ ℝ^n: (m satır, n sütun).
yx∂y/∂x ∈ ℝ^{m × n}Denominator layout (gradient convention)#
∂y/∂x — x'in shape'i satır olarak gelir
Eğer ∈ ℝ^m, ∈ ℝ^n: (yukarıdakinin transpozu).
yx∂y/∂x ∈ ℝ^{n × m}Hangi doğru?#
İkisi de doğru — sadece farklı konvansiyon. Karışıklık şudur: paper'lar her ikisini de kullanıyor. PyTorch implicit olarak denominator layout kullanıyor (gradient'in shape'i parametrenin shape'iyle aynı).
Mühendislik tavsiyesi: Bir konvansiyon seç (genelde denominator çünkü PyTorch öyle), tüm hesaplamalarını ona göre yap. Karıştırma!
7. NN'de Sık Karşılaşılan Türevler#
Bir mühendisin ezbere bilmesi gereken türevler:
| Operasyon | İleri (forward) | Geri (backward) |
|---|---|---|
y = Wx + b | linear | ∂y/∂W = x^T∂y/∂x = W∂y/∂b = 1 |
y = σ(x) | 1/(1+e^{-x}) | y(1-y) |
y = tanh(x) | tanh(x) | 1 - y² |
y = ReLU(x) | max(0, x) | 1 |
y = softmax(x) | e^{x_i} / Σe^{x_j} | dense Jacobian (aşağıda) |
L = CE(y, t) | -Σ t_i log(y_i) | dense ama softmax ile birleşince zarif |
Softmax Jacobian#
y_i = e^{x_i} / Σ_k e^{x_k}Matris formunda: .
J = diag(y) - y y^TBu Jacobian dense ve vektör girdisinin softmax'ı ile parametrize.
8. Softmax + Cross-Entropy: Sihirli Sadeleşme#
Bir LLM'in son katmanı tipik olarak:
logits → softmax → probs → cross-entropy with target
İki ayrı türev hesaplayıp çarparsan complicated. Ama birleştirip türev alınca çok zarif sonuç:
Setup#
- Logits: ∈ ℝ^V (V = vocab size)
z - Probs:
y = softmax(z) - Target: (one-hot veya integer)
t - Loss: (sadece doğru sınıfın log'u)
L = -log(y_t)
Türev (manuel)#
L = -log(y_t) = -log(e^{z_t} / Σ e^{z_k}) = -z_t + log(Σ e^{z_k}) ∂L/∂z_i = -[i == t] + e^{z_i} / Σ e^{z_k} = -[i == t] + y_i = y_i - [i == t] = y_i - t_i (one-hot t için)
Sonuç (göz alıcı)#
Predicted - target. Bu kadar basit.
Niye önemli?#
- Numerik stabilite: softmax + log'u ayrı hesaplamak overflow riski; birleştirilmiş (veya
log_softmax + nll_loss) stabildir.cross_entropy - Hız: tek geçişte gradient.
- Sezgi: "ne kadar yanılmıştın" doğrudan output'tan target'ı çıkarınca buluyorsun.
PyTorch'un fonksiyonu bu birleşimi otomatik yapıyor — sen log_softmax çağırmıyorsun, zaten içerdiği için.
F.cross_entropynn.CrossEntropyLosspython
import torchimport torch.nn.functional as F # Setuptorch.manual_seed(0)logits = torch.randn(1, 5, requires_grad=True) # 1 örnek, 5 sınıftarget = torch.tensor([2]) # doğru sınıf: 2 # Forwardloss = F.cross_entropy(logits, target)print("Loss:", loss.item()) # Backward (autograd)loss.backward()print("Autograd grad:", logits.grad) # Manuel: grad = softmax(logits) - one_hot(target)probs = F.softmax(logits.detach(), dim=-1)one_hot = torch.zeros_like(probs)one_hot[0, target] = 1.0manual_grad = probs - one_hotprint("Manual grad:", manual_grad) # Karşılaştırprint("Diff:", (logits.grad - manual_grad).abs().max().item()) # ~0Softmax + cross-entropy zarif türevini manuel doğrulama.
9. Manuel Backprop — Bir Mini-Ağda Adım Adım#
Şimdi her şeyi birleştirelim. Basit bir 2-katmanlı ağ:
x ∈ ℝ^3 → W₁ ∈ ℝ^{4×3}, b₁ ∈ ℝ^4 → h = ReLU(W₁x + b₁) → W₂ ∈ ℝ^{2×4}, b₂ ∈ ℝ^2 → z = W₂h + b₂ → L = CE(z, t)
Forward#
z₁ = W₁ x + b₁ h = ReLU(z₁) = max(0, z₁) z₂ = W₂ h + b₂ L = -log(softmax(z₂)[t])
Backward (zincir kuralı)#
∂L/∂z₂ = softmax(z₂) - one_hot(t) (yukarıdaki sihir) ∂L/∂W₂ = ∂L/∂z₂ · h^T (outer product) ∂L/∂b₂ = ∂L/∂z₂ ∂L/∂h = W₂^T · ∂L/∂z₂ ∂L/∂z₁ = ∂L/∂h · (z₁ > 0) (ReLU türevi: 1 if z₁>0) ∂L/∂W₁ = ∂L/∂z₁ · x^T ∂L/∂b₁ = ∂L/∂z₁
python
import torch torch.manual_seed(0)x = torch.randn(3)W1 = torch.randn(4, 3, requires_grad=True)b1 = torch.randn(4, requires_grad=True)W2 = torch.randn(2, 4, requires_grad=True)b2 = torch.randn(2, requires_grad=True)t = torch.tensor(1) # Forwardz1 = W1 @ x + b1h = torch.relu(z1)z2 = W2 @ h + b2loss = torch.nn.functional.cross_entropy(z2.unsqueeze(0), t.unsqueeze(0)) # Backward (autograd)loss.backward() # Manuel hesaplaprobs = torch.softmax(z2, dim=0)one_hot = torch.zeros_like(probs)one_hot[t] = 1.0dL_dz2 = probs - one_hot # (2,)dL_dW2 = dL_dz2.unsqueeze(1) @ h.detach().unsqueeze(0) # (2, 4)dL_db2 = dL_dz2 # (2,)dL_dh = W2.detach().T @ dL_dz2 # (4,)dL_dz1 = dL_dh * (z1.detach() > 0).float() # (4,) ReLU türevidL_dW1 = dL_dz1.unsqueeze(1) @ x.unsqueeze(0) # (4, 3)dL_db1 = dL_dz1 # Karşılaştırprint("W1 grad diff:", (W1.grad - dL_dW1).abs().max().item())print("b1 grad diff:", (b1.grad - dL_db1).abs().max().item())print("W2 grad diff:", (W2.grad - dL_dW2).abs().max().item())print("b2 grad diff:", (b2.grad - dL_db2).abs().max().item())# Hepsi ~0 → manuel hesap doğru ✓Manuel backprop ile PyTorch autograd'ı bit-exact eşleme.
🎯 İşte backprop'un tamamı bu
Yukarıdaki 10 satırlık manuel hesap, Llama 3 8B'nin 32 layer'ında 32x tekrarlanan şey. Karmaşıklık ölçektendir, matematik aynıdır. Karpathy nanoGPT'sini 200 satırda yazıyor; sen şimdi her satırını anlıyorsun.
10. Vanishing ve Exploding Gradients#
Zincir kuralı şunu öğretir: gradient, birçok matrisin çarpımıdır.
∂L/∂W₁ = (∂L/∂z₂) · (W₂^T) · (ReLU') · (W₁) · ...
Eğer her matrisin eigenvalue'ları küçük (< 1) ise: çarpım sıfıra gider → vanishing gradient. Erken katmanlar öğrenmiyor.
Eğer eigenvalue'lar büyük (> 1) ise: çarpım patlar → exploding gradient. NaN loss.
Çözümler (Modül 17'de detay)#
- Residual connections (skip): zincir kısalır, gradient direkt akar
- Layer normalization / RMSNorm: aktivasyonları normalize
- Gradient clipping: ise scale
||grad||₂ > τ - Initialization (Xavier, He, Kaiming, μP): başlangıçta gradient varyansını dengele
- Better activations (GeLU, SwiGLU): kaydetme ve gradient akışı dengeli
11. PyTorch Autograd — İçeriye Bir Bakış#
PyTorch autograd'i bir computational graph kurar:
- Her tensor () bir node
requires_grad=True - Her operasyon bir edge
- Forward pass'te ara çıkışlar saklanır (memory!)
- çağrılınca topological order'da reverse'lenir
backward()
Kontrol akışı#
x = torch.tensor(1.0, requires_grad=True) y = x ** 2 z = y * 3 print(z.grad_fn) # MulBackward0 print(y.grad_fn) # PowBackward0 print(x.grad_fn) # None (leaf) z.backward() print(x.grad) # 6.0 (dz/dx = 6x = 6)
.detach() ve with torch.no_grad()#
.detach()with torch.no_grad()Bazı işlemleri graph'ten çıkar: gradient hesaplanmasın, bellek tutmasın.
y = x.detach() # x ile bağı koparır with torch.no_grad(): z = some_computation(x) # inference için ideal
.backward() ikinci kez#
.backward()Default'ta computational graph free'lenir. Tekrar istersen: .
backward()retain_graph=TrueModül 2'de autograd'i sıfırdan yazacağız (micrograd Türkçe).
12. Mini Egzersizler#
-
Skaler türev:(softplus). Türevi nedir? Sigmoid'le bağı var mı?
f(x) = log(1 + e^x) -
Vektör gradient:(x ∈ ℝ^n).
f(x) = ||x||₂² = x^T xnedir?∇f -
Matrisle gradient:.
f(W) = ||Wx - y||₂²nedir? (Hint: chain rule.)∂f/∂W -
Softmax türev şekli: 5 sınıflı softmax çıktısı için Jacobian shape ne? Dense mi, diagonal mi?
-
Cross-entropy farklı yazım: t = one-hot yerine t = integer index olsa,formülü değişir mi?
∂L/∂z
Bu Derste Neler Öğrendik?#
✓ Skaler türev → kısmi türev → gradient
✓ Jacobian (vektör → vektör) ve Hessian (skaler → matris)
✓ Zincir kuralı'nın matris versiyonu — backprop'un kalbi
✓ Numerator vs denominator layout — konvansiyon karmaşası
✓ NN'de yaygın türevler: linear, sigmoid, ReLU, softmax
✓ Softmax + cross-entropy zarif türevi:
✓ Manuel backprop — bir mini ağda adım adım PyTorch'la karşılaştırma
✓ Vanishing/exploding gradient sezgisi ve çözümleri
✓ PyTorch autograd'in nasıl çalıştığına bir bakış
predicted - targetSıradaki Ders#
1.4 — Chain Rule ve Backpropagation: Mini-Autograd Sıfırdan
Karpathy'nin 'ını Türkçe sıfırdan inşa edeceğiz. class'ı, , operator overloading, topological sort'u. 100 satırlık autograd motoru — bu kursun en eğitici lab'larından biri.
microgradValue__add____mul__backward()Sık Sorulan Sorular
Var. **PyTorch denominator layout** kullanır — yani gradient'in shape'i her zaman **parametrenin shape'i ile aynı**. `W.grad` ve `W` aynı shape'te. Bu konvansiyonu benimsersen, transpoz nereye gerek olduğunu kolay tahmin edersin: parametre shape'i koruyacak şekilde. Paper'larda denominator layout daha yaygın (Goodfellow Deep Learning Book), numerator layout matematik kitaplarında. PyTorch bilen biri için: 'parametre shape'i şekli bozma' altın kuralı.
Yorumlar & Soru-Cevap
(0)Yorum yazmak için giriş yap.
Yorumlar yükleniyor...
İlgili İçerikler
Modül 0: Kurs Çerçevesi ve Atölye Kurulumu
LLM Engineer Kimdir? Junior'dan Staff'a Yapay Zekâ Mühendisliği Kariyer Haritası
Öğrenmeye BaşlaModül 0: Kurs Çerçevesi ve Atölye Kurulumu
Kurs Felsefesi: Neden Bu Yol, Neden Bu Sıra — 8 Aylık Müfredatın İskeleti
Öğrenmeye BaşlaModül 0: Kurs Çerçevesi ve Atölye Kurulumu