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

ResNet — Skip Connection

ResNet & residual learning
৮ মিনিট পড়া মাঝারি · Intermediate PyTorch hands-on

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

  • Degradation problem — কেন deep stack ভেঙে পড়ে
  • Residual learning — $F(x) + x$-এর intuition ও math
  • Bottleneck block — ResNet-50/101/152
  • Skip connection-এ gradient flow analysis
  • PyTorch-এ ResNet-18 from scratch
  • Modern descendants — DenseNet, ResNeXt, Wide ResNet

১ · Degradation problem — paradox

২০১৫-এর আগে CNN community-এর ধারণা ছিল — "deeper = better"। VGG ১৯ layer থেকে ৩০ layer-এ গেলে accuracy বাড়ার কথা। বাস্তবে — ৩০-৫৬ layer-এর plain stack-এর train accuracy পড়ে যায়।

  • Overfitting না — train accuracy-ও কমে।
  • Vanishing gradient-ও না — BN দিয়ে fix করা যাচ্ছিল।
  • "Optimization difficulty" — He et al.-এর identification।
Degradation

Deep network-এর optimizer identity function-ও শিখতে কষ্ট পায়। শুধু extra layer-গুলো $H(x) = x$ output করলেই baseline accuracy match হত — কিন্তু solver সেটা পারে না।

২ · Residual learning — He-এর insight

যদি network-এর কাজ identity শেখা হয় — সেটা সরাসরি না শিখিয়ে, বলি "input-এর সাথে কী যোগ করতে হবে"।

Plain block: $y = H(x)$ — full mapping শিখতে হয়।
Residual block: $y = F(x) + x$ — শুধু "residue" $F(x)$ শিখতে হয়।

যদি optimal $H(x) = x$ হয় — $F(x) = 0$ শেখা trivially সহজ (সব weight $\to 0$)। Plain network-এ identity শেখা সম্পূর্ণ ভিন্ন কাজ।

ভাবুন আপনি একটি দোকানে ঢুকলেন। Plain network — বলবে "এই কাস্টমার-কে শূন্য থেকে full description তৈরি কর"। ResNet — বলবে "এই কাস্টমার আগের কাস্টমারের চেয়ে কী ভিন্ন"। দ্বিতীয়টা প্রায়ই সহজ — সাধারণত খুব কম ভিন্নতা থাকে। "কিছু না বদলালেও" $F(x) = 0$ — সেটাও সহজ।

৩ · Residual block — basic ও bottleneck

Basic block (ResNet-18, 34):

  • Conv $3 \times 3$ → BN → ReLU
  • Conv $3 \times 3$ → BN
  • + skip connection
  • ReLU

Bottleneck block (ResNet-50, 101, 152):

  • Conv $1 \times 1$ → BN → ReLU (channel reduce)
  • Conv $3 \times 3$ → BN → ReLU (spatial)
  • Conv $1 \times 1$ → BN (channel expand)
  • + skip connection
  • ReLU

৪ · Skip connection — শুধু copy বা projection

Input ($x$) এবং $F(x)$-এর shape একই হলে — skip directly $x$।

Spatial বা channel mismatch হলে — $1 \times 1$ projection conv:

$$y = F(x) + W_s \cdot x$$

(stride-2 দিয়ে spatial কমান এবং $1 \times 1$ দিয়ে channel adjust)।

৫ · Gradient flow — magical math

Backward pass-এ:

$$\frac{\partial L}{\partial x_l} = \frac{\partial L}{\partial x_L} \cdot \left( 1 + \frac{\partial}{\partial x_l} \sum_{i=l}^{L-1} F(x_i) \right)$$

  • $1$-এর term — sum-এ direct gradient flow। Vanishing impossible।
  • Gradient deep layer থেকে shallow layer-এ unaltered পৌঁছে।
  • This single insight — DL-কে ১০০০ layer-এ যেতে দিল (২০১৬-র "Deep Residual Learning")।

৬ · ResNet-18 — PyTorch from scratch

Python · PyTorch
import torch
import torch.nn as nn
import torch.nn.functional as F

