এই পর্বে যা শিখবেন
- Deep network কেন overfit করে, আর train/val-এর ফারাক কীভাবে পড়বেন
- Weight decay-কে “সংকোচন, তারপর ধাপ” হিসেবে, আর Adam-এ L2 বনাম AdamW-এর পার্থক্য
- Dropout train আর eval mode-এ কী করে, কোথায় বসাবেন, আর MC dropout দিয়ে অনিশ্চয়তার আভাস
- Early stopping, weight-এর EMA ও SWA, আর ensemble: খরচ আর লাভ
- ইচ্ছা করে overfit করা একটি network-এ প্রতিটি কৌশলের সত্যিকারের প্রভাব মাপা
এই কোর্সের পর্ব ১০-এ training loop, AdamW আর patience-সহ early stopping লিখেছেন, আর পর্ব ০৯-এ দেখেছেন nn.Dropout train mode-এ টিকে থাকা মানকে 1/(1 − p) দিয়ে গুণ করে। Regularization-এর তত্ত্ব (L1/L2-এর জ্যামিতি, MAP, early stopping-কে implicit regularization হিসেবে দেখা) মেশিন লার্নিং কোর্সের পর্ব ১৭-এ আছে, আর bias–variance আর learning curve AI-এর ভিত্তি কোর্সের পর্ব ৬১-এ। এখানে প্রশ্ন একটাই: লাখ লাখ parameter-এর network-এ এই কৌশলগুলো আসলে কী করে, আর কতটা কাজে লাগে? পাতায় চালানো যায় এমন তিনটি NumPy ব্লক আছে (প্রথমবার প্যাকেজ নামতে কয়েক সেকেন্ড লাগে); PyTorch-এর সব আউটপুট ডেস্কটপের সত্যিকারের run থেকে।
১ · Deep network কেন overfit করে, আবার কেন generalize করে
বোর্ড পরীক্ষার আগে দুই ছাত্রের কথা ভাবুন। একজন টেস্ট পেপারের ৫০টি প্রশ্নের উত্তর হুবহু মুখস্থ করল; আরেকজন নিয়মটা বুঝল। টেস্ট পেপারে দুজনেই ১০০ পায়। আসল পরীক্ষায় প্রশ্ন একটু ঘুরিয়ে দিলে প্রথমজন আটকে যায়। Model-এর জন্য train ডেটা টেস্ট পেপার, validation আসল পরীক্ষার মহড়া। Overfitting হলো মুখস্থ করা; regularization হলো এমন নিয়ম, যা মুখস্থ করাকে কঠিন করে আর নিয়ম শেখাকে সহজ রাখে।
একটি MLP-এর parameter প্রায়ই train উদাহরণের সংখ্যার চেয়ে অনেক বেশি। অংশ ৭-এর network-এ ১৮ লাখের বেশি parameter, আর train-এ মাত্র ১০০০টি ছবি; ৩০ epoch-এর মধ্যে train accuracy ১.০০০ হয়ে যায়। Zhang ও সহকর্মীরা (ICLR ২০১৭) দেখিয়েছিলেন, বড় network এলোমেলো label-ও পুরোপুরি মুখস্থ করতে পারে। তবু বাস্তবে এরা নতুন ডেটায় ভালো করে, কারণ implicit regularization: ছোট weight থেকে শুরু, SGD-এর noise আর সীমিত ধাপ নিজেই সরল সমাধানের দিকে টানে। পর্ব ০৬-এ double descent-এ দেখেছেন, আকার বাড়ালে test ভুল সবসময় এক দিকে চলে না। তাই deep learning-এ regularization মানে পুরোনো bias–variance-এর সরল হিসাব নয়; এগুলো এমন হাতিয়ার, যার প্রভাব মেপে দেখতে হয়।
নিচের ছবিতে training-এর প্রতিটি স্তরে কোন regularizer কাজ করে, তা দেখানো হলো। এই পর্বে মূলত optimizer, model আর weight-এর গড়ের অংশ; ডেটা আর loss-এর অংশ পরের পর্বগুলোতে।
Regularizer কোথায় কাজ করে
Where each regularizer acts in the training pipeline
২ · NumPy-তে ইচ্ছা করে overfit — কোনো regularization নেই, weight decay আর dropout
সবচেয়ে পরিষ্কার পরীক্ষা: খুব কম ডেটায় খুব বড় network. নিচের ব্লকে sin(3x)-এর ১২টি noisy বিন্দু (noise-এর মানবিচ্যুতি ০.২৫, তাই সেরা সম্ভাব্য val MSE প্রায় ০.০৬), আর ১ → ২০০ (tanh) → ১-এর network, Adam দিয়ে ৩০০০ ধাপ। একই শুরুর weight থেকে তিনবার train: কিছু ছাড়া, weight decay λ = ০.৩ দিয়ে, আর dropout p = ০.৩ দিয়ে। Backward-এর সূত্র পর্ব ০৪-এর; Adam-এর derivation মেশিন লার্নিং কোর্সের পর্ব ১৪-এ।
import numpy as np, matplotlib.pyplot as plt
rng = np.random.default_rng(0); f = lambda x: np.sin(3 * x) # ১২টি train, ২০০টি val বিন্দু
xtr = np.sort(rng.uniform(-1, 1, 12)); ytr = f(xtr) + rng.normal(0, 0.25, 12)
xva = np.linspace(-1, 1, 200); yva = f(xva) + rng.normal(0, 0.25, 200)
H = 200 # 1 → 200 hidden → 1
def predict(P, x, p=0.0, r=None, relu=False): # p > 0 আর r দিলে dropout চালু (train mode)
z = x[:, None] @ P[0] + P[1]; h = np.maximum(z, 0) if relu else np.tanh(z)
m = (r.random(h.shape) >= p) / (1 - p) if p > 0 else 1.0 # inverted dropout mask
return h, m, (h * m) @ P[2] + P[3]
def fit(wd=0.0, p=0.0, relu=False, steps=3000, lr=0.01):
r = np.random.default_rng(1)
P = [r.normal(0, 6, (1, H)), r.normal(0, 4, H), r.normal(0, H ** -0.5, (H, 1)), np.zeros(1)]
M = [np.zeros_like(a) for a in P]; V = [np.zeros_like(a) for a in P]
for t in range(1, steps + 1):
h, m, out = predict(P, xtr, p, r, relu)
g = 2 * (out - ytr[:, None]) / len(xtr) # MSE-এর gradient
dh = (g @ P[2].T) * m * ((h > 0) if relu else 1 - h ** 2)
G = [xtr[None, :] @ dh, dh.sum(0), (h * m).T @ g, g.sum(0)]
for i in range(4):
if i in (0, 2): P[i] *= 1 - lr * wd # weight decay: আগে সংকোচন (bias বাদ)
M[i] = 0.9 * M[i] + 0.1 * G[i]; V[i] = 0.999 * V[i] + 0.001 * G[i] ** 2 # Adam
P[i] -= lr * (M[i] / (1 - 0.9 ** t)) / (np.sqrt(V[i] / (1 - 0.999 ** t)) + 1e-8)
return P
mse = lambda P, x, y: np.mean((predict(P, x)[2][:, 0] - y) ** 2)
runs = {"none": fit(), "weight decay 0.3": fit(wd=0.3), "dropout 0.3": fit(p=0.3)}
for name, P in runs.items():
print(f"{name:16s} train {mse(P, xtr, ytr):.4f} | val {mse(P, xva, yva):.4f} | ||W2|| {np.linalg.norm(P[2]):.2f}")
plt.scatter(xtr, ytr, c="k", zorder=3, label="train points"); plt.plot(xva, f(xva), "k:", label="true sin(3x)")
for name, P in runs.items(): plt.plot(xva, predict(P, xva)[2][:, 0], label=name)
plt.ylim(-2, 2); plt.xlabel("x"); plt.ylabel("y"); plt.legend(fontsize=8); plt.title("12 points, 200 hidden units"); plt.show()আউটপুট (পাতার Python-এ চালানো; MSE দুটি, নিচে চিত্রও আঁকা হয়):
none train 0.0070 | val 0.4324 | ||W2|| 1.92
weight decay 0.3 train 0.0226 | val 0.1001 | ||W2|| 1.58
dropout 0.3 train 0.0443 | val 0.0764 | ||W2|| 0.28
কিছু ছাড়া network ১২টি বিন্দুর প্রায় সবগুলো ছুঁয়ে যায় (train MSE ০.০০৭, noise-এর ০.০৬২৫-এর চেয়েও কম: অর্থাৎ noise-ও মুখস্থ), আর বিন্দুগুলোর মাঝখানে চিত্রে বাঁকা ঢেউ আঁকে; val MSE ০.৪৩২. Weight decay-এ train ভুল একটু বাড়ল, val নামল ০.১০০-এ; dropout-এ train ভুল আরও বেশি, val সবচেয়ে কম ০.০৭৬. দুটিই একই কাজ করছে: train-এ একটু খারাপ হওয়ার বিনিময়ে নতুন ডেটায় ভালো। ||W2|| হলো শেষ layer-এর weight-এর দৈর্ঘ্য; weight decay সেটি ছোট রাখে, আর dropout-এ তা ০.২৮, কারণ ২০০ unit-এর অনেকগুলো মিলে কাজ ভাগ করে, কোনো একটির ওপর ভর নেই। মনে রাখুন, এটি একটি seed-এর একটি run; λ বা p বদলালে, বা অন্য seed-এ, সংখ্যা বদলাবে।
৩ · Weight decay — প্রতি ধাপে শূন্যের দিকে একটু টান
Weight decay-এর ধারণা সরল: প্রতিটি ধাপে প্রতিটি weight-কে একটু ছোট করুন, যাতে শুধু যে weight-গুলো loss কমাতে সত্যিই দরকার, সেগুলো বড় থাকে। Learning rate η (eta) আর decay-এর হার λ (lambda) হলে decoupled রূপ:
w ← w · (1 − η·λ) (সংকোচন), তারপর w ← w − η · ধাপ(g)
এখানে g হলো loss-এর gradient, আর “ধাপ” SGD-তে g নিজেই, Adam-এ m̂/(√v̂ + ε). আরেকটি পুরোনো রূপ হলো L2 regularization: loss-এ (λ/2)·‖w‖² যোগ করা, যাতে gradient হয় g + λw. সাধারণ SGD-তে দুটি হুবহু এক। Adam-এ এক নয়, কারণ λw অংশটিও Adam-এর √v̂ দিয়ে ভাগ হয়। Loshchilov আর Hutter (arXiv ২০১৭, ICLR ২০১৯) এই পার্থক্য দেখিয়ে AdamW প্রস্তাব করেন। নিচের stepper একটি weight-এ দুটি পথ পাশাপাশি দেখায়।
| নিয়ম | |
| হিসাব | |
| নতুন w |
- শুরু. একটি weight w = ২.০, তার loss-gradient g = ০.৮, learning rate ০.১, decay λ = ০.৫.
- সংকোচন. Decoupled weight decay আগে w-কে (১ − ০.১ × ০.৫) = ০.৯৫ দিয়ে গুণ করে: ২.০ থেকে ১.৯. Gradient এখানে কোনো ভূমিকা রাখে না।
- ধাপ. তারপর সাধারণ SGD ধাপ: ১.৯ − ০.১ × ০.৮ = ১.৮২.
- SGD-তে L2 একই. Loss-এ (λ/২)w² যোগ করলে gradient ০.৮ + ০.৫ × ২.০ = ১.৮, আর w = ২.০ − ০.১৮ = ১.৮২. সাধারণ SGD-তে দুটি পথ এক জায়গায় পৌঁছায়।
- Adam-এ L2. Adam-এর প্রথম ধাপে m̂/√v̂ = g'/|g'|, তাই ধাপের আকার শুধু η = ০.১, gradient বড় হোক বা ছোট। L2-এর অংশ ভাগে মিলিয়ে গেল: w = ১.৯, decay-এর কোনো আলাদা প্রভাব নেই।
- AdamW. আগে সংকোচন (১.৯), তারপর loss-gradient-এর Adam ধাপ (০.১): w = ১.৮. এখানে decay আর Adam-এর ধাপ দুটিই পুরোপুরি কাজ করল। পরের ধাপগুলোতেও Adam + L2-এ যে weight-এর gradient বড়, তার decay বেশি চাপা পড়ে।
- শুধু decay. Gradient শূন্য হলে (weight কোনো কাজে লাগছে না) প্রতি ধাপে ০.৯৫ গুণ: ১০ ধাপে ২.০ × ০.৯৫১০ = ১.১৯৭৫. অপ্রয়োজনীয় weight এভাবে ধীরে ধীরে শূন্যের দিকে যায়।
PyTorch-এ torch.optim.AdamW(params, lr, weight_decay=λ) ঠিক অংশ ২-এর NumPy কোডের মতো আগে p.mul_(1 − lr·λ) করে। দুটি ব্যবহারিক কথা। প্রথম, bias আর normalization layer-এর weight-এ সাধারণত decay দেওয়া হয় না; তাই parameter দুই দলে ভাগ করা হয় (অংশ ৭-এর কোডে p.ndim > 1 দিয়ে)। দ্বিতীয়, η·λ-ই আসল সংকোচন, তাই learning rate বদলালে decay-এর শক্তিও বদলায়। λ-এর আকার, parameter group আর schedule-এর সঙ্গে সম্পর্ক পর্ব ১৫ (Optimizer আর learning-rate schedule)-এ সত্যিকারের run দিয়ে দেখবেন।
৪ · Dropout গভীরে — train আর eval-এ কী ঘটে, আর কোথায় বসাবেন
একটি গার্মেন্টস কারখানার লাইনের কথা ভাবুন, যেখানে প্রতিদিন এলোমেলোভাবে কয়েকজন কর্মী ছুটিতে থাকেন। লাইনটিকে এমনভাবে সাজাতে হয় যে কোনো একজনের ওপর সব নির্ভর না করে; প্রত্যেকে অন্যের কাজও কিছুটা জানেন। পরিদর্শনের দিন (eval) সবাই উপস্থিত। Dropout ঠিক এটাই করে: train-এ প্রতিটি ধাপে কিছু unit বন্ধ, তাই network কোনো একক পথের ওপর ভর দিতে পারে না।
PyTorch-এর inverted dropout-এ train mode-এ প্রতিটি মান p সম্ভাবনায় শূন্য হয়, আর টিকে থাকা মান 1/(1 − p) দিয়ে গুণ হয়। ফলে প্রত্যাশিত মান (expected value) বদলায় না: E[h̃] = (1 − p) · h/(1 − p) = h. Eval mode-এ কিছুই বন্ধ হয় না, কিছুই গুণ হয় না। নিচে ছয়টি unit-এর একটি layer, p = ০.৫.
| ধাপ | |
| h | |
| mask | |
| পরের layer পায় | |
| Σ w·(…) |
- Activation. ReLU-এর পরে ছয়টি unit-এর মান h. পরের layer এগুলোকে w দিয়ে গুণ করে যোগ করবে।
- Mask. Train mode-এ প্রতিটি unit স্বাধীনভাবে ০.৫ সম্ভাবনায় বাদ। এবারের mask রাখল ১, ৩ আর ৬ নম্বর unit.
- গুণ. টিকে থাকা মান ১/(১ − ০.৫) = ২ দিয়ে গুণ: ১.২ → ২.৪, ০.৮ → ১.৬, ১.৫ → ৩.০. এই গুণের জন্যই গড় একই থাকে।
- Train-এর output. ২.৪ × ০.৫ + ১.৬ × ১ + ৩.০ × ০.২ = ৩.৪. এই একটি mask-এ মানটি eval-এর চেয়ে অনেক আলাদা; প্রতিটি ধাপে network একটু আলাদা “ছোট network” দেখে।
- Eval mode. Mask নেই, গুণও নেই: ০.৬ + ০ + ০.৮ + ০.৫ − ০.২৫ + ০.৩ = ১.৯৫.
model.eval()ঠিক এটাই চালু করে। - গড়. সম্ভাব্য ২৬ = ৬৪টি mask-এর output-এর গড় ঠিক ১.৯৫, eval-এর সমান। ১০,০০০টি এলোমেলো mask-এ গড় ১.৯৪০, মানবিচ্যুতি ১.১৯: train-এ এই noise-ই regularizer.
কোথায় বসাবেন? MLP-তে সাধারণ জায়গা hidden layer-এর activation-এর পরে: Linear → ReLU → Dropout. শেষ layer-এর (logits-এর) পরে কখনো নয়, কারণ তাতে loss-এর input-ই এলোমেলো হয়। হার সাধারণত বড় fully-connected layer-এ ০.২–০.৫, input-এ থাকলে আরও কম। CNN-এর convolution layer-এ সাধারণ dropout কম কাজে দেয়, কারণ পাশের pixel প্রায় একই তথ্য বহন করে; সেখানে পুরো channel বাদ দেওয়া nn.Dropout2d বা পরের দিকের fully-connected অংশে dropout বেশি দেখা যায় (CNN পর্ব ২০–২৬-এ)। Transformer-এ attention-এর weight-এ আর residual যোগের আগে ছোট হারে dropout থাকে; খুব বড় ডেটায় pretraining-এ অনেকে dropout শূন্য রাখেন বলে রিপোর্ট আছে। BatchNorm-এর সঙ্গে dropout মেশালে train আর eval-এর পরিসংখ্যানে অমিল হতে পারে; ক্রম আর ঝুঁকি পর্ব ১৪ (Weight initialization আর normalization)-এ।
eval()-এর সুইচ: Dropout layer নিজে জানে না আপনি train করছেন না validation; সে শুধু self.training flag দেখে। অংশ ৭-এর dropout model-কে train mode-এ রেখে একই val set দুবার মাপলে সত্যিকারের run-এ accuracy এলো ০.৭৮৯ আর ০.৭৯১, eval mode-এ স্থির ০.৮১৪. torch.no_grad() এই সুইচ নয়; সেটি শুধু graph বানানো বন্ধ করে (পর্ব ১০)।
৫ · MC dropout — অনিশ্চয়তার এক ঝলক
Inference-এর সময় যদি dropout ইচ্ছা করে চালু রাখি আর একই input-এ অনেকবার forward করি? প্রতিবার আলাদা “ছোট network” আলাদা উত্তর দেবে; উত্তরগুলোর ছড়ানো ভাব (spread) একটি অনিশ্চয়তার আভাস। Gal আর Ghahramani (ICML ২০১৬) এই MC dropout-কে একটি approximate Bayesian পদ্ধতি হিসেবে ব্যাখ্যা করেন (variational inference-এর ধারণা মেশিন লার্নিং কোর্সের পর্ব ৪৮-এ)। প্রত্যাশা: train ডেটা যেখানে নেই, সেখানে spread বাড়বে, অর্থাৎ epistemic uncertainty. নিচের ব্লক আগের ব্লকের dropout network (tanh) আর একই ভাবে train করা একটি ReLU network-এ ৩০০টি mask চালায়; train বিন্দু শুধু −১ থেকে ১-এর মধ্যে। আগের ব্লক একবার চালানো থাকলে এটি সেটির ফল ব্যবহার করে।
nets = {"tanh": (runs["dropout 0.3"], False), "relu": (fit(p=0.3, relu=True), True)}
xs = np.linspace(-3, 3, 121); out = abs(xs) > 1 # train ডেটা শুধু -1 থেকে 1-এর মধ্যে
for name, (P, relu) in nets.items():
r = np.random.default_rng(7) # ৩০০টি এলোমেলো dropout mask
S = np.stack([predict(P, xs, 0.3, r, relu)[2][:, 0] for _ in range(300)])
sd = S.std(0); ev = predict(P, xs, relu=relu)[2][:, 0]
print(f"{name}: x=0-তে {S.mean(0)[60]:.3f} ± {sd[60]:.3f} (eval {ev[60]:.3f}) | x=3-এ {S.mean(0)[120]:.3f} ± {sd[120]:.3f}")
print(f" গড় spread: ডেটার ভেতরে {sd[~out].mean():.3f}, বাইরে {sd[out].mean():.3f}")
plt.plot(xs, S.mean(0), label=f"{name} MC mean"); plt.fill_between(xs, S.mean(0) - 2 * sd, S.mean(0) + 2 * sd, alpha=0.25)
plt.scatter(xtr, ytr, c="k", zorder=3, label="train points"); plt.axvspan(-1, 1, color="gray", alpha=0.1)
plt.ylim(-6, 4); plt.xlabel("x"); plt.legend(fontsize=8); plt.title("MC dropout: mean ± 2 sd (300 masks)"); plt.show()আউটপুট (পাতার Python-এ চালানো):
tanh: x=0-তে -0.115 ± 0.162 (eval -0.109) | x=3-এ 0.009 ± 0.183
গড় spread: ডেটার ভেতরে 0.164, বাইরে 0.179
relu: x=0-তে -0.126 ± 0.123 (eval -0.124) | x=3-এ -1.178 ± 3.114
গড় spread: ডেটার ভেতরে 0.221, বাইরে 1.458
দুটি network, দুটি আলাদা গল্প। ReLU network-এ ডেটার বাইরে spread ছয় গুণের বেশি (০.২২১ থেকে ১.৪৫৮), আর x = ৩-এ ±৩.১১: “এখানে আমি জানি না” ধরনের সংকেত। Tanh network-এ ডেটার বাইরে spread প্রায় একই (০.১৬৪ বনাম ০.১৭৯), কারণ দূরে গেলে tanh ±১-এ আটকে যায় আর output একটি স্থির মানে থামে। অর্থাৎ MC dropout-এর “অনিশ্চয়তা” architecture-এর ওপর নির্ভর করে; এটি নিখুঁত মাপ নয়, একটি সস্তা আভাস। MC গড় আর eval-এর মান প্রায় এক (−০.১১৫ বনাম −০.১০৯), যা অংশ ৪-এর প্রত্যাশার নিয়ম। PyTorch-এ শুধু dropout layer-কে train mode-এ রেখে কীভাবে করবেন, তা অনুশীলন ৪-এ।
৬ · Early stopping আর weight-এর গড় — EMA আর SWA
Early stopping আর patience-এর কোড পর্ব ১০-এ লিখেছেন। এখানে দুটি নতুন কথা। প্রথম, কোন metric দেখে থামবেন তা গুরুত্বপূর্ণ: অংশ ৭-এর run-এ val loss epoch ৩-এ সবচেয়ে কম, কিন্তু val accuracy সবচেয়ে বেশি epoch ২৪-এ। দ্বিতীয়, শেষের weight না নিয়ে weight-এর গড় নেওয়া যায়।
Learning rate স্থির থাকলে SGD-এর weight সমাধানের চারপাশে লাফাতে থাকে, কারণ প্রতিটি mini-batch-এর gradient-এ noise আছে। সেই লাফানো weight-এর exponential moving average (EMA) রাখা যায়: w̄ ← β·w̄ + (১ − β)·w, যেখানে β (beta) ০.৯৯ বা ০.৯৯৯-এর মতো। EMA training-এ কোনো প্রভাব ফেলে না; gradient শুধু আসল weight-এ যায়, EMA পাশে আলাদা কপি। ধারণাটি পুরোনো: Polyak আর Juditsky (১৯৯২)-এর iterate averaging. Stochastic Weight Averaging (SWA; Izmailov ও সহকর্মী, UAI ২০১৮) training-এর শেষ দিকে কয়েকটি epoch-এর weight-এর সমান গড় নেয়, প্রায়ই একটি বড় বা চক্রাকার learning rate-এর সঙ্গে। নিচে বাজারঘরের ডেলিভারি সময়ের একটি সরল linear model-এ ৪টির ছোট batch দিয়ে noisy SGD.
import numpy as np, matplotlib.pyplot as plt
rng = np.random.default_rng(42) # বাজারঘর: দূরত্ব (কিমি, স্কেল করা) → ডেলিভারির সময় (মিনিট)
x = rng.uniform(-1, 1, 400); y = 30 + 8 * x + rng.normal(0, 6, 400)
xtr, ytr, xva, yva = x[:300], y[:300], x[300:], y[300:]
A = np.c_[np.ones(300), xtr]; w_best = np.linalg.lstsq(A, ytr, rcond=None)[0] # train-এর নিখুঁত সমাধান
w = np.zeros(2); ema = w.copy(); beta = 0.98; raw_hist, ema_hist = [], []
for step in range(1, 1501):
b = rng.integers(0, 300, 4) # ৪টির ছোট batch: gradient-এ অনেক noise
err = w[0] + w[1] * xtr[b] - ytr[b]
w = w - 0.1 * np.array([err.mean(), (err * xtr[b]).mean()])
ema = beta * ema + (1 - beta) * w # weight-এর EMA, gradient-এ কোনো প্রভাব নেই
raw_hist.append(w.copy()); ema_hist.append(ema.copy())
R, E = np.array(raw_hist[500:]), np.array(ema_hist[500:]) # প্রথম ৫০০ ধাপ বাদ
val = lambda w: np.mean((w[0] + w[1] * xva - yva) ** 2)
print("train-এর নিখুঁত সমাধান:", np.round(w_best, 3))
print(f"শেষ ১০০০ ধাপে নিখুঁত সমাধান থেকে গড় দূরত্ব: raw {np.linalg.norm(R - w_best, axis=1).mean():.3f}"
f" | EMA {np.linalg.norm(E - w_best, axis=1).mean():.3f}")
print(f"শেষ ধাপে val MSE: raw {val(w):.3f} | EMA {val(ema):.3f} | নিখুঁত {val(w_best):.3f}")
print(f"শেষ ১০০০ ধাপে val MSE-এর গড়: raw {np.mean([val(v) for v in R]):.3f} | EMA {np.mean([val(v) for v in E]):.3f}")
plt.plot(np.array(raw_hist)[:, 1], lw=0.6, label="raw slope w1")
plt.plot(np.array(ema_hist)[:, 1], lw=2, label=f"EMA (beta={beta})")
plt.axhline(w_best[1], c="k", ls=":", label="least-squares slope"); plt.xlabel("step"); plt.ylabel("w1")
plt.legend(); plt.title("Noisy SGD weights vs their EMA"); plt.show()আউটপুট (পাতার Python-এ চালানো; নিচে slope-এর পথের চিত্র):
train-এর নিখুঁত সমাধান: [29.633 9.049]
শেষ ১০০০ ধাপে নিখুঁত সমাধান থেকে গড় দূরত্ব: raw 0.851 | EMA 0.368
শেষ ধাপে val MSE: raw 40.334 | EMA 38.490 | নিখুঁত 38.227
শেষ ১০০০ ধাপে val MSE-এর গড়: raw 38.875 | EMA 38.326
নিখুঁত সমাধান: ভিত্তি প্রায় ২৯.৬ মিনিট আর slope ৯.০৫. কাঁচা weight সেখান থেকে গড়ে ০.৮৫১ দূরে লাফায়, EMA মাত্র ০.৩৬৮ দূরে: দ্বিগুণের বেশি কাছে। শেষ ধাপে কাঁচা weight-এর val MSE ৪০.৩৩, EMA-র ৩৮.৪৯, যা নিখুঁত সমাধানের ৩৮.২৩-এর খুব কাছে। চিত্রে কাঁচা slope কাঁপছে, EMA মসৃণ রেখায় চলছে। β = ০.৯৮ মানে মোটামুটি শেষ ১/(১ − β) = ৫০ ধাপের গড়; β বড় হলে মসৃণ কিন্তু ধীর। Deep network-এ loss-এর ভূমি convex নয়, তাই গড় সবসময় ভালো জায়গায় পড়বে, এমন নিশ্চয়তা নেই; তবে একই basin-এর কাছাকাছি weight-এর গড় প্রায়ই চওড়া, স্থির জায়গায় বসে।
PyTorch-এ এর জন্য torch.optim.swa_utils: AveragedModel(model, multi_avg_fn=get_ema_multi_avg_fn(0.999)) দিয়ে EMA, শুধু AveragedModel(model) দিয়ে সমান গড় (SWA), সঙ্গে SWALR scheduler. প্রতি ধাপে opt.step()-এর পরে ema.update_parameters(model). Model-এ BatchNorm থাকলে গড় weight-এর জন্য running statistics নতুন করে মাপতে হয়: torch.optim.swa_utils.update_bn(loader, swa_model).
৭ · PyTorch-এ সত্যিকারের তুলনা — ১০০০টি Fashion-MNIST ছবি, বড় MLP
এবার আসল network. Fashion-MNIST (Xiao, Rasul আর Vollgraf, ২০১৭; Zalando Research, MIT licence) হলো ১০ শ্রেণির পোশাকের ২৮ × ২৮ ধূসর ছবি; torchvision দিয়ে নামানো। ইচ্ছা করে overfit করার জন্য train-এ মাত্র ১০০০টি ছবি, validation-এ train অংশের আরও ৫০০০টি, আর শেষ মাপের জন্য আলাদা ১০,০০০টি test ছবি। Model: ৭৮৪ → ১০২৪ → ১০২৪ → ১০, মোট ১৮,৬৩,৬৯০টি parameter; AdamW, lr ০.০০১, ৩২-এর batch, ৬০ epoch. প্রতিটি run-এ একবারে একটিই জিনিস বদলানো হয়েছে। Script-এর মূল অংশ:
def make_mlp(p):
return nn.Sequential(
nn.Linear(784, 1024), nn.ReLU(), nn.Dropout(p),
nn.Linear(1024, 1024), nn.ReLU(), nn.Dropout(p),
nn.Linear(1024, 10))
model = make_mlp(args.p)
decay = [p for n_, p in model.named_parameters() if p.ndim > 1] # bias-এ decay নয়
no_decay = [p for n_, p in model.named_parameters() if p.ndim == 1]
opt = torch.optim.AdamW([{"params": decay, "weight_decay": args.wd},
{"params": no_decay, "weight_decay": 0.0}], lr=1e-3)
ema = AveragedModel(model, multi_avg_fn=get_ema_multi_avg_fn(args.ema)) if args.ema else None
for epoch in range(1, args.epochs + 1):
model.train()
for b in torch.randperm(1000, generator=gen).split(32):
loss = F.cross_entropy(model(Xtr[b]), ytr[b])
opt.zero_grad(); loss.backward(); opt.step()
if ema: ema.update_parameters(model)
trl, tra, _ = evaluate(model, Xtr, ytr); val, vaa, _ = evaluate(model, Xva, yva) # eval() + no_grad
...
if args.patience: # early stopping
if val < best[0]: best, bad = (val, epoch, copy.deepcopy(model.state_dict())), 0
else: bad += 1
if bad >= args.patience:
model.load_state_dict(best[2]); breakখেয়াল করুন: dropout প্রতিটি hidden ReLU-এর পরে, শেষ Linear-এর পরে নয়। Ensemble মানে seed ০, ১ আর ২-এর তিনটি “কিছু ছাড়া” model-এর softmax probability-র গড়। সত্যিকারের run (ডেস্কটপ, CPU):
~/bazarghar-dl$ uv run python reg.py --tag none
[none] torch 2.15.0+cpu | python 3.14.4 | CPU-তে 21 s
~/bazarghar-dl$ uv run python reg.py --patience 10 --tag es
[es] থামল epoch 13-এ, best epoch 3 ফেরানো হলো
~/bazarghar-dl$ uv run python reg.py --wd 0.5 --tag wd05 # একইভাবে wd2, drop05 (--p 0.5),
~/bazarghar-dl$ uv run python reg.py --ema 0.999 --tag ema # none_s1, none_s2 (--seed 1, 2)
…
~/bazarghar-dl$ uv run python summary.py
config train acc/loss │ val acc/loss │ test acc/loss
none (60 ep) 1.000 0.000 │ 0.815 1.485 │ 0.813 1.526
early stop 0.883 0.325 │ 0.792 0.591 │ 0.787 0.606
weight decay 0.5 1.000 0.001 │ 0.810 0.953 │ 0.811 0.973
weight decay 2.0 0.965 0.154 │ 0.784 0.816 │ 0.777 0.818
dropout 0.5 0.993 0.036 │ 0.814 1.025 │ 0.810 1.066
EMA 0.999 0.999 0.007 │ 0.814 0.798 │ 0.810 0.824
ensemble of 3 1.000 0.000 │ 0.814 1.250 │ 0.812 1.293
dropout model, train mode-এ val acc দুবার: [0.789, 0.791] | eval mode-এ: 0.8136
প্রতিটি run CPU-তে ১৪–২৫ সেকেন্ড (একটি স্থানীয় run). টেবিলটি সৎভাবে পড়লে শিক্ষাটি একটু অপ্রত্যাশিত: accuracy-তে প্রায় কোনো পার্থক্য নেই; সব config-এর test accuracy ০.৭৭৭ থেকে ০.৮১৩. বড় পার্থক্য loss-এ। কিছু ছাড়া model-এর val loss ১.৪৮৫, অথচ epoch ৩-এ তা ছিল ০.৫৯১: model ভুল উত্তরগুলোতেও প্রায় ১০০% নিশ্চিত হয়ে গেছে, অর্থাৎ calibration নষ্ট (মেশিন লার্নিং কোর্সের পর্ব ২৬)। Dropout, weight decay ০.৫ আর ensemble loss কমায়, EMA সবচেয়ে বেশি (০.৭৯৮)। Weight decay ২.০ বেশি জোরালো: train accuracy ০.৯৬৫-এ আটকে, test accuracy সবচেয়ে কম। Early stopping val loss দেখে epoch ৩-এর weight ফেরাল, তাই loss-এ ভালো কিন্তু accuracy-তে খারাপ। ১০০০টি ছবিতে আসল সীমা ডেটার পরিমাণ; সেখানে সবচেয়ে কার্যকর regularizer প্রায়ই আরও ডেটা বা data augmentation.
Val loss প্রতি epoch-এ — সত্যিকারের run
Validation cross-entropy per epoch, 1000 Fashion-MNIST images (values above 1.6 clipped)
শেষে একটি দক্ষতা, যা সব learning curve-এ লাগে: train আর val-এর ফারাক পড়া। নিচের stepper একই “কিছু ছাড়া” run-এর কয়েকটি epoch দেখায় (সব সংখ্যা সত্যিকারের run-এর hist_none.json থেকে)।
| epoch | |
| train loss / acc | |
| val loss / acc | |
| accuracy-র ফারাক | |
| রোগনির্ণয় |
- Epoch ১. দুটি loss-ই নামছে, ফারাক ছোট (accuracy-তে ০.০৬৩)। এখানে থামলে underfit: model এখনো যথেষ্ট শেখেনি।
- Epoch ৩. Val loss সবচেয়ে কম, ০.৫৯১. Val loss দেখে early stopping ঠিক এই epoch ফেরায়।
- Epoch ১০. Val loss বেড়ে ০.৭২৪, কিন্তু val accuracy বেড়ে ০.৭৯৯. পরস্পরবিরোধী নয়: কিছু ভুল উত্তরে model বেশি নিশ্চিত হচ্ছে (loss বাড়ে), আবার কিছু নতুন উদাহরণ ঠিক করছে (accuracy বাড়ে)।
- Epoch ২৪. Val accuracy সবচেয়ে বেশি, ০.৮১৬. Accuracy দেখে থামালে এখানে থামতেন; কোন metric দেখবেন, তা আপনার কাজের ওপর নির্ভর করে।
- Epoch ৬০. Train loss ০.০০০, accuracy ১.০০০: পুরো মুখস্থ। Val accuracy একই, কিন্তু val loss সর্বনিম্নের প্রায় আড়াই গুণ। এই model-এর probability বিশ্বাসযোগ্য নয়।
- Dropout, epoch ৬০. Accuracy-র ফারাক প্রায় একই (০.১৭৯), কিন্তু val loss ১.০২৫. এখানে dropout মুখস্থ ঠেকাতে পারেনি; ভুলের ওপর অতি-আত্মবিশ্বাস কমিয়েছে। ফারাক বড় থাকলে আরও ডেটা, augmentation বা ছোট model ভাবুন।
৮ · আরও regularizer, ensemble আর কোনটি কখন
Ensemble. কয়েকটি আলাদা seed-এর model-এর probability-র গড় (ensemble) প্রায় সবসময় একটি model-এর চেয়ে স্থির; Lakshminarayanan ও সহকর্মীরা (NeurIPS ২০১৭) এই “deep ensemble”-কে অনিশ্চয়তা মাপার একটি শক্ত baseline হিসেবে দেখান। খরচ: train আর inference দুটিই ততগুণ। Bagging আর voting-এর মূল ধারণা মেশিন লার্নিং কোর্সের পর্ব ৩৩-এ। আমাদের run-এ তিনটি model-এর ensemble val loss ১.৪৮৫ থেকে ১.২৫০-এ আনল, accuracy প্রায় একই; তিনটিই একই ভাবে মুখস্থ করলে গড়ও বেশি সাহায্য করে না।
আরও কয়েকটি, সংক্ষেপে: label smoothing target-কে একটু নরম করে (যেমন ০.৯ আর বাকিটা অন্য শ্রেণিতে ভাগ), তাই অতি-নিশ্চিত হওয়া কঠিন; বিস্তারিত পর্ব ১৩ (Deep learning-এর loss)-এ। Mixup (Zhang ও সহকর্মী, ICLR ২০১৮) দুটি ছবি আর তাদের label-এর ওজনযুক্ত মিশ্রণ বানায়; CutMix (Yun ও সহকর্মী, ICCV ২০১৯) একটি ছবির টুকরো আরেকটিতে বসায়; দুটিই পর্ব ২৪ (Data augmentation)-এ। Stochastic depth (Huang ও সহকর্মী, ECCV ২০১৬) train-এ residual block-এর পুরো শাখা এলোমেলোভাবে বাদ দেয়; একে DropPath-ও বলা হয়, আর গভীর residual network ও Vision Transformer-এ দেখা যায় (residual connection পর্ব ১৭-এ)।
| কৌশল | বাড়তি খরচ | মূল knob | কখন আগে ভাববেন |
|---|---|---|---|
| Weight decay (AdamW) | প্রায় শূন্য | λ, সঙ্গে lr | প্রায় সব সময়; bias/norm বাদ |
| Early stopping | বরং সময় বাঁচায় | patience, কোন metric | প্রায় সব সময়, checkpoint-সহ |
| Dropout | কম; একটু ধীর শেখা | p, কোন layer | বড় fully-connected অংশ, কম ডেটা |
| Data augmentation | ডেটা লোডিং-এ সময় | কোন রূপান্তর | ছবি, শব্দ, টেক্সট: প্রায়ই সবচেয়ে কার্যকর |
| EMA / SWA | weight-এর একটি কপি | β, কখন শুরু | noisy training, বড় model, diffusion |
| Ensemble | N গুণ train ও inference | N, বৈচিত্র্য | প্রতিযোগিতা, অনিশ্চয়তা জরুরি হলে |
আগে একটি regularization ছাড়া baseline দিয়ে নিশ্চিত হোন যে model overfit করতে পারে (পর্ব ১৮-এ এক batch overfit). তারপর weight decay আর early stopping, তারপর ডেটা-ভিত্তিক কৌশল, তারপর dropout বা EMA. প্রতিবার একটি বদল, কয়েকটি seed, validation-এ তুলনা, আর চূড়ান্ত config test set-এ একবার।
আরও গভীরে: Dropout-এর মূল প্রবন্ধ Hinton ও সহকর্মীদের ২০১২ সালের arXiv লেখা আর Srivastava ও সহকর্মীদের ২০১৪ সালের JMLR প্রবন্ধ। Weight decay আর L2-এর পার্থক্য Loshchilov ও Hutter-এর “Decoupled Weight Decay Regularization”-এ। BatchNorm-এর পরের weight-এ scale বদলালে output বদলায় না, তাই সেখানে weight decay আসলে কার্যকর learning rate বদলায়; এই ব্যাখ্যা van Laarhoven (২০১৭) আর পরের কিছু কাজে আলোচিত। Weight-এর গড়ের ধারা থেকে “model soup” (Wortsman ও সহকর্মী, ২০২২): একই pretrained বিন্দু থেকে fine-tune করা কয়েকটি model-এর weight-এর গড়; তবে এটি তখনই কাজ করে বলে রিপোর্ট, যখন model-গুলো loss-এর একই basin-এ থাকে।
পরীক্ষা ও ইন্টারভিউতে:
- p = ০.২-এর inverted dropout-এ train-এ টিকে থাকা মান কত দিয়ে গুণ হয়? ১/(১ − ০.২) = ১.২৫; eval-এ কিছুই না।
- Adam-এ L2 আর AdamW-এর পার্থক্য? L2-এর λw অংশ Adam-এর √v̂ দিয়ে ভাগ হয়; AdamW সরাসরি w·(১ − ηλ) করে, gradient থেকে আলাদা।
- lr ০.০০১, λ ০.০৫, gradient শূন্য; ১০,০০০ ধাপে weight কত গুণ? (১ − ০.০০০০৫)১০০০০ ≈ e−০.৫ ≈ ০.৬০৭.
- Train accuracy ১.০, val accuracy স্থির, val loss বাড়ছে: কী হচ্ছে? Overfitting, ভুল উত্তরে অতি-আত্মবিশ্বাস; early stopping, decay, augmentation, calibration ভাবুন।
- EMA β = ০.৯৯৯ মোটামুটি কত ধাপের গড়? ১/(১ − β) = ১০০০ ধাপ।
৯ · AI-এর যুগে — regularization নিয়ে AI-এর পরামর্শ যাচাই
“আমার model overfit করছে, কী করব?” জিজ্ঞেস করলে AI assistant প্রায় সবসময় একই তালিকা দেয়: dropout ০.৫, weight decay, early stopping. তালিকাটি ভুল নয়, কিন্তু অংশ ৭-এ দেখলেন, ফল ডেটা আর metric-এর ওপর নির্ভর করে। AI প্রায়ই model.eval() ভুলে যায়, logits-এর পরে dropout বসায়, Adam-এ weight_decay-কে AdamW-এর সমান ধরে, BatchNorm আর bias-এ decay দেয়, MC dropout-এর spread-কে “calibrated confidence” বলে, আর একটি seed-এর একটি run দেখে উপসংহার টানে। তাই পরামর্শের সঙ্গে পরীক্ষার পরিকল্পনাও চান।
AI-কে এভাবে জিজ্ঞেস করুন:
AI-এর regularization পরামর্শ হাতে পেলে — যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১বড় network এলোমেলো label-ও মুখস্থ করতে পারে — তাহলে আসল ডেটায় সে generalize করে কেন?
২০১৭ সালে Zhang ও সহকর্মীদের “Understanding deep learning requires rethinking generalization” (ICLR) প্রবন্ধ একটি সরল পরীক্ষা করে। CIFAR-10-এর ছবির label এলোমেলো করে দিলেও প্রচলিত CNN train ডেটায় প্রায় শূন্য ভুলে পৌঁছায়; শুধু সময় বেশি লাগে। অথচ সেই একই architecture আসল label-এ ভালো generalize করে। পুরোনো তত্ত্বে model-এর ক্ষমতা (যেমন VC dimension বা Rademacher complexity) দিয়ে generalization ব্যাখ্যা করা হতো; কিন্তু যে model এলোমেলো label মুখস্থ করতে পারে, তার ক্ষমতা এত বড় যে সেই সীমা কিছুই বলে না।
তাহলে ব্যাখ্যা কোথায়? প্রবন্ধটি দেখায়, explicit regularization (weight decay, dropout, augmentation) সাহায্য করে কিন্তু একমাত্র কারণ নয়; সেগুলো বাদ দিলেও model মোটামুটি ভালো generalize করে। তাই নজর যায় implicit regularization-এর দিকে: ছোট weight থেকে শুরু, SGD-এর noise, সীমিত ধাপ, আর architecture-এর নিজস্ব ঝোঁক (inductive bias). Linear model-এ শূন্য থেকে শুরু করা gradient descent minimum-norm সমাধানে যায় (পর্ব ০৬); deep network-এ এমন সুনির্দিষ্ট ফল এখনো আংশিক। Double descent, flat minima-র ধারণা, আর “আসল ডেটা সরল কাঠামোর, এলোমেলো label নয়” এই যুক্তি একসঙ্গে ব্যাখ্যার অংশ। অংশ ২-এর NumPy পরীক্ষায় দেখেছেন, ১২টি বিন্দু আর ২০০ unit-এ noise-ও মুখস্থ হয়; কিন্তু Fashion-MNIST-এ মুখস্থ করার পরেও accuracy ০.৮১ থাকল: মুখস্থ আর generalization একসঙ্গে ঘটতে পারে।
এর ব্যবহারিক মানে হলো, regularization-এর প্রভাব আগে থেকে অনুমান করা কঠিন; মেপে দেখতে হয়। এটি গবেষণার একটি খোলা প্রশ্ন, তাই কেউ “deep learning কেন কাজ করে তা পুরো বোঝা গেছে” বললে সতর্ক থাকুন।
মূল উপলব্ধি: মুখস্থ করার ক্ষমতা থাকা মানেই খারাপ generalization নয়; optimizer, architecture আর ডেটার কাঠামো মিলে implicit regularization কাজ করে, আর explicit regularizer তার ওপরে একটি সমন্বয়।
প্র ০২Dropout একসময় প্রায় সব network-এ ছিল; এখন অনেক CNN-এ কম দেখা যায়, আবার Transformer-এ ছোট হারে থাকে। কেন?
Dropout প্রথম বড় পরিসরে আলোচিত হয় Hinton ও সহকর্মীদের ২০১২ সালের arXiv লেখায়, আর পূর্ণ রূপে Srivastava ও সহকর্মীদের ২০১৪ সালের JMLR প্রবন্ধে। তাঁদের যুক্তি দুটি: unit-গুলো একে অন্যের ভুল ঢাকতে শেখে (co-adaptation), dropout তা ভাঙে; আর প্রতিটি ধাপে আলাদা ছোট network train হয়, তাই eval-এ পুরো network অনেক ছোট network-এর এক ধরনের গড়, একটি সস্তা ensemble. ২০১২ সালের AlexNet-এর বড় fully-connected layer-এ dropout গুরুত্বপূর্ণ ভূমিকা রেখেছিল বলে প্রবন্ধে উল্লেখ আছে।
পরে তিনটি বদল আসে। প্রথম, BatchNorm (২০১৫) নিজেই কিছুটা regularizing noise আনে, আর dropout-এর সঙ্গে মেশালে train আর eval-এর পরিসংখ্যানে অমিল হতে পারে বলে কিছু কাজে দেখা যায়। দ্বিতীয়, আধুনিক CNN-এ বড় fully-connected layer প্রায় নেই; global average pooling আর একটি ছোট শেষ layer, তাই dropout-এর জায়গাই কম। তৃতীয়, data augmentation আর weight decay প্রায়ই বেশি কার্যকর। ফলে ResNet-ধরনের CNN-এ dropout কম দেখা যায়, যদিও শেষ layer-এর আগে বা Dropout2d রূপে এখনো আছে।
Transformer-এর মূল ২০১৭ সালের নকশায় ০.১ হারের dropout ছিল: প্রতিটি sub-layer-এর output-এ residual যোগের আগে, আর embedding-এ; অনেক implementation attention-এর weight-এও dropout দেয়। খুব বড় ডেটায় pretraining-এ, যেখানে model ডেটার একেকটি উদাহরণ খুব কমবার দেখে, overfitting-এর ঝুঁকি কম; তাই কিছু বড় language model dropout শূন্য রেখে train হয়েছে বলে রিপোর্ট আছে। ছোট ডেটায় fine-tuning-এ আবার dropout আর weight decay ফিরে আসে।
মূল উপলব্ধি: Dropout-এর মূল্য নির্ভর করে architecture আর ডেটার পরিমাণের ওপর; বড় fully-connected অংশ আর কম ডেটায় এটি বেশি কাজে আসে, অন্য জায়গায় অন্য regularizer প্রায়ই ভালো।
প্র ০৩“Weight decay আর L2 regularization একই জিনিস” — এই কথা কখন সত্য, কখন নয়, আর তাতে কী আসে যায়?
Weight decay শব্দটি neural network-এর পুরোনো চর্চা থেকে; Krogh আর Hertz-এর “A Simple Weight Decay Can Improve Generalization” (NIPS, ১৯৯১-এর সম্মেলন) এর একটি পরিচিত সূত্র। সাধারণ SGD-তে loss-এ (λ/২)‖w‖² যোগ করা আর প্রতি ধাপে w-কে (১ − ηλ) দিয়ে গুণ করা গাণিতিকভাবে এক, যা অংশ ৩-এর stepper-এ ১.৮২ = ১.৮২ দিয়ে দেখেছেন। তাই অনেক library-তে optimizer-এর weight_decay argument আসলে gradient-এ λw যোগ করে, অর্থাৎ L2.
Adam-এর মতো adaptive optimizer-এ এই সমতা ভেঙে যায়। L2-এর λw অংশ gradient-এর সঙ্গে মিশে √v̂ দিয়ে ভাগ হয়। যে weight-এর gradient বড়, তার v̂ বড়, তাই তার decay কার্যত ছোট; যে weight কম ব্যবহৃত, তার decay তুলনায় বড়। Loshchilov আর Hutter (arXiv ২০১৭, ICLR ২০১৯) দেখান, decay-কে gradient থেকে আলাদা করলে (AdamW) সঠিক λ খোঁজা সহজ হয়, আর তাঁদের পরীক্ষায় generalization ভালো হয়। এর পরে AdamW অনেক Transformer training-এর সাধারণ পছন্দ হয়ে ওঠে। PyTorch-এ torch.optim.Adam(weight_decay=…) L2 করে, torch.optim.AdamW decoupled; নামের এই মিল AI assistant-দের একটি পরিচিত ভুলের উৎস।
আরেকটি সূক্ষ্মতা: BatchNorm বা LayerNorm-এর আগের weight-এ scale বদলালে output বদলায় না। সেখানে weight decay আসলে weight-কে ছোট রেখে কার্যকর learning rate বাড়ায়; এই ব্যাখ্যা নিয়ে কিছু গবেষণা আছে, তবে বিস্তারিত বিতর্কিত। তাই একই λ বিভিন্ন architecture-এ একই প্রভাব ফেলে না।
মূল উপলব্ধি: SGD-তে weight decay আর L2 এক, Adam-এ নয়; deep learning-এ AdamW-এর decoupled decay ব্যবহার করুন, আর λ-কে learning rate-এর সঙ্গে মিলিয়ে বাছুন।
প্র ০৪MC dropout-এর spread-কে কি model-এর অনিশ্চয়তা হিসেবে বিশ্বাস করা যায়? Deep ensemble কেন প্রায়ই ভালো?
Gal আর Ghahramani (ICML ২০১৬) দেখান, dropout-সহ train করা network-কে একটি নির্দিষ্ট ধরনের variational approximation হিসেবে দেখা যায়; তাই inference-এ dropout চালু রেখে অনেকবার forward করলে predictive distribution-এর একটি আনুমানিক রূপ পাওয়া যায়। এর আকর্ষণ স্পষ্ট: model বা training কিছুই বদলাতে হয় না, শুধু T বার forward.
তবে সীমাও আছে। অংশ ৫-এ দেখেছেন, tanh network-এ ডেটার বাইরে spread প্রায় বাড়েনি, ReLU-তে অনেক বেড়েছে; অর্থাৎ ফল architecture-এর ওপর নির্ভর করে। সত্যিকারের Fashion-MNIST run-এ dropout model-এ MC dropout-এর ৫০টি pass-এ ভুল উত্তরের spread (০.২৫৬) ঠিক উত্তরের (০.০৯৬) চেয়ে বেশি এসেছে: একটি কাজের সংকেত। কিন্তু একেবারে এলোমেলো noise-এর ছবিতেও model গড়ে ০.৭৫৬ সর্বোচ্চ probability দিল, যা একটি পোশাকের ছবি না হলেও। Osband (২০১৬) সহ কয়েকজন যুক্তি দেন, dropout-এর হার স্থির থাকলে ডেটা বাড়লেও এই অনিশ্চয়তা কমে না, যা Bayesian অনিশ্চয়তার স্বভাবের সঙ্গে মেলে না।
Lakshminarayanan ও সহকর্মীদের deep ensemble (NeurIPS ২০১৭) আলাদা seed-এর কয়েকটি model train করে probability গড় করে। Ovadia ও সহকর্মীদের ২০১৯ সালের তুলনামূলক পরীক্ষায় distribution shift-এর অধীনে ensemble প্রায়ই MC dropout-এর চেয়ে ভালো calibrated ছিল বলে রিপোর্ট। খরচ অবশ্য N গুণ। ব্যবহারিক নিয়ম: অনিশ্চয়তা জরুরি হলে ensemble বা অন্তত MC dropout, কিন্তু যেকোনো ক্ষেত্রে আলাদা held-out ডেটায় calibration মাপুন (মেশিন লার্নিং কোর্সের পর্ব ২৬), আর ডাক্তারি বা আর্থিক সিদ্ধান্তে এই সংখ্যাকে নিশ্চিত সত্য ভাববেন না।
মূল উপলব্ধি: MC dropout অনিশ্চয়তার একটি সস্তা আভাস, নিখুঁত মাপ নয়; deep ensemble বেশি খরচে সাধারণত বেশি নির্ভরযোগ্য, আর দুটিকেই calibration দিয়ে যাচাই করতে হয়।
প্র ০৫Weight-এর গড় (EMA, SWA) কেন কাজ করে, আর ensemble-এর সঙ্গে এর পার্থক্য কী?
ধারণাটি stochastic optimization-এর পুরোনো ফল: Polyak আর Juditsky (১৯৯২) দেখান, SGD-এর iterate-গুলোর গড় নিলে কিছু শর্তে অনুমান প্রায় সর্বোত্তম গতিতে নির্ভুল হয়, যদিও প্রতিটি iterate নিজে noise-এ কাঁপে। অংশ ৬-এর ছোট উদাহরণে ঠিক এটাই দেখেছেন: কাঁচা weight নিখুঁত সমাধান থেকে গড়ে ০.৮৫১ দূরে, EMA ০.৩৬৮.
Deep network-এ loss convex নয়, তাই গড় নিলে দুটি পাহাড়ের মাঝের খারাপ জায়গায় পড়ার ঝুঁকি আছে। Izmailov ও সহকর্মীরা (UAI ২০১৮) যুক্তি দেন, training-এর শেষে learning rate বড় বা চক্রাকার রাখলে SGD একই চওড়া উপত্যকার (basin) বিভিন্ন কিনারায় ঘোরে; সেগুলোর গড় উপত্যকার মাঝখানে বসে, যা তাঁদের মতে generalization-এর জন্য ভালো। এটিই SWA. EMA আরও সহজ: প্রতি ধাপে চলমান গড়, আর diffusion model আর কিছু বড় vision model-এর training-এ EMA weight দিয়ে মূল্যায়ন একটি প্রচলিত অভ্যাস বলে জানা যায়। অংশ ৭-এর run-এ EMA val loss সবচেয়ে কমিয়েছে (০.৭৯৮), কিন্তু β = ০.৯৯৯ শুরুতে খুব ধীর ছিল; সেজন্য অনেকে EMA কিছু ধাপ পরে শুরু করেন বা β ধীরে বাড়ান।
Ensemble আর weight-এর গড়ের পার্থক্য মৌলিক। Ensemble output-এর গড় নেয়: N টি আলাদা model, N গুণ inference খরচ, আর model-গুলো আলাদা basin-এ থাকলেও কাজ করে, বরং বৈচিত্র্য যত বেশি তত ভালো। Weight-এর গড় parameter-এর গড় নেয়: একটিই model, inference খরচ বাড়ে না, কিন্তু শুধু তখনই কাজ করে যখন weight-গুলো একই basin-এর। দুটি আলাদা seed থেকে শুরু করা network-এর weight সরাসরি গড় করলে সাধারণত খুব খারাপ model পাওয়া যায়, কারণ hidden unit-গুলোর ক্রম আলাদা।
মূল উপলব্ধি: একই training পথের weight-এর গড় প্রায় বিনা খরচে noise কমায়; আলাদা model-এর জ্ঞান মেলাতে চাইলে output-এর গড় (ensemble) লাগে।
অনুশীলন
প্রথমে খাতায় করুন, তারপর উত্তর মেলান।
-
পূর্ণ numerical: (ক) একটি layer-এর activation h = [২.০, ০.৫, ১.০, ০.০, ৩.০], inverted dropout p = ০.২, আর এবারের mask [১, ০, ১, ১, ১]. পরের layer কী পায়? প্রতিটি unit-এর প্রত্যাশিত মান কত? (খ) AdamW-এ lr = ০.০০১, λ = ০.০৫; একটি weight-এর gradient সবসময় শূন্য হলে ১০,০০০ ধাপে সেটি কত গুণ হয়? (গ) EMA-তে β = ০.৯৯৯. ১০০০ ধাপ আগের weight-এর ওজন কত? Epoch-প্রতি ৩২ ধাপ হলে EMA মোটামুটি কত epoch “মনে রাখে”?
(ক) টিকে থাকা মান ১/(১ − ০.২) = ১.২৫ দিয়ে গুণ: [২.৫, ০, ১.২৫, ০, ৩.৭৫] (চতুর্থটি h-এই ০)। প্রত্যাশিত মান প্রতিটির জন্য h নিজেই: ০.৮ × ১.২৫h = h. এই mask-এ যোগফল ৭.৫, eval-এ ৬.৫; একটি mask-এ পার্থক্য স্বাভাবিক। (খ) প্রতি ধাপে গুণক ১ − ০.০০১ × ০.০৫ = ০.৯৯৯৯৫. ১০,০০০ ধাপে ০.৯৯৯৯৫১০০০০ ≈ e−০.৫ ≈ ০.৬০৬৫. (গ) k ধাপ আগের weight-এর ওজন (১ − β)βk = ০.০০১ × ০.৯৯৯১০০০ ≈ ০.০০১ × ০.৩৬৮ = ০.০০০৩৬৮, অর্থাৎ সাম্প্রতিক weight-এর প্রায় ৩৭%. কার্যকর দৈর্ঘ্য ১/(১ − β) = ১০০০ ধাপ ≈ ১০০০/৩২ ≈ ৩১ epoch; অংশ ৭-এ EMA-র val loss শুরুতে এত বেশি থাকার কারণ এটাই।
-
সমালোচনা ও নকশা: একটি দল ৫০০টি পণ্যের ছবি দিয়ে বাজারঘরের ক্যাটাগরি classifier বানাচ্ছে। AI assistant-এর পরিকল্পনা: (১) প্রতিটি layer-এর পরে, শেষ logits-সহ,
nn.Dropout(0.5); (২)torch.optim.Adam(model.parameters(), weight_decay=0.01), BatchNorm আর bias-সহ সব parameter-এ; (৩) val accuracy দেখে patience ২-এর early stopping; (৪) ২০টি seed চালিয়ে test set-এ সেরাটি রিপোর্ট; (৫) MC dropout-এর গড় probability-কে “calibrated confidence” হিসেবে গ্রাহকের পর্দায় দেখানো। সমস্যাগুলো কী, আর আপনার নকশা কী হবে?১: logits-এর পরে dropout loss-এর input এলোমেলো করে; dropout শুধু hidden activation-এর পরে, আর CNN হলে convolution অংশে কম বা Dropout2d. ২:
Adam(weight_decay)আসলে L2, Adam-এর ভাগে চাপা পড়ে;AdamWনিন, আর bias ও normalization-এর decay শূন্য রাখতে দুটি parameter group. ৩: ছোট val set-এ accuracy খুব noisy (১০০টি ছবিতে এক ঘর = ১%), patience ২ খুব অধৈর্য; val loss বা দুটিই দেখুন, patience বড়, best checkpoint ফেরান। ৪: test set-এ সেরা seed বাছাই মানে test-এ overfitting; seed-এর গড় ± মানবিচ্যুতি validation-এ, test-এ শুধু চূড়ান্ত config একবার। ৫: MC dropout-এর probability calibrated নয়, noise-এর ছবিতেও উঁচু probability দিতে পারে; held-out ডেটায় calibration মাপুন, দরকারে temperature scaling. নকশা: pretrained model থেকে transfer learning (পর্ব ২৩), augmentation, AdamW + parameter group, early stopping, সম্ভব হলে EMA বা ছোট ensemble; প্রতিটি বদল আলাদা করে কয়েকটি seed-এ মাপা। -
আউটপুট অনুমান করুন: চালানোর আগে লিখে ফেলুন নিচের কোড কী ছাপবে (মানগুলো কোন কোন সংখ্যা হতে পারে আর কোন লাইন নিশ্চিত, তা বলাই যথেষ্ট)।
import torch, torch.nn as nn torch.manual_seed(0) drop = nn.Dropout(p=0.5) x = torch.ones(8) print(drop(x)) drop.eval() print(drop(x)) print(drop.training, drop(x).sum().item())tensor([0., 0., 2., 0., 0., 0., 2., 2.]) tensor([1., 1., 1., 1., 1., 1., 1., 1.]) False 8.0(সত্যিকারের run, PyTorch 2.15.0, CPU.) নতুন তৈরি module default-ভাবে train mode-এ, তাই প্রথম লাইনে প্রতিটি মান হয় ০ নয়তো ১/(১ − ০.৫) = ২; কোনগুলো শূন্য, তা seed-এর ওপর নির্ভর করে (এখানে ৮টির ৫টি শূন্য, যদিও গড়ে ৪টি হওয়ার কথা)। এটুকু নিশ্চিত: ০ আর ২ ছাড়া কোনো মান আসবে না।
eval()-এর পরে dropout কিছুই করে না, তাই সব ১, যোগফল ৮.০, আরtrainingflagFalse. -
কোড লিখুন: PyTorch-এ একটি
mc_predict(model, X, T)function লিখুন, যা model-কে eval mode-এ রেখে শুধু dropout layer-গুলোকে train mode-এ চালায়, T বার softmax probability নেয়, আর গড় ও মানবিচ্যুতি ফেরায়। কেন পুরো model-কেtrain()করা ঠিক নয়?@torch.no_grad() def mc_predict(model, X, T=50): model.eval() for m in model.modules(): # শুধু dropout-কে train mode-এ if isinstance(m, nn.Dropout): m.train() P = torch.stack([model(X).softmax(-1) for _ in range(T)]) # (T, N, C) model.eval() return P.mean(0), P.std(0)পুরো model
train()করলে BatchNorm থাকলে সে batch-এর নিজস্ব পরিসংখ্যান ব্যবহার করবে আর running mean বদলে দেবে; তাই শুধু dropout-কে আলাদা করে চালু করা হয়। শেষে আবারeval(), যাতে পরে কেউ ভুল mode-এ না পায়। অংশ ৭-এর dropout model-এ ৫,০০০টি val ছবিতে সত্যিকারের run:MC acc 0.8112 | sd of predicted class: correct 0.096, wrong 0.256; আর ১০০০টি এলোমেলো noise-এর ছবিতেmean max-prob 0.756 | sd 0.308. ভুল উত্তরে spread বেশি, কাজের সংকেত; কিন্তু noise-এও উঁচু probability, তাই এটিকে নিখুঁত মাপ ভাববেন না।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি overfit করা network-এ regularization বাছাইয়ের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- Regularization ছাড়া baseline train করে train আর val-এর curve আঁকা
- Train/val-এর ফারাক দেখে overfitting নিশ্চিত করা
- AdamW-এর weight decay আর best checkpoint-সহ early stopping যোগ করা
- Augmentation, dropout বা EMA একবারে একটি করে যোগ করা
- প্রতিটি config কয়েকটি seed-এ চালিয়ে validation-এ তুলনা করা
- বাছাই করা config test set-এ একবার মাপা
PyTorch-এর nn.Dropout(p=0.2) train mode-এ যে মানগুলো বাদ পড়ে না, সেগুলোকে কী করে?
- অপরিবর্তিত রাখে
- ১.২৫ দিয়ে গুণ করে
- ০.৮ দিয়ে গুণ করে
- ০.২ দিয়ে গুণ করে
AdamW-এ lr = ০.০১ আর weight_decay = ০.১. একটি weight-এর মান ১.০ আর এই ধাপে তার loss-gradient শূন্য (Adam-এর ধাপও শূন্য)। এক ধাপ পরে weight কত?
- ১.০
- ০.৯
- ০.৯৯৯
- ০.৯৯
Adam optimizer-এ loss-এর সঙ্গে L2 শাস্তি যোগ করা আর AdamW-এর decoupled weight decay-এর মূল পার্থক্য কী?
- L2-এর অংশ Adam-এর √v̂ দিয়ে ভাগ হয়; AdamW-এর decay সেই ভাগের বাইরে থাকে
- AdamW-এ λ লাগে না
- কোনো পার্থক্য নেই, দুটি গাণিতিকভাবে এক
- AdamW শুধু bias-এ decay দেয়
একটি classifier-এর epoch ১০ থেকে ৬০-এ train accuracy ০.৯৭ থেকে ১.০০, val accuracy প্রায় ০.৮০–০.৮২-এ স্থির, আর val loss ০.৭২ থেকে ১.৪৯-এ ওঠে। কোন ব্যাখ্যা সবচেয়ে ঠিক?
- Model underfit করছে, আরও বড় model লাগবে
- Validation-এর কোডে নিশ্চিত bug আছে
- Learning rate খুব কম, তাই বাড়ালেই ঠিক হবে
- Overfitting: ভুল উত্তরে অতি-আত্মবিশ্বাস বাড়ছে, যদিও ঠিক-ভুলের সংখ্যা প্রায় একই
MC dropout দিয়ে একটি input-এর অনিশ্চয়তার আভাস পেতে inference-এর সময় কী করতে হয়?
- Model eval mode-এ রেখে একবার forward করা
- শুধু dropout layer চালু রেখে একই input-এ অনেকবার forward করে গড় আর spread নেওয়া
- আলাদা seed-এ কয়েকটি model আবার train করা
- p বাড়িয়ে একবার forward করা
EMA-তে β = ০.৯৯৯ আর epoch-প্রতি ৩২টি optimizer ধাপ। EMA weight মোটামুটি কত epoch-এর weight-এর গড়ের মতো আচরণ করে?
- শুধু শেষ epoch
- প্রায় ১০০০ epoch
- প্রায় ৩১ epoch
- শুরু থেকে সব epoch সমান ওজনে
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- মুখস্থ বনাম নিয়ম: বড় network কম ডেটা মুখস্থ করতে পারে; regularization train-এ একটু খারাপ হওয়ার বিনিময়ে নতুন ডেটায় ভালো করার চেষ্টা। প্রভাব আগে থেকে জানা যায় না, মাপতে হয়।
- Weight decay: আগে w·(১ − ηλ), তারপর ধাপ। SGD-তে L2-এর সমান, Adam-এ নয়; AdamW ব্যবহার করুন, bias আর normalization বাদ।
- Dropout: train-এ বাদ আর ১/(১ − p) গুণ, eval-এ কিছুই না; hidden activation-এর পরে, logits-এর পরে নয়;
model.eval()ছাড়া validation-এর সংখ্যা এলোমেলো। - Early stopping আর weight-এর গড়: কোন metric দেখে থামবেন তা ভেবে বাছুন; EMA/SWA বিনা inference-খরচে noise কমায়, ensemble বেশি খরচে output মেলায়।
- অনিশ্চয়তা: MC dropout আর ensemble-এর spread একটি আভাস, নিখুঁত probability নয়; calibration আলাদা করে মাপুন।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ১৭ · Vanishing আর exploding gradient — residual connection আর gradient clippingপরবর্তী পর্বস্তরে স্তরে gradient মাপা, residual connection আর gradient clipping বোঝা।
- ডিপ লার্নিং, NLP আর Generative AI · কোর্স হোম৯১টি পর্ব১৪টি মডিউলের পুরো রোডম্যাপ; পর্ব ১৭ (Vanishing আর exploding gradient) আর পর্ব ২৪ (Data augmentation) এখান থেকে খুলবেন।
- পর্ব ১০ · Training loopআগের পর্বEarly stopping, patience, best checkpoint আর eval()/no_grad()-এর মূল কোড।
- পর্ব ০৬ · Network কী শিখতে পারেআগের পর্বOverparameterization, double descent আর implicit regularization.
- মেশিন লার্নিং · পর্ব ১৭ · Regularization-এর তত্ত্বআগের ভিত্তিL1/L2-এর জ্যামিতি, MAP আর early stopping-এর তত্ত্ব।
- AI-এর ভিত্তি · পর্ব ৬১ · Overfitting, bias আর varianceআগের ভিত্তিLearning curve আর ridge/lasso দিয়ে regularization-এর প্রথম পরিচয়।
- মেশিন লার্নিং · পর্ব ২৬ · Probability calibrationপাশের ট্র্যাকReliability diagram আর temperature scaling: অতি-নিশ্চিত model ঠিক করা।