Pooling — Max ও Avg
এই পাঠে যা শিখবেন
- Max pooling ও Average pooling — গাণিতিক সংজ্ঞা
- Pooling-এর তিন উদ্দেশ্য — downsample, translation invariance, receptive field
- Global Average Pooling — modern CNN-এর head
- Stride convolution বনাম pooling — কখন কোনটা
- PyTorch
MaxPool2d,AvgPool2d,AdaptiveAvgPool2d
১ · Pooling — কেন দরকার
Convolution-এর পর feature map-এর spatial dimension সাধারণত একই থাকে (same padding-এ)। কিন্তু গভীর network-এ দরকার:
- Compute কমানো: $224 \times 224$ feature map পরিষ্কারভাবে process করা ব্যয়বহুল।
- Receptive field বাড়ানো: ছোট spatial size-এ একই kernel — input-এর বড় region cover।
- Translation invariance: ছোট shift-এ একই output।
- Overfitting কমানো: spatial detail কমে — generalize ভাল।
Pooling একটি window (সাধারণত $2 \times 2$) input-এর উপর slide করে — প্রতিটি window-এ একটি single value output।
২ · Max Pooling
$2 \times 2$ window-এ ৪টি value-এর সর্বোচ্চটি output: $$O[i, j] = \max_{(a, b) \in \text{window}} I[i \cdot s + a, \; j \cdot s + b]$$ Default stride = window size (overlap নেই)।
উদাহরণ:
$$I = \begin{bmatrix} 1 & 3 & 2 & 4 \\ 5 & 6 & 7 & 8 \\ 3 & 2 & 1 & 0 \\ 1 & 2 & 3 & 4 \end{bmatrix} \xrightarrow{\text{MaxPool 2×2}} \begin{bmatrix} 6 & 8 \\ 3 & 4 \end{bmatrix}$$
প্রতি $2 \times 2$ block-এ সর্বোচ্চ — output $4 \times 4 \to 2 \times 2$।
৩ · Average Pooling
$$O[i, j] = \frac{1}{k^2} \sum_{(a, b) \in \text{window}} I[i \cdot s + a, \; j \cdot s + b]$$
একই উদাহরণে:
$$\xrightarrow{\text{AvgPool 2×2}} \begin{bmatrix} (1+3+5+6)/4 & (2+4+7+8)/4 \\ (3+2+1+2)/4 & (1+0+3+4)/4 \end{bmatrix} = \begin{bmatrix} 3.75 & 5.25 \\ 2.0 & 2.0 \end{bmatrix}$$
৪ · Max বনাম Avg — কখন কোনটা
- Max: "presence" detection — কোনো feature আছে কিনা। Sharp, discriminative।
- Avg: "smooth summary" — overall texture। Stable, less noisy।
- Empirical: early-mid layers-এ Max প্রায়ই ভাল (sharp feature), final layer-এ Avg (global summary)।
৫ · Global Average Pooling — modern CNN-এর head
Traditional CNN: Conv → Pool → ... → Flatten → FC → Output. Flatten-এর পর FC-তে millions of parameter।
Network-in-Network (Lin et al., ২০১৪) idea — Flatten + FC সরিয়ে Global Average PoolingGlobal Average Pooling (GAP)প্রতিটি feature map-এর সম্পূর্ণ spatial mean — একটি single number per channel। Output: $C$-D vector। Modern CNN-এ FC-র জায়গায়।:
Input: $C \times H \times W$. Output: $C$-dimensional vector ($C$টি channel, প্রতিটি channel-এর spatial mean)।
$$\text{GAP}(I)[c] = \frac{1}{H \cdot W} \sum_{i, j} I[c, i, j]$$
- Parameter zero — overfitting risk minimal।
- Spatial structure সম্পূর্ণ collapse — শুধু channel-wise summary।
- ResNet, DenseNet, EfficientNet — সবার head।
৬ · PyTorch — তিনটি pooling
import torch
import torch.nn as nn
# একটি ছোট 4x4 feature map
x = torch.tensor([
[1, 3, 2, 4],
[5, 6, 7, 8],
[3, 2, 1, 0],
[1, 2, 3, 4],
], dtype=torch.float32).view(1, 1, 4, 4)
# Max pooling
maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
print("Max:\n", maxpool(x).squeeze())
# Average pooling
avgpool = nn.AvgPool2d(kernel_size=2, stride=2)
print("\nAvg:\n", avgpool(x).squeeze())
# Global Average Pooling — output 1x1 per channel
gap = nn.AdaptiveAvgPool2d(1)
print("\nGAP:", gap(x).squeeze())
৭ · Stride convolution — pooling-এর alternative
Modern CNN-এ অনেক ক্ষেত্রে separate pool layer-এর জায়গায় conv-এ stride 2:
- Pool: fixed (max বা avg), parameter-less।
- Stride conv: learnable downsample — kernel কীভাবে summarize শেখে।
- ResNet, DenseNet — stride-2 conv।
- VGG — pool layer।
import torch.nn as nn
# Pool-based downsample
pool_block = nn.Sequential(
nn.Conv2d(64, 128, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
)
# Stride-conv-based downsample
stride_block = nn.Sequential(
nn.Conv2d(64, 128, 3, stride=2, padding=1),
nn.ReLU(),
)
# একই output spatial size — different parameter behavior
৮ · Pooling-এর problem
- Information loss: spatial detail হারায় — segmentation/detection-এ অসুবিধা।
- Aliasing: stride-2 pooling-এ shift-equivariance ভেঙে যায় (Zhang ২০১৯, "Making CNNs Shift-Invariant Again")।
- Backprop: max pool-এ gradient শুধু max position-এ flow — অন্য neuron train পায় না।
৯ · Modern usage summary
- Stem-এ: ৭×৭ conv stride 2 + ৩×৩ MaxPool stride 2 (ResNet)।
- Mid layers: stride-2 conv (ResNet, DenseNet) বা MaxPool (VGG)।
- Head: Global Average Pool → linear classifier।
- Detection/Segmentation: pool কমিয়ে atrous/dilated conv (DeepLab)।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ "Pooling = translation invariance" — common claim। কিন্তু Zhang (২০১৯) দেখান CNN actually shift-invariant না। কী ঘটে, এবং কী fix?
Aliasing — signal processing-এর ক্লাসিক সমস্যা। stride-2 sampling Nyquist criterion ভাঙে।
সমস্যাটি:
- Stride-2 pool — input-এর প্রতি ২য় position।
- Input ১ pixel shift করলে — pool-এর "even" position-গুলো "odd" হয়ে যায়।
- Output সম্পূর্ণ ভিন্ন — invariance fail।
Empirical verification:
- Zhang showed — image ১ pixel shift করলে CNN-এর top-1 prediction probability ৪০% case-এ বদলায়।
- Same image, slightly different translation → different class।
- Adversarial-এর কাছাকাছি behavior।
Fix — anti-aliased pooling:
- Stride-2 max pool-এর আগে blur (low-pass filter) — Nyquist preserve।
- Triangle filter বা Gaussian — typical।
- Performance + invariance দু'টোই improve।
BlurPool implementation:
class BlurPool(nn.Module):
def __init__(self, channels, stride=2):
super().__init__()
kernel = torch.tensor([1., 2., 1.])
kernel = kernel[:, None] * kernel[None, :]
kernel = kernel / kernel.sum()
self.register_buffer('kernel',
kernel[None, None].repeat(channels, 1, 1, 1))
self.stride = stride
def forward(self, x):
return F.conv2d(x, self.kernel,
stride=self.stride,
padding=1,
groups=x.shape[1])
Adoption:
- Antialiased ResNet — accuracy + robustness improve।
- Detection/Segmentation — bigger gain।
- Computational cost — minimal।
Other invariance approaches:
- Data augmentation: random crops train invariance imposed।
- Group equivariant CNN: rotation/scale invariance built-in।
- Transformer: patches different invariance properties।
Theoretical foundation:
- Sampling theorem — band-limited signal proper sampling।
- CNN-এ filtered বনাম unfiltered downsampling।
- Classical signal processing wisdom — DL-এ rediscovered।
Modern best practice:
- Stride-2 conv better than stride-2 pool (learnable filter)।
- Average pool — implicit smoothing।
- BlurPool — explicit anti-aliasing।
- Strong augmentation — data-driven invariance।
মূল উপলব্ধি: "Pooling = translation invariance" — partially true। Aliasing-এর জন্য actual invariance imperfect। BlurPool, stride-conv, augmentation — combined approach। Robustness-এ critical, especially safety-critical applications।
প্র ০২ "Global Average Pooling vs Flatten + FC" — Network-in-Network paper-এর big idea। GAP-এর benefits কী, কোথায় limitation?
GAP — Lin et al. (২০১৪) "Network in Network"। CNN architecture-এ পরিবর্তন।
Traditional CNN head:
- Conv → ... → Flatten → FC(4096) → FC(4096) → FC(1000)।
- VGG-16 — শেষের ৩টি FC layer-এ ১২০M parameter (পুরো network-এর ৯০%)।
- Overfitting risk বিশাল।
GAP head:
- Conv → ... → GAP → FC(num_classes)।
- Parameter — শুধু final FC ($C \times \text{classes}$)।
- Spatial structure সম্পূর্ণ collapse।
Benefits:
- Massive parameter reduction: 90%+ less।
- Less overfitting: small data-এ critical।
- Input size flexibility: different resolution accept।
- Interpretability: CAM (Class Activation Map) সহজ।
CAM-এর secret sauce:
- Last conv feature map (before GAP) — semantic spatial info।
- FC weight × feature map = heatmap of class evidence।
- "Where is the model looking?" — visualization।
Limitation — spatial info loss:
- Object position information loss।
- Detection/segmentation-এ direct GAP কাজে লাগে না।
- Fine-grained classification — sometimes underperform।
Modern variants:
- Generalized Mean Pooling (GeM): $\left(\frac{1}{N}\sum x^p\right)^{1/p}$ — learnable $p$।
- Attention pool: learnable spatial weights।
- Concat pool: GAP + GMP concatenated।
Adoption history:
- NIN (২০১৪) introduce।
- GoogLeNet (২০১৪) — adopted।
- ResNet (২০১৫) — standard।
- Modern CNN — universal।
When NOT to use GAP:
- Object detection — spatial info needed (ROI pool)।
- Semantic segmentation — pixel-level prediction।
- Small input — Flatten + FC sometimes better।
- Fine-grained — bilinear pool variants।
মূল উপলব্ধি: GAP — DL architecture design-এর elegant innovation। Parameter কমে + interpretability + flexibility। Classification-এ universal। কিন্তু spatial task-এ alternative। "Less is more" — DL-এ powerful principle। Modern CNN — GAP without question।
প্র ০৩ Max pooling-এ backprop কীভাবে কাজ করে? শুধু max position-এ gradient — এটা সমস্যা?
Max pool — non-differentiable। কিন্তু DL-এ "subgradient" বা "selector" interpretation works।
Forward:
- Window-এ max value select।
- সেই position-এর index store (cache)।
Backward:
- Output gradient — শুধু max position-এ pass।
- অন্য position — gradient 0।
- "Hard selector" — discrete decision।
Implementation:
# PyTorch internal — pseudo
class MaxPoolBackward:
def forward(self, x):
self.indices = x.argmax_per_window()
return x.max_per_window()
def backward(self, grad_output):
grad_input = zeros_like(x)
grad_input.scatter_(self.indices, grad_output)
return grad_input
Sparse gradient সমস্যা:
- 2x2 max pool — 75% neuron-এ gradient 0।
- "Dead" neurons — never update।
- Non-max neurons learning slow।
Avg pool comparison:
- Avg — সব 4 neuron-এ equal gradient (1/4)।
- Smoother backprop।
- সব neuron train পায়।
Soft alternatives:
- LogSumExp: $\log \sum e^x$ — smooth max approximation।
- Soft pool: weighted average — weight = $e^x / \sum e^x$।
- Stochastic pool: probability proportional to value।
Why max still works:
- Different windows — different position max।
- Aggregate — effective gradient flow।
- Empirical performance — strong।
- Sparse gradient — implicit regularization।
Implementation detail:
- Tied gradient between consecutive samples (cudnn cached indices)।
- Variable window for irregular input।
- Adaptive max pool — different output sizes।
Theoretical view:
- Subgradient — non-differentiable function-এর জন্য।
- Almost everywhere differentiable — measure-zero ties।
- Gradient method-এ acceptable।
Practical tips:
- Network depth-এ avg-এর চেয়ে max popular।
- Dead neuron occasional — large enough capacity।
- BN + ReLU — overall flow maintain।
- Average for smoothing, max for detection।
Recent insights:
- Vision Transformer — pooling avoid (different architecture)।
- Modern CNN — stride conv replaces max pool।
- Pure pool architecture rare আজ।
মূল উপলব্ধি: Max pool-এর gradient sparse — surprising kintu effective। Non-differentiable point-এ subgradient ব্যবহার। Soft alternatives exist কিন্তু practical performance gap small। Modern trend — stride conv বা pure attention। Classical max pool — historical importance + simplicity।
প্র ০৪ Bangladesh-এর একটি রোগী X-ray classifier বানাচ্ছেন (TB detection)। Pooling architecture কীভাবে design করবেন? কোথায় aggressive, কোথায় conservative?
Medical imaging — high stakes। Pooling decision careful।
Domain considerations:
- X-ray: 1024×1024 typical resolution।
- TB lesion — small spatial features (cm scale)।
- Class imbalance: TB rare disease (5-10%)।
- Critical: false negative প্রাণহানি।
Architecture choice:
- Backbone: ResNet50 / DenseNet121 (medical-pretrained)।
- CheXNet (Stanford) — DenseNet121 — chest X-ray gold standard।
- Modern: Vision Transformer fine-tune।
Pooling strategy:
(১) Early — aggressive:
- Stem: 7×7 conv stride 2 + 3×3 max pool stride 2।
- 1024×1024 → 256×256 quickly।
- Compute reduction priority।
- Low-level features stable।
(২) Mid — conservative:
- Stride-2 conv between blocks।
- Max pool avoid (lesion ছোট)।
- Atrous/dilated conv consider।
(৩) Late — minimal:
- Final stage — 14×14 spatial keep।
- No additional pooling।
- Receptive field already large।
(৪) Head:
- Global Average Pooling।
- FC → binary (TB vs no TB)।
- Dropout 0.3-0.5 (small data)।
Modified for TB-specific:
class TBClassifier(nn.Module):
def __init__(self, backbone='densenet121'):
super().__init__()
self.backbone = timm.create_model(
backbone,
pretrained=True,
features_only=True,
)
# Multi-scale feature pyramid
self.fpn = FeaturePyramidNetwork()
self.gap = nn.AdaptiveAvgPool2d(1)
self.head = nn.Sequential(
nn.Dropout(0.4),
nn.Linear(256, 2),
)
Multi-scale strategy:
- FPN (Feature Pyramid Network) — multi-scale lesions।
- Different resolution combine।
- Small + large lesions detect।
Augmentation (Bangladesh climate):
- Brightness — exposure variation।
- Contrast — image quality differ।
- Random crops — orientation।
- Mixup — class imbalance address।
Validation strategy:
- Stratified k-fold।
- Site-wise hold-out (different hospital)।
- Sensitivity-specificity trade-off।
- FROC analysis — lesion localization।
Bangla deployment context:
- Rural clinic — low-resource hardware।
- Mobile app — quantized model।
- Offline inference — no cloud।
- Local language UI — actionable results।
Edge case:
- X-ray quality variation।
- Equipment difference (Siemens vs GE)।
- Chest size variation।
- Pediatric vs adult।
Regulatory:
- BMRC approval।
- Doctor in loop — never autonomous।
- Confidence calibration critical।
- Uncertainty quantification।
Resource-constrained tips:
- Knowledge distillation: ResNet50 → MobileNetV3।
- Quantization: INT8।
- ONNX runtime mobile।
- Edge device benchmark।
মূল উপলব্ধি: Medical imaging-এ pooling design — domain-specific। Aggressive early (compute), conservative mid (lesion), minimal late (receptive field already enough)। GAP standard head + dropout। Multi-scale FPN small lesion-এ। Bangladesh deployment — quantization + offline + Bangla UI। Doctor + AI partnership — patient safety।
অনুশীলন
-
Output shape: Input $(1, 64, 56, 56)$, MaxPool2d(
kernel=2, stride=2) — output shape কত?$(1, 64, 28, 28)$. Channel একই থাকে, spatial dim অর্ধেক।
-
Hand-calc: Input $\begin{bmatrix} 2 & 4 & 1 & 0 \\ 6 & 5 & 3 & 2 \\ 1 & 2 & 7 & 8 \\ 4 & 3 & 9 & 6 \end{bmatrix}$ — Max ও Avg pool 2×2।
Max: $\begin{bmatrix} 6 & 3 \\ 4 & 9 \end{bmatrix}$।
Avg: $\begin{bmatrix} 4.25 & 1.5 \\ 2.5 & 7.5 \end{bmatrix}$।
-
Architecture: $32 \times 32$ CIFAR-10 input থেকে শুরু — ৪টি conv block, প্রতিটির পর MaxPool 2x2, এবং শেষে GAP + FC।
class CifarCNN(nn.Module): def __init__(self): super().__init__() def block(c_in, c_out): return nn.Sequential( nn.Conv2d(c_in, c_out, 3, padding=1), nn.BatchNorm2d(c_out), nn.ReLU(inplace=True), nn.MaxPool2d(2), ) self.features = nn.Sequential( block(3, 32), # 32 -> 16 block(32, 64), # 16 -> 8 block(64, 128), # 8 -> 4 block(128, 256), # 4 -> 2 ) self.gap = nn.AdaptiveAvgPool2d(1) self.fc = nn.Linear(256, 10) def forward(self, x): x = self.features(x) x = self.gap(x).flatten(1) return self.fc(x)
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পাঠ ১৯ · Receptive field পরবর্তী পাঠ Conv ও pool-এর সাথে receptive field কীভাবে বাড়ে।
- পাঠ ১৭ · Convolution আগের পাঠ Pooling-এর partner — conv operation।
- পাঠ ২০ · LeNet ও AlexNet এই module প্রথম দুটি landmark CNN architecture।
- সব AI Courses দেখুন ABCL TECH Python, ML, DL, NLP, CV, GenAI, RL, MLOps — সব AI কোর্স একসাথে।