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

Convolution — Sliding Kernel

Convolution operation — the heart of CNN
৮ মিনিট পড়া মাঝারি · Intermediate PyTorch hands-on

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

  • Convolution-এর গণিত — element-wise multiply ও sum
  • Kernel, stride, padding — output shape সূত্র
  • Channels — RGB image ও multi-filter
  • MLP বনাম CNN — parameter কত কম
  • PyTorch nn.Conv2d — হাতে-কলমে
  • Translation equivariance — কেন CNN ছবিতে এত ভাল

১ · MLP কেন ছবিতে ব্যর্থ

একটি $224 \times 224$ RGB ছবি = $150{,}528$-মাত্রিক vectorVectorসংখ্যার সাজানো তালিকা। ছবিকে flatten করলে — প্রতিটি pixel একটি সংখ্যা, পুরোটা মিলে একটি বিশাল ভেক্টর।। এর সাথে ১০০০ neuron-এর একটি hidden layer যুক্ত করলে — $150{,}528 \times 1000 \approx 1.5 \times 10^8$ parameter। শুধু একটি layer-এ ১৫ কোটি weight!

  • Memory blow-up — train করা কঠিন।
  • Pixel-গুলোর spatial relationship হারিয়ে যায় (flatten করলে neighbor কে, কে দূরে — মডেলের কাছে অর্থহীন)।
  • একটি বিড়ালের ছবি ১০ pixel ডানে সরালে — সম্পূর্ণ ভিন্ন input vector। MLP-কে আবার শিখতে হয়।

Yann LeCun (১৯৮৯) — এই সমস্যাগুলো solve করতে convolutional layer propose করলেন। অনুপ্রেরণা — Hubel-Wiesel-এর visual cortex গবেষণা (১৯৬২ Nobel Prize)।

২ · Convolution — কী ঘটছে?

ভাবুন একটি ছোট torch (kernel) — $3 \times 3$ — যা ছবির উপর slide করছে। প্রতি পজিশনে — torch-এর নিচের ৯টি pixel আর kernel-এর ৯টি weight element-wise multiply করে যোগ — একটি সংখ্যা। সেই সংখ্যা output-এর সেই পজিশনে বসে।

Convolution operation

Input $I$, kernel $K$ (size $k \times k$), output $O$:
$$O[i, j] = \sum_{a=0}^{k-1} \sum_{b=0}^{k-1} K[a, b] \cdot I[i+a, j+b]$$

একই kernel পুরো image-এ — তাই বলে parameter sharing।

প্রযুক্তিগতভাবে — এটা cross-correlation, true mathematical convolution-এ kernel flip হয়। কিন্তু DL-এ "convolution" বলতে এই simpler version বুঝায় — kernel শেখা যায়, flip-এর প্রয়োজন নেই।

ভাবুন আপনি একটি ৩×৩ stamp (kernel) নিয়ে একটি বড় কাগজে (image) প্রতিটি অবস্থানে চাপ দিচ্ছেন। প্রতি পজিশনে — stamp-এর ছাপ আর কাগজের নিচের অংশের সাথে মিল কতটা সেটা একটি সংখ্যা হিসেবে লিখলেন। পুরো কাগজ ঘুরে এই সংখ্যাগুলো একটি নতুন image তৈরি করে — সেটাই feature map।

৩ · একটি ছোট উদাহরণ — হাতে কষুন

Input ($5 \times 5$):

$$I = \begin{bmatrix} 1 & 2 & 3 & 0 & 1 \\ 0 & 1 & 2 & 3 & 1 \\ 3 & 1 & 0 & 2 & 2 \\ 2 & 0 & 1 & 3 & 0 \\ 1 & 2 & 3 & 1 & 0 \end{bmatrix}, \quad K = \begin{bmatrix} 1 & 0 & -1 \\ 1 & 0 & -1 \\ 1 & 0 & -1 \end{bmatrix}$$

এই $K$ — একটি বিখ্যাত vertical edge detector (Sobel-like)। উপরের-বাম অবস্থানে output:

$$O[0,0] = (1 \cdot 1) + (2 \cdot 0) + (3 \cdot -1) + (0 \cdot 1) + (1 \cdot 0) + (2 \cdot -1) + (3 \cdot 1) + (1 \cdot 0) + (0 \cdot -1) = 1 - 3 + 0 - 2 + 3 + 0 = -1$$

Kernel slide করে পরের পজিশনে — আবার একই হিসাব। পুরো image-এর জন্য — output একটি $3 \times 3$ feature mapFeature Mapএকটি convolution layer-এর output — প্রতিটি অবস্থানে kernel-এর pattern-এর তীব্রতা। যেখানে pattern শক্তিশালী, সেখানে value বড়।।

৪ · Stride, padding ও output shape

Stride ($s$): kernel একবারে কত pixel লাফায়।

  • $s=1$ — সব পজিশন (default)।
  • $s=2$ — অর্ধেক resolution output (downsample)।

Padding ($p$): input-এর চারপাশে শূন্য (zero) যোগ — যাতে border pixel-ও ভালভাবে cover হয়।

  • padding=0 ("valid") — output ছোট।
  • padding=k//2 ("same") — output input-এর সমান (stride=1-এ)।
Output shape সূত্র

Input $H \times W$, kernel $k \times k$, padding $p$, stride $s$: $$H_{\text{out}} = \left\lfloor \frac{H + 2p - k}{s} \right\rfloor + 1$$ একই সূত্র width-এর জন্যও।

উদাহরণ: $H = 224, k = 3, p = 1, s = 1$ → $H_{\text{out}} = (224 + 2 - 3)/1 + 1 = 224$ (same padding)।

৫ · Channels — RGB ও multi-filter

একটি RGB image — $3$টি channel (R, G, B)। তাই kernel-ও $3 \times 3 \times 3$ — প্রতিটি channel-এর জন্য আলাদা slice। তিনটি slice-এর contribution যোগ → একটি single feature map।

একটি conv layer-এ সাধারণত একাধিক kernel — যেমন $64$টি। তাই output-এর $64$ channel। প্রতিটি channel ভিন্ন pattern detect করে — কোনোটি horizontal edge, কোনোটি vertical, কোনোটি curve, ইত্যাদি।

Convention: একটি conv layer-এর parameter count = $C_{\text{in}} \times k \times k \times C_{\text{out}} + C_{\text{out}}$ (bias সহ)। MLP-র তুলনায় এটি অনেক কম — image-এর সব pixel-এর সাথে সব pixel-এর connection নয়।
Convolution — kernel ছবিতে slide Input 5×5 · Kernel 3×3 · Output 3×3 📷 Input 3×3 patch 🔍 Kernel 1 0 -1 1 0 -1 1 0 -1 vertical edge ✨ Output -1 feature map multiply sum প্রতি পজিশনে — element-wise × + sum → একটি output সংখ্যা। Kernel slide করে — পুরো feature map।
Convolution — input-এর প্রতিটি 3×3 patch-এর সাথে kernel multiply ও sum। Output = feature map।

৬ · PyTorch দিয়ে — হাতে-কলমে

Python · PyTorch
import torch
import torch.nn as nn

# একটি RGB ছবির batch — (batch=1, channels=3, height=224, width=224)
x = torch.randn(1, 3, 224, 224)

# Conv2d: in=3, out=64, kernel=3, padding=1 (same)
conv = nn.Conv2d(in_channels=3, out_channels=64,
                 kernel_size=3, stride=1, padding=1)

y = conv(x)
print("Input shape:", x.shape)     # [1, 3, 224, 224]
print("Output shape:", y.shape)    # [1, 64, 224, 224]
print("Parameters:", sum(p.numel() for p in conv.parameters()))
# 3*64*3*3 + 64 = 1792

    
মাত্র 1792 parameter — অথচ ১৫,০৫২৮-D input থেকে ৬৪টি feature map তৈরি। MLP হলে কোটি কোটি weight লাগত।

৭ · একটি known kernel apply — vertical edge

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

# একটি grayscale image (batch=1, channel=1, 5x5)
img = torch.tensor([
    [1, 2, 3, 0, 1],
    [0, 1, 2, 3, 1],
    [3, 1, 0, 2, 2],
    [2, 0, 1, 3, 0],
    [1, 2, 3, 1, 0],
], dtype=torch.float32).view(1, 1, 5, 5)

# Vertical edge kernel (1, 1, 3, 3)
K = torch.tensor([
    [1.0, 0.0, -1.0],
    [1.0, 0.0, -1.0],
    [1.0, 0.0, -1.0],
]).view(1, 1, 3, 3)

out = F.conv2d(img, K, padding=0)
print("Output shape:", out.shape)  # [1, 1, 3, 3]
print("Output:\n", out.squeeze())

    
Output-এর প্রথম cell -1 — উপরে হিসাব করেছিলেন, মিলে গেল। প্রতিটি cell — vertical edge-এর strength সেই অবস্থানে।

৮ · Translation equivariance — কেন CNN দারুণ

একই kernel পুরো image-এ apply। ফলে — যদি input-এ একটি pattern $\Delta$ পরিমাণ সরে যায়, output-ও ঠিক $\Delta$ সরে যায়। এই property-কে বলে translation equivarianceTranslation EquivarianceInput-এ shift হলে output-ও সমান shift। CNN-এর built-in property — pooling-এর সাথে মিলে translation invariance। MLP-তে এটি নেই — সব pixel আলাদা weight।।

  • একটি বিড়ালের মুখ image-এর যে কোনো জায়গায় থাকুক — একই kernel detect করবে।
  • MLP-তে এটা নেই — pixel position বদলালে weight বদলায়, model-কে আবার শিখতে হয়।

৯ · Conv vs MLP — parameter comparison

$28 \times 28$ MNIST → $128$ hidden:

  • MLP: $784 \times 128 = 100{,}352$ weight।
  • Conv (16 filters, 3×3): $1 \times 16 \times 3 \times 3 = 144$ weight + 16 bias = $160$।

৬০০ গুণ কম! তবু image-এ অনেক ভাল perform — কারণ inductive bias সঠিক।

Convolution সব data-র জন্য না। Time-series-এ 1D conv ভাল, কিন্তু tabular data (csv table) বা graph-এ MLP/GNN ভাল। Inductive bias data structure-এর সাথে match করা উচিত।

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

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

প্র ০১ "Convolution = cross-correlation, math-এ flip ঘটে কিন্তু DL-এ না" — এই pedagogical detail কি গুরুত্বপূর্ণ? কেন DL-এ flip-এর প্রয়োজন নেই?

Pure mathematics-এ convolution-এর সংজ্ঞায় kernel flip ($K[a,b] \to K[-a,-b]$) থাকে। DL-এ যেটাকে "convolution" বলে — সেটা technically cross-correlation। তবু DL practitioner ও PyTorch — সবাই "convolution" শব্দটি ব্যবহার করে।

কেন flip-এর দরকার নেই?

  • True convolution-এ kernel flip — তাই signal processing-এ associativity ও Fourier theorem ভালভাবে কাজ করে।
  • DL-এ kernel-এর values শেখা হয়। flipped বা not flipped — দু'ক্ষেত্রেই একই function express করা যায়, শুধু weight-এর arrangement ভিন্ন।
  • তাই — flip skip করে computation সরল রাখা হয়।

কোথায় পার্থক্য মাটারে?

  • Pre-defined filter (Gaussian blur, Sobel) — math-এ flip আশা করে। PyTorch-এ flip manually করতে হবে যদি signal-processing semantics চান।
  • Theoretical paper পড়লে — author-এর convention check করুন।
  • Fourier-domain analysis (spectral CNN) — true convolution লাগে।

Practical consequence:

  • Standard image classification, segmentation — flip irrelevant।
  • Custom kernel design (not learned) — খেয়াল রাখুন।
  • Backprop — gradient-এর দিক flip-এ change, কিন্তু framework এটা ঠিকভাবে handle করে।

মূল উপলব্ধি: "Convolution" নামে DL-এ যা ঘটে — cross-correlation। তবু নাম convention হিসাবে stuck। শেখা framework-এ — "kernel-এর সাথে patch-এর element-wise multiply + sum" — এটাই মূল operation।

প্র ০২ Kernel size — কেন প্রায়ই $3 \times 3$? $5 \times 5$ বা $7 \times 7$ কখন ভাল? $1 \times 1$ kernel কী কাজ করে?

Kernel size CNN architecture-এর key design choice। আধুনিক network-এ pattern স্পষ্ট।

৩×৩ — VGG-এর gift:

  • VGG (২০১৪) — দুটি ৩×৩ stack = একটি ৫×৫-এর সমান receptive fieldReceptive Fieldএকটি neuron output value calculate করতে input-এর কত বড় region দেখে। CNN-এ depth বাড়ার সাথে receptive field বাড়ে।।
  • Parameter — $2 \times (3 \times 3) = 18$ vs $5 \times 5 = 25$. কম।
  • দু'টি ReLU — non-linearity বেশি, expressive power বেশি।
  • তাই ৩×৩ এখন de facto standard।

৫×৫ ও ৭×৭ — কখন?

  • First layer: ResNet-এ ৭×৭, AlexNet-এ ১১×১১ — input image-এ বড় context capture।
  • Coarse feature: low-resolution feature map-এ বড় kernel।
  • Computational trade-off: বড় kernel → বেশি FLOPs।

১×১ — Network-in-Network (২০১৪):

  • Spatial mixing করে না — শুধু channel-এ linear combination।
  • Channel reduction (bottleneck) — Inception, ResNet-এ critical।
  • Feature recombination — non-linearity-র সাথে এক ধরনের MLP per pixel।
  • Parameter cheap — $C_{in} \times C_{out}$ only।

Modern variations:

  • Depthwise separable (MobileNet): ৩×৩ depthwise + ১×১ pointwise — ৮-৯× কম compute।
  • Dilated convolution: সাজানো গর্ত — receptive field বড়, parameter সমান।
  • Large kernel CNN (ConvNeXt, RepLKNet): ৭×৭ থেকে ৩১×৩১ — Vision Transformer challenge।

Kernel size selection rule of thumb:

  • Default — ৩×৩।
  • Stem (first layer) — ৭×৭ stride ২।
  • Channel manipulation — ১×১।
  • Mobile/edge — depthwise ৩×৩।
  • Bigger context চাই — dilation বা large kernel।

মূল উপলব্ধি: ৩×৩ accidentally global standard হয়নি — receptive field বনাম parameter বনাম non-linearity-র perfect balance। ১×১ — channel-এর জন্য MLP। বড় kernel বিশেষ ক্ষেত্রে। Architecture design-এ kernel size = first decision।

প্র ০৩ "Inductive bias" কী? CNN-এর কোন bias-গুলো image-এর জন্য ভাল কিন্তু text বা tabular data-র জন্য খারাপ?

Inductive bias = মডেলের built-in assumption যা data-এর structure সম্পর্কে। সঠিক bias = কম data-তে ভাল generalization।

CNN-এর তিন core bias:

  • Locality: nearby pixel-গুলো related — ৩×৩ window যথেষ্ট immediate context-এর জন্য।
  • Parameter sharing (translation equivariance): একই pattern image-এর যে কোনো জায়গায় হতে পারে।
  • Hierarchical composition: low-level (edge) → mid-level (texture) → high-level (object part) — layer-by-layer build-up।

Image-এ এই bias সঠিক:

  • Pixel neighbor strongly correlated।
  • একটি বিড়াল image-এর যে কোনো জায়গায় থাকতে পারে।
  • Edge → curve → eye → face — natural hierarchy।

Text-এ CNN — মিশ্র:

  • Local n-gram detection ভাল (sentence classification)।
  • কিন্তু long-range dependency দুর্বল — RNN/Transformer ভাল।
  • Word order semantics-এ critical, kernel এটা কিছুটা miss।

Tabular-এ CNN — খারাপ:

  • Column-গুলোর order arbitrary — locality assumption invalid।
  • Translation equivariance অর্থহীন।
  • XGBoost/LightGBM/MLP — better।

Graph-এ CNN — partially:

  • Regular grid graph-এ কাজ করে।
  • Irregular graph (social network) — Graph Convolution Network (GCN) — generalized।

3D/video — extension:

  • 3D CNN — temporal locality।
  • Spatiotemporal — video, medical CT scan।

Vision Transformer — minimal bias:

  • ViT (২০২০) locality drop — patches দিয়ে।
  • বড় data দরকার (CNN-এর তুলনায় ৩-১০ গুণ)।
  • Bias কম → flexibility বেশি, কিন্তু data hungry।

Bias-data trade-off:

  • Small data — strong bias (CNN inductive bias) win।
  • Large data — minimal bias (Transformer) win।
  • "No free lunch" — bias দরকার কোথাও থেকে।

মূল উপলব্ধি: Inductive bias = ML practitioner-এর সবচেয়ে গুরুত্বপূর্ণ design tool। Data structure-এর সাথে match করা bias = sample-efficient model। CNN — image-এর genius match। Tabular-এ XGBoost, sequence-এ Transformer। "কোন model best?" — depends on data structure।

প্র ০৪ একটি Bangladeshi vehicle license plate detection system বানাচ্ছেন। CNN-এর প্রথম conv layer-এ কী input shape, kernel, padding, stride বাছবেন? কেন?

Practical CNN design — Bangladesh-এর context-এ। License plate Bengali numeral, formatting unique।

Input considerations:

  • Camera image — 1080p (1920×1080) সাধারণ।
  • Resize — 640×640 বা 800×600 অনুকূল।
  • RGB — 3 channel।
  • Plate ছোট hoy অনেক সময় — high resolution রাখা ভাল।

প্রথম conv layer (stem):

nn.Conv2d(
    in_channels=3,
    out_channels=64,
    kernel_size=7,
    stride=2,
    padding=3,
    bias=False,
)
# Output: 320×320×64 (640 input থেকে)

কেন এই choice?

  • kernel=7: বড় receptive field — license plate-এর initial structure।
  • stride=2: spatial downsample — compute কমাতে।
  • padding=3: "same" feel — border feature retain।
  • out=64: diverse low-level filter (edge, color)।
  • bias=False: পরে BN — bias redundant।

সম্পূর্ণ stem:

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),  # further downsample
)
# Output: 160×160×64

License plate-specific concerns:

  • Aspect ratio: Bangladeshi plate ~3:1 wide। Square input-এ distortion।
  • Bengali numeral: ০, ১, ৬ visually similar — fine-grained features।
  • Lighting variability: Dhaka day/night — augmentation critical।

Architecture pipeline:

  • Stage 1: Detection — YOLO-style — plate bounding box।
  • Stage 2: Segmentation — exact plate boundary।
  • Stage 3: OCR — character recognition (CRNN বা Transformer)।

Input augmentation:

transforms = A.Compose([
    A.RandomBrightnessContrast(0.3, 0.3, p=0.5),
    A.HueSaturationValue(20, 30, 20, p=0.5),
    A.GaussianBlur(blur_limit=3, p=0.3),
    A.RandomRain(p=0.2),  # Bangladesh rainy season
    A.MotionBlur(blur_limit=5, p=0.3),
    A.Resize(640, 640),
    A.Normalize(),
])

Bangla character-specific:

  • Synthetic data: font + augmentation pipeline।
  • Real data labeling: Bengali OCR difficulty — careful labeling।
  • Regional variation: Dhaka, Chittagong, Sylhet — slight format difference।

Compute considerations:

  • Edge deployment (traffic police camera) — MobileNet/EfficientNet base।
  • Cloud inference — ResNet50/Swin Transformer।
  • Real-time — 30 FPS target।

Plate detection-এ specific tweaks:

  • Anchor box — wide rectangular (aspect ratio 3:1)।
  • Multi-scale — distance variation।
  • Confidence threshold — false positive vs miss trade-off।

মূল উপলব্ধি: Conv layer hyperparameter — domain-specific choice। 7×7 stride 2 — image classification standard। কিন্তু license plate, medical imaging, satellite — কাস্টম tuning। Bangladesh license plate — Bengali numerals, aspect ratio, lighting, weather — সব মাথায় রেখে পুরো pipeline design। Compute-quality trade-off — deployment context-এ depend।

অনুশীলন

  1. Output shape: Input $32 \times 32$, kernel $5 \times 5$, padding $2$, stride $1$ — output shape কত?

    $H_{\text{out}} = (32 + 2 \cdot 2 - 5)/1 + 1 = 32$। Output: $32 \times 32$ (same padding)।

  2. Parameter count: Conv2d(in_channels=64, out_channels=128, kernel_size=3) — কত weight + bias?

    Weight: $64 \times 128 \times 3 \times 3 = 73{,}728$। Bias: $128$। Total: $73{,}856$।

  3. Code: $28 \times 28$ MNIST input-এর জন্য ৩-layer CNN — প্রতিটি conv এর পর ReLU, এবং শেষে flatten + linear → 10 classes।
    import torch.nn as nn
    
    class TinyCNN(nn.Module):
        def __init__(self):
            super().__init__()
            self.features = nn.Sequential(
                nn.Conv2d(1, 16, 3, 1, 1), nn.ReLU(),
                nn.Conv2d(16, 32, 3, 1, 1), nn.ReLU(),
                nn.Conv2d(32, 64, 3, 1, 1), nn.ReLU(),
            )
            self.head = nn.Sequential(
                nn.Flatten(),
                nn.Linear(64 * 28 * 28, 10),
            )
        def forward(self, x):
            return self.head(self.features(x))

    (Pooling ছাড়া simple version। পরের পাঠে pooling-এ কমাবেন।)

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

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