পাঠ ১১ · ৪০-এর মধ্যে · মডিউল ২

SGD ও Mini-batch

Stochastic gradient descent & mini-batches
৬ মিনিট পড়া মাঝারি · Intermediate PyTorch hands-on

এই পাঠে যা শিখবেন

  • Gradient descent-এর তিন variant — batch, SGD, mini-batch
  • Learning rate $\eta$-এর প্রভাব ও tuning
  • Mini-batch noise — bug না feature?
  • PyTorch DataLoader — efficient batching
  • Common pitfall: shuffling, last incomplete batch

১ · Gradient descent — মূল idea

Loss function $L(w)$ — parameters $w$-এর উপর। লক্ষ্য — $L$-কে minimize করা। Gradient $\nabla L$ "সর্বাধিক বৃদ্ধির দিক" দেখায়। তাই বিপরীত দিকে যান:

$$w \leftarrow w - \eta \nabla_w L(w)$$

যেখানে $\eta$ হলো learning rateLearning Rateপ্রতিটি step-এ কতটা update করব — সবচেয়ে গুরুত্বপূর্ণ hyperparameter। বেশি = divergence, কম = খুব slow। সাধারণত 0.001-0.1। — step size।

ভাবুন আপনি কুয়াশায় পাহাড় থেকে নামছেন। সবচেয়ে নিচে যেতে চান। কোন দিকে slope সবচেয়ে বেশি — সেদিকে এক পা ফেলুন। বারবার এই কাজ — গভীরে পৌঁছাবেন। Step size বেশি — উল্টো দিকে লাফ। Step size কম — সারা দিন।

২ · তিন variant — কতটা data এক step-এ

একটি training set-এ $N$ sample। প্রতিটি step-এ gradient হিসাব করতে কতটি sample ব্যবহার?

তিন strategy

১) Batch GD: সব $N$ sample → 1 update।
২) SGD: 1 sample → 1 update।
৩) Mini-batch SGD: $B$ samples (32, 64, 128, ...) → 1 update।

Batch GD:

$$\nabla L = \frac{1}{N} \sum_{i=1}^{N} \nabla \ell(x_i, y_i)$$

  • True gradient — exact direction।
  • সমস্যা: $N$ বড় হলে memory ও slow।
  • 1M sample = 1 update-এর জন্য 1M forward+backward।

SGD (single-sample):

$$\nabla L \approx \nabla \ell(x_i, y_i) \quad \text{(random } i\text{)}$$

  • Noisy estimate — কিন্তু expectation-এ সঠিক।
  • $N$ updates per epoch — দ্রুত progress।
  • GPU underutilized — single sample inefficient।

Mini-batch SGD (modern default):

$$\nabla L \approx \frac{1}{B} \sum_{i \in \text{batch}} \nabla \ell(x_i, y_i)$$

  • Noise কম, GPU parallelism ভাল।
  • Typical $B$: 32, 64, 128, 256।
  • Sweet spot — সব practical DL এই strategy।

৩ · Learning rate — সবচেয়ে গুরুত্বপূর্ণ knob

$\eta$-এর effect দেখুন:

  • খুব বড় ($\eta = 1.0$): divergence — loss explode।
  • বড় ($\eta = 0.1$): দ্রুত কিন্তু oscillation।
  • মাঝারি ($\eta = 0.01$): typical sweet spot।
  • ছোট ($\eta = 0.0001$): stable কিন্তু painfully slow।
Learning rate "হাতে tune" করার বদলে modern practice — learning rate finder (Smith ২০১৭)। Small থেকে large পর্যন্ত $\eta$ swept, loss curve থেকে optimal বাছা। FastAI library এই pattern popularize করেছে।

৪ · Noise — bug না feature?

Mini-batch SGD-এর gradient true gradient-এর noisy estimate। অবাক ব্যাপার — এই noise সাহায্য করে।

  • Local minima escape: noise-এর ধাক্কায় shallow trap থেকে মুক্তি।
  • Saddle point escape: high-D-তে saddle বহু — noise gradient zero থেকে বেরোতে সাহায্য।
  • Implicit regularization: SGD flat minima-এ যায় — যা generalize ভালো (Keskar ২০১৭)।
  • Generalization mystery: পুরোপুরি বুঝে ওঠা যায়নি — DL theory-র active research।
