3.4.5 · D4Convolutional Neural Networks

Exercises — CNN architecture design

3,659 words17 min readBack to topic

Prerequisite bricks: 3.401-convolution-operation, 3.4.02-pooling-layers, 3.4.03-activation-functions, 3.4.04-batch-normalization, 4.2.03-vanishing-gradient.


Level 1 — Recognition

L1.1 — Name the four design dimensions

Problem. A CNN architecture is fully described by four knobs. Name all four and, in one phrase each, say what each knob controls.

Recall Solution

The four knobs (straight from the parent note):

  1. Depth — number of layers stacked; controls the feature hierarchy (edges → parts → objects).
  2. Width — number of channels per layer; controls capacity (how many parallel detectors).
  3. Connectivity — how layers wire together (plain sequential, skip/residual, or DenseNet-style dense skip connections). Careful: here "dense" means dense skip connections (every layer feeds every later layer, as in DenseNet), not fully-connected "dense layers." This knob solves training problems like vanishing gradients.
  4. Receptive field — how much of the input one deep neuron can "see"; controls how much context is available.

L1.2 — Match innovation to network

Problem. Match each innovation to the first famous network that used it: (a) ReLU + Dropout at scale, (b) only kernels stacked deep, (c) skip connections, (d) parallel multi-scale branches.

Recall Solution
  • (a) → AlexNet (2012)
  • (b) → VGGNet (2014)
  • (c) → ResNet (2015)
  • (d) → Inception / GoogLeNet (2014)

Level 2 — Application

L2.1 — Receptive field of stacked convs

Problem. You stack convolution layers, each with a kernel, stride 1 (the window slides one pixel at a time), same padding (zeros added at the border so each map keeps its size). What is the receptive field (side length) of one neuron in the top layer, measured on the input?

Recall Solution

What "receptive field" (RF) means, from zero. The receptive field of a top neuron is the side length of the patch of input pixels that can possibly influence it. We now derive the growth formula on this page rather than borrowing it.

