3.4.12Convolutional Neural Networks

Image classification pipeline

3,086 words14 min readdifficulty · medium2 backlinks

Overview

The image classification pipeline is the end-to-end workflow that transforms raw pixel data into predicted class labels using convolutional neural networks. Understanding this pipeline is critical because it reveals how CNs systematically extract hierarchical features and make decisions—the foundation of computer vision systems.

Figure — Image classification pipeline

[!intuition] Why Do We Need a Pipeline?

Raw images are just arrays of numbers (pixel values). A human sees "cat" or "dog" instantly, but a computer sees [[123, 45, 67], [89, 201, 34], ...]. The pipeline bridges this gap by:

  1. Standardizing input → All images same size, normalized values
  2. Extracting features hierarchically → Edges → Textures → Parts → Objects
  3. Making probabilistic decisions → "83% dog, 15% cat, 2% wolf"

The key insight: We don't manually engineer features (like "whiskers" or "flopy ears"). The CNN learns what features matter through training data.


[!definition] Pipeline Components

The image classification pipeline consists of:

  1. Preprocessing Stage: Resize, normalize, augment input images
  2. Feature Extraction Stage: Convolutional + pooling layers learn hierarchical representations
  3. Classification Stage: Fully connected layers map features to class probabilities
  4. Postprocessing Stage: Interpret outputs, apply thresholds, visualize

[!formula] Pipeline Mathematics

1. Preprocessing: Normalization

Why normalize? Neural networks learn faster when inputs are on similar scales (typically [0,1] or [-1,1]).

xnormalized=xrawμσx_{\text{normalized}} = \frac{x_{\text{raw}} - \mu}{\sigma}

Derivation from first principles:

Start with raw pixel values xraw[0,255]x_{\text{raw}} \in [0, 255].

Step 1: Subtract mean μ\mu to center data around zero:

x=xrawμx' = x_{\text{raw}} - \mu

Why this step? Centers the data so positive/negative values balance. Helps gradient descent converge faster (symmetric around origin).

Step 2: Divide by standard deviation σ\sigma to scale variance:

xnormalized=xσ=xrawμσx_{\text{normalized}} = \frac{x'}{\sigma} = \frac{x_{\text{raw}} - \mu}{\sigma}

Why this step? Makes variance = 1 across all features. Without this, features with large values dominate the loss function.

Common practice: Use ImageNet statistics (μ=[0.485,0.456,0.406]\mu = [0.485, 0.456, 0.406], σ=[0.229,0.224,0.225]\sigma = [0.229, 0.224, 0.225] for RGB) for transfer learning.


2. Forward Pass Through CNN

The forward pass transforms input XRH×W×3X \in \mathbb{R}^{H \times W \times 3} through LL layers:

h(0)=Xh(l)=f(l)(h(l1);θ(l))for l=1,,Ly^=softmax(h(L))\begin{align} h^{(0)} &= X \\ h^{(l)} &= f^{(l)}(h^{(l-1)}; \theta^{(l)}) \quad \text{for } l = 1, \ldots, L \\ \hat{y} &= \text{softmax}(h^{(L)}) \end{align}

Derivation of the flow:

Layer 1-3 (Convolutional blocks): Extract local features

h(1)=ReLU(Conv(h(0))+b(1))h^{(1)} = \text{ReLU}(\text{Conv}(h^{(0)}) + b^{(1)})

Each convolution: hi,j,k(l)=m,n,cwm,n,c,k(l)hi+m,j+n,c(l1)h^{(l)}_{i,j,k} = \sum_{m,n,c} w^{(l)}_{m,n,c,k} \cdot h^{(l-1)}_{i+m, j+n, c}

Why convolution? Shares weights across spatial locations → translation invariance. Learns edges (layer 1), textures (layer 2), parts (layer 3).

Pooling: hpooled(l)=MaxPool(h(l))h^{(l)}_{\text{pooled}} = \text{MaxPool}(h^{(l)}) reduces spatial dimensions by 2×.

Why pooling? (1) Reduces parameters → less overfitting. (2) Creates spatial invariance → "cat in top-left" same as "cat in center".

Layer 4-5 (Fully connected): Global reasoning

h(4)=ReLU(W(4)flatten(h(3))+b(4))h^{(4)} = \text{ReLU}(W^{(4)} \cdot \text{flatten}(h^{(3)}) + b^{(4)})

Why flatten? Transition from spatial feature maps to feature vector for classification.

Output layer: Map to class logits

z=W(5)h(4)+b(5),zRCz = W^{(5)} h^{(4)} + b^{(5)}, \quad z \in \mathbb{R}^{C}

where CC = number of classes.


3. Softmax: Logits to Probabilities

The softmax function converts raw scores (logits) to valid probabilities:

y^i=ezij=1Cezj\hat{y}_i = \frac{e^{z_i}}{\sum_{j=1}^{C} e^{z_j}}

Derivation from first principles:

Goal: Transform arbitrary real numbers ziz_i into probabilities y^i\hat{y}_i such that:

  1. y^i[0,1]\hat{y}_i \in [0, 1]
  2. i=1Cy^i=1\sum_{i=1}^{C} \hat{y}_i = 1

Step 1: Exponentiate to make all positive:

y~i=ezi\tilde{y}_i = e^{z_i}

Why this step? ex>0e^x > 0 for all xx. Also, exe^x is monotonic: higher logit → higher probability.

Step 2: Normalize to sum to 1:

y^i=y~ij=1Cy~j=ezij=1Cezj\hat{y}_i = \frac{\tilde{y}_i}{\sum_{j=1}^{C} \tilde{y}_j} = \frac{e^{z_i}}{\sum_{j=1}^{C} e^{z_j}}

Why this step? Division by the sum forces y^i=1\sum \hat{y}_i = 1 (probability axiom).

Why not just normalize ziz_i directly? Because softmax amplifies differences: if z1=10,z2=8z_1 = 10, z_2 = 8, then y^1/y^2e27.4\hat{y}_1 / \hat{y}_2 \approx e^2 \approx 7.4 (strong preference). Linear normalization would give 10/18÷8/18=1.2510/18 \div 8/18 = 1.25 (weak preference).


4. Loss Function: Cross-Entropy

The cross-entropy loss measures prediction error:

L(θ)=1Ni=1Nc=1Cyi,clog(y^i,c)\mathcal{L}(\theta) = -\frac{1}{N} \sum_{i=1}^{N} \sum_{c=1}^{C} y_{i,c} \log(\hat{y}_{i,c})

Derivation from information theory:

Step 1: For a single example, true label is yy (one-hot: ytrue=1y_{\text{true}} = 1, others = 0). We want to maximize log(y^true)\log(\hat{y}_{\text{true}}).

Why? Maximizing log probability = maximizing probability (log is monotonic). Log makes math nicer (product → sum in gradients).

Step 2: For one-hot yy, only the true class contributes:

Lsingle=c=1Cyclog(y^c)=log(y^true)\mathcal{L}_{\text{single}} = -\sum_{c=1}^{C} y_c \log(\hat{y}_c) = -\log(\hat{y}_{\text{true}})

Why this step? If y^true=0.9\hat{y}_{\text{true}} = 0.9, loss = log(0.9)=0.105-\log(0.9) = 0.105 (small). If y^true=0.1\hat{y}_{\text{true}} = 0.1, loss = log(0.1)=2.303-\log(0.1) = 2.303 (large). Penalizes wrong predictions heavily.

Step 3: Average over all NN examples:

L=1Ni=1Nlog(y^i,truei)\mathcal{L} = -\frac{1}{N} \sum_{i=1}^{N} \log(\hat{y}_{i, \text{true}_i})

Why average? Makes loss scale-invariant to batch size.


[!example] Worked Example 1: Single Image Through Pipeline

Problem: Classify a224×224 RGB image of a dog using a pre-trained ResNet-50.

Step 1 - Preprocessing:

Original image: Xraw[0,255]224×224×3X_{\text{raw}} \in [0, 255]^{224 \times 224 \times 3}

Normalize using ImageNet stats:

X[c]=Xraw[c]/255μcσcX[c] = \frac{X_{\text{raw}}[c] / 255 - \mu_c}{\sigma_c}

For red channel at pixel (100, 100): Xraw=180X_{\text{raw}} = 180

Xnorm=180/2550.4850.229=0.7060.4850.229=0.965X_{\text{norm}} = \frac{180/255 - 0.485}{0.229} = \frac{0.706 - 0.485}{0.229} = 0.965

Why this step? Matches the distribution ResNet was trained on → better transfer learning.

Step 2 - Feature Extraction:

After conv1 (7×7, stride 2): 112×112×64112 \times 112 \times 64 After layer1 (residual blocks): 56×56×25656 \times 56 \times 256 After layer2: 28×28×51228 \times 28 \times 512 After layer3: 14×102414 \times 1024 After layer4: 7×7×20487 \times 7 \times 2048

Why dimensions shrink? Each pooling/stride divides spatial size by 2. Depth increases to capture more complex features.

After global average pooling: 1×1×20481 \times 1 \times 2048 → flattened to R2048\mathbb{R}^{2048}

Why global average pooling? Reduces 7×7 feature map to single vector (one number per channel). Spatial location no longer matters—we care about "is there a dog?" not "where is the dog?".

Step 3 - Classification:

Fully connected layer: z=Wh+bz = W \cdot h + b, where WR1000×2048W \in \mathbb{R}^{1000 \times 2048} (ImageNet has 1000 classes).

Suppose z=[3.2,0.8,1.5,5.7,]z = [3.2, 0.8, -1.5, 5.7, \ldots] (logits).

Softmax for class 0 (dog): y^0=e3.2e3.2+e0.8+e1.5+e5.7+\hat{y}_0 = \frac{e^{3.2}}{e^{3.2} + e^{0.8} + e^{-1.5} + e^{5.7} + \ldots}

If denominator e5.7\approx e^{5.7} (largest logit dominates), then y^0=e3.2/e5.7=e2.50.082\hat{y}_0 = e^{3.2}/e^{5.7} = e^{-2.5} \approx 0.082 (8%).

Suppose zdog-class=5.7z_{\text{dog-class}} = 5.7 is highest → y^dog0.85\hat{y}_{\text{dog}} \approx 0.85 (85% confidence).

Why this step? Softmax spreads probability mass according to relative logit magnitudes. High logit → high probability.

Step 4 - Postprocessing:

Decision: argmaxcy^c=dog\arg\max_c \hat{y}_c = \text{dog}

Confidence threshold: If max probability< 0.7, output "uncertain".

Why threshold? Prevents overconfident wrong predictions on out-of-distribution images.


[!example] Worked Example 2: Batch Processing

Problem: Process a batch of 32 images through the pipeline. How does batching affect computation?

Step 1 - Batch Construction:

Individual images: XiR224×224×3X_i \in \mathbb{R}^{224 \times 224 \times 3} for i=1,,32i = 1, \ldots, 32

Stacked batch: BR32×224×3\mathcal{B} \in \mathbb{R}^{32 \times 224 \times 3}

Why batching? (1) GPU paralelism: All32 convolutions happen simultaneously. (2) Stable gradients: Averaging over 32 examples reduces noise.

Step 2 - Forward Pass:

Convolution on batch:

h(1)[b]=ReLU(WX[b]+b1)for b=1,,32h^{(1)}[b] = \text{ReLU}(W * X[b] + b_1) \quad \text{for } b = 1, \ldots, 32

Why this step? Same weights WW applied to all 32 images (shared parameters). Output: R32×112×112×64\mathbb{R}^{32 \times 112 \times 112 \times 64}.

After all layers: B(L)R32×1000\mathcal{B}^{(L)} \in \mathbb{R}^{32 \times 1000} (32 logit vectors).

Step 3 - Loss Computation:

For image ii with true label yiy_i:

Li=log(y^i,yi)\mathcal{L}_i = -\log(\hat{y}_{i, y_i})

Batch loss:

Lbatch=132i=132Li\mathcal{L}_{\text{batch}} = \frac{1}{32} \sum_{i=1}^{32} \mathcal{L}_i

Why this step? Average loss over batch provides stable gradient estimate for backpropagation.

Example numbers: If28/32 images classified correctly (probability > 0.9), 4 wrong:

Lbatch28×0.105+4×2.30332=2.94+9.2132=0.38\mathcal{L}_{\text{batch}} \approx \frac{28 \times 0.105 + 4 \times 2.303}{32} = \frac{2.94 + 9.21}{32} = 0.38

Why this matters? Low loss (< 0.5) indicates good performance. High loss (> 2) indicates poor predictions.


[!mistake] Common Mistakes

Mistake 1: Forgetting to Normalize Test Images

Wrong approach: Train with normalized images, test with raw [0, 255] pixels.

Why it feels right: "The model should handle any input."

Steel-man: The instinct is correct that models should be robust, but distribution shift breaks learned features. If training images have mean 0 and variance 1, but test images have mean 127 and variance 1000, the neurons will receive inputs far outside their training range. ReLU activations that learned to fire at 0.5 will now see values like 500—completely saturating or dying.

The fix: Always apply the same preprocessing pipeline (resize, normalization, augmentation disabled) at test time. Save the training statistics (μ\mu, σ\sigma) and reuse them.

Code example:

# Training
train_mean = train_data.mean()
train_std = train_data.std()
 
# Testing (CORRECT)
test_normalized = (test_data - train_mean) / train_std

Mistake 2: Applying Softmax Before Cross-Entropy Loss

Wrong approach:

logits = model(x)
probs = softmax(logits)
loss = cross_entropy(probs, y)  # WRONG

Why it feels right: "Cross-entropy needs probabilities, so I should softmax first."

Steel-man: The confusion arises because mathematically, cross-entropy is defined on probabilities. However, numerically, computing ezie^{z_i} for large ziz_i causes overflow. If zi=1000z_i = 1000, then e1000e^{1000} is too large to represent in float32. The "log-sum-exp" trick used internally by frameworks requires raw logits.

The fix: Use cross_entropy_with_logits (PyTorch: F.cross_entropy, TensorFlow: tf.nn.softmax_cross_entropy_with_logits). These functions combine softmax + log + cross-entropy with numerical stability.

Why it works: Internally computes:

log(y^i)=zilog(jezj)=ziLogSumExp(z)\log(\hat{y}_i) = z_i - \log\left(\sum_j e^{z_j}\right) = z_i - \text{LogSumExp}(z)

LogSumExp trick: LSE(z)=max(z)+log(jezjmax(z))\text{LSE}(z) = \max(z) + \log\left(\sum_j e^{z_j - \max(z)}\right) prevents overflow.


Mistake 3: Using Softmax for Multi-Label Classification

Wrong approach: Image has both "cat" and "dog" (multi-label). Use softmax → forces y^cat+y^dog=1\hat{y}_{\text{cat}} + \hat{y}_{\text{dog}} = 1.

Why it feels right: "Softmax worked for single-label, so it should work for multi-label."

Steel-man: The issue is softmax's normalization constraint. If an image truly contains both cat and dog, we want y^cat=0.9\hat{y}_{\text{cat}} = 0.9 AND y^dog=0.85\hat{y}_{\text{dog}} = 0.85 (both high). But softmax forces them to compete: if y^cat=0.9\hat{y}_{\text{cat}} = 0.9, then y^dog0.1\hat{y}_{\text{dog}} \leq 0.1 (since they must sum to 1).

The fix: Use sigmoid activation for each class independently:

y^c=σ(zc)=11+ezc\hat{y}_c = \sigma(z_c) = \frac{1}{1 + e^{-z_c}}

Now cy^c\sum_c \hat{y}_c can be anything (0 to CC). Use binary cross-entropy loss:

L=1Cc=1C[yclog(y^c)+(1yc)log(1y^c)]\mathcal{L} = -\frac{1}{C} \sum_{c=1}^{C} [y_c \log(\hat{y}_c) + (1 - y_c) \log(1 - \hat{y}_c)]

Example: Image contains cat (label 1) and dog (label 1). With sigmoid, can predict y^cat=0.92\hat{y}_{\text{cat}} = 0.92, y^dog=0.87\hat{y}_{\text{dog}} = 0.87 simultaneously.


[!recall]- Explain Like I'm Twelve

Imagine you're a detective trying to identify animals in photos. Here's your process:

Step 1 - Get the photo ready: All photos need to be the same size (like making all your Pokémon cards the same dimensions). You also adjust the brightness so they all look similar—not too dark, not too bright.

Step 2 - Look for clues (features): First, you notice simple things like edges (is there a round shape? pointy ears?). Then you combine those to see textures (fur? scales?). Then body parts (four legs? a tail?). Finally, you put it all together: "This is a dog!"

The cool part? The computer figures out what clues matter BY ITSELF. You don't tell it "look for whiskers." It discovers through practice that whiskers mean cat.

Step 3 - Make your guess: Instead of saying "It's a dog!" with 100% certainty, you say "I'm 85% sure it's a dog, 10% sure it's a wolf, 5% sure it's a cat." That's what softmax does—turns your confidence into percentages that add up to 100%.

Step 4 - Learn from mistakes: If you said "90% cat" but it was actually a dog, the system feels really bad (high loss). Next time, it adjusts its detective skills to avoid that mistake.

The whole pipeline is like an assembly line at a factory: raw photo → cleaned photo → extracted clues → final answer. Each step does one job well, and together they solve the puzzle!


[!mnemonic] PREP-SCORE

Preprocess: Resize and normalize Run forward pass: Conv layers extract features Exponentiate: Softmax logits to probabilities Predict: Choose argmax class

Softmax for probabilities Cross-entropy for loss Optimize with backprop Repeat for each batch Evaluate on test set


Connections

  • Convolutional layers: The core feature extraction mechanism
  • Batch normalization: Stabilizes training in deep pipelines
  • Data augmentation: Expands preprocessing to improve generalization
  • Transfer learning: Reuses trained pipelines for new tasks
  • Softmax activation: Converts logits to probabilities
  • Cross-entropy loss: Measures classification error
  • Backpropagation: Computes gradients to update pipeline weights
  • ResNet architecture: A specific pipeline with skip connections
  • Multi-label classification: Modified pipeline for multiple simultaneous classes
  • Object detection: Extends pipeline to localize objects (not just classify)

#flashcards/ai-ml

What are the four main stages of the image classification pipeline? :: 1) Preprocessing (resize, normalize), 2) Feature extraction (conv+pooling layers), 3) Classification (FC layers), 4) Postprocessing (interpret outputs)

