Chapter 10

ব্যাকপ্রোপাগেশন

Backpropagation
🎬 Deep Learning-এর হৃদয়
Forward propagation দিয়ে output বের হলো, Loss দিয়ে ভুলের পরিমাপ হলো — এবার মূল প্রশ্ন: কোন weight কতটা বদলালে loss কমবে? এই প্রশ্নের উত্তরই Backpropagation। ১৯৮৬ সালে Rumelhart, Hinton, Williams এর একটি পেপার আবার Deep Learning-কে জীবন দেয়।

মূল ধারণা — Chain Rule প্রয়োগ

Backprop মানে output-এর ভুল থেকে শুরু করে পেছনের দিকে প্রতিটি weight পর্যন্ত gradient হিসাব করা। Chain rule দিয়ে layer-by-layer derivative গুণ করা হয়।

∂L/∂W = (∂L/∂a) × (∂a/∂z) × (∂z/∂W)

চারটি ধাপ

STEP
Forward

Input থেকে output বের করুন, প্রতিটি z, a save করুন।

STEP
Loss

Predicted ও true থেকে loss হিসাব করুন।

STEP
Backward

Output থেকে শুরু করে প্রতিটি layer-এর gradient।

STEP
Update

Gradient দিয়ে weight update — w = w - lr × ∂L/∂w।

একটি ছোট্ট নেটওয়ার্কে হাতে-কলমে

ধরুন: 2 input → 2 hidden → 1 output, sigmoid activation, MSE loss।

δ_output = (a - y) × σ'(z) δ_hidden = (W·δ_output) × σ'(z_hidden) ∂L/∂W = δ × a_prev.T

NumPy-তে সম্পূর্ণ Backprop

import numpy as np

def sigmoid(z): return 1/(1+np.exp(-z))
def sig_deriv(a): return a * (1 - a)

# Toy data: XOR
X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([[0],[1],[1],[0]])

np.random.seed(0)
W1 = np.random.randn(2, 4)
b1 = np.zeros((1, 4))
W2 = np.random.randn(4, 1)
b2 = np.zeros((1, 1))
lr = 0.5

for epoch in range(5000):
    # Forward
    z1 = X @ W1 + b1
    a1 = sigmoid(z1)
    z2 = a1 @ W2 + b2
    a2 = sigmoid(z2)

    # Loss (MSE)
    loss = np.mean((a2 - y)**2)

    # Backward
    dz2 = (a2 - y) * sig_deriv(a2)        # (4,1)
    dW2 = a1.T @ dz2                       # (4,1)
    db2 = dz2.sum(axis=0, keepdims=True)

    dz1 = (dz2 @ W2.T) * sig_deriv(a1)    # (4,4)
    dW1 = X.T @ dz1                        # (2,4)
    db1 = dz1.sum(axis=0, keepdims=True)

    # Update
    W2 -= lr * dW2; b2 -= lr * db2
    W1 -= lr * dW1; b1 -= lr * db1

    if epoch % 1000 == 0:
        print(f"Epoch {epoch}: loss = {loss:.4f}")

print("Prediction:\n", a2.round(2))
🔑 Computational Graph
Backprop আসলে computational graph-এ reverse mode auto-differentiation। PyTorch/TensorFlow এই graph automatically তৈরি করে — আপনাকে গণিত করতে হয় না, শুধু loss.backward() বললেই হয়।

PyTorch-এ একই কাজ

import torch
import torch.nn as nn

net = nn.Sequential(nn.Linear(2,4), nn.Sigmoid(), nn.Linear(4,1), nn.Sigmoid())
opt = torch.optim.SGD(net.parameters(), lr=0.5)
loss_fn = nn.MSELoss()

X = torch.tensor([[0,0],[0,1],[1,0],[1,1]], dtype=torch.float)
y = torch.tensor([[0],[1],[1],[0]], dtype=torch.float)

for epoch in range(5000):
    pred = net(X)
    loss = loss_fn(pred, y)
    opt.zero_grad()
    loss.backward()    # ← Backprop magic
    opt.step()

সাধারণ সমস্যা

⚠️ Vanishing ও Exploding Gradient
  • Vanishing: অনেক layer-এ sigmoid/tanh ব্যবহার → gradient ০-এর দিকে যায় → প্রথম layer শেখে না।
  • Exploding: Weight বড় হলে gradient বিস্ফোরিত হয় → NaN।
  • সমাধান: ReLU, proper initialization (He/Xavier), Batch Normalization, gradient clipping।

অনুশীলন

১. উপরের XOR কোডে activation ReLU-তে বদলান — কী হয়?

২. Learning rate পরিবর্তন করে (0.01, 1.0, 10.0) loss curve observe করুন।

মিনি প্রজেক্ট

🚀 আজকের চ্যালেঞ্জ
শুধু NumPy দিয়ে 3-layer নেটওয়ার্ক বানিয়ে sklearn.datasets.make_moons dataset-এ train করুন। Loss curve plot করুন।

ইন্টারভিউ প্রশ্ন

  1. Backpropagation কী এবং কেন chain rule দরকার?
  2. Vanishing ও exploding gradient — কারণ ও সমাধান।
  3. Autograd কী?
  4. loss.backward() কী করে ভেতরে?

সারসংক্ষেপ

✨ এই অধ্যায়ে যা শিখলাম
  • Backprop = chain rule দিয়ে gradient propagate করা।
  • Forward → Loss → Backward → Update — মূল চক্র।
  • পরের অধ্যায়ে শিখব gradient ব্যবহার করে weight update-এর algorithm — Gradient Descent।