Gradient descent — তিন variant data per update vs noise vs speed Batch GD all N samples smooth path slow, memory-heavy Mini-batch SGD B samples (32-256) slight noise SWEET SPOT SGD (1 sample) 1 sample at a time very noisy GPU underused Mini-batch — practice-এ universal: GPU-efficient + noise-balanced + statistically reliable।
Loss landscape-এ three trajectories — batch smooth slow, SGD noisy fast, mini-batch optimal।

৫ · Scratch SGD — NumPy

Python · NumPy
import numpy as np

np.random.seed(0)

# একটি linear regression toy
N = 500
X = np.random.randn(N, 1)
y = 3 * X.flatten() + 2 + 0.5 * np.random.randn(N)

# Initialize
w, b = np.random.randn(), 0.0
lr = 0.05
batch_size = 32

for epoch in range(20):
    # Shuffle
    idx = np.random.permutation(N)
    X_sh, y_sh = X[idx], y[idx]

    losses = []
    for i in range(0, N, batch_size):
        Xb = X_sh[i:i+batch_size]
        yb = y_sh[i:i+batch_size]

        # Forward
        y_pred = (Xb * w + b).flatten()
        loss = ((y_pred - yb) ** 2).mean()

        # Gradient
        dw = 2 * ((y_pred - yb) * Xb.flatten()).mean()
        db = 2 * (y_pred - yb).mean()

        # SGD update
        w -= lr * dw
        b -= lr * db
        losses.append(loss)

    if epoch % 5 == 0:
        print(f"epoch {epoch}: loss = {np.mean(losses):.4f}, w = {w:.3f}, b = {b:.3f}")

print(f"\nTrue: w=3, b=2 — Learned: w={w:.3f}, b={b:.3f}")

    
প্রতিটি epoch — পুরো data এর উপর একবার pass। প্রতিটি step — 32-sample-এর gradient। True $w, b$-এর কাছে পৌঁছানো — SGD-র সরল demonstration।

৬ · PyTorch DataLoader — efficient batching

Production-এ আপনি কখনো নিজে batch বানাবেন না। PyTorch DataLoader — shuffling, batching, parallel loading — সব handle করে।

Python · PyTorch
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset

torch.manual_seed(0)
N = 500
X = torch.randn(N, 1)
y = 3 * X.squeeze() + 2 + 0.5 * torch.randn(N)

# Dataset + DataLoader
ds = TensorDataset(X, y)
loader = DataLoader(ds, batch_size=32, shuffle=True, num_workers=0)

# Simple model
model = nn.Linear(1, 1)
opt = torch.optim.SGD(model.parameters(), lr=0.05)

for epoch in range(20):
    losses = []
    for Xb, yb in loader:
        y_pred = model(Xb).squeeze()
        loss = ((y_pred - yb) ** 2).mean()

        opt.zero_grad()
        loss.backward()
        opt.step()
        losses.append(loss.item())

    if epoch % 5 == 0:
        w = model.weight.item()
        b = model.bias.item()
        print(f"epoch {epoch}: loss = {sum(losses)/len(losses):.4f}, w={w:.3f}, b={b:.3f}")

    

৭ · Common pitfalls

  • Shuffle ভুলে যাওয়া: Order-dependent learning, generalization খারাপ। shuffle=True সবসময়।
  • Last batch incomplete: 100 samples, batch 32 → শেষ batch-এ 4। Statistic noisy। Solution: drop_last=True (training)।
  • Test-এ shuffle: অপ্রয়োজনীয় কিন্তু harmless। Validation-এ deterministic seed।
  • num_workers=0: data load main thread-এ — GPU idle। Set 4-8 in production।
  • zero_grad ভুলে যাওয়া: gradient জমা হয়, ভুল update। প্রতি step-এ opt.zero_grad()।

৮ · Batch size — bigger always better?

DL লোকেদের mantra ছিল "batch size যত বেশি, generalization তত খারাপ"। কিন্তু modern research বলে — careful learning rate scaling-এ large batch ঠিকঠাক চলে (Goyal ২০১৭, "Large minibatch SGD")।

  • Linear scaling rule: batch ২x → learning rate ২x।
  • Warmup: শুরুতে gradual lr increase — large batch-এর divergence prevent।
  • LARS, LAMB: per-layer adaptive — ImageNet 32k batch, BERT 64k batch।
