DL GEN AI · Week 3

CNN theory: why it exists, what slides, what shapes it

What this page stands on. A dense layer computes \(z = Wx + b\), then an activation \(a = g(z)\); an MLP stacks those and trains by gradient descent. An image is just a grid of numbers — say 32×32 pixels, 3 color channels.

This page takes the dense layer apart, because on image data it is the wrong machine. §1 fixes what an image is, and §2 defines the words the rest of the page uses so that no term arrives undefined. §§3–7 say why convolution is the only thing that could come next; §§8–12 show the thing sliding and name the two constraints; §13 runs the two claims in torch; §§14–15 shape it into a real classifier; §§16–17 place it in history.

flowchart LR
  IMG[image as a grid] --> FAIL[three MLP failures]
  FAIL --> FIX[two constraints]
  FIX --> SLIDE[filter slides]
  SLIDE --> KNOB[stride and pad]
  KNOB --> LAYERS[pool norm dropout]
  LAYERS --> ARCH[classifier]

Failures motivate the constraints; the constraints leave a sliding filter; knobs and layers turn the filter into a classifier.

The rule you will break first — all the numbers survive flattening; what dies is the geometry. Nothing is thrown away by turning a 28×28 image into a 784-vector. Every pixel value is still there. What is gone is the fact that this pixel sits next to that one. An MLP cannot exploit a fact it cannot see, and after flattening it cannot see this one. Everything below is a consequence.

1 · What the machine actually sees

A digital image is not a picture to a program. It is a grid of numbers, and each cell is a pixel — the smallest unit. You see a cat; the program sees a matrix. A 32×32 colour image is a 32 × 32 × 3 array of numbers, each 0–255 (the 3 is RGB); a 480×480 JPG is 480 × 480 × 3. That array is all the computer gets. The job: turn it into class probabilities, e.g. 0.80 cat, 0.15 dog, 0.05 bird. There is no perception step. That is the entire gap between you and the model.

Three kinds of image matter here, and they differ only in how many numbers each pixel carries:

TypeChannelsPer pixelRange
Binary11 bit0 or 1
Grayscale18 bits0 (black) to 255 (white)
Colour (RGB)33 × 8 bits0–255 each, one per channel

A colour image is three stacked grids — one red, one green, one blue, each called a channel — held as a single tensor. A 224×224 RGB image is therefore a \(224 \times 224 \times 3\) array, which is

\[ 224 \cdot 224 \cdot 3 = 150{,}528 \]

input dimensions. Hold that number. §4 turns it into 22 billion.

1.1 · The tasks differ in the shape of the output

Vision modelling is not one problem. It is several, and the distinction that matters for the whole week is what the network must hand back.

Keep the last one in mind. When the output is a grid the same size as the input, "the answer moves when the image moves" is not a defect — it is exactly what you asked for. This is the distinction between equivariance (per-pixel outputs that transform with the input) and invariance (a single label that ignores the transform) — the distinction that makes a convolutional layer the right tool instead of an approximate one.

2 · The words this page uses

The words below carry the rest of the page. Each is defined once, and the later sections use them without re-explaining.

2.1 · Image tensor, pixel, channel depth

An image tensor is the array a vision model reads. Torch orders it (N, C, H, W): N images in the batch, C channels, H rows and W columns. Eight RGB photos at 224×224 are (8, 3, 224, 224). A pixel is one (row, column) position. A channel is one grid of numbers, one per position, and the channel depth is how many such grids are stacked: 3 for RGB, 1 for grayscale.

2.2 · Kernel, filter, feature map

A kernel — the same thing as a filter — is a small grid of learned weights. It slides over the input; at each stop it multiplies the patch under it by its weights and adds the products into one number. Its depth always equals the input's channel depth, so a 3×3 kernel on an RGB image is 3×3×3. A feature map, also called an activation map, is the grid of those numbers written by one kernel. One kernel writes one feature map; 64 kernels write 64, so the output depth is the filter count.

2.3 · Stride and padding

Stride is how far the kernel moves per step. Stride 1 moves one pixel, so neighbouring stops share most of their patch. Stride 2 moves two, so the kernel makes about half as many stops per side. Padding is a border of zeros, P pixels deep on each side of the input. It lets a kernel centre on an edge pixel, and padding 1 with a 3×3 kernel at stride 1 leaves H and W unchanged.

2.4 · Receptive field