class BasicBlock(nn.Module):
    expansion = 1
    def __init__(self, in_ch, out_ch, stride=1):
        super().__init__()
        self.conv1 = nn.Conv2d(in_ch, out_ch, 3, stride, 1, bias=False)
        self.bn1   = nn.BatchNorm2d(out_ch)
        self.conv2 = nn.Conv2d(out_ch, out_ch, 3, 1, 1, bias=False)
        self.bn2   = nn.BatchNorm2d(out_ch)
        if stride != 1 or in_ch != out_ch:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_ch, out_ch, 1, stride, bias=False),
                nn.BatchNorm2d(out_ch),
            )
        else:
            self.shortcut = nn.Identity()

    def forward(self, x):
        out = F.relu(self.bn1(self.conv1(x)), inplace=True)
        out = self.bn2(self.conv2(out))
        out = out + self.shortcut(x)  # skip!
        return F.relu(out, inplace=True)

class ResNet18(nn.Module):
    def __init__(self, num_classes=1000):
        super().__init__()
        self.stem = nn.Sequential(
            nn.Conv2d(3, 64, 7, 2, 3, bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(3, 2, 1),
        )
        self.layer1 = self._make(64, 64, 2, 1)
        self.layer2 = self._make(64, 128, 2, 2)
        self.layer3 = self._make(128, 256, 2, 2)
        self.layer4 = self._make(256, 512, 2, 2)
        self.gap    = nn.AdaptiveAvgPool2d(1)
        self.fc     = nn.Linear(512, num_classes)

    def _make(self, in_ch, out_ch, n_block, stride):
        layers = [BasicBlock(in_ch, out_ch, stride)]
        for _ in range(n_block - 1):
            layers.append(BasicBlock(out_ch, out_ch))
        return nn.Sequential(*layers)

    def forward(self, x):
        x = self.stem(x)
        x = self.layer1(x); x = self.layer2(x)
        x = self.layer3(x); x = self.layer4(x)
        x = self.gap(x).flatten(1)
        return self.fc(x)

model = ResNet18()
print("Params:", sum(p.numel() for p in model.parameters()))
# ~11.7M

    
Residual Block — y = F(x) + x Skip connection (red) gradient flow nirantar রাখে x (input) Conv 3×3 → BN → ReLU Conv 3×3 → BN skip (identity) + ReLU y (output) F(x) — residue শেখা (small change) y = F(x) + x
Residual block — main path $F(x)$, skip path identity। Output = sum। Gradient backprop-এ skip vanishing prevent।

৭ · ResNet variants

  • ResNet-18: 2-2-2-2 BasicBlock। 11.7M params।
  • ResNet-34: 3-4-6-3 BasicBlock। 21M params।
  • ResNet-50: 3-4-6-3 Bottleneck। 25M params।
  • ResNet-101: 3-4-23-3 Bottleneck। 44M params।
  • ResNet-152: 3-8-36-3 Bottleneck। 60M params।

৮ · ResNet-এর descendants

  • DenseNet (২০১৬): "all-to-all" skip — every layer-এ আগের সব layer concatenate।
  • ResNeXt (২০১৬): ResNet + Inception cardinality — parallel branch।
  • Wide ResNet (২০১৬): shallow but wide।
  • Highway Networks (২০১৫): ResNet-এর gated cousin।
  • Pre-activation ResNet: BN-ReLU আগে, conv পরে।
  • Transformer: "x + Attention(x)" — direct residual idea।

৯ · কেন এত successful

  • Optimization easier: identity sub-network always available।
  • Gradient flow: direct path shallow → deep।
  • Implicit ensemble: exponentially many sub-paths (Veit et al. ২০১৬)।
  • BN compatibility: mean stable, not exploding।
  • Generalization: empirically strong across task।
ResNet-50 আজও computer vision-এর de facto baseline। Pre-trained model freely available, transfer learning excellent। নতুন task-এ — first try ResNet-50 (or ResNet-18 quick prototype)।

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

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

প্র ০১ "ResNet — implicit ensemble of shallower networks" (Veit, Wilber, Belongie ২০১৬) — এই interpretation কী? Skip connection drop করলে কী ঘটে?

Veit et al.-এর "Residual Networks Behave Like Ensembles of Relatively Shallow Networks" — ResNet-এর alternative theoretical understanding।

Ensemble interpretation:

  • $n$ residual block — $2^n$ possible path।
  • Each block — skip বা F(x) "binary choice"।
  • প্রতিটি path — different network।
  • Output — সব path-এর effective sum।

Mathematical expansion:

  • $y_3 = y_2 + F_3(y_2) = (y_1 + F_2(y_1)) + F_3(y_1 + F_2(y_1))$।
  • Recursive expand — $2^n$ sub-network-এর sum।
  • Direct path (all skip) — input passthrough।
  • Long path (all F) — full computation।

Empirical evidence:

  • Test time block drop — small accuracy drop।
  • Plain network — single block drop দেদার damage।
  • Multiple block drop — gradual degradation।

Path length distribution:

  • Most paths — relatively short (5-17 blocks)।
  • Long paths — exist but contribute less।
  • Effective depth small।

Stochastic Depth (Huang ২০১৬):

  • Train-এ randomly block drop।
  • Test-এ full network।
  • Implicit shorter ensemble।
  • 1200-layer ResNet train possible।

Implementation:

class StochasticBlock(nn.Module):
    def __init__(self, in_ch, out_ch, drop_p=0.0):
        super().__init__()
        self.block = BasicBlock(in_ch, out_ch)
        self.drop_p = drop_p

    def forward(self, x):
        if self.training and torch.rand(1) < self.drop_p:
            return x  # skip block
        return self.block(x)

Implications:

  • "Deep" misnomer — effectively shallow ensemble।
  • Path diversity learning-এ key।
  • Architecture-এ "hidden" parallel computation।
  • Training dynamics — multi-scale interaction।

Theoretical implications:

  • Generalization bound — depth less important।
  • Width vs depth trade-off।
  • Wide ResNet (shallower wider) competitive।
  • Architecture exploration insight।

Modern relevance:

  • EfficientNet — scaling balance based on this insight।
  • Transformer — similar residual ensemble structure।
  • NAS — block-wise search natural।

Counter-argument:

  • "Pure ensemble" overstates।
  • Path interaction matters।
  • Joint training — pure ensemble different।
  • Empirical limit।

Practical implications:

  • ResNet robust — block fail tolerable।
  • Transfer learning effective।
  • Layer pruning practical।
  • Stochastic depth regularization।

Bangladesh edge deployment:

  • Block pruning model size reduce।
  • Adaptive inference compute save।
  • Mobile-friendly variants।
  • Quality-cost trade-off।

মূল উপলব্ধি: ResNet — single deep network deceptive। Actually $2^n$ shallow path ensemble। Skip connection block-level ensemble enable। Stochastic depth regularization extension। Modern architecture — ensemble interpretation pervasive। Practical pruning, robustness, transfer learning insight। DL theory-র elegant alternative perspective।

প্র ০২ Pre-activation ResNet (He et al. ২০১৬) — original ResNet-এর successor। কী পরিবর্তন, কেন এটা better gradient flow?

He et al.-এর follow-up paper "Identity Mappings in Deep Residual Networks" — ResNet design refinement।

Original ResNet block:

  • Conv → BN → ReLU → Conv → BN → ADD → ReLU
  • BN-ReLU after conv (post-activation)।
  • Final ReLU after sum।

Pre-activation version:

  • BN → ReLU → Conv → BN → ReLU → Conv → ADD
  • BN-ReLU before conv (pre-activation)।
  • No ReLU after sum।
  • Identity path completely clean।

Why "identity matters":

  • Original — sum-এর পরে ReLU।
  • ReLU non-linear — identity path এ "interferes"।
  • Pre-activation — sum after conv, no ReLU।
  • Pure additive identity flow।

Mathematical advantage:

  • $y = x + F(x)$ exactly।
  • Gradient: $\frac{\partial L}{\partial x} = \frac{\partial L}{\partial y} \cdot (1 + \frac{\partial F}{\partial x})$।
  • The "1" — pure identity path, never blocked।
  • Original-এ ReLU sometimes derivative 0।

Empirical results:

  • ResNet-1001 — pre-activation যথেষ্ট train।
  • ResNet-1001 (post-activation) — diverge।
  • 200-layer-এ ~1% accuracy gain।
  • Deeper network easier।

Implementation:

class PreActBlock(nn.Module):
    def __init__(self, in_ch, out_ch, stride=1):
        super().__init__()
        self.bn1   = nn.BatchNorm2d(in_ch)
        self.conv1 = nn.Conv2d(in_ch, out_ch, 3,
                               stride, 1, bias=False)
        self.bn2   = nn.BatchNorm2d(out_ch)
        self.conv2 = nn.Conv2d(out_ch, out_ch, 3,
                               1, 1, bias=False)
        self.shortcut = (
            nn.Conv2d(in_ch, out_ch, 1, stride, bias=False)
            if (stride != 1 or in_ch != out_ch)
            else nn.Identity()
        )

    def forward(self, x):
        out = F.relu(self.bn1(x), inplace=True)
        shortcut = self.shortcut(out if not isinstance(self.shortcut, nn.Identity) else x)
        out = self.conv1(out)
        out = F.relu(self.bn2(out), inplace=True)
        out = self.conv2(out)
        return out + shortcut

Comparison summary:

  • Post-activation (original): ReLU(x + F(x))
  • Pre-activation: x + F(x), F has BN-ReLU first
  • Cleaner identity path
  • Better very-deep training

Why post-activation worked too:

  • 50-152 layer — ReLU effect minor।
  • Deeper — accumulate problem।
  • Most production ResNet still post-activation।

Modern adoption:

  • 1000-layer experiments — pre-activation।
  • Standard 50-152 — post-activation।
  • Both pre-trained available।
  • Choice depends on depth।

Transformer parallel:

  • Pre-LN Transformer (newer)।
  • Post-LN Transformer (original)।
  • Same gradient flow consideration।
  • Pre-LN training stability।

Practical recommendations:

  • Standard depth — original sufficient।
  • Very deep experimentation — pre-activation।
  • NAS — both options consider।
  • Domain-specific tune।

Bangladesh deployment:

  • Standard ResNet sufficient most cases।
  • Custom training scenarios — pre-activation।
  • Pre-trained both available।
  • Architecture detail rarely matters production।

মূল উপলব্ধি: Pre-activation ResNet — refinement focused on gradient flow। Identity path কোনো interference নেই। Very deep network train enable। Production-এ rare necessity but theoretical important। Transformer-এ similar pattern (Pre-LN/Post-LN)। Architecture detail matters scaling extreme। Standard usage — original sufficient।

প্র ০৩ "Skip connection = বিপ্লব" — কেন? এই simple addition কেন এত গুরুত্বপূর্ণ ছিল CNN evolution-এ?

Skip connection — ML history-র সবচেয়ে impactful single idea-গুলোর একটি। Simple কিন্তু transformative।

Pre-skip era সমস্যা:

  • Vanishing gradient — sigmoid/tanh deep network।
  • Optimization difficulty — even 30 layer struggle।
  • BN আশাকাল করল — কিন্তু 100+ layer impossible।
  • Architecture barrier।

Skip connection ফল:

  • 1000+ layer network train possible।
  • ImageNet error 3% (human-level)।
  • Detection, segmentation — সব advance।
  • Foundation model era enable।

Cross-architecture impact:

  • Transformer: "x + Attention(x), x + FFN(x)" — fundamental।
  • U-Net: encoder-decoder skip — segmentation revolution।
  • DenseNet: all-to-all extreme version।
  • Wide ResNet, ResNeXt, EfficientNet: সব residual।

Why "small" addition transformative:

  • Optimization landscape smooth।
  • Identity mapping easy learn।
  • Gradient direct flow।
  • Training dynamics stable।

The minimal change argument:

  • Pre-ResNet block: $y = F(x)$।
  • Post-ResNet block: $y = F(x) + x$।
  • Single addition operation।
  • No new learnable parameter।
  • Compute negligible increase।

Theoretical perspective:

  • Optimization: identity easy reach।
  • Generalization: implicit regularization।
  • Ensemble: exponential path।
  • Information flow: bypass available।

Beyond DL:

  • Highway networks (Schmidhuber, ২০১৫) — gated version।
  • LSTM cell state — temporal skip।
  • Recurrent skip — sequence model।
  • Idea pervasive across architecture।

Industrial transformation:

  • Pre-ResNet — DL niche application।
  • Post-ResNet — every CV task।
  • Foundation model basis।
  • Modern AI infrastructure।

Hinton's quote:

  • "The most important idea in deep learning"।
  • (Across many talks)।
  • Not exaggeration।
  • Skip connection central role।

Modern variations:

  • Dense: all-to-all।
  • Multi-scale: different resolution।
  • Attention residual: Transformer।
  • Gated: learnable weights।

Why was it "missed" so long:

  • Field's depth focus — kept adding layers।
  • Hindsight obvious — পেতে কঠিন।
  • Empirical observation pre-ResNet।
  • Theoretical understanding post-hoc।

Lesson for researchers:

  • Simple ideas powerful।
  • Question fundamental assumption।
  • Architecture detail matters।
  • Theory follow practice।

Bangladesh implication:

  • Modern model adopt — skip standard।
  • Training stability default।
  • Transfer learning effective।
  • Local task — modern architecture।

মূল উপলব্ধি: Skip connection — DL-এর foundational breakthrough। Single addition operation, transformative impact। Optimization, generalization, gradient flow — সব address। Modern architecture-এ universal। Bangladesh — modern model standard usage, skip implicit। ML innovation — sometimes simplest idea most powerful। ResNet legacy — eternal।

প্র ০৪ Bangladesh medical imaging-এ ResNet-50 fine-tune করছেন chest X-ray-তে। Limited data (~5000 image)। কী strategy অনুসরণ করবেন?

Medical imaging + small data + ResNet-50 — practical Bangladesh scenario। Strategy carefully balance।

Pre-trained model selection:

  • ImageNet pretrained — natural image, transferable।
  • RadImageNet — medical pretrained — better।
  • CheXNet — DenseNet121, chest X-ray specific।
  • Best: domain-pretrained + ImageNet।

Transfer learning options:

  • (1) Feature extraction: freeze all + new head।
  • (2) Fine-tune top: freeze early + train last layers।
  • (3) Full fine-tune: all weights train, low lr।
  • (4) Discriminative lr: different lr per layer।

5000 sample - approach 2 ভাল:

import torchvision.models as m

model = m.resnet50(weights='IMAGENET1K_V2')

# Replace head
model.fc = nn.Sequential(
    nn.Dropout(0.5),
    nn.Linear(2048, 14),  # 14 disease class
)

# Freeze early layers
for p in model.layer1.parameters():
    p.requires_grad = False
for p in model.layer2.parameters():
    p.requires_grad = False

# Train layer3, layer4, fc
trainable = [p for p in model.parameters() if p.requires_grad]
optim = torch.optim.AdamW(trainable, lr=1e-4, weight_decay=0.01)

Discriminative learning rates:

params = [
    {'params': model.layer3.parameters(), 'lr': 1e-5},
    {'params': model.layer4.parameters(), 'lr': 1e-4},
    {'params': model.fc.parameters(),     'lr': 1e-3},
]
optim = torch.optim.AdamW(params, weight_decay=0.01)

Augmentation strategy:

train_transform = A.Compose([
    A.Resize(256, 256),
    A.RandomCrop(224, 224),
    A.HorizontalFlip(p=0.5),  # X-ray দু'দিকে symmetric
    A.RandomRotation(10),
    A.ColorJitter(0.1, 0.1, 0.1),
    A.GaussianBlur(blur_limit=3, p=0.3),
    A.GaussNoise(p=0.3),
    A.Normalize(),
    ToTensorV2(),
])
# Test transform: শুধু resize + center crop + normalize

Class imbalance handling:

  • TB rare (~5-10%)।
  • Weighted CrossEntropyLoss।
  • Focal loss alternative।
  • SMOTE for minority class।

Training schedule:

  • Stage 1: head only train (5 epoch)।
  • Stage 2: top blocks unfreeze (15 epoch)।
  • Stage 3: full unfreeze low lr (10 epoch)।
  • Cosine annealing lr schedule।

Regularization:

  • Dropout 0.5 in head।
  • Weight decay 0.01।
  • Mixup augmentation।
  • Label smoothing 0.1।

Validation strategy:

  • 5-fold cross-validation।
  • Stratified by disease label।
  • Hold-out test from different hospital।
  • Bangladesh-specific test set।

Bangladesh-specific challenges:

  • X-ray equipment variation (Siemens, GE, locally manufactured)।
  • Image quality difference।
  • Patient population — different baseline।
  • Radiologist labeling consistency।

Domain adaptation:

  • Synthetic data — local hospital simulation।
  • Test-time augmentation।
  • Adversarial training।
  • Self-supervised pretrain on unlabeled BD X-rays।

Ensemble strategy:

  • 5 models from k-fold।
  • Test-time augmentation।
  • Model averaging।
  • ~2-3% accuracy gain।

Interpretability:

  • Grad-CAM visualization।
  • Attention map।
  • Doctor verification।
  • Explainable predictions।

Calibration:

  • Probability calibrate (temperature scaling)।
  • Uncertainty quantification (MC Dropout)।
  • Confidence threshold।
  • Doctor-in-loop borderline।

Deployment:

  • ONNX export।
  • Quantization (INT8)।
  • Mobile deployment (rural clinic)।
  • Bangla report generation।

Active learning:

  • Uncertain samples — expert label।
  • Iterate dataset growth।
  • Cost-effective improvement।

Validation metrics:

  • AUC-ROC per class।
  • F1 score।
  • Sensitivity-specificity।
  • NPV/PPV (clinical context)।

Realistic expectations:

  • 5000 sample — 80-85% accuracy।
  • Comparable to junior radiologist।
  • Senior radiologist ground truth।
  • Continuous improvement।

Regulatory:

  • BMRC (Bangladesh Medical Research Council) approval।
  • Doctor-in-loop mandatory।
  • Liability framework।
  • Patient consent।

মূল উপলব্ধি: Medical imaging fine-tune — careful strategy। Pretrained foundation + augmentation + class balance + validation। ResNet-50 strong baseline। Discriminative lr + staged unfreezing optimal। Bangladesh — domain adaptation + Bangla integration + regulatory compliance। 5000 sample challenging but achievable। Iterative improvement via active learning। Doctor-AI partnership clinical safety।

অনুশীলন

  1. Math: একটি BasicBlock-এ input ($x$) shape $(8, 64, 56, 56)$, stride=1, in=out=64। Output shape কত?

    $F(x)$: padding 1, stride 1 → $(8, 64, 56, 56)$. Skip identity → same। Sum → $(8, 64, 56, 56)$।

  2. Bottleneck params: Bottleneck block, in=256, mid=64, out=256, kernel-গুলো 1-3-1, stride=1। Conv params (bias=False) কত?

    Conv1 ($1 \times 1$): $256 \times 64 = 16{,}384$।

    Conv2 ($3 \times 3$): $64 \times 64 \times 9 = 36{,}864$।

    Conv3 ($1 \times 1$): $64 \times 256 = 16{,}384$।

    Total: $69{,}632$ + BN params.

  3. Pre-trained ResNet-18: CIFAR-10-এর জন্য torchvision ResNet-18 fine-tune।
    import torchvision.models as m
    
    model = m.resnet18(weights='IMAGENET1K_V1')
    # CIFAR-10: 10 classes, replace fc
    model.fc = nn.Linear(512, 10)
    # Note: CIFAR 32x32 — stem 7x7/2 + maxpool aggressive
    # Better: replace stem with 3x3 stride 1, no maxpool
    model.conv1 = nn.Conv2d(3, 64, 3, 1, 1, bias=False)
    model.maxpool = nn.Identity()

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

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