Practical advice: GPU memory যত allow করে, ততটাই batch — কিন্তু মাঝে মাঝে কম batch-ও test করুন। Default 32-128 — most cases best। 1024+ batch — special techniques দরকার।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ "SGD-এর noise generalization-কে সাহায্য করে" — এটি DL theory-র এক mystery। কোন কোন hypothesis বর্তমানে আছে এই generalization gap explain করতে?

DL theory-র সবচেয়ে আকর্ষণীয় open problem। Empirically দেখা যায় SGD large-batch-এর চেয়ে generalize better — কেন?

Hypothesis ১: Flat minima preference (Keskar ২০১৭)

  • SGD noise narrow/sharp minima থেকে escape।
  • Wide/flat minima-এ আটকে যায়।
  • Flat minima-এ small parameter perturbation → small loss change → generalize better।
  • Counter-evidence: Dinh et al. (২০১৭) — sharp/flat reparameterization-এ change!

Hypothesis ২: Implicit bias toward simple solutions

  • SGD-এর iterative nature simple function prefer করে।
  • Linear net + SGD → minimum norm solution।
  • Neural net analogue active research।

Hypothesis ৩: Stochastic differential equation (SDE) framing

  • SGD ≈ continuous SDE: $dw = -\nabla L \, dt + \sigma \, dW$।
  • Noise scale $\sigma \propto \sqrt{lr/B}$।
  • High noise → exploration → flat region।

Hypothesis ৪: Information bottleneck

  • Tishby et al. — DL-এ "compression phase" থাকে।
  • SGD এই compression promote করে।
  • Controversial but influential idea।

Hypothesis ৫: Edge of stability

  • Cohen et al. (২০২১) — SGD train-এ Hessian eigenvalue $2/lr$-এ দৌড়ায়।
  • Boundary-তে chaos-এর কাছে।
  • Implicit regularization।

Hypothesis ৬: Batch size scaling laws

  • McCandlish (২০১৮) — "critical batch size" — beyond which gradient noise irrelevant।
  • Smaller batch → more updates → more noise → better generalization।

What we know empirically:

  • Large batch + linear lr scaling — usually OK upto certain limit।
  • Beyond critical batch — generalization drop।
  • LARS, LAMB optimizer mitigate but not eliminate।
  • Long training compensates for less noise।

What's still unclear:

  • Why DL generalize at all (over-parameterization paradox)।
  • Exact role of SGD vs initialization vs architecture।
  • Theoretical bound usually loose।

Recent advances:

  • Neural Tangent Kernel — infinite-width analysis।
  • Mean field theory — finite-width treatment।
  • Random matrix theory — initialization analysis।

মূল উপলব্ধি: SGD generalization mystery — DL theory-র holy grail। Empirically magic, theoretically still puzzling। PhD research-এ pile। Practitioner-এর জন্য — recipe কাজ করে, exact reason না জানলেও চলে।

প্র ০২ OpenAI GPT-4 train করেছে millions of GPU-hour, বিশাল batch (4M+ tokens)। এত বড় batch-এ noise কোথায় গেল? Generalization কীভাবে maintain?

LLM training-এর scale standard SGD intuition-কে stress-test করে। কিন্তু modern techniques-এ এটি workable।

LLM training scale:

  • GPT-3: 175B params, 300B token, ~3M batch।
  • GPT-4: rumored ~1.7T total params, much larger batch।
  • LLaMA-2 70B: 4M token batch।
  • "Critical batch size" passed long ago।

Why it still works:

  • (১) Massive dataset: 1T+ tokens — overfitting risk minimal even with low noise।
  • (২) Adam-class optimizer: per-parameter adaptive lr — large batch-এ stable।
  • (৩) Long training schedule: 1 epoch usually — many small steps।
  • (৪) Cosine lr decay + warmup: careful annealing।
  • (৫) Architecture scale: over-parameterization implicit regularizer।
  • (৬) Data quality filtering: noise reduce data-end-এ।

Distributed training necessity:

  • Single GPU 4M batch impossible।
  • Data parallel: same model, different data shard।
  • Tensor parallel: model split across GPUs।
  • Pipeline parallel: layers across GPUs।
  • 3D parallelism: all combined।