Why the padding/stride matter here. With stride 1 the window moves one pixel per step, so consecutive receptive fields overlap by the maximum amount — this is what makes the growth a clean per layer. Same padding just keeps every map the same so we can count reach without the map shrinking; it does not change the RF arithmetic, it only keeps the bookkeeping tidy. (With valid padding the maps would shrink by each layer, but each neuron's reach on the input is still — padding affects map size, not receptive field.)

The picture — walk it row by row. The figure below shows four stacked rows of grid cells drawn like a chalk sketch: the bottom row is the input, and each higher row is the output of one conv. A single yellow cell at the very top is one top neuron; blue dashed lines fan down from it forming a "cone of vision," and coloured bands (blue, then pink, then yellow) mark how wide that cone gets at each lower row. Trace downward:

  • The yellow top neuron reads a window (blue band) in the row just below — width 3.
  • Each of those blue neurons itself reads a window one row lower (pink band). The leftmost blue neuron reaches 1 further left, the rightmost reaches 1 further right, so the pink span is wide.
  • Down one more row (yellow band on the input), the span widens again by to width 7.

Figure — CNN architecture design
Figure: a "cone of vision." One top neuron (yellow) fans out through each layer; the highlighted span widens 3 → 5 → 7, i.e. +2 per layer, giving .

The rule you can read straight off the picture: every extra layer adds exactly to the width — 1 pixel of new reach on each side, because a window centered on a pixel extends 1 left and 1 right. The centre pixel is shared with the layer below, so it is not recounted. That is why it is per layer, not .

Assemble the formula. Start from a single pixel (width 1), add for each of the layers: For : , i.e. a region. (This same is quoted in the parent note; above is its self-contained derivation.)

L2.2 — Parameter count: one vs two

Problem. A layer keeps the channel count at throughout. Compare the number of weights (ignore bias) of one conv versus two stacked convs. Give both formulas and the percentage saving.

Recall Solution

Where the formula comes from: each output channel needs a full stack across all input channels, and there are output channels. So weights . Here .

  • One : .
  • Two : .

Saving: Bonus insight: the two stack also inserts two ReLU nonlinearities instead of one — more expressive and cheaper, which is the whole VGG thesis.

L2.3 — Bottleneck parameter saving

Problem. Input has 256 channels. Compare (a) a direct conv producing 256 channels, versus (b) a bottleneck: (a) via ; (b) via then via . Spatial size stays fixed. Compute weights of each and the saving.

Recall Solution

Use weights .

  • (a) Direct : .
  • (b) reduce: . Then : . Total: .

Saving: Why the helps: a conv mixes channels without touching spatial patterns — cheap. It shrinks the channel dimension so the expensive works on a thinner stack.


Level 3 — Analysis

L3.1 — Why the "" saves ResNet

Problem. A residual block computes . Show algebraically why the gradient flowing back through this block cannot fully vanish, and contrast with a plain (non-skip) block.

Recall Solution

Setup. is the block input; is what the conv layers compute (the "residual"). The output is their elementwise sum, so , and are all tensors of the same shape (say flattened to a vector of length ).

What we differentiate and why. During backprop we need how the output changes when the input changes, because that factor multiplies the gradient as it travels backward (chain rule). For vector-valued and this "factor" is not a single number but a Jacobian matrix , a table whose entry is . Here is the identity matrix (1's on the diagonal, 0's elsewhere) — the Jacobian of "copy the input unchanged." It is the matrix version of the scalar ""; picturing it as a plain "" is a convenient shorthand, but the true object is the identity matrix .

Plain block (no skip): output is just , so the local Jacobian is alone. Stack of these and the backprop factor is a product of matrices . If these matrices shrink vectors (all singular values ), the product decays exponentially → vanishing gradient (see 4.2.03-vanishing-gradient).

Residual block: the Jacobian is . Even if (the layers learn nothing useful), the block still passes the gradient through as the gradient unchanged. The identity term guarantees a "highway" straight back for every channel and every spatial position at once, which is why the trick works for full multi-channel tensors, not just a scalar toy.

Figure — CNN architecture design
Figure: the residual block. The straight top path is the learned mapping (Conv+ReLU → Conv); the curved yellow arrow underneath is the identity "skip" that carries straight to the pink node, where . That yellow arrow is the gradient highway giving the term.

L3.2 — Depth needed for a target receptive field

Problem. Input is . You want a neuron whose receptive field covers at least pixels, using convs. Ignore pooling first: how many conv layers alone are needed? Then explain why pooling is used instead.

Recall Solution

Convs alone. Using the derived in L2.1 (self-contained there), require : That's a lot of layers just to widen vision.

Why pooling wins — deriving from scratch. First, a reminder of stride: the stride is how many pixels the window jumps between placements. A pool (stride 2) replaces every block of pixels with one summary pixel, so one step on the pooled map corresponds to two pixels of movement on the map below — that "jump of 2" is exactly the stride. Now put a conv on top of the pooled map and ask how wide its input footprint is, measured back on the pre-pool map:

  • The conv reads neighbouring pooled pixels. Neighbouring pooled pixels are apart on the map below (that's the stride-2 "multiplier"), so their centres span pixels; but each pooled pixel itself already summarised the old receptive field .
  • Carrying that reach through: the new receptive field becomes . The factor 2 is the stride of the pool (each step downstairs jumps 2 pixels); the is the usual kernel border reach from L2.1.

The punchline: pooling makes RF grow multiplicatively (a factor of 2 every pool) whereas plain convs only add each. Multiplication beats addition, so interleaving a handful of pools reaches in far fewer layers than 50 — which is exactly why every classic net alternates conv stacks with pooling.


Level 4 — Synthesis

L4.1 — Design an Inception branch's output depth

Problem. An Inception module receives and has four branches producing 64, 128, 64, 64 channels respectively. Each branch keeps spatial size at . What is the concatenated output shape, and why must each branch keep the same spatial size?

Recall Solution

Inception concatenates along the channel (depth) axis. Spatial dims must match so the sheets stack cleanly. Why same spatial size: you cannot stack a sheet on a sheet — they don't align. Every branch therefore uses padding so each keeps ; only the channel counts add up. See 3.401-convolution-operation for how "same" padding preserves size.

L4.2 — Global average pooling replaces the FC head

Problem. A net ends with a feature block and must output 1000 class scores. Design a fully-convolutional head using global average pooling instead of flatten→FC(1000). State the shapes at each step and one advantage.

Recall Solution

Steps and shapes:

  1. Global average pool over the plane: average each channel's 49 values → .
  2. conv with 1000 filters (mixes 512 channels into 1000): .
  3. Softmax over the 1000 → probabilities.

Why this is nice: no flatten means no dependence on a fixed input size — the average pool collapses whatever spatial size remains, so the same weights accept different image sizes. It also drops the huge FC weight matrix ( params) to almost nothing, cutting overfitting (a form of 6.3.01-model-compression).

L4.3 — Where to place BatchNorm

Problem. You are placing BatchNorm (BN) and ReLU around a conv in a residual block. Give the standard ordering and justify why BN comes before ReLU in the classic ResNet layout.

Recall Solution

BN = BatchNorm = batch normalization — a layer that re-centres and re-scales its inputs to roughly zero-mean, unit-variance across the batch (full details in 3.4.04-batch-normalization).

Standard order: .

Why BN before ReLU: BN re-centres and re-scales the conv output to roughly zero-mean, unit-variance before the nonlinearity. If ReLU came first, it would already have thrown away all negatives (clamped them to 0), so BN would be normalising a distribution that is already half-dead — losing information and biasing the mean upward. Normalising first means ReLU sees a well-conditioned, centred input, so a healthy fraction of activations stay positive (alive), and gradients flow through them; this stabilises and speeds up training. (Later variants like "pre-activation ResNet" reorder to , but the classic ResNet block is .)


Level 5 — Mastery

L5.1 — Full parameter budget of a mini-VGG block

Problem. Design and cost a small VGG-style block for a input: Conv(64,3×3) → Conv(64,3×3) → MaxPool → Conv(128,3×3) → Conv(128,3×3). Count the total conv weights (ignore bias, ignore BN). Show each layer.

Recall Solution

Apply layer by layer (, so ):

Layer Weights
Conv 1 3 64
Conv 2 64 64
MaxPool (no weights)
Conv 3 64 128
Conv 4 128 128

Total: weights.

Insight: pooling has zero parameters (it just picks maxima), yet the cost per layer keeps rising because channels grow. This is exactly why the channel-doubling rule (L5.2 below) is a budget balancer, not a freebie.

L5.2 — Channel doubling keeps FLOPs constant

Problem. A stage has feature map with channels, conv. After a pool, each halve and channels double to . Show that the per-layer FLOPs are unchanged.

Recall Solution

FLOPs model (from parent): — every output position runs one multiply-add per output channel.

Before pool: .

After pool + double: , , : The from spatial shrink and the from channel growth cancel — FLOPs are constant. That's why "double the channels when you halve the resolution" is the standard rule: it keeps each stage's compute balanced.

L5.3 — Choosing an architecture family for a constraint

Problem. You must deploy a classifier on a phone with tight memory, but you have only ~2000 labelled training images of a rare bird species. Which two architecture decisions from the parent note do you combine, and why?

Recall Solution

Decision A — Transfer learning (3.5.01-transfer-learning): with only 2000 images, training a deep net from scratch would overfit badly. Start from a network pretrained on ImageNet (edges/textures/parts are already learned) and fine-tune the top layers. This addresses the data scarcity.

Decision B — Model compression / efficient blocks (6.3.01-model-compression): the phone constraint means you want a small backbone — favour bottleneck () blocks (L2.3, 74% fewer params) and a global-average-pool head (L4.2, kills the huge FC). This addresses the memory constraint.

Why this combo: transfer learning fixes the statistics problem (too little data), compression fixes the hardware problem (too little memory). They are orthogonal — one does not solve the other, so you need both. Tune the fine-tuning learning rate and number of unfrozen layers via 5.1.02-hyperparameter-tuning.

L5.4 — Predict failure mode of a 40-layer plain net

Problem. A colleague stacks 40 plain conv layers (no skips, no BN) with sigmoid activations and reports that training accuracy is worse than a 20-layer version. Diagnose the cause and prescribe the two fixes the parent note supports.

Recall Solution

Diagnosis — vanishing gradients, not overfitting. The key clue is that training error (not just test error) is higher. Overfitting would make test error worse while training error kept dropping. Higher training error means the deep net cannot even be optimised. With sigmoids, each layer's derivative is ; multiplying 40 of them (chain rule) shrinks the gradient toward the early layers to near zero, so they barely learn (see L3.1 and 4.2.03-vanishing-gradient).

Fix 1 — Residual (skip) connections: the Jacobian (L3.1) gives gradients a highway back to early layers.

Fix 2 — BatchNorm (BN) + ReLU (3.4.04-batch-normalization, 3.4.03-activation-functions): BN keeps activation distributions well-scaled layer to layer, and ReLU's derivative is exactly 1 for positive inputs (no shrink), so gradients survive. Together these are precisely why ResNet-50 trains fine at 50 layers while a 40-layer plain sigmoid net degrades.


Recall One-line self-test

Weights of a conv layer ::: Receptive field of stacked convs ::: The ResNet backprop Jacobian ::: (identity matrix, not a scalar 1) Rule when spatial size halves ::: double the channels (keeps FLOPs constant)