The receptive field of one output cell is the region of the input that can change its value. One 3×3 convolution gives 3×3. Stack a second 3×3 on top and the cell reads three cells of the first map, each of which already read 3×3 of the input, so it sees 5×5. Every extra 3×3 layer at stride 1 adds one pixel of reach on each side: n stacked 3×3 layers see \((2n+1) \times (2n+1)\).

2.5 · Parameter sharing, equivariance, invariance

Parameter sharing is the rule that one kernel uses the same weights at every position. The layer stores the kernel once, so its parameter count does not grow with H and W. The consequence is translation equivariance: shift the input one pixel and the feature map shifts one pixel with the same values. Translation invariance is stronger: the output does not change at all. A classifier wants invariance for its final label; pooling (§14) buys part of it by discarding position inside each window.

2.6 · Pooling

Pooling replaces each small window of a feature map with one number. A 2×2 max pool with stride 2 keeps the largest value in each 2×2 block, so both sides halve and the channel depth is untouched. It has no weights, so training cannot change it. Discarding the exact position inside the block is the point: a feature that moves one pixel usually survives.

3 · Why the dense layer is wrong for images

Take a table: rows are samples, columns are features like "age" and "income". The features have no spatial relationship to each other — swapping their columns changes nothing. That is precisely the structure a fully connected layer assumes: an unordered bag of features, every one connected to every one. For a table, that assumption is correct and costs nothing.

An image is not a table. A 28×28 picture is a grid, and the grid's geometry is real information: pixel (10, 10) sits beside pixel (10, 11), and every visual feature lives in such neighbourhoods. Flatten the grid to 784 numbers and all notion of "neighbour" is gone — the network cannot reach the geometry. Three separate failures follow, and none of them is fixed by tuning, more epochs, or a wider hidden layer.

4 · Failure 1 — the parameter count is not a tuning problem

A fully connected layer from 150,528 inputs to one hidden unit needs 150,528 weights — per unit. Hidden layers are normally wider than their input, so a shallow network lands around

\[ 150{,}528^2 = 22{,}658{,}678{,}784 \]

weights. Twenty-three billion. Training them needs matching training data, matching memory, and matching computation. No labelled image dataset contains 23 billion examples.

A smaller version makes the same point: a 100×100 RGB image is \(100 \cdot 100 \cdot 3 = 30{,}000\) inputs, and a first hidden layer of only 1,000 neurons already costs 30 million weights. A modern sensor outputs far more than 100×100, so multiply that by another factor of ten and it is unwieldy immediately.

So this failure is not "expensive". It is impossible — and it is the weakest of the three, because it is a resource problem that better hardware would eventually paper over. Hold that thought; the next two are not resource problems at all.

5 · Failure 2 — the network has no idea what "nearby" means

Nearby image pixels are statistically related. In an image of a shoe, the pixel at \((i,j)\) has a lot to say about \((i,j+1)\) and very little to say about the pixel on the opposite corner.

A fully connected layer has no notion of "nearby". It treats the relationship between every input pair as equal, because from its point of view there is no arrangement of the inputs to have a relationship with — just an index.

The experiment that settles it. Randomly permute the pixels of every training image and every test image, using the same fixed permutation everywhere. Retrain. The resulting network trains with no practical difference in performance — effectively true for any fully connected layer on any image dataset.

Draw the conclusion properly, because it is stronger than it first looks. Not "permuting hurts a little" — it does not hurt at all. The label survived the permutation, because the label was a property of the multiset of pixels, and the fully connected layer reads only a multiset. A fully connected layer is blind to image geometry, by construction, in a way that no amount of training data can fix. It has no input that carries position.

6 · Failure 3 — shift the image and every input changes

An image of a tree is still an image of a tree if you shift it left by a few pixels. But that shift changes every input to the network. So a fully connected model must learn the pattern of pixels that signify a tree separately at every position. That is worse than inefficient — it is a direct loss of accuracy, and of data efficiency, on the way.

Watch the failure happen. Train on images with the cat near the centre, and the network learns position-specific weights that look for a cat in the middle. Move the cat, and the network starts failing — not gracefully degrading, failing, because the thing it learned was tied to a location. The goal of any vision network is the opposite: identify the object regardless of where it sits in the frame.

7 · The fix: two constraints, and convolution is what's left over

Take the fully connected layer and forbid two things. Nothing else changes.

Constraint 1 — locality. An output neuron connects only to a small neighbourhood of inputs, not the whole image.
Constraint 2 — weight sharing. That same small set of weights is translated across the entire image, and used to compute an output at every location.