Effective batch math:

  • Local batch (per GPU): 1-8 sequences।
  • Global batch (synced): 1024-4096 sequences।
  • Token batch: sequences × seq_length = millions।

Gradient accumulation:

  • Memory limit → multiple "micro-batches" accumulate।
  • Effective batch = micro_batch × accumulation_steps × world_size।
  • Practically — memory ও batch decoupled।

Generalization in LLM:

  • "Zero-shot" capabilities → strong generalization।
  • Held-out benchmark performance steadily improves।
  • "Memorization" partial but bounded।
  • Scaling laws (Chinchilla, Hoffman) — predictable improvement।

Recent insight (Chinchilla):

  • Compute optimal: model size ∝ data tokens।
  • Earlier (GPT-3): under-trained big model।
  • LLaMA — smaller model, more data, better quality।

Bangladesh-এ implication:

  • Train from scratch infeasible — open weight fine-tune।
  • LoRA, QLoRA — parameter-efficient।
  • Bangla data quality > quantity।

মূল উপলব্ধি: LLM scale at "post-SGD-theory frontier"। Empirical-driven engineering। Noise role-এর traditional intuition বিকৃত। Better mental model — over-parameterization + massive data + adaptive optimizer + long horizon = magic।

প্র ০৩ Imbalanced dataset (যেমন Bangladesh-এ rare disease classification, 99% negative)। Random mini-batch-এ minority class কম থাকবে। Learning কী problematic? কীভাবে solve?

Real-world ML-এর সবচেয়ে frequent challenge। Bangladesh-এ medical imaging, fraud detection, defect inspection — সব imbalanced।

Problem:

  • Random batch-এ majority class dominate।
  • Loss-এ majority weight বেশি।
  • Model "always predict negative" শিখে — 99% accuracy কিন্তু useless।
  • Minority recall poor।

Solution category 1: Data-level

  • Random over-sampling: minority replicate। Risk: overfitting।
  • Random under-sampling: majority subsample। Risk: information loss।
  • SMOTE: minority synthesize via interpolation। Tabular-এ effective।
  • ADASYN: SMOTE-এর adaptive variant।
  • Augmentation: minority class-এ aggressive augment (image rotation, noise, etc.)।

Solution category 2: Sampling-level

  • Stratified batch: প্রতি batch-এ class proportion fixed।
  • Class-balanced sampling: equal samples per class।
  • WeightedRandomSampler (PyTorch):
    weights = [1.0/class_count[y] for y in labels]
    sampler = WeightedRandomSampler(weights, len(weights))
    loader = DataLoader(ds, batch_size=32, sampler=sampler)

Solution category 3: Loss-level

  • Class weights:
    w = torch.tensor([1.0, 99.0])  # rare class বেশি weight
    loss = F.cross_entropy(out, y, weight=w)
  • Focal loss (Lin ২০১৭): well-classified examples-এর weight কমায়।

    $$FL = -(1-p)^\gamma \log p$$

    Object detection-এ standard।
  • Class-balanced loss (Cui ২০১৯): "effective number" based weighting।

Solution category 4: Threshold tuning

  • Default 0.5 — imbalanced-এ ভুল।
  • ROC curve থেকে optimal threshold।
  • Precision-recall curve preferable।

Evaluation matters:

  • Accuracy useless — always look at:
  • Precision, Recall (per class)।
  • F1-score (harmonic mean)।
  • AUC-ROC, AUC-PR।
  • Confusion matrix।
  • Per-class accuracy।

Production system:

  • Cost-sensitive learning — false negative cost > false positive (medical)।
  • Anomaly detection alternative — one-class SVM, isolation forest।
  • Active learning — uncertain examples human-label।

Bangladesh case study (rare disease):

  • 10000 X-ray, 50 positive (TB)।
  • Step 1: Stratified split — train/val both class।
  • Step 2: WeightedRandomSampler।
  • Step 3: Focal loss।
  • Step 4: Recall-optimized threshold।
  • Step 5: Augmentation on positive (rotation, contrast)।
  • Step 6: Ensemble — multiple models।

মূল উপলব্ধি: Imbalanced data — universal real-world problem। Single solution rarely enough। Combine sampling + loss + evaluation। Domain expert-এর knowledge crucial — false positive vs negative cost-এ। Bangladesh-এ medical AI গড়তে এই skill mandatory।