Why do we normalize images before feeding them to a CNN?
To center data (mean 0) and scale variance (std 1) so gradients converge faster and all features contribute equally to the loss, preventing features with large raw values from dominating

Derive the softmax function from the requirement that outputs must be valid probabilities :: Need P(y_i) ∈ [0,1] and Σ P(y_i) = 1. Step 1: Exponentiate logits to make positive: ỹ_i = e^(z_i). Step 2: Normalize by sum: ŷ_i = e^(z_i) / Σ_j e^(z_j). This satisfies both constraints.

What is the cross-entropy loss for a single example and why does it penalize wrong predictions heavily?
L = -log(ŷ_true). If ŷ_true = 0.9, L = 0.105 (small). If ŷ_true = 0.1, L = 2.303 (large). The log function grows rapidly as probability approaches 0, heavily penalizing confident wrong predictions.
Why does the spatial size decrease and depth increase as we go deeper in a CNN?
Each pooling or strided convolution divides spatial dimensions by 2, while depth (number of filters) increases to capture more complex features. Early layers: many pixels, simple features (edges). Deep layers: few pixels, complex features (objects).
What is the purpose of global average pooling before the classification layer?
Reduces a 7×7×2048 feature map to a single 2048-dimensional vector by averaging each channel. This makes the representation spatially invariant (location doesn't matter) and reduces parameters for the final FC layer.
Why should you never apply softmax before passing logits to cross-entropy loss?
Numerical stability. Computing e^(z_i) for large z_i causes overflow. Built-in functions use the log-sum-exp trick: log(ŷ_i) = z_i - LSE(z), where LSE(z) = max(z) + log(Σ e^(z_j - max(z))) prevents overflow.
What is the difference between softmax and sigmoid for multi-label classification?
Softmax forces Σ ŷ_i = 1 (probabilities compete—if cat is high, dog must be low). Sigmoid treats each class independently: ŷ_c = 1/(1+e^(-z_c)), allowing multiple high probabilities simultaneously (image can be both cat AND dog).
Why is batch processing beneficial in the image classification pipeline?
1) GPU parallelism: All images in batch processed simultaneously. 2) Gradient stability: Averaging loss over multiple examples reduces noise in gradient estimates, leading to smother convergence.
What happens if you forget to normalize test images using training statistics?
Distribution shift breaks learned features. If training normalized to mean=0, std=1 but testing uses raw [0,255] pixels, neurons receive out-of-range inputs (e.g., 500 instead of 0.5), causing ReLU saturation or death. Always apply same preprocessing with saved training μ and σ.