Locality alone buys you the parameter reduction and hands the layer a real notion of nearby pixels. Weight sharing alone buys you the parameter reduction and gives every position the same feature detector. Together they buy all three things this page needs: far fewer parameters, explicit use of spatial relationships, and no re-learning a pattern at every position.

Here is the part worth sitting with. A convolutional layer is exactly what is left after you impose these two constraints on a fully connected layer. You did not choose it from a menu. You took the machine you already understand, removed everything you did not need, and the residue has a name. §10 walks the algebra that makes this precise.

Payoff in one comparison. A fully connected output unit on a 224×224 RGB image needs 150,528 weights. An entire convolutional layer with an 11×11 kernel producing 96 output channels needs

\[ 11 \cdot 11 \cdot 3 \cdot 96 = 34{,}848 \]

weights — for all 96 feature maps at once. The convolutional layer completes 96 full passes over the image using fewer weights than a single fully connected neuron would need.

Why equivariance comes out of this for free. Because the same weights slide, moving the input by one pixel moves the output by one pixel and leaves the numbers unchanged. Shift the image, get the same features back, shifted. That is equivariance, and it is not an extra feature of convolution — it is what "weight sharing" means when you follow the consequence. Pooling (§14) is what partially converts equivariance into the invariance that classification needs.

8 · The flashlight: what one filter does

Picture a flashlight beam covering a 5×5 patch in the top-left corner, then sliding across the whole image one step at a time. The flashlight is the filter (also called kernel or neuron); the patch it lights is the receptive field. The filter itself is an array of numbers — the weights — and its depth must match the input's, so here it is 5 × 5 × 3. A biological aside is worth having: Hubel and Wiesel (1962) found visual-cortex neurons that fire only for edges at one orientation, organised in columns. Specialised detectors, each with its own job — that is the whole idea behind a filter.

At each position: multiply filter values by the pixel values underneath, element by element (75 multiplications for a 5×5×3 filter), add them up, write down one number. Slide to the next position, repeat. A 5×5 filter fits in 784 positions on a 32×32 image, so the output is a 28 × 28 × 1 array — the activation map (feature map). Use two filters instead of one and you get 28 × 28 × 2. More filters, deeper output, more information kept.

8.1 · Compute one output by hand

Patch the filter currently covers, and a vertical-edge filter:

input patch filter (left +1, right −1)
1 2 3 1 0 -1
4 5 6 1 0 -1
7 8 9 1 0 -1

Elementwise multiply, then sum — keep the left column, drop the middle, subtract the right:

\[ (1-3) + (4-6) + (7-9) = -2 + -2 + -2 = -6 \]

Output: −6. Left brighter than right gives positive, right brighter gives negative, uniform gives zero. This filter was written by hand to show the arithmetic. In a trained network nobody writes it: random weights plus gradient descent on the loss arrive at detectors of the same kind. A curve detector tells the same story: 6600 where the curve is, 0 where it is not.

9 · Going deeper: edges become objects

First-layer filters detect edges, colours, curves. Feed their activation maps into a second conv layer and its filters combine those into semicircles and corners; deeper still, paws and beaks; at the end, filters that fire on handwriting or pink objects (Zeiler–Fergus visualised exactly this ladder). Each layer's input describes where the previous layer's features were, so depth builds abstraction. Receptive fields grow with depth: a deeper filter sees a wider region of the original image through the layers below it.

Then the fully connected layer caps the network: it takes the last activation maps and outputs one number per class (10 for digits). It learns which high-level features vote for which class — paw-maps vote dog, wing-maps vote bird — as weights on the previous layer. Training is four steps on repeat: forward pass, loss, backward pass (which weights contributed, via dL/dW), weight update against the gradient, scaled by the learning rate. Too large a rate overshoots; too small crawls.

10 · The two constraints, on one page

This is the derivation, with the jargon translated. A dense layer on a 28×28 image flattened to 784 inputs, with 784 hidden units, needs \(784^2 = 614{,}656\) weights — and on the grid its weight needs an index for input row, input column, and hidden unit, i.e. a 4th-order tensor. Two facts about natural images then delete almost all of it:

Constraint 1 — weight sharing (translation equivariance). A vertical edge top-left and the same edge bottom-right are the same feature, so the detector should not care where it sits: shifting the input should shift the output. Therefore a weight may depend only on the relative offset between input and output, not on absolute position. In symbols, each absolute-position weight collapses onto an offset weight (\(w\) indexed by position becomes \(v\) indexed by offset). The parameter count now equals the size of \(v\) — independent of image size. Equivariance (shift in → shift out) falls out for free; nobody bolted it on. Invariance is the stronger property, and pooling is what buys it.

Constraint 2 — locality. A pixel correlates strongly with its neighbours and barely at all with the far side of the image, so set \(v\) to zero outside a small window (say 3×3). The sum shrinks to that window. That is the convolutional layer, and there is nothing further to derive.

LayerWeightsDepends on image size?
Dense, 784 inputs → 784 hidden614,656yes, quadratically
Conv 3×3, 1 input channel → 8 output channels72no
Conv 3×3, 3 input channels → 64 output channels (+ 64 biases)1,728 (+ 64)no

Channels bring back a 4th-order tensor, but a small one: one filter per output channel, each seeing all input channels, so \(C_i \times C_o \times K \times K\) weights plus \(C_o\) biases. For 224×224 RGB → 64 maps that is 1,728 weights doing the work the dense layer needed billions for.

The count is the visible symptom; the restricted family is the cause. These two constraints forbid every mapping that treats one position differently from another, so the layer can only express functions built from the same detector everywhere. That is a much smaller family of functions than the dense layer can express, and a smaller family that still fits the training data is the standard reason to expect lower test error. A dense network can represent a shifted edge; it has to learn that edge again at every position, from data at every position.

Convolution vs cross-correlation, in one sentence. True convolution flips the kernel before sliding; PyTorch's nn.Conv2d does not flip (it cross-correlates). Harmless: the kernel is learned, so training learns whichever orientation it needs. Say "convolution" to people, "cross-correlation" when a hand-computed value disagrees with a textbook.

11 · A filter firing, and how far it sees

6×6 image: rows 0–2 hold 30, rows 3–5 hold 0 — one horizontal step. Filter: 3×3, top row +1, bottom row −1. Valid convolution gives 4×4. Straddling the step:

\[ (30+30+30) - (0+0+0) = 90 \]

The output spikes to 90 at the transition and sits near zero elsewhere. A filter reports change, never brightness. Real filters are not designed like this one — Gaussian init, then forward–loss–backprop until convergence, and the task decides the detectors.

The demo filter is hand-picked; real ones never are. Every CNN filter starts as random noise and becomes whatever the loss needs.

One filter on one input gives one 2D feature map. A layer holds many filters, so its output is a 3D volume — one slice per filter. A neuron's receptive field is the input region affecting it. Layer 1: exactly the filter size. Stack two 3×3 layers and each layer-2 neuron reads 3×3 of layer 1, each of which read 3×3 of the input:

\[ 3 + 3 - 1 = 5 \]

Deeper neurons see wider regions, so the network builds edges → corners → parts → objects without being told to.

12 · Kernel size, 1×1, stride, padding

3×3 is the default. Two stacked 3×3 layers cover the same 5×5 field as one 5×5 filter with fewer multiplications (18 vs 25) and a nonlinearity in between. Large kernels (5×5, 7×7) appear in early layers on large inputs to buy context fast.

A 1×1 convolution looks at one pixel across all channels. 32 filters of size 1×1×192 on a 56×56×192 volume give 56×56×32: same spatial size, fewer channels. It aggregates channel information per pixel, followed by a nonlinearity — a fully connected layer over channels.

Stride is the step size: S=1 moves one pixel, S=2 skips one. Strided convolution downsamples while learning, and usually replaces pooling in modern nets. Padding adds zero borders: valid means none (output shrinks), same means just enough to preserve the input size (e.g. pad 1 with a 3×3 filter at stride 1). Padding also gives edge pixels the same coverage central pixels get. One formula runs every size question (\(W\) in, \(K\) filter, \(P\) pad, \(S\) stride):

\[ W_{out} = \left\lfloor\frac{W - K + 2P}{S}\right\rfloor + 1 \]

Check: 32×32, 5×5, P=0, S=1 → 28 (our §8 flashlight). 32×32, 3×3, P=1, S=2, 64 filters → 16×16×64. After each convolution comes nonlinearity (ReLU, \(\max(0,x)\) — negatives to zero, trains faster than tanh/sigmoid).

13 · Two claims, checked in torch

Two claims carry this page: a dense layer cannot hold an image, and the shape of a feature map follows from stride and padding. Both take a few lines to run. Predict each answer before you read the output under the code.

13.1 · The parameter gap

Predict first. A dense layer takes a 32×32 RGB image to 10 outputs. A 3×3 convolution takes the same image to 16 channels. Which holds more weights, and by what factor?

import torch, torch.nn as nn

dense = nn.Linear(32 * 32 * 3, 10)
conv  = nn.Conv2d(3, 16, 3)

print(32 * 32 * 3)                                  # 3072
print(sum(p.numel() for p in dense.parameters()))   # 30730
print(sum(p.numel() for p in conv.parameters()))    # 448
print(conv(torch.zeros(1, 3, 64, 64)).shape)        # torch.Size([1, 16, 62, 62])

30,730 = 3,072 × 10 weights + 10 biases. 448 = 3×3×3×16 weights + 16 biases. Both counts include the bias, because parameters() yields it.

What happens. The dense layer holds 30,730 parameters and the convolution holds 448. The dense layer has about 69 times as many. The gap is not the interesting part. The dense count is tied to one input size: at 64×64 the flattened image has \(64 \cdot 64 \cdot 3 = 12{,}288\) inputs, so the same layer becomes \(12{,}288 \times 10 + 10 = 122{,}890\) parameters. The convolution's 448 is the same at 32×32, at 64×64, and at 512×512, because the kernel is stored once and used at every position. That is parameter sharing, and it is why the failure in §4 has no fix inside the dense layer.

13.2 · The output shape with padding and stride

Predict first. A (1, 3, 32, 32) input goes through four 3×3 convolutions: no padding at stride 1; padding 1 at stride 1; padding 1 at stride 2; no padding at stride 2. Predict each output side before you run it.

x = torch.zeros(1, 3, 32, 32)

print(nn.Conv2d(3, 16, 3)(x).shape)                        # torch.Size([1, 16, 30, 30])
print(nn.Conv2d(3, 16, 3, padding=1)(x).shape)             # torch.Size([1, 16, 32, 32])
print(nn.Conv2d(3, 16, 3, stride=2, padding=1)(x).shape)   # torch.Size([1, 16, 16, 16])
print(nn.Conv2d(3, 16, 3, stride=2)(x).shape)              # torch.Size([1, 16, 15, 15])

30 = 32 − 3 + 1; 32 = 32 + 2 − 3 + 1; 16 = ⌊31 ÷ 2⌋ + 1; 15 = ⌊29 ÷ 2⌋ + 1.

What happens. Padding 1 keeps 32×32 because the ring of zeros gives every edge pixel a full window. Stride 2 gives 16×16 because it visits every second position. The padding still does work there: without it the same layer returns 15×15, since the first stop must fit the whole kernel inside the border. The channel count is 16 in all four cases, set by the number of filters and never by the input size. §12's formula is these four lines in symbols.

14 · Pooling, normalisation, dropout

A 2×2 max-pool with stride 2 halves each spatial dimension, has no parameters, and keeps the strongest activation per patch. Halving twice per block is what makes later convolutions cheap, widens the receptive field, and tolerates small shifts — the maximum survives wherever it sits inside its patch. Average pooling smooths instead of selecting; both are applied per channel. Global pooling averages each whole feature map to one number — e.g. 512 maps of 7×7 become 512 activations feeding the head.

Deep layers see shifting input distributions as early weights move, which slows training and over-sensitises init. BatchNorm standardises each channel over the batch and spatial positions, then restores representational power with two learned parameters per channel:

\[ \hat{x} = \frac{x - \mu_B}{\sqrt{\sigma^2_B + \epsilon}}, \qquad y = \gamma \hat{x} + \beta \]

Training uses batch statistics; inference uses running averages (momentum 0.1) because a single image has no meaningful batch. That is the entire reason for train() vs eval() mode. Side effects: higher learning rates, less init sensitivity, mild regularisation.

Dropout zeroes activations, never weights, with probability \(p\) — only during training. Survivors are scaled by \(\frac{1}{1-p}\) (so \(p=0.5\) doubles them), keeping the expected value identical at test time, when every neuron is active and unscaled. Forcing random neurons out stops co-adaptation: no neuron can rely on its neighbours being present. It matters most in the fully connected head, where most of the weights live.

15 · The full classifier, and feeding it

Stack conv blocks (convolution → ReLU → pool), flatten, classify. Spatial size shrinks while channel count grows — fewer positions, richer features per position. A Fashion-MNIST classifier makes the shapes concrete:

StageOutput
Input1×28×28
Conv 32 + pool32×14×14
Conv 64 + pool64×7×7
Conv 128 + pool128×3×3
Flatten → FC 128 (+dropout) → FC 101152 → 128 → 10

\(128 \cdot 3 \cdot 3 = 1152\). Count biases too — everyone forgets them.

CNNs memorise small datasets, and labelled images are expensive. Augmentation synthesises training data with class-preserving transforms — rotation, flips, scaling, cropping, colour jitter. The rule is one sentence: the cat must still be a cat. Each transform teaches the model one invariance for free. The setup: 60k train / 10k test, pixels to [0,1], batch 64, ~5 epochs.

16 · History: why the design looks like this

The instinct to say "CNNs are the deep learning innovation" is wrong by about twenty years. The architecture is old. What is new is that anyone could afford to train one.

YearWhat happenedWhy it matters for this week
1988–89 CNNs applied to handwriting recognition, phoneme recognition, signature verification (LeCun et al. 1989a, Waibel et al. 1989, Bromley et al. 1993). Max pooling dates to Zhou & Chellappa (1988), average pooling to LeCun et al. (1989a). The building blocks all existed before the field had a name for itself.
1998 LeNet (LeCun et al.) classifies 28×28 grayscale handwritten digits. Convolution layers, then fully connected layers; sigmoid activations rather than ReLUs; average pooling rather than max pooling. It ran on cheques. "Immediately recognisable as a precursor of modern networks" — same skeleton, three details changed. Also the origin of the 28×28 input that recurs below.
1999–2011 The long winter. CNNs get sidelined; the field chases MLPs, SVMs and hand-engineered features, because CNNs needed data and GPUs that did not exist yet. The architecture was not rejected on the merits. It was waiting on its enablers.
2009 ImageNet collated (Deng et al.) with a classification challenge attached: 1,281,167 training images, 1,000 categories. Data at a scale where "more data" and "more parameters" could trade off.
2011 Before deep networks, the state of the art made ~25% top-5 error on ImageNet. The number AlexNet is measured against.
2012 AlexNet (Krizhevsky et al.). Eight hidden layers, five convolutional then fully connected, ReLU. 11×11 stride 4 → 96 channels; max pool; 5×5 → 256; three 3×3 → 13×13×256; max pool → 6×6×256; FC 4096, 4096, 1000. ~60M parameters, most of them in the fully connected layers. SGD momentum 0.9, batch 128, dropout, L2, 2048× data augmentation. 16.4% top-5, 38.1% top-1. "This result revealed the potential of deep learning and kick-started the modern era of AI research." It became the starting point for modern deep convolutional networks.
2014 VGG — fundamentally the same design, far deeper: 19 hidden layers, 144M parameters, 6.8% top-5 / 23.7% top-1. Then network-in-network's 1×1 convolutions and GoogLeNet's inception blocks. For years, error fell as depth rose. Depth was the lever, and AlexNet had already shown the block was not the bottleneck.
2015→ Deeper networks become hard to train without modifications — residual connections and normalization. Current ImageNet leaders (ViT, SWIN) are transformers. The shape of everything after it. And note what survived the handoff: CNNs are still the backbone under everything generative — the diffusion models behind today's image generators are U-Nets, convolutional networks with a skip path.

16.1 · The two things the history actually teaches

The idea was right long before the enablers were. LeNet's architecture was essentially final in 1998 and was not competitive again until 2012. Fourteen years of the design sitting idle is the strongest available evidence that a good architecture and a trainable architecture are different properties — one is mathematics, the other is data and hardware.

The 2012 leap came from a stack of things, not from a new kind of layer. AlexNet's contribution was depth, ReLU, dropout, heavy augmentation, and GPUs used in parallel — all five of which existed separately beforehand. Nobody reading the 2012 paper found a new operator in it. When a result looks like a single idea, look at the training regime around it before you go hunting for the idea.

17 · The 9 papers in one paragraph

AlexNet (2012) is the coming-out party: 5 conv layers + dropout + augmentation, 16.4% top-5 error on ImageNet, five days on two GTX 580s. ZF Net (2013) shrinks the first filter to 7×7 to keep pixel information and adds the deconv visualisation — layers 1–2 show edges/circles, 3–5 dogs' faces and flowers. VGG (2014) says keep it deep and simple: only 3×3 (two stacked ≈ one 5×5, with an extra ReLU) and double filters after each pool. GoogLeNet (2015) breaks the sequential stack with the Inception module — 1×1 bottlenecks before 3×3/5×5 plus pooling in parallel, no fully connected head, 12× fewer parameters than AlexNet. ResNet (2015) adds the skip: H(x) = F(x) + x, so each block learns the delta — 152 layers, 3.6% error. Then detection (R-CNN → Fast → Faster: share the conv computation, then learn the region proposals too), GANs (generator vs discriminator), captioning (CNN + RNN), spatial transformers.

Drill · 24 questions

Click an option to check your answer. Each question maps to one section above. Options are shuffled on every load and on every reset, so position tells you nothing.

Q1 · The permutation test

Take a fully connected image classifier. Shuffle the pixels of every training image and every test image with the same fixed permutation, then train and evaluate exactly as normal. What happens to the accuracy?
  1. Accuracy drops sharply — the pixel arrangement is where the label lives
  2. Accuracy is essentially unchanged — the layer cannot tell which pixel was where
  3. Accuracy drops only for colour images — the three channels break under permutation
  4. Accuracy is unchanged — but every learned weight is now meaningless

Q2 · The parameter count

A 224×224 RGB image gives 150,528 inputs. A fully connected hidden layer of the same width as its input needs how many weights?
  1. 150,528 × 3 = 451,584
  2. 150,528 × 224 = 33,718,272
  3. 150,528² = 22,658,678,784
  4. 2 × 150,528 = 301,056

Q3 · Moving the object

You train on images where the object sits near the centre. At test time the same object appears in a different part of the frame. What does a fully connected network do?
  1. Generalises — the learned features are position-independent by construction
  2. Generalises — averaging over the hidden layer washes the position out
  3. Fails — it learned a separate set of weights for each position
  4. Fails — the input dimensions no longer match the trained weight matrix

Q4 · The two constraints

A convolutional layer is what you get by starting from a fully connected layer and imposing two constraints on it. Which two?
  1. Locality, and weight sharing across positions
  2. Locality, and dimensionality reduction
  3. Weight sharing, and a residual connection around each unit
  4. Dimensionality reduction, and a residual connection around each unit

Q5 · LeNet's three differences

LeNet (1998) is an immediately recognisable precursor of modern CNNs. Which of these was not true of it?
  1. It stacked convolutional layers, then fully connected layers
  2. It used ReLU activations in place of sigmoids
  3. It used average pooling where modern networks use max pooling
  4. It classified 28×28 grayscale images of handwritten digits

Q6 · The 2012 number

Before deep networks, the best method made about 25% top-5 error on ImageNet. AlexNet cut that to what?
  1. 6.8%
  2. 16.4%
  3. 23.7%
  4. 38.1%

Q7 · AlexNet to VGG

Between AlexNet and VGG the training regime barely changed. The most important difference was structural. What was it?
  1. Many more channels in the first convolutional layer
  2. Replacing max pooling with average pooling
  3. Deeper stacks of the same convolutional-plus-pooling block
  4. Replacing ReLU activations with sigmoid activations

Q8 · What depth licenses

ImageNet error kept falling as architectures got deeper through the 2010s, and then deeper networks became hard to train. What does that combination license you to conclude about depth in a CNN?
  1. Deeper helps until training breaks, and the break needs residual connections
  2. Deeper always helps, so depth is the only thing worth adding to a CNN
  3. Deeper helps less than adding training images once past a few layers
  4. Depth matters less than the choice of pooling layer at every size of network

Q9 · The flashlight

A 5×5×3 filter slides over a 32×32×3 image at stride 1 with no padding. How many multiplications per position, and what is the output shape with one filter?
  1. 25 multiplications, 32×32×3 out
  2. 75 multiplications, 28×28×1 out
  3. 75 multiplications, 32×32×1 out
  4. 784 multiplications, 28×28×3 out

Q10 · Which constraint does which job

Two constraints convert a dense layer on an image into a convolution. Which one makes the kernel independent of image size, and which one makes the sum run over a 3×3 window and nothing more?
  1. Locality does the first, weight sharing does the second
  2. Weight sharing does the first, locality does the second
  3. Weight sharing does both, locality adds the activation function
  4. Locality does both, weight sharing adds the bias term

Q11 · Counting the layers

A 3×3 convolutional layer takes a 3-channel input and produces 64 output channels. How many weights does it have, not counting biases?
  1. 9
  2. 64
  3. 1,152
  4. 1,728

Q12 · The edge detector

A 3×3 filter of all ones in the left column, all zeros in the middle, and all −1 in the right column is applied to the patch [[1,2,3],[4,5,6],[7,8,9]]. Ignore bias and activation. What is the single output value?
  1. −18
  2. 0
  3. −6
  4. 6

Q13 · Flip or not

A true convolution flips the kernel before sliding it. PyTorch's nn.Conv2d does not. Why is using "convolution" for the un-flipped version safe?
  1. Flipping the kernel changes only the bias, never the output value
  2. A flipped kernel spans the same pixels, so the two differ by a relabelling of what the kernel means
  3. The two definitions agree whenever the kernel is symmetric about its centre
  4. Flipping is undone by the activation function, so both give the same output

Q14 · Why the convolutional net generalises better

A dense network and a convolutional one both fit a set of randomly translated digit templates perfectly, and the convolutional one has far lower test error. The reason is not the parameter count. What is it?
  1. The convolutional net searches a smaller family of mappings, all of them plausible for this data
  2. The convolutional net has more parameters, so it fits the true pattern more precisely
  3. The dense net cannot represent the translation, so it fails on every shifted input
  4. The convolutional net trains faster, so it reaches a better optimum within the budget

Q15 · The 90

6×6 image (30s rows 0–2, 0s rows 3–5). 3×3 filter, top row +1, bottom row −1. Output straddling the step?
  1. 30
  2. 90
  3. 0
  4. 270

Q16 · Stacked field

7×7 image, two stacked 3×3 convolutions. Input region per layer-2 neuron?
  1. 3×3
  2. 6×6
  3. 9×9
  4. 5×5

Q17 · Output size

32×32 input, 3×3 kernel, padding 1, stride 2, 64 filters. Output?
  1. 30×30×64
  2. 32×32×64
  3. 16×16×64
  4. 16×16×3

Q18 · 1×1 convolution

32 filters of 1×1×192 on a 56×56×192 volume. Output, and what changed?
  1. 56×56×192 — nothing changes, it only adds nonlinearity
  2. 56×56×32 — channels shrink, spatial size kept
  3. 28×28×32 — spatial and channel dims both shrink
  4. 54×54×32 — valid convolution shrinks the spatial dims

Q19 · Pooling

2×2 max-pool, stride 2, on a 14×14×32 volume. Output?
  1. 7×7×32
  2. 7×7×8
  3. 14×14×32
  4. 7×7×1

Q20 · Dropout scaling

Dropout with p=0.5 during training. What happens to a surviving activation, and what happens at test time?
  1. Halved at train, doubled at test
  2. Unchanged at train, halved at test
  3. Doubled at train, unchanged at test
  4. Doubled at train, halved at test

Q21 · The 1152

Final conv block outputs 128 maps of 3×3. Flattened length into the FC layer?
  1. 384
  2. 1152
  3. 128
  4. 2304

Q22 · Augmentation rule

Which augmentation is legitimate for a cat classifier?
  1. Horizontal flip — the label is unchanged
  2. Cropping to the background with the cat removed — harder negatives
  3. Occluding the cat entirely — teaches robustness
  4. Recolouring the cat neon green — wider colour invariance

Q23 · Tensor shape and depth

Eight RGB images at 224×224 enter a conv layer with 64 filters at stride 1. What is the input tensor, and what is the channel depth after the layer?
  1. (8, 224, 224, 3) in; depth 3 out
  2. (8, 3, 224, 224) in; depth 3 out
  3. (8, 3, 224, 224) in; depth 64 out
  4. (3, 8, 224, 224) in; depth 64 out

Q24 · The 448

A 3×3 convolution reads 3 channels and writes 16, with bias. A dense layer reads a flattened 32×32×3 image and writes 10, with bias. How many parameters does each hold?
  1. 432 and 30,720 — biases are counted separately
  2. 448 and 30,730
  3. 1,728 and 3,072
  4. 448 and 3,072

Hands-on

  1. Predict the value for the 3×3 patch in §8.1. Then write the filter as a torch tensor and run it on the patch with torch.nn.functional.conv2d. Check −6, and check that a patch of all 5s gives 0.
  2. Predict the output side for 32×32 with 5×5, P=0, S=1; with 3×3, P=1, S=2; and with 7×7, P=3, S=1. Run all three; check 28, 16, and 32.
  3. Predict the parameter count of a 3×3 conv reading 3 channels and writing 8, and of the dense layer from 32×32×3 to 10. Run both; check 224 and 30,730. Then run the conv on a 64×64 input and say why its count did not move.
  4. Predict how many padded 3×3 layers give one output cell an 11×11 receptive field. Stack that many all-ones kernels on a 15×15 input that is zero except for a 1 at the centre, and count the non-zero cells: 121 = 11×11.
  5. Predict what the 448 becomes if the input is grayscale instead of RGB. The kernel depth falls to 1, so the count is 3×3×1×16 + 16 = 160. Run it and check.

One-line understanding. Images are grids, a fully connected layer reads them as unordered bags, and convolution is what remains once you force every neuron to see only a small neighbourhood and force every position to share one set of weights.