প্র ০৪ আপনি একটি model train করছেন। Loss curve smooth decline না হয়ে wild oscillate করছে। কী কী cause হতে পারে, কীভাবে diagnose ও fix?

Training instability — beginner ও expert উভয়েই face করেন। Diagnosis structured থাকা চাই।

সম্ভাব্য cause:

  • Learning rate বেশি: step too big, oscillation/divergence।
  • Batch size ছোট: excessive noise।
  • Bad initialization: activation explode/vanish।
  • Data issue: outlier, mislabeled, inconsistent।
  • Loss function ভুল: regression-এ cross-entropy, etc.।
  • Numerical instability: overflow, NaN।
  • Architecture pathology: skip connection missing, BN missing।

Diagnosis steps:

  • (১) LR sweep:
    # LR finder
    for lr in [1e-5, 1e-4, 1e-3, 1e-2, 1e-1]:
        train_for_few_steps(lr)
        plot_loss
    Loss vs lr — smooth decline-এর peak point optimal।
  • (২) Smaller batch test: batch ↓ → noise ↑। Convergence pattern বদলায়?
  • (৩) Single sample overfit: 1 sample memorize পারলে — code ঠিক, data-এ issue।
  • (৪) Gradient norm monitor:
    total_norm = sum(p.grad.norm() ** 2 for p in model.parameters()) ** 0.5
    log(total_norm)
  • (৫) Activation histogram: dead/saturated neuron detect।

Fix priority:

  • (১) Lower learning rate: first try — / 10।
  • (২) Gradient clipping:
    torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
  • (৩) Larger batch: noise reduce।
  • (৪) Warmup schedule:
    lr = base_lr * min(step / warmup_steps, 1)
  • (৫) Better optimizer: SGD → Adam — adaptive lr।
  • (৬) Batch Normalization: stabilize activation distribution।
  • (৭) Better init: Kaiming for ReLU, Xavier for tanh।

Pattern recognition:

  • Steady decrease then explode: lr too high, bad clip absent।
  • NaN immediately: bad initialization, data NaN।
  • Plateau then oscillate: stuck in saddle, lr decay needed।
  • Large oscillation continuously: noise too high, batch ↑।
  • Sharp spikes: outlier data point, loss clip বা data clean।

Tools:

  • Weights & Biases — loss, lr, gradient histogram।
  • TensorBoard — local alternative।
  • Lightning logger — built-in।

Robust training recipe:

  • Always: gradient clipping।
  • Always: warmup + cosine decay।
  • Always: validation monitor।
  • Always: checkpoint frequent।
  • Sanity check: 1 sample overfit before full training।

মূল উপলব্ধি: Loss curve = training-এর pulse। Wild oscillation = system unstable। Lower lr + clip gradient = ৭০% solution। Systematic diagnosis-এ remaining ৩০%। Practice-এই debugging intuition গড়ে।

অনুশীলন

  1. হিসাব: 10000 sample, batch 32। 1 epoch-এ কত step? 50 epoch train-এ মোট কত step?

    1 epoch = $\lceil 10000 / 32 \rceil = 313$ step। 50 epoch → $313 \times 50 = 15{,}650$ step।

  2. Code: একটি DataLoader তৈরি করুন — batch=64, shuffle=True, drop_last=True।
    from torch.utils.data import DataLoader, TensorDataset
    ds = TensorDataset(X, y)
    loader = DataLoader(ds, batch_size=64, shuffle=True, drop_last=True, num_workers=4)
  3. Debug: এই training loop-এ কী ভুল?
    for x, y in loader:
        out = model(x)
        loss = criterion(out, y)
        loss.backward()
        optimizer.step()

    optimizer.zero_grad() missing — gradient জমা হবে। Fix:

    for x, y in loader:
        optimizer.zero_grad()      # ← critical
        out = model(x)
        loss = criterion(out, y)
        loss.backward()
        optimizer.step()

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

কোড রানার কাজ না করলে? ব্রাউজারে কাজ না করলে Google Colab ব্যবহার করুন — Google-এর ফ্রি অনলাইন Python পরিবেশ, শুধু Gmail অ্যাকাউন্ট লাগে।
পূর্ববর্তী পাঠ
পাঠ ১০ · Computational graph