Concept Map

input to

resize normalize augment

formula x minus mu over sigma

conv plus pooling layers

edges to textures to parts

fully connected layers

softmax

interpret and threshold

final output

gives

used in

CNN learns features from

Raw pixel data

Preprocessing stage

Normalized input X

Feature extraction stage

Hierarchical features

Classification stage

Class logits h L

Class probabilities

Postprocessing stage

Predicted class label

Weight sharing

Translation invariance

Training data

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, image classification pipeline ka core idea bahut simple hai — computer ko ek image sirf numbers ka array dikhti hai, jaise [123, 45, 67...], jabki humein turant "cat" ya "dog" samajh aata hai. Toh yeh pipeline ek bridge ki tarah kaam karti hai jo raw pixels ko final prediction tak le jaati hai. Pehle preprocessing hoti hai (image ko same size karo, values normalize karo), phir feature extraction (convolution aur pooling layers se edges se lekar poori objects tak features seekhna), phir classification (fully connected layers se probabilities banana), aur last mein postprocessing. Sabse important baat yeh hai ki hum manually features nahi banate — jaise "whiskers" ya "flopy ears" — balki CNN khud training data se seekhta hai ki kaunse features matter karte hain.

Ab yeh samajhna zaroori hai ki har step kyun hai. Normalization isliye karte hain kyunki neural network tab fast seekhta hai jab saare inputs similar scale par hon — mean subtract karke data ko zero ke around center karte hain, aur standard deviation se divide karke variance ko balance karte hain, taaki bade values wale features loss function ko dominate na karein. Convolution ka magic yeh hai ki weights spatial locations pe share hote hain, jisse translation invariance milti hai — matlab cat kahin bhi ho, model pehchan lega. Pooling parameters kam karke overfitting rokta hai aur spatial invariance deta hai.

Aakhir mein softmax raw scores (logits) ko proper probabilities mein convert karta hai — jaise "83% dog, 15% cat, 2% wolf" — taaki saari values 0 se 1 ke beech hon aur sum exactly 1 ho. Yeh pipeline samajhna isliye critical hai kyunki yahi computer vision ki poori foundation hai — chahe aap face recognition banao, medical imaging karo, ya self-driving car, yahi end-to-end flow har jagah kaam aata hai. Ek baar yeh intuition clear ho gaya, toh baaki advanced architectures samajhna bahut easy ho jaata hai.

Go deeper — visual, from zero

Test yourself — Convolutional Neural Networks

Connections