Backpropagation — chain rule
এই পাঠে যা শিখবেন
- Chain rule কী — single variable থেকে multi-variable
- Forward ও backward pass — pseudo-code-এ
- একটি ছোট network-এ হাতে-কলমে gradient হিসাব
- PyTorch-এ
backward()ভেতরে কী ঘটে - Common pitfalls — gradient zero, exploding gradient
১ · Backpropagation — কেন দরকার
একটি neural network-এর লক্ষ্য — lossLossমডেলের ভুলের পরিমাপ — একটি scalar সংখ্যা। যত কম, তত ভাল prediction। Training-এর সময় এটি minimize করা হয়। minimize করা। কিন্তু একটি GPT-3-এর ১৭৫ বিলিয়ন parameter — প্রতিটির জন্য কীভাবে বুঝব loss কমাতে কোন দিকে যেতে হবে?
উত্তর — gradientGradientএকটি function কতটা পরিবর্তিত হয় input পরিবর্তিত হলে — partial derivatives-এর vector। Loss কমানোর সঠিক দিক দেখায় (negative gradient)।। প্রতিটি weight-এর জন্য $\frac{\partial L}{\partial w}$ চাই — loss এই weight-এর সাপেক্ষে কতটা সংবেদনশীল। Backpropagation এই gradient গণনার efficient algorithm।
১) Forward pass: input → output, প্রতিটি স্তরে value store।
২) Backward pass: loss → input, chain rule প্রয়োগ করে প্রতিটি weight-এর gradient।
২ · Chain rule — gradient-এর প্রাণ
Calculus থেকে: যদি $y = f(g(x))$, তবে
$$\frac{dy}{dx} = \frac{dy}{dg} \cdot \frac{dg}{dx}$$
উদাহরণ: $y = (3x + 1)^2$। ধরা যাক $u = 3x + 1$, তাহলে $y = u^2$।
$\frac{dy}{du} = 2u$, $\frac{du}{dx} = 3$ → $\frac{dy}{dx} = 2u \cdot 3 = 6(3x+1)$।
৩ · ছোট network — হাতে-কলমে
একটি একদম সরল network: এক input $x$, একটি hidden neuron, এক output।
$$z = wx + b, \quad a = \sigma(z), \quad L = \tfrac{1}{2}(a - y)^2$$
যেখানে $\sigma$ হলো sigmoid। প্রশ্ন — $\frac{\partial L}{\partial w}$ কত?
Chain rule:
$$\frac{\partial L}{\partial w} = \frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial z} \cdot \frac{\partial z}{\partial w}$$
প্রতিটি local gradient হিসাব করি:
- $\frac{\partial L}{\partial a} = (a - y)$ — error signal।
- $\frac{\partial a}{\partial z} = \sigma(z)(1 - \sigma(z)) = a(1-a)$ — sigmoid-এর derivative।
- $\frac{\partial z}{\partial w} = x$ — linear-এর derivative।
একসাথে:
$$\frac{\partial L}{\partial w} = (a - y) \cdot a(1-a) \cdot x$$
৪ · দুই-স্তর network — gradient flow
এবার একটি hidden layer যোগ করি: input $x$ → hidden $h$ → output $\hat{y}$।
$$z_1 = w_1 x + b_1, \quad h = \sigma(z_1)$$ $$z_2 = w_2 h + b_2, \quad \hat{y} = \sigma(z_2)$$ $$L = \tfrac{1}{2}(\hat{y} - y)^2$$
Output layer-এর weight $w_2$:
$$\frac{\partial L}{\partial w_2} = \underbrace{(\hat{y} - y)}_{\delta_2} \cdot \hat{y}(1-\hat{y}) \cdot h$$
Hidden layer-এর weight $w_1$: এখানে chain আরও দীর্ঘ —
$$\frac{\partial L}{\partial w_1} = \underbrace{(\hat{y}-y) \cdot \hat{y}(1-\hat{y}) \cdot w_2}_{\delta_1} \cdot h(1-h) \cdot x$$
মূল সূত্র: পরবর্তী স্তরের error signal আগের স্তরে $w_2$ দিয়ে গুণিত হয়ে আসে। এটাই "error backpropagation"।
৫ · Local gradient + upstream gradient
Backprop-এর সরল mental model — প্রতিটি node-এ ভাবুন:
Forward: input থেকে output হিসাব, এবং intermediate value সংরক্ষণ।
Backward: upstream gradient গ্রহণ → local gradient দিয়ে গুণ → downstream-এ পাঠানো।
downstream = upstream × local
যেমন একটি multiplication node $z = xy$: local gradient হলো $\frac{\partial z}{\partial x} = y$ এবং $\frac{\partial z}{\partial y} = x$। Upstream থেকে $\frac{\partial L}{\partial z}$ পেলে, downstream-এ $y \cdot \frac{\partial L}{\partial z}$ ও $x \cdot \frac{\partial L}{\partial z}$ পাঠাবে।
৬ · NumPy দিয়ে scratch backprop
PyTorch ছাড়াই — একটি ছোট MLP-তে gradient হিসাব। বুঝতে শ্রেষ্ঠ উপায়।
import numpy as np
np.random.seed(0)
# একটি ছোট MLP: 2 → 3 → 1
W1 = np.random.randn(2, 3) * 0.5
b1 = np.zeros(3)
W2 = np.random.randn(3, 1) * 0.5
b2 = np.zeros(1)
def sigmoid(z):
return 1 / (1 + np.exp(-z))
# Sample input ও target
x = np.array([0.5, -0.2])
y = 1.0
# Forward pass
z1 = x @ W1 + b1 # (3,)
h = sigmoid(z1)
z2 = h @ W2 + b2 # (1,)
y_hat = sigmoid(z2)
loss = 0.5 * (y_hat - y) ** 2
print(f"loss = {loss[0]:.4f}")
# Backward pass — chain rule হাতে-কলমে
dL_dyhat = (y_hat - y) # (1,)
dyhat_dz2 = y_hat * (1 - y_hat) # sigmoid'
dL_dz2 = dL_dyhat * dyhat_dz2 # (1,)
dL_dW2 = h.reshape(-1, 1) @ dL_dz2.reshape(1, -1) # (3, 1)
dL_db2 = dL_dz2
dL_dh = dL_dz2 @ W2.T # (3,)
dh_dz1 = h * (1 - h)
dL_dz1 = dL_dh * dh_dz1
dL_dW1 = x.reshape(-1, 1) @ dL_dz1.reshape(1, -1) # (2, 3)
dL_db1 = dL_dz1
print("dL/dW2 shape:", dL_dW2.shape) # (3, 1)
print("dL/dW1 shape:", dL_dW1.shape) # (2, 3)
print("dL/dW1[0]:", dL_dW1[0])
backward() ঠিক এই কাজই করে — শুধু সব operation-এ automatic।
৭ · PyTorch-এ verify
import torch
# একই scenario — autograd দিয়ে
torch.manual_seed(0)
W1 = torch.randn(2, 3, requires_grad=True) * 0.5
b1 = torch.zeros(3, requires_grad=True)
W2 = torch.randn(3, 1, requires_grad=True) * 0.5
b2 = torch.zeros(1, requires_grad=True)
# requires_grad ঠিকভাবে সেট করতে নতুন leaf tensor
W1 = W1.detach().requires_grad_(True)
b1 = b1.detach().requires_grad_(True)
W2 = W2.detach().requires_grad_(True)
b2 = b2.detach().requires_grad_(True)
x = torch.tensor([0.5, -0.2])
y = torch.tensor([1.0])
# Forward
z1 = x @ W1 + b1
h = torch.sigmoid(z1)
z2 = h @ W2 + b2
y_hat = torch.sigmoid(z2)
loss = 0.5 * (y_hat - y) ** 2
# Backward — autograd সব gradient compute করে
loss.backward()
print("dL/dW2:", W2.grad)
print("dL/dW1:", W1.grad)
হাতে হিসাব ও autograd-এর values মিলে যাবে। এই-ই backprop-এর মূল verification।
৮ · গণনার সাশ্রয় — কেন backprop efficient
Naive approach — প্রতিটি weight-এর জন্য আলাদা finite-difference $\frac{L(w+\epsilon) - L(w)}{\epsilon}$। ১০০ মিলিয়ন parameter-এ ১০০ মিলিয়ন forward pass! অসম্ভব।
Backprop: একটি forward + একটি backward — সব gradient একসাথে। Cost ≈ $2 \times$ forward। এটাই DL-কে বাস্তব করেছে।
৯ · Common pitfalls
- Vanishing gradient: sigmoid/tanh-এর derivative শূন্যের কাছে — deep network-এ gradient হারিয়ে যায়। সমাধান: ReLU, Batch Norm, residual।
- Exploding gradient: বড় weight × বড় gradient — সংখ্যা NaN। সমাধান: gradient clipping।
- Gradient accumulation: PyTorch
.gradজমা হয়। প্রতি step-এoptimizer.zero_grad()দিতে ভুলবেন না। - In-place ops: autograd graph corrupt করতে পারে।
x += 1-এর বদলেx = x + 1।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ Backpropagation algorithm ১৯৬০-এর দশকে control theory-তে পরিচিত ছিল। তবু DL-এ "discovered" বলে ১৯৮৬-এর Rumelhart-Hinton-Williams পেপারকে। কী কারণে সেই পেপার এত গুরুত্বপূর্ণ?
AI history-র সবচেয়ে interesting story-গুলোর একটি। Backprop multiple times "rediscovered"। Linnainmaa (১৯৭০, master's thesis), Werbos (১৯৭৪, PhD), Parker (১৯৮৫) — সবাই algorithm-এর form ছিল। কিন্তু Rumelhart-Hinton-Williams (RHW) ১৯৮৬ Nature paper "Learning representations by back-propagating errors" ই DL revolution-এর spark।
RHW-র contribution কেন distinctive:
- Empirical demonstration: XOR সমাধান, simple internal representation শেখা — concrete proof।
- Connectionist framing: brain-inspired, neuro-scientific community-তে appeal।
- Clear pedagogy: notation accessible, formula reproducible।
- Right venue: Nature — wide reach। Werbos-এর PhD thesis কেউ পড়েনি।
- Right moment: Symbolic AI winter-এর সময় alternative প্রয়োজন।
কেন আগের কাজ ignored:
- Linnainmaa-এর কাজ Finnish, control theory context — AI community-এর বাইরে।
- Werbos PhD থেকে statistics/economics তে gravitate করেছিলেন।
- Computational power inadequate — large network train অসম্ভব ছিল।
- Symbolic AI dominant — "neural net" considered fringe।
RHW-র পরও দীর্ঘ winter (১৯৯৫-২০১২):
- SVM, kernel methods superior performance ছোট ডেটায়।
- Vanishing gradient — deep network train কঠিন।
- Hardware limitation — CPU-only।
- Big data + GPU + ImageNet (২০১২) — তবেই DL fly।
মূল উপলব্ধি: Scientific "discovery" শুধু algorithm-এর প্রথম formulation না — community-তে adoption, demonstration, pedagogy সব। Hinton-এর persistence ৪০ বছর — DL-এর mother। ২০১৮ Turing Award তাই।
Bangladesh-এ পাঠ: ভাল idea publish + demonstrate + accessible — এই ৩-T critical। শুধু গণিত যথেষ্ট না।
প্র ০২ Forward-mode আর reverse-mode automatic differentiation — দু'টোর difference কী? Backprop = reverse-mode কেন DL-এ better?
Automatic differentiation (AD) সাধারণত দু'ভাবে — forward ও reverse। দু'টোই chain rule, কিন্তু order ভিন্ন। Choice depends on input/output dimension।
Forward-mode AD:
- Input থেকে output — input-এর প্রতিটি variable-এর সাপেক্ষে derivative compute হয়।
- $f: \mathbb{R}^n \to \mathbb{R}^m$ — যদি $n$ ছোট, কার্যকর।
- প্রতি forward pass — একটি input variable-এর সব output gradient।
- মোট cost: $n \times \text{forward cost}$।
Reverse-mode AD (backprop):
- Output থেকে input — প্রতিটি output-এর সাপেক্ষে input-এর derivative।
- $m$ ছোট হলে কার্যকর।
- প্রতি backward — একটি output-এর সব input gradient।
- মোট cost: $m \times \text{forward cost}$।
DL-এ scenario:
- Input (parameters): $n = $ লক্ষ-কোটি।
- Output (loss): $m = 1$ (একটি scalar)।
- $m \ll n$ → reverse-mode বহুগুণ efficient।
উদাহরণ ResNet-50 (২৫M params):
- Forward-mode: ২৫M × forward = অকল্পনীয়।
- Reverse-mode: ১ × forward + ১ × backward ≈ ২× forward = চলবে।
Memory trade-off:
- Forward-mode — minimal memory, no activation save।
- Reverse-mode — সব intermediate activation save (memory $O(\text{depth})$)।
- সমাধান: gradient checkpointing — কিছু activation save, বাকি recompute।
কখন forward-mode useful:
- Few inputs, many outputs — যেমন physics-informed neural network।
- Jacobian-vector product (JVP) compute — JAX-এর primitive।
- Sensitivity analysis।
Hybrid approaches:
- Forward-over-reverse: Hessian-vector product।
- Reverse-over-forward: alternative second-order।
- JAX
jvp,vjp,hessian— composable।
Theoretical insight:
- Backprop discovered হয়েছিল control theory ও statistics-এ — DL-এর বহু আগে।
- Reverse-mode AD = "adjoint method" নামেও পরিচিত (continuous version)।
- ODE-NN, neural ODE-তে adjoint method ব্যবহৃত।
মূল উপলব্ধি: Mode-এর choice — input/output dimension-এ। DL-এ scalar loss + millions params → reverse-mode king। Forward-mode niche but useful। AD theory DL-এর চেয়ে মৌলিক — physics, finance, optimization-এও।
প্র ০৩ Backprop নিয়ে Hinton-এর সাম্প্রতিক বিতর্ক — তিনি বলেছেন brain probably backprop ব্যবহার করে না। তাহলে কি backprop AI-র wrong path? বিকল্প কী আছে?
২০২২-২০২৩-এ Hinton-এর "forward-forward" paper ও multiple talks DL community-তে কাঁপন তুলেছে। ৪০ বছর backprop-এর champion এখন alternatives খুঁজছেন।
Brain-এর backprop সমস্যা:
- Symmetric weights problem: backprop forward ও backward path-এ একই weight ব্যবহার করে। জীববৈজ্ঞানিকভাবে অসম্ভব — neuron-এর synapse direction-specific।
- Global error signal: backprop-এ loss একটি global signal — সারা network-এ broadcast। Brain-এ এমন mechanism নেই।
- Sequential dependency: backward pass forward pass complete-এর জন্য অপেক্ষা করতে হয়। Brain real-time, asynchronous।
- Memory storage: Backprop-এর জন্য সব intermediate activation store দরকার। Brain তা করে না।
Biologically plausible alternatives:
- Feedback alignment (Lillicrap, ২০১৬): backward path-এ random fixed weight ব্যবহার — তবু কাজ করে! Symmetric weight প্রয়োজন না।
- Direct Feedback Alignment: error সরাসরি deep layer-এ — sequential dependency কমায়।
- Equilibrium propagation: energy-based — local update only।
- Predictive coding: top-down prediction + bottom-up correction। Hierarchical Bayesian framework।
- Forward-forward (Hinton, ২০২২): দু'টি forward pass — positive (real data) ও negative (perturbed)। Layer-wise local objective।
Forward-forward-এর promise:
- No backward pass — pure forward।
- Each layer self-contained objective।
- Asynchronous, distributed-friendly।
- Sleep-cycle interpretation (positive day, negative dream)।
Forward-forward-এর সীমাবদ্ধতা:
- এখনো MNIST-এ backprop থেকে দুর্বল।
- Theoretical convergence guarantee weak।
- Large-scale (ImageNet) test হয়নি যথাযথভাবে।
তবু backprop কেন dominate:
- Empirically supreme — সব benchmark-এ।
- Hardware ও software optimized।
- Theoretical analysis well-developed।
- "AI need not be brain-like" — কিছু researcher-এর position।
Hardware perspective:
- Neuromorphic chip (Intel Loihi, IBM TrueNorth) — local update favor।
- Backprop on neuromorphic hardware কঠিন।
- If neuromorphic mainstream — alternatives essential।
মূল উপলব্ধি: Backprop "wrong" না — but possibly suboptimal long-term। Brain-inspired AI-এ alternatives রয়েছে। Hinton-এর self-questioning শেখায় — best researcher = own work-এ critical। আগামী দশকে hybrid approaches দেখব হয়তো — backprop-এর সাথে local rules-এর mix।
প্র ০৪ আপনি একটি ৫০-layer network train করছেন। Loss explode করে NaN হয়ে যাচ্ছে। কী কী cause হতে পারে, কীভাবে diagnose ও fix করবেন?
প্রতিটি DL practitioner-এর nightmare। NaN debugging — মৌলিক skill।
সম্ভাব্য কারণ:
- Exploding gradient: backprop-এ gradient বিশাল হয়ে যায়।
- Learning rate বেশি: বড় step, divergence।
- Bad initialization: weight scale wrong।
- Numerical instability: log(0), divide by zero।
- Mixed precision overflow: FP16 range সীমিত।
- Bad data: NaN বা Inf input।
Diagnostic steps:
- (১) Anomaly detection:
torch.autograd.set_detect_anomaly(True) # কোন operation NaN cause করেছে — stack trace - (২) Gradient norm monitor:
for name, p in model.named_parameters(): if p.grad is not None: print(name, p.grad.norm().item()) - (৩) Loss explosion track:
# Per-step loss log if torch.isnan(loss) or loss > 1e6: print("Anomaly at step", step) - (৪) Activation statistics:
def hook(module, input, output): print(module, output.mean(), output.std(), output.max()) model.register_forward_hook(hook) - (৫) Data check:
assert not torch.isnan(X).any() assert not torch.isinf(X).any()
Fix strategies — priority order:
- (১) Lower learning rate: 0.01 → 0.001 → 0.0001। সবচেয়ে সহজ ও effective।
- (২) Gradient clipping:
অসাধারণ — explosion থামায় immediately।torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) - (৩) Better initialization:
- Xavier — sigmoid/tanh-এর জন্য।
- Kaiming — ReLU-এর জন্য।
- Default PyTorch init usually decent।
- (৪) Batch Normalization বা LayerNorm: activation distribution stabilize করে।
- (৫) Residual connections: deep network-এ gradient flow improve।
- (৬) Warmup schedule:
শুরুতে gentle, পরে full speed।lr = base_lr * min(1, step / warmup_steps) - (৭) Mixed precision careful:
scaler = torch.cuda.amp.GradScaler() scaler.scale(loss).backward() # FP16 overflow protect - (৮) Loss function fix:
nn.BCEWithLogitsLossinstead ofBCELoss(sigmoid(x))— numerically stable।F.cross_entropy— log-softmax fused।log(x + 1e-8)— small epsilon।
Architecture-specific:
- Transformer: pre-LN > post-LN (more stable)।
- RNN: gradient clipping critical। LSTM/GRU > vanilla RNN।
- GAN: separate optimizer, careful balance।
Production checklist:
- NaN detection in training loop।
- Checkpoint frequent — recovery easy।
- Gradient histogram (TensorBoard/W&B)।
- Learning rate finder (Smith ২০১৭)।
মূল উপলব্ধি: NaN debugging — systematic detective work। Lower LR + clip gradient — ৮০% case fix। বাকি — initialization, normalization, architecture। Practice দিয়েই intuition গড়ে।
অনুশীলন
-
Chain rule: $y = \sin(x^2 + 1)$। $\frac{dy}{dx}$ কী?
$u = x^2 + 1$ ধরলে $y = \sin(u)$। $\frac{dy}{du} = \cos(u)$, $\frac{du}{dx} = 2x$। তাই $\frac{dy}{dx} = 2x \cos(x^2+1)$।
-
Hand backprop: $z = wx + b$, $a = \text{ReLU}(z)$, $L = a^2$। যদি $w = 2, x = 1.5, b = -1$, $\frac{\partial L}{\partial w}$ কত?
$z = 2(1.5) - 1 = 2$ → $a = 2$ → $L = 4$।
Chain: $\frac{\partial L}{\partial w} = \frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial z} \cdot \frac{\partial z}{\partial w} = 2a \cdot 1 \cdot x = 2(2)(1.5) = 6$।
(ReLU $z > 0$ হলে derivative = 1)
-
PyTorch verify: উপরের প্রশ্নটি autograd-এ verify করুন।
import torch w = torch.tensor(2.0, requires_grad=True) x = torch.tensor(1.5) b = torch.tensor(-1.0, requires_grad=True) z = w * x + b a = torch.relu(z) L = a ** 2 L.backward() print(w.grad) # tensor(6.)
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পাঠ ১০ · Computational graph পরবর্তী পাঠ Backprop যেখানে চলে — graph-এর গাঠন।
- পাঠ ০৮ · PyTorch tensor আগের পাঠ Autograd-এর foundation।
- পাঠ ১৪ · Vanishing/Exploding gradient এই পাঠের সাথে সম্পর্কিত Backprop-এর সবচেয়ে কুখ্যাত সমস্যা।
- সব AI Courses দেখুন ABCL TECH Python, ML, DL, NLP, CV, GenAI, RL, MLOps — সব AI কোর্স একসাথে।