Unit 5 · Deep Learning Foundation · Course Outcomes CO2, CO3

The same picture, read two different ways.

Three small shapes. A convolutional network sees each one all at once and separates them without difficulty. A recurrent network reads them one row at a time and cannot tell two of them apart at all — because the only difference is in the first row, and by the sixth row it has forgotten. Everything in this unit follows from that gap and from the architectures invented to close it.

Section 5.1

A ring, a bar and a hook

What features would you write by hand?

Six by six, black and white. The ring is hollow, the bar is solid, and the hook is a bar with its top row removed.

You could write a hole-detector and a top-row check in an afternoon, and it would work perfectly here. Section 5.1 is about why that stops being possible at scale, and what replaces it.

Colour contract class 1 — ring class 2 — bar class 3 — hook trainable — weights being learned now frozen — weights held fixed
The colour contract, and one new pair

Three classes now, so the three accents are the three shapes: rose for ring, teal for bar, violet for hook. Amber keeps the meaning it has had since Unit 1 — what the model is learning — but in section 5.3 it acquires a partner. Amber means trainable and grey means frozen, and the whole of transfer learning is a decision about where to draw the line between them.

What you need before this chapter

This unit leans on Unit 4 more heavily than any other leans on its predecessor. From 4.2: the convolution output-size formula, parameter counting for convolutional and dense layers, pooling, and the fact that the flatten-to-dense layer usually holds most of a CNN's weights. From 4.3: that a gradient travelling backwards is multiplied by one factor per layer, and that a product of factors below 1 vanishes geometrically — section 5.4 is that argument applied to time rather than depth. From 4.4: backpropagation and the four equations. From 4.6 and 4.7: batch normalisation, and why initialisation scale decides whether a deep network trains. From 2B: ROC and AUC, which section 5.5 extends to more than two classes.

Sections 5.2 and 5.4 will not re-derive any of that. If the convolution parameter formula or the vanishing-gradient product is not fluent, go back to 4.2 and 4.3 first — an hour there will save three here.

The spine: three shapes, and two ways of looking at them

One dataset runs through the whole unit. Three 6×6 binary images, and the trick is that we will feed them to two completely different architectures and compare what each finds easy.

The three shapes RING BAR HOOK 0 0 1 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 1 1 0 0 1 1 0 1 1 1 1 0 0 1 1 1 1 0 1 1 0 0 1 1 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 0 1 1 0 0 0 1 1 1 1 0 0 1 1 1 1 0 row sums, reading top to bottom: RING 2 4 4 4 4 2 BAR 4 4 4 4 4 4 HOOK 0 4 4 4 4 4 ↑ BAR and HOOK differ at the FIRST step and nowhere else.

That last line is the design of the whole unit. The bar and the hook are identical except for their top row. A convolutional network is handed the entire grid, so this is a trivial distinction — the difference is right there in the input, no more distant than any other pixel. A recurrent network reading top to bottom sees the difference at step one and must then carry it, unused, through five more steps before it is asked for an answer.

That is a long-range dependency, and it is the thing recurrent architectures are good and bad at. Six steps is a very short range by real standards — a sentence is thirty tokens, a document is thousands — which makes the failure in section 5.4 all the more striking.

The spine, and where each section uses it
SectionWhat it does with the three shapes
5.1Writes a hand-crafted feature by hand, then asks what happens when the shapes become photographs.
5.2Runs two edge filters over each and reads off the signatures; builds the architecture around them.
5.3Treats a large pretrained network as a fixed feature extractor for these three classes, and counts what is trainable.
5.4Feeds the row sums as a sequence and watches a plain RNN lose the first step. Then fixes it with a gate.
5.5Scores twelve predictions across the three classes, where every AUC is 1.0000 and accuracy is 0.8333.
One thing to hold on to from the start

Depth is not the point. A network is not better because it has more layers; it is better when the layers let it represent something it could not represent before, and Unit 4 showed exactly what that means with one hidden layer and XOR.

What changes in this unit is engineering. Convolution encodes an assumption about images, recurrence encodes an assumption about sequences, transfer learning reuses features somebody else paid to learn, and gates encode an assumption about memory. Each is a constraint that happens to be true of a particular kind of data, and each is worth exactly as much as that truth — which is 4.2's closing argument, restated as the theme of the unit.


5.1

Deep Learning versus Machine Learning

Not "more layers". The difference is who designs the features — and the honest version of the comparison includes the cases where the older approach still wins.

The question

Every model in Units 2 and 3 was handed features somebody chose. The eight students came with practice hours and assignments already measured; the twelve clustered students came with two columns that a human decided were the relevant ones. Where do those columns come from, and what happens when nobody knows what they should be?

The intuition

Two pipelines, differing at one step.

Classical machine learningraw data → HUMAN designs features → model learns weights → prediction (weeks of domain expertise) (minutes) Deep learningraw data → MODEL learns features AND weights, together → prediction (hours of compute)

That is the whole distinction, and it is worth resisting the temptation to state it as "deep learning uses more layers". A gradient-boosted tree ensemble has thousands of components and is not deep learning; a two-layer network trained on raw pixels is. The dividing line is whether the representation is designed or learned.

The term for the learned version is representation learning, and Unit 4 already showed it in miniature: the hidden layer that mapped XOR's B and C onto the same point was not classifying anything, it was inventing a coordinate system in which a line would work. Deep learning is that, stacked, on data where nobody could have invented the coordinates by hand.

The formal treatment

Stacking representation-learning layers produces a feature hierarchy, and on images the hierarchy is legible enough to have been catalogued.

What the layers of a trained vision network respond to
DepthResponds toReceptive fieldTransfers to
Layer 1Oriented edges, colour blobs3–7 pixelsEssentially any image task
Layers 2–3Corners, textures, simple curves10–40 pixelsMost natural-image tasks
MiddleObject parts — wheels, eyes, letters50–150 pixelsRelated domains only
LastWhole objects, class-specific configurationsMost of the imageAlmost nothing — replace it

The right-hand column is section 5.3 in advance: the reason transfer learning works at all is that the early layers of the hierarchy are generic, so somebody else's edge detectors are as good as yours and cost nothing.

The worked example

Worked 5.1 — hand-craft features for the three shapes, then break them
the classical approach, honestly done
Design features that separate ring, bar and hook. Then test whether they survive a one-pixel shift.
Step 1 — look at the shapes and invent two numbers

The ring is the only one with a hole, so count the ink in the central 2×2 block. The bar and hook differ in their top row, so count the ink there.

Two hand-designed features
Shapetotal inkcentre 2×2top rowvariance of row sums
ring20020.889
bar24440.000
hook20402.222
the rule: if centre == 0 → RING elif top row == 4 → BAR else → HOOK three classes, two integers, 100% accuracy, and no training at all.

This is not a straw man. It is genuinely the right answer for this problem — it is exact, it is instant, it needs no data, and you can explain it to anyone in one sentence. A CNN on the same task needs 55 parameters and a training run to reach the same place. When a hand-crafted feature works, use it.

Step 2 — now shift every image one pixel to the right
The same features after a one-pixel translation
Shapetotal inkcentre 2×2top rowrule says
ring1822not ring → HOOK  
bar2444BAR  ✓
hook2040HOOK  ✓
One pixel of translation and the ring is misclassified.
The centre feature read 0 and now reads 2, because "the central 2×2 block" is defined by absolute position and the hole moved.
A convolutional layer would not have noticed: it is equivariant to translation by construction, per 4.2.

The failure is instructive because it is not a failure of cleverness. A better hand-crafted feature exists — count connected background regions, and the ring has two while the others have one, which is translation-invariant and would survive this test. The point is that you had to think of it, and you have to think of it again for rotation, for scale, for noise, for lighting, and for every variation the world produces.

When each approach wins

An honest comparison
Classical MLDeep learning
Data neededHundreds to thousandsThousands to millions, unless transferring
ComputeSeconds to minutes, CPUHours to weeks, GPU
Feature effortHigh — the main costLow, replaced by architecture choice
InterpretabilityOften direct: coefficients, split rulesPoor, and approximate at best — 4.8
Best onTabular data, small samples, cases needing an audit trailImages, audio, text, anything with spatial or sequential structure
Fails whenRaw data has no meaningful hand-designable featuresData is scarce, or structure is absent

The historical marker usually quoted is ImageNet 2012, where a convolutional network reached 15.3% top-5 error against 26.2% for the best hand-engineered entry — a drop of 10.9 points in one year, larger than the previous several combined. What made it possible was not a new idea; convolutional networks dated from the 1980s. It was three things arriving together: enough labelled data, GPUs fast enough to use it, and the ReLU-plus-initialisation combination from sections 4.3 and 4.7 that made deep networks trainable at all.

Depth — the case where the older methods still win, and why

On tabular data — rows of heterogeneous columns, the kind in a spreadsheet or a database — gradient-boosted trees are still generally at least as good as neural networks, and often better. This is not nostalgia; it has been measured repeatedly and it has a reason.

Deep learning's advantage comes from architectural assumptions that match the data: convolution assumes that nearby inputs are related and that patterns recur at different positions; recurrence assumes an ordering. Tabular data satisfies neither. Column 5 and column 6 have no spatial relationship, and permuting the columns changes nothing about the problem. So a network has no useful prior to exploit and must learn everything from scratch, while a tree ensemble's axis-aligned splits are a natural fit for exactly this structure — and, per 2.3.4, are invariant to any monotone rescaling of a column, which spares all of the preprocessing a network needs.

The practical rule that follows: choose the method by the structure of the data, not by the recency of the method. If your features are meaningful named columns, start with gradient boosting. If your input is pixels, waveform or text, start with a pretrained network. This is 2.3.7's argument in a larger costume — a model's assumptions are worth exactly as much as their truth.

The visualization

Designed features against learned ones
interactive — perturb the shapes and watch which survives
hand-crafted3 / 3centre and top-row rule
learned features3 / 3two 3×3 edge filters
centre feature0, 4, 4ring, bar, hook
parameters2hand-crafted, versus 55 learned
 

The left column is the three shapes under the current perturbation, the middle shows the two hand-designed numbers, and the right shows the horizontal-edge response pooled separately over the top and bottom halves. Press Shift 1 px and the hand-crafted rule breaks on the ring while the convolutional signature is unchanged — because the filters slide, so a shifted pattern produces a shifted response rather than a different one.

One detail in that signature is worth pausing on. Pooling the response over the whole image gives ring and hook the identical value, and only splitting it into top and bottom halves separates them. That is section 5.2's caveat about global average pooling in miniature: it discards spatial information, which is exactly why it belongs at the very end of a network and not in the middle.

The pitfalls

Where marks are lost
  • Defining deep learning as "many layers". The distinction is learned versus designed representations. A boosted ensemble has more components than most networks and is not deep learning.
  • Claiming deep learning needs no feature engineering. It replaces feature design with architecture design, data augmentation and preprocessing choices. The effort moves, it does not vanish.
  • Reaching for a network on 500 rows of tabular data. Almost always the wrong call. Gradient boosting will beat it, train in seconds, and be inspectable.
  • Assuming more depth is always better. Unit 4 showed that 30 plain layers do not train at all without residual connections and careful initialisation. Depth is a cost that must be paid for.
  • Ignoring the compute and energy cost in a comparison. A model that gains one point for a hundred times the compute has not obviously won, and 4.8's reporting checklist asks for the budget.
  • Forgetting that a hand-crafted feature can be the correct answer. Worked 5.1's rule is exact, instant and interpretable. Reaching past it for a network would be a mistake.

Practice

P5.1.1 (direct) — Design a translation-invariant hand-crafted feature that distinguishes the ring from the bar and hook, and say what it costs.

Count connected background regions. The ring encloses a hole, so its background splits into two components — the outside and the interior. The bar and the hook are solid, so their background is a single connected region.

feature: number of connected components of the ZERO pixels ring → 2 bar → 1 hook → 1 translation-invariant: sliding the shape does not change the count. rotation-invariant too, and scale-invariant.

What it costs. A connected-components algorithm — flood fill or union-find — which is perhaps thirty lines rather than the one line that "count the central 2×2" needed. It also handles the boundary case badly: a ring touching the image edge may have its interior merge with the outside, so it needs padding. And it does nothing at all to separate bar from hook, so the top-row feature is still required and is still translation-fragile in the vertical direction.

That progression is the honest experience of feature engineering: each fix is reasonable, each is more code, and each handles one variation. The 2000s were spent doing this for natural images, and the resulting pipelines plateaued around 74% on ImageNet before being replaced wholesale.

P5.1.2 (variation) — For each task, say whether you would start with classical ML or deep learning, and why: (a) predicting loan default from 40 named financial columns, 8,000 rows; (b) classifying 50,000 chest X-rays; (c) forecasting daily sales from 3 years of history; (d) transcribing 200 hours of speech.

(a) Classical — gradient boosting. Tabular, moderate n, named columns with real meaning. None of deep learning's structural assumptions apply, boosting will match or beat a network, and the lending context almost certainly requires an explanation for each decision, which 2.6 and 4.8 both say a network cannot give faithfully.

(b) Deep learning — and specifically transfer learning. Images have exactly the structure convolution assumes. 50,000 is a lot for medicine but small for training from scratch, so start from an ImageNet-pretrained backbone per section 5.3. Watch for the grouped-split trap: multiple images per patient must not straddle the train/test boundary.

(c) Classical first. Three years of daily data is about 1,100 points, which is far too few for a sequence model to learn from. Start with a statistical baseline — seasonal naive, then ARIMA or a boosted model on lag features, which converts the problem to tabular. Deep sequence models become worth it at thousands of related series, not one short one.

(d) Deep learning, unambiguously. Raw audio has both spatial structure in the spectrogram and long-range sequential structure, hand-crafted phonetic features were tried for decades and lost, and 200 hours is a reasonable amount of data. This is the case where nothing else is competitive.

The pattern across all four: structure in the raw input, and enough data to learn it, are the two conditions. Fail either and classical methods are the better start.

P5.1.3 (interpretation) — A team replaces a logistic regression with a deep network on a tabular task. Accuracy rises from 0.834 to 0.841 and training time goes from 2 seconds to 4 hours. Assess.

The 0.7-point gain is probably not real, and even if it is, it is probably not worth it. Take those in order.

Is it real? A single run of each, with no variance estimate, on a difference of seven thousandths. Section 4.8 established that run-to-run variation from the seed alone is often larger than this. Report both as a mean and spread over several seeds and compare with a paired test on shared folds, per 2.4.6 — the honest answer may well be that the two are indistinguishable. Also check whether the network's hyperparameters were tuned on the test set while the logistic regression's were not, which would manufacture exactly this size of gap.

Is it the right comparison? The relevant baseline for tabular data is not logistic regression, it is gradient boosting, which would likely beat both and train in under a minute. Comparing a network against the weakest classical option and declaring deep learning superior is a rigged contest.

Is it worth it? Seven thousandths of accuracy for 7,200× the training time, plus GPU cost, plus the loss of interpretability that 2.6 may make legally necessary, plus a much harder deployment and monitoring story. Unless each point of accuracy carries very large value, this is a clear no.

What would change the answer: if the gain were several points, if it held up across seeds and against a boosting baseline, and if the task genuinely had structure the network could exploit that the tabular framing was hiding.

P5.1.4 (synthesis) — Using 4.1 and 4.2, explain precisely in what sense a hidden layer "learns features", and why that phrase is more than a metaphor.

It is literal, and Unit 4 computed it. In section 4.1 the XOR network's hidden layer mapped the four inputs to (0,0), (1,0), (1,0), (2,1). Those two numbers are features: derived quantities, computed from the raw inputs, in terms of which the task becomes easy. The output layer is a plain linear classifier operating on them, and it succeeds only because the features were good.

What makes them features rather than arbitrary numbers is that they are fitted to the objective. A hand-designed feature is chosen by a human before seeing how well the downstream model does with it. A hidden unit's weights receive a gradient from the loss, through the output layer, by the chain rule — so the feature is adjusted precisely in the direction that helps the final prediction. Section 4.4's δ₁ = (W₂ᵀδ₂) ⊙ φ'(z₁) is the mechanism: the blame the output assigns is what shapes the representation.

And 4.2 shows the same thing with a constraint attached. A convolutional filter is a feature detector whose weights are learned, and the constraint of weight sharing means the feature it learns is the same everywhere in the image. The edge kernels of Worked 4.2 were hand-written to make the arithmetic checkable; a trained network's first layer discovers filters that look very much like them, without being told, because oriented edges are genuinely the useful thing to compute first.

So the honest statement of the difference is narrow and specific: classical ML optimises the model given the features, deep learning optimises the features and the model together against the same objective. Everything else — depth, GPUs, data scale — is what makes that joint optimisation practical rather than what makes it different in kind.


5.2

CNN Architecture

Section 4.2 gave the convolution operation, the output-size formula and the parameter count. This section is about what you build out of them, and about the one connection that made depth work.

The question

You can compute the output size and parameter count of any convolutional layer. Now you have to choose: how many layers, how many filters each, where to downsample, what to put at the end. Those choices differ by two orders of magnitude in parameter count and several points in accuracy, so they are not arbitrary.

And one prior question dominates all of them. Section 4.7 established that a 30-layer plain network does not train at all, no matter how it is initialised. So how does a 152-layer network exist?

The standard block, and the shape of a network

The pattern almost every vision network follows[ conv 3×3 → BatchNorm → ReLU ] × 2 → downsample repeat, DOUBLING the channels each time you HALVE the resolution ... global average pooling → dense → softmax 224×224×3 → 112×112×64 → 56×56×128 → 28×28×256 → 14×14×512 → 7×7×512 → GAP → 512 → classes

The doubling rule is worth understanding rather than memorising. Halving both spatial dimensions divides the number of positions by four; doubling the channels multiplies the work per position by roughly four. So the computation per block stays roughly constant while the representation moves from many positions with few features to few positions with many features. That is the feature hierarchy of section 5.1, expressed as arithmetic.

Global average pooling — the single biggest parameter saving available

Section 4.2 found that 96.4% of a small CNN's parameters sat in the dense layer immediately after the flatten. At full scale it is worse.

A 7×7×512 feature map into 1000 classesflatten → dense: (7·7·512 + 1) × 1000 = 25,089,000 GAP → dense: (512 + 1) × 1000 = 513,000 a factor of 49

Global average pooling replaces each 7×7 channel with its mean, giving one number per channel. It has no parameters, it accepts any input size — which flatten cannot, since the flattened length depends on the resolution — and it is more resistant to overfitting because it cannot memorise position-specific detail. The cost is that all spatial information is discarded at that point, which is why it goes at the very end and not earlier.

1×1 convolutions

A 1×1 kernel looks pointless — it sees one pixel. But a filter always spans every input channel, so a 1×1 convolution is a learned linear combination across channels at each position independently. It changes the channel count without touching the spatial dimensions, and it costs almost nothing.

Worked 5.2a — the bottleneck block
an 88% saving
Compare a direct 3×3 convolution from 256 channels to 256, against a 1×1 down to 64, a 3×3 at 64, and a 1×1 back up to 256.
DIRECT 3×3, 256 → 256: (3·3·256 + 1) × 256 = 2305 × 256 = 590,080 BOTTLENECK 1×1, 256 → 64 : (1·1·256 + 1) × 64 = 257 × 64 = 16,448 3×3, 64 → 64 : (3·3·64 + 1) × 64 = 577 × 64 = 36,928 1×1, 64 → 256: (1·1·64 + 1) × 256 = 65 × 256 = 16,640 total = 70,016
70,016 against 590,080 — an 88.1% saving, for the same input and output shape.
The expensive 3×3 now operates on 64 channels instead of 256, and 3×3 cost scales with the product of input and output channels.
The two 1×1 layers also add two extra non-linearities, so the block is arguably more expressive as well as cheaper.

This is the block ResNet-50 and everything after it are built from, and it is why GoogLeNet reached better accuracy than VGG-16 with 6.8 million parameters against 138 million. The 3×3 convolution does the spatial work; the 1×1 convolutions manage how many channels it has to do it on.

Residual connections — the answer to section 4.7's problem

Section 4.3 computed that a gradient travelling back through L layers is multiplied by L factors, and section 4.7 showed that even with He initialisation a very deep plain network trains badly. The empirical finding that motivated the fix is sharper than either: a 56-layer plain network had higher training error than a 20-layer one. Not test error — training error. The deeper network could represent everything the shallower one could, by setting the extra layers to the identity, and gradient descent could not find that solution.

The residual blockplain: y = F(x) residual: y = F(x) + x the "skip" or "shortcut" connection so the block learns the RESIDUAL F(x) = y − x rather than y itself. setting F = 0 gives the identity, which is now the EASY case rather than something the layers must conspire to produce. the gradient: ∂y/∂x = ∂F/∂x + 1 that +1 is an additive path with derivative exactly 1, so the gradient reaches earlier layers even when ∂F/∂x has vanished.

The +1 is the whole mechanism and it is worth seeing why it matters against 4.3's arithmetic. In a plain network the backward signal is a product of L factors, and a product of numbers below 1 dies geometrically. In a residual network each block contributes (1 + ∂F/∂x), so even if every ∂F/∂x is tiny the product is near 1 rather than near 0. Addition rescues what multiplication destroys — and section 5.4 will make exactly the same move again, in time rather than depth, with the LSTM's cell state.

A residual block costs nothing extra: the identity shortcut has no parameters. Only when the block changes the channel count is a 1×1 projection needed, and at 64→128 that is 8,320 parameters against the block's 73,856.

The architectures worth knowing by name, with the numbers
NetworkyearparametersImageNet top-5 errorthe idea it contributed
LeNet-5199860 KConvolution and pooling, on digits
AlexNet201262 M15.3%ReLU, dropout, GPUs, augmentation — at scale
VGG-162014138 M7.3%Only 3×3 kernels, stacked deep
GoogLeNet20146.8 M6.7%1×1 bottlenecks, parallel branches, GAP
ResNet-50201525.6 M5.25%Residual connections — depth becomes possible
ResNet-152201560.2 M4.49%The same, 152 layers deep

Read the highlighted row against VGG-16 above it. GoogLeNet used 5% of VGG's parameters and achieved lower error in the same year. Parameter count is not capability; where the parameters go is. VGG spent 102 million of its 138 million on three dense layers at the end, which global average pooling would have removed almost entirely.

Depth — receptive field, and diagnosing an architecture that cannot see

Section 4.2 gave the rule that L stacked 3×3 layers reach 2L+1 input pixels. With pooling the growth is much faster, because every downsample doubles the jump — the distance in input pixels between adjacent output positions.

3×3 convs with a 2×2 pool after every second layer: after conv2 RF = 5 after conv6 RF = 32 after conv4 RF = 14 after conv8 RF = 68 after conv10 RF = 140 so ten convolutions and five pools reach 140 pixels — without pooling, twenty layers would be needed for the same reach.

Compute this when a network underperforms on large objects. If the object spans 200 pixels and the receptive field of the deciding layer is 68, the units making the decision have never seen the whole object, and no amount of training or data will fix it. The remedies are more downsampling, dilated convolutions — which insert gaps in the kernel to enlarge the receptive field without extra parameters or resolution loss — or simply a deeper network.

The converse diagnosis matters too. A receptive field far larger than the object means most of what each unit sees is irrelevant context, which wastes capacity and invites the network to learn background correlations rather than the object. A model that classifies cows correctly only on grass is the standard cautionary example, and it is a receptive-field-and-data problem rather than an architecture bug.

The worked example

Worked 5.2b — a network for the three shapes, end to end
every shape and count
Design and cost a small CNN for the 6×6 shapes, using the patterns above. Then say what each layer contributes.
Shapes and parameters, layer by layer
LayerOutputParameterscount
input6 × 6 × 10
conv 3×3, 4 filters, same6 × 6 × 4(3·3·1 + 1) × 440
BatchNorm6 × 6 × 42 × 48
ReLU6 × 6 × 40
maxpool 2×23 × 3 × 40
conv 3×3, 8 filters, same3 × 3 × 8(3·3·4 + 1) × 8296
BatchNorm3 × 3 × 82 × 816
global average pooling8none0
dense 3 → softmax3(8 + 1) × 327
total387
387 parameters, of which 336 are convolutional and 27 are the classifier.
Had the 3×3×8 map been flattened instead of average-pooled, the dense layer would have cost (3·3·8 + 1) × 3 = 219 — eight times the 27, on a network this small.
At 7×7×512 into 1000 classes that same substitution is worth 24.6 million parameters.

What the layers do on this data is legible because the data is tiny. The first convolution's four filters can learn the vertical and horizontal edge detectors of Worked 4.2 plus two more; after ReLU and pooling, the second convolution combines them into "has horizontal edges anywhere" and similar. Global average pooling then reduces each of eight channels to a single number, and the dense layer weights those eight numbers into three class scores.

The signatures those filters produce are what makes the three classes separable. From Worked 4.2's kernels: the bar produces no horizontal-edge response at all — it is uniform top to bottom, so every horizontal difference is zero — while the ring and hook both do. That single number nearly separates the bar by itself.

The visualization

Where the parameters go, and what depth buys
interactive — build an architecture and watch the counts
total parameters0for 1000 classes
in the head0the classifier alone
head share0%of the whole network
receptive field0input pixels at the last conv
 

Each bar is one stage, sized by its parameter count. Switch the head from global average pooling to flatten and watch the last bar dominate everything to its left — that single substitution is the difference between VGG's 138 million parameters and GoogLeNet's 6.8 million. Turn on bottlenecks and the convolutional bars shrink by roughly 88% while the shapes stay identical.

The pitfalls

Where marks are lost
  • Flattening a large feature map into a dense layer. The most expensive mistake available, and global average pooling fixes it in one line.
  • Thinking a 1×1 convolution does nothing. It combines across all input channels, so it is a learned channel mixer and the basis of every bottleneck block.
  • Adding depth without residual connections. Beyond about twenty plain layers, training error goes up. Depth is only available because of the skip connection.
  • Believing more parameters means more capability. GoogLeNet beat VGG-16 with 5% of the parameters. Where they go matters more than how many.
  • Forgetting to check the receptive field. If the deciding units cannot see the whole object, nothing else will help.
  • Keeping the bias in a convolution followed by BatchNorm. BN subtracts the mean, so the bias is exactly redundant — 4.6's point, and it recurs in every block here.
  • Ordering the block wrongly. Conv → BN → ReLU is standard. Putting BN after the activation is a different and generally worse network, and exam answers are marked on the order.

Practice

P5.2.1 (direct) — Count the parameters of a residual block with two 3×3 convolutions on 128 channels, with BatchNorm after each. Then say what changes if the block must go from 64 channels to 128.
SAME channels, 128 → 128: conv 1: (3·3·128 + 1) × 128 = 1153 × 128 = 147,584 BN 1: 2 × 128 = 256 conv 2: (3·3·128 + 1) × 128 = 147,584 BN 2: 2 × 128 = 256 identity shortcut = 0 total = 295,680 CHANGING channels, 64 → 128: conv 1: (3·3·64 + 1) × 128 = 577 × 128 = 73,856 conv 2: (3·3·128 + 1) × 128 = 147,584 BN 1 + BN 2 = 512 projection shortcut, 1×1, 64 → 128: (1·1·64 + 1) × 128 = 65 × 128 = 8,320 total = 230,272

The shortcut is free when the shapes match and costs 8,320 when they do not — about 3.6% of the block. That is why ResNet keeps the channel count constant within a stage and changes it only at the stage boundary: each change costs a projection, so you make as few as possible.

P5.2.2 (variation) — A network has conv layers with kernels 3, 3, 5, 3 and a 2×2 pool after the second layer. Compute the receptive field at the output.
track the receptive field r and the JUMP j (input pixels between adjacent output positions). Start r = 1, j = 1. a layer with kernel k and stride s: r ← r + (k − 1)·j then j ← j·s conv 3×3, s=1: r = 1 + 2(1) = 3 j = 1 conv 3×3, s=1: r = 3 + 2(1) = 5 j = 1 pool 2×2, s=2: r = 5 + 1(1) = 6 j = 2 conv 5×5, s=1: r = 6 + 4(2) = 14 j = 2 conv 3×3, s=1: r = 14 + 2(2) = 18 j = 2

18 input pixels. The jump is what makes the later layers count for more: the 5×5 kernel added 4 × 2 = 8 pixels rather than 4, because after pooling each of its inputs already summarised a 2-pixel step. That is why downsampling early is such an efficient way to buy reach, and why a network that never pools needs to be very deep to see anything large.

P5.2.3 (interpretation) — A 40-layer plain CNN reaches 71% training accuracy; a 20-layer version of the same design reaches 82% training accuracy. Explain, and give the fix.

This is the degradation problem, and the key observation is that it is training accuracy. Overfitting would show as a training-accuracy gain with a validation loss, so this is not overfitting. And it cannot be a capacity limit, because the 40-layer network strictly contains the 20-layer one — set the extra twenty layers to the identity and it reproduces the smaller network exactly. So a solution at least as good demonstrably exists and optimisation failed to find it.

The cause is that the identity is hard for a stack of plain layers to represent. Each layer would have to learn weights that reproduce its input exactly, which is a precise and unlikely configuration for a randomly initialised layer to reach. Combined with the vanishing gradients of 4.3, the deeper network's early layers barely move.

The fix is residual connections. Writing each block as y = F(x) + x makes the identity the default rather than a target: setting F = 0 is easy, since it just means driving the block's weights toward zero, which weight decay is pushing them toward anyway. Add BatchNorm per 4.6 and check He initialisation per 4.7. With those three, 40 layers trains, and so does 152.

Worth stating the general lesson: a model that can represent a solution and cannot find it is an optimisation problem, not a capacity problem, and the two need opposite fixes. Section 4.7's XOR result — 16.5% success at exactly sufficient capacity — is the same phenomenon at the smallest possible scale.

P5.2.4 (synthesis) — Using 4.3, explain why a residual connection helps, and identify what other mechanism in this course does the same thing by the same means.

The mechanism is turning a product into a sum. Section 4.3 established that a gradient crossing L layers is multiplied by L factors, one per layer, and that a product of factors below 1 decays geometrically — ten sigmoid layers cost a factor of 10⁶ even at their most favourable point. A residual block changes the local derivative from ∂F/∂x to ∂F/∂x + 1. Because of that +1, the product across blocks contains a term that is exactly 1 no matter how small every ∂F/∂x becomes, so the gradient reaches the earliest layers intact.

Put geometrically, the skip connection gives the gradient a highway from the loss to every layer, bypassing the multiplicative chain. The network can still use F when it helps; it simply is not forced to route everything through it.

The other mechanism is the LSTM's cell state, in section 5.4. A plain recurrent network's hidden state is updated multiplicatively, hᵗ = tanh(wₕhᵗ₋₁ + …), so the gradient across T steps is a product of T factors and dies exactly as depth does — at wₕ = 0.5 over twenty steps, a factor of 1.9 × 10⁻⁶. The LSTM replaces it with cᵗ = f · cᵗ₋₁ + i · g, an addition, whose derivative ∂cᵗ/∂cᵗ₋₁ is exactly the forget gate f. With f near 1 the gradient passes essentially unchanged, which is called the constant error carousel and is the same idea as the residual highway.

So the two headline architectural advances of the 2010s — residual networks for depth, gated recurrence for time — are the same insight applied to two different axes: when a repeated multiplication destroys a signal, add instead.


5.3

Transfer Learning and Fine-Tuning

Somebody has already paid for millions of images' worth of edge detectors. The only real decision is where to draw the line between the weights you keep and the weights you retrain.

The question

You have 300 labelled images of our three shapes and you want a network. Section 4.8 said 300 examples against millions of parameters is a variance disaster, and section 5.1 said deep learning needs data it does not have here. Is the answer really to give up and hand-craft features?

No, because of one fact from section 5.1's feature hierarchy: the early layers of every vision network learn nearly the same thing. Oriented edges, colour blobs, corners, textures. Those are properties of natural images, not of ImageNet, so a network trained on a million photographs has already learned the features your 300 images would have needed.

The intuition

You are not learning to see. You are learning what to call the things you already see. A pretrained network is a very expensive pair of eyes that somebody else trained; you are attaching a new opinion to the end of it.

The formal treatment

The three strategies, from cheapest to most expensive1. FEATURE EXTRACTION freeze the whole backbone, replace the head, train only the head the backbone becomes a fixed function; you are fitting a linear model on its output, which is Unit 2 with better features 2. FINE-TUNING the top freeze the early blocks, unfreeze the last one or two, train those plus the head, at a LOW learning rate 3. FULL FINE-TUNING unfreeze everything, train at a low learning rate only sensible with a lot of data
Worked 5.3 — what is actually trainable
counted on a real backbone
Take a VGG-style backbone of 14,751,616 parameters in five convolutional blocks, and attach a 3-class head after global average pooling. Count the trainable parameters under each strategy.
the backbone, block by block: block 1 (2 convs, 64 ch) 75,648 block 2 (2 convs, 128 ch) 221,440 block 3 (3 convs, 256 ch) 1,475,328 block 4 (3 convs, 512 ch) 5,899,776 block 5 (3 convs, 512 ch) 7,079,424 total 14,751,616 the new head, after global average pooling to a 512-vector: dense 3: (512 + 1) × 3 = 1,539
Trainable against frozen, for the same network
Strategytrainablefrozen% trainable
Feature extraction1,53914,751,6160.01%
Fine-tune block 57,080,9637,672,19248.00%
Fine-tune blocks 4 and 512,980,7391,772,41687.99%
Full fine-tuning14,753,1550100.00%
Feature extraction trains 1,539 parameters — one hundredth of one percent of the network.
With 300 images that is five examples per parameter, which is a perfectly ordinary supervised learning problem.
Training the same architecture from scratch would mean 14.75 million parameters against 300 images, which is hopeless.

Notice how unevenly the parameters are distributed. Blocks 4 and 5 hold 12.98 million of the 14.75 million, 88% of the network, because parameter count scales with the product of input and output channels and those blocks run at 512. So "unfreeze the last block" already means unfreezing almost half the network, and the phrase "just fine-tune the top" is doing more work than it sounds like.

Which strategy, and why

The standard four-quadrant guide
Small datasetLarge dataset
Similar domain
(natural photographs)
Feature extraction. Too little data to fine-tune safely, and the features already fit.Fine-tune the whole network at a low rate. You can afford it and it will help.
Different domain
(X-rays, satellite, spectrograms)
Freeze the early blocks, retrain the later ones plus the head. The hardest case — consider a smaller model or heavy augmentation.Fine-tune everything, or train from scratch. With enough data the pretrained start still usually converges faster.

The axis that governs this is the feature hierarchy of section 5.1. Early layers are generic and transfer everywhere; late layers are task-specific and transfer only within a domain. So the less your domain resembles the source, the further down you must retrain — and the more data you need to do it without overfitting.

The learning rate is not a detail herethe pretrained weights are already near a good solution, so a large step destroys them before the gradient signal is meaningful. head training (random init): η ≈ 10⁻³ fine-tuning (pretrained): η ≈ 10⁻⁵ to 10⁻⁴ at η = 10⁻³, one hundred steps with gradient norm 1 move a weight by up to 0.1 — comparable to the weights themselves. The backbone can be destroyed within one epoch, which is called catastrophic forgetting. standard recipe: 1. freeze the backbone, train the head to convergence at 10⁻³ 2. THEN unfreeze the top blocks and continue at 10⁻⁵

Step 1 exists because a randomly initialised head produces large, meaningless gradients on its first batches, and those gradients flow straight into the backbone if it is unfrozen. Train the head first and the gradients reaching the backbone are already sensible.

Depth — two traps that make transfer learning silently wrong

The BatchNorm trap. Section 4.6 established that BatchNorm behaves differently at training and test time, using batch statistics for one and running averages for the other. A "frozen" backbone containing BatchNorm layers is usually not frozen: unless the layer is explicitly put in inference mode, it keeps updating its running mean and variance from your new data, and those statistics silently drift away from what the frozen weights expect. The symptom is a model that trains well and evaluates badly, and it is one of the most common bugs in applied transfer learning. Setting requires_grad = False stops the weights moving; it does not stop the statistics updating.

The preprocessing trap. A pretrained network expects exactly the preprocessing it was trained with — the same input size, the same channel order, and the same normalisation constants. Feed it images scaled to [0,1] when it was trained on ImageNet-mean-subtracted inputs and every activation is shifted, so the carefully learned features fire on the wrong things. This produces a model that is worse than random initialisation while looking entirely reasonable in code.

Both traps share a shape worth recognising: the failure is silent and the code runs. The defence is to check that the frozen backbone produces identical outputs before and after your training loop touches it, which is three lines and catches both.

The visualization

Where you draw the freeze line
interactive — amber is trainable, grey is frozen
trainable1,539parameters being learned
% of network0.01%amber share
examples per parameter0.19above ~1 is comfortable
recommendedfrom the four-quadrant rule
 

Each bar is one block of the backbone, sized by parameter count, amber where trainable and grey where frozen. Notice how much amber appears the moment you unfreeze block 5 — almost half the network in a single step, because the deep blocks are where the parameters live. Slide the dataset size and the recommendation changes; tick the domain box and it changes again.

The pitfalls

Where marks are lost
  • Fine-tuning at the head's learning rate. 10⁻³ on a pretrained backbone erases it within an epoch. Use 10⁻⁵ to 10⁻⁴.
  • Unfreezing the backbone before the head has converged. A random head sends meaningless gradients into good weights. Train the head first, always.
  • Forgetting BatchNorm layers keep updating when "frozen". Put them in inference mode explicitly.
  • Using different preprocessing from the pretrained model. Same size, same channel order, same normalisation constants. Non-negotiable.
  • Fine-tuning everything on 300 images. That is 14.75 million parameters against 300 examples — the variance problem transfer learning was supposed to avoid.
  • Assuming ImageNet features suit any image. Medical scans, satellite imagery and spectrograms are visually unlike photographs. Transfer still usually helps, but expect to retrain further down.
  • Reporting the source model's accuracy as evidence. That a backbone scores 76% on ImageNet says nothing about your three classes.

Practice

P5.3.1 (direct) — A pretrained backbone outputs a 2048-vector after global average pooling. You have 1,200 images in 5 classes. Give the head, its parameter count, and the examples-per-parameter ratio.
simplest head: dense 2048 → 5, softmax (2048 + 1) × 5 = 10,245 parameters examples per parameter = 1,200 / 10,245 = 0.12

That ratio is uncomfortable — roughly eight parameters per example — so even this minimal head can overfit. Three reasonable responses: add L2 or dropout before the dense layer per 4.6; reduce the feature dimension first with a 1×1 convolution or a small bottleneck dense layer, though that adds its own parameters; or simply accept it and rely on early stopping, which costs nothing and is what most practitioners do.

Note what would happen with a two-layer head, 2048 → 256 → 5: that is 524,544 + 1,285 = 525,829 parameters against 1,200 images, a ratio of 0.002. A deeper head is almost always the wrong instinct in transfer learning, because the backbone has already done the representation learning and all that remains is a linear decision.

P5.3.2 (variation) — You have 80,000 labelled chest X-rays and an ImageNet-pretrained ResNet-50. Which strategy, and what would you do differently from the photographs case?

Large dataset, different domain — so fine-tune everything, at a low learning rate, after first training the head. 80,000 images is enough to move 25.6 million parameters without immediately overfitting, and X-rays are visually unlike photographs, so the later layers' ImageNet features — dog faces, wheels, textures of fur — are largely useless and need replacing.

What changes from the photographs case. The preprocessing must be rethought: X-rays are single-channel and are usually replicated to three channels to fit the pretrained input, and their intensity distribution is nothing like ImageNet's, so the normalisation constants deserve checking rather than copying. Augmentation must respect the domain — horizontal flips change left from right lung and can invert a diagnosis, whereas they are free on photographs. And the split must be grouped by patient, since several images from one patient in both train and test inflates the score, which is 2.1's leakage rule in its most common clinical form.

What to expect. Pretraining still helps here, mostly through faster convergence and a better optimum rather than through the features themselves surviving. It is worth running a from-scratch baseline to measure how much, because at 80,000 images the gap is often smaller than people assume, and knowing its size tells you whether to invest in more data or in a better architecture.

P5.3.3 (interpretation) — A transfer-learned model reaches 94% training and 61% validation accuracy. Freezing more layers changes nothing. Diagnose.

The fact that freezing more layers does not help is the informative part, because freezing is the strongest capacity reduction available in this setting. If cutting the trainable parameters by an order of magnitude leaves validation unmoved, the 33-point gap is not caused by having too many trainable parameters — so it is not ordinary overfitting, and more regularisation will not fix it either. This is P4.6.3's situation again: the intervention worked as designed and the diagnosis was wrong.

Check the silent failures first, in this order. Preprocessing mismatch: is the input normalised exactly as the source model expects? BatchNorm still updating in the "frozen" backbone? Both produce a model that behaves inconsistently between training and evaluation and are cheap to rule out. Then leakage or grouping in the split, which inflates training-side performance whenever near-duplicate images straddle the boundary.

Then consider distribution shift. If validation images differ systematically from training ones — different source, device, time period — no capacity change closes the gap. Diagnose by evaluating on a held-out slice of the training distribution: a high score there and a low score on validation is shift, not variance.

And check the head is not simply too weak. If the domain is far from the source, a frozen backbone may not produce linearly separable features at all, in which case both training and validation would be poor — which they are not here, so this is the least likely of the four.

P5.3.4 (synthesis) — Using 1.6, 1.7 and 2.5, explain what transfer learning is doing in statistical terms.

It is a constraint on the hypothesis space, which is exactly 1.7's definition of regularisation. Freezing the backbone does not merely reduce the parameter count — it fixes the function computed by most of the network, so the model you are actually fitting is a linear classifier on a fixed 512-dimensional representation. Worked 5.3's 1,539 trainable parameters is the honest capacity of that model, and 1.6's variance term is computed from that number rather than from 14.75 million.

The bias that constraint introduces is where the subtlety is. A hard constraint always adds bias, and here the bias is the assumption that ImageNet's features suffice for your task. When the domains are close, the assumption is nearly true and the bias is nearly free, which is why feature extraction on photographs works so well. When the domains are far apart, the same constraint is expensive — and that is precisely what the four-quadrant table encodes: how far down to retrain is a judgement about how much of the source's bias you can afford.

The connection to 2.5 is closer than it looks. Semi-supervised learning used unlabelled data to learn structure that labelled data alone could not support. Transfer learning does the same thing with a different source: someone else's labelled data, in a different task, used to learn a representation. Both are answers to "I do not have enough labels", and both work only when an assumption holds — the cluster and smoothness assumptions in 2.5, feature transferability here. Self-supervised pretraining, which Unit 5's further reading points at, is the version that merges them: learn the representation from unlabelled data in the target domain, then attach a small head, which is the dominant paradigm in modern practice for exactly this reason.


5.4

Recurrent Networks, LSTM and GRU

Section 4.3's vanishing-gradient argument, applied to time instead of depth — and a fix that is the same idea as the residual connection.

The question

A convolutional network takes a fixed-size input and looks at all of it at once. What do you do with a sentence of unknown length, a share price, or a recording? You could pad everything to a fixed size and use a dense layer, but then position 1 and position 2 get entirely separate weights, so nothing learned about one transfers to the other — the same objection section 4.2 raised against dense layers on images.

The intuition

Read the sequence one element at a time, and carry a summary of everything seen so far. At each step, combine the new element with the running summary to produce an updated summary. The same combining function is used at every step, which is weight sharing across time exactly as convolution is weight sharing across space.

That running summary is the hidden state, and it is the network's entire memory. Whatever is not in it is gone.

The formal treatment

The simple recurrent networkhᵗ = tanh( Wₕₓ xᵗ + Wₕₕ hᵗ₋₁ + b ) h₀ = 0 yᵗ = Wₖₕ hᵗ + bₖ the SAME Wₕₓ, Wₕₕ, b at every timestep — weight sharing over time. parameters for input dim d and hidden size h: h(d + h) + h independent of sequence length

Training uses backpropagation through time: unroll the network into T copies, run ordinary backpropagation, and sum the gradients for the shared weights across all timesteps. It is not a new algorithm — it is section 4.4 applied to a network that happens to reuse its weights.

And that is where the trouble is. Unrolling T steps produces a network of depth T, so section 4.3's argument applies with full force.

The gradient through time is a product∂hᵗ/∂hᵗ₋₁ = Wₕₕᵀ · diag(tanh′(zᵗ)) so across T steps: ∂hᵗ/∂h₁ = ∏ᵗ Wₕₕᵀ · diag(tanh′) with a scalar hidden unit this is just wₕᵗ⁻¹ times a product of tanh derivatives, all of which are at most 1: wₕ T = 5 T = 10 T = 20 T = 50 0.5 6.25 × 10⁻² 1.95 × 10⁻³ 1.91 × 10⁻⁶ 1.78 × 10⁻¹⁵ 0.9 6.56 × 10⁻¹ 3.87 × 10⁻¹ 1.35 × 10⁻¹ 5.73 × 10⁻³ 1.0 1.00 1.00 1.00 1.00 1.1 1.46 2.36 6.12 1.07 × 10² 1.5 5.06 3.84 × 10¹ 2.22 × 10³ 4.25 × 10⁴ only wₕ = 1 exactly is stable, and that is a measure-zero coincidence.

Compare with section 4.3's number: ten sigmoid layers cost a factor of 9.5 × 10⁻⁷, and twenty recurrent steps at wₕ = 0.5 cost 1.9 × 10⁻⁶. It is the same failure, and twenty steps is a very short sequence.

The exploding side has a cheap fix — gradient clipping, capping the global gradient norm, which section 4.4 already recommended. The vanishing side does not, and needs an architectural change.

The worked example

Worked 5.4a — a plain RNN reads the shapes and loses the first row
the spine, as a sequence
Feed each shape's row sums, scaled by 1/4, into a one-unit RNN with wₓ = −2, b = +1, and h₀ = 0. The weights are chosen so that a zero first row drives the state positive and a full row drives it negative. Can the final state distinguish the bar from the hook?
Step 1 — the sequences
RING x = 0.5, 1.0, 1.0, 1.0, 1.0, 0.5 BAR x = 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 HOOK x = 0.0, 1.0, 1.0, 1.0, 1.0, 1.0 BAR and HOOK are identical from t = 2 onward.
Step 2 — run it, with wₕ = 0.5
hᵗ = tanh(−2xᵗ + 0.5hᵗ₋₁ + 1) BAR t=1: tanh(−2 + 0 + 1) = tanh(−1) = −0.762 t=2: tanh(−2 − 0.381 + 1) = tanh(−1.381) = −0.881 t=3: −0.894 t=4: −0.895 t=5: −0.895 t=6: −0.895218 HOOK t=1: tanh( 0 + 0 + 1) = tanh(+1) = +0.762 t=2: tanh(−2 + 0.381 + 1) = tanh(−0.619) = −0.551 t=3: −0.855 t=4: −0.891 t=5: −0.895 t=6: −0.895179 separation at t = 1: |−0.761594 − 0.761594| = 2 tanh(1) = 1.523188 separation at t = 6: |−0.895218 + 0.895179| = 0.000039
The network sees the difference perfectly at step 1 — a separation of 1.5232 — and has lost it by step 6, down to 0.000039.
That is a reduction by a factor of 39,000 over five steps.
A classifier reading only the final state cannot distinguish bar from hook.
Step 3 — and raising wₕ does not help

The obvious response is that wₕ = 0.5 is forgetting too fast, so raise it. Here is what actually happens.

Final-step separation of bar from hook, across the recurrent weight
wₕ0.30.50.70.90.951.0
separation at t = 60.0000100.0000390.0000600.0000620.0000600.000058

It never rises above 0.00006. The reason is that the problem is not only the gradient — it is the forward pass. Every step pushes h toward the saturated region of tanh, where the function is flat, and two states that differ slightly both get mapped to nearly the same output. The distinction is destroyed on the way forward, before backpropagation is even involved.

This is worth being precise about, because "vanishing gradients" is the usual slogan and it is only half the story. A saturating recurrent unit has a vanishing memory as well: information about early inputs is compressed out of the state regardless of what the gradients do.

The LSTM — add instead of multiplying

The fix is the same move that section 5.2's residual connection made. A plain RNN's state is transformed multiplicatively at every step. An LSTM adds a second state, the cell state, which is updated by addition and controlled by learned gates.

The LSTM cellall four gates take [xᵗ, hᵗ₋₁] as input: fᵗ = σ(Wᶠ · [hᵗ₋₁, xᵗ] + bᶠ) FORGET how much of the old cell to keep iᵗ = σ(Wᵢ · [hᵗ₋₁, xᵗ] + bᵢ) INPUT how much of the new to admit gᵗ = tanh(Wᵗ · [hᵗ₋₁, xᵗ] + bᵗ) CANDIDATE what the new content is oᵗ = σ(Wₒ · [hᵗ₋₁, xᵗ] + bₒ) OUTPUT how much of the cell to expose cᵗ = fᵗ ⊙ cᵗ₋₁ + iᵗ ⊙ gᵗ the cell state — ADDITIVE hᵗ = oᵗ ⊙ tanh(cᵗ) the hidden state the gates are sigmoids, so they lie in (0,1) and act as soft switches. ∂cᵗ/∂cᵗ₋₁ = fᵗ exactly. With f near 1 the gradient passes through unchanged — the CONSTANT ERROR CAROUSEL.

Set that against the plain RNN's ∂hᵗ/∂hᵗ₋₁ = wₕ tanh′. Over 100 steps, an LSTM with f = 0.99 retains 0.99¹⁰⁰ = 0.366 of the gradient. A plain RNN with wₕ = 0.99 and a typical tanh′ ≈ 0.5 retains (0.495)¹⁰⁰ = 2.9 × 10⁻³¹. A factor of 10³⁰.

Worked 5.4b — an LSTM cell that solves the same problem
exact, and by hand
Set the gates so the cell latches its first input and holds it: f = 1 always, i = 1 at t = 1 and 0 afterwards, gᵗ = tanh(2xᵗ − 1). Trace the cell state for all three shapes.
cᵗ = fᵗcᵗ₋₁ + iᵗgᵗ with c₀ = 0 t = 1: i = 1, so c₁ = 0 + g₁ = tanh(2x₁ − 1) RING x=0.5 → tanh(0) = 0.0000 BAR x=1.0 → tanh(1) = +0.7616 HOOK x=0.0 → tanh(−1) = −0.7616 t = 2..6: i = 0 and f = 1, so cᵗ = cᵗ₋₁ — UNCHANGED RING c = 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000 BAR c = +0.7616, +0.7616, +0.7616, +0.7616, +0.7616, +0.7616 HOOK c = −0.7616, −0.7616, −0.7616, −0.7616, −0.7616, −0.7616
Separation of bar from hook at t = 6: |0.7616 − (−0.7616)| = 1.5232.
That is exactly the number the plain RNN had at step 1 — both are 2 tanh(1). The two architectures see the same difference at the start; one keeps it and one does not.
Against the plain RNN's 0.000039 at step 6, that is a factor of 39,000.
And ∂c₆/∂c₁ = f₆f₅f₄f₃f₂ = 1 exactly, so the gradient survives as perfectly as the signal does.

Two honest qualifications. These gate values were set by hand to make the arithmetic exact; a trained LSTM learns them, and it learns them because the gradient reaching step 1 is large enough to inform the update — which is the property the architecture was designed to provide. And a real forget gate is a sigmoid, so it can never be exactly 1; at f = 0.99 the cell decays slowly rather than not at all, which is why very long sequences remain hard even for LSTMs and why attention eventually replaced them.

Note also what the cell is doing conceptually. It is a set of memory slots with a learned read-write policy: the input gate decides when to write, the forget gate when to erase, and the output gate what to expose. The gates are computed from the data, so when to remember is itself learned.

The GRU, and how to choose

Gated recurrent unit — the same idea, two gates instead of three rᵗ = σ(Wᵣ · [hᵗ₋₁, xᵗ]) RESET zᵗ = σ(Wᶻ · [hᵗ₋₁, xᵗ]) UPDATE h̃ᵗ = tanh(W · [rᵗ ⊙ hᵗ₋₁, xᵗ]) hᵗ = (1 − zᵗ) ⊙ hᵗ₋₁ + zᵗ ⊙ h̃ᵗ no separate cell state; the update gate does both jobs, since keeping the old state and admitting the new are forced to sum to 1.
Parameter cost, for input dimension d and hidden size h
CellFormulad=100, h=256Notes
Simple RNNh(d + h) + h91,392Cannot hold long context
GRU3[h(d + h) + h]274,176Faster, fewer parameters, usually as good
LSTM4[h(d + h) + h]365,568The default when in doubt; separate cell state

The honest guidance is that GRU and LSTM perform comparably on most tasks, with the GRU 25% cheaper and faster. Try the GRU first; reach for the LSTM if the sequences are very long or the GRU underperforms. The choice between them is far less consequential than the choice to use gates at all.

Depth — what replaced all of this, and why it belongs in the same story

Even a gated cell processes a sequence one step at a time, which has two costs. Every element must pass through T sequential updates, so information from step 1 competes with everything since for room in a fixed-size state. And the computation cannot be parallelised across time, because step t needs step t−1, so training on long sequences is slow no matter how much hardware you have.

Attention removes both. Instead of carrying a summary forward, it lets every position look directly at every other position and weight them by relevance — a softmax over similarity scores, which is precisely the softmax of 3.1.4 and 4.3 in a new role. The path from step 1 to step 100 becomes length 1 rather than length 100, so nothing has to survive a chain of updates, and every position can be computed simultaneously.

The cost is quadratic: T positions each attending to T positions is O(T²) in time and memory, against a recurrent network's O(T). That trade — parallelism and direct access, paid for in quadratic cost — is why transformers displaced recurrent networks for text from around 2018, and why efficient-attention research is an active field. Recurrent models remain sensible for streaming data, very long sequences where quadratic cost is prohibitive, and small-scale problems.

The visualization

Memory over time: a plain RNN against a gated cell
interactive — watch the first row survive or vanish
separation at t=11.523bar against hook
separation at the end0.000039what the classifier sees
retained0.003%of the original difference
gradient factor1.9e-6across the whole sequence
 

The teal and violet traces are the bar and the hook, and the shaded band between them is the separation the final classifier has to work with. On the simple RNN the band pinches shut within three steps and no setting of wₕ keeps it open. Switch to the LSTM cell and the band stays exactly as wide as it was at step 1, for any sequence length — until you lower the forget gate below 1, at which point it decays again, slowly, at a rate you can read off directly.

The pitfalls

Where marks are lost
  • Saying the vanishing gradient is only about gradients. Worked 5.4a shows the forward signal vanishing too, which is why raising wₕ does not help. Both matter.
  • Confusing the cell state with the hidden state. cᵗ is the additive memory; hᵗ = oᵗ ⊙ tanh(cᵗ) is the gated view of it that leaves the cell.
  • Getting the LSTM parameter count wrong. Four gates, each a full h(d+h)+h. Three gates for the GRU.
  • Forgetting that the weights are shared across time. BPTT sums the gradient contributions from every timestep before updating once.
  • Applying gradient clipping to the vanishing problem. Clipping caps large gradients; it cannot inflate small ones. It fixes explosion only.
  • Using a bidirectional RNN for a streaming task. It needs the whole sequence before producing any output, so it is unavailable for real-time use however well it scores offline.
  • Claiming an LSTM "solves" long-range dependencies. It extends the range by a large factor. A sigmoid forget gate cannot equal 1, so the decay is slowed, not removed — which is why attention exists.

Practice

P5.4.1 (direct) — An LSTM cell has cᵗ₋₁ = 2.0 and gate pre-activations zᶠ = 2, zᵢ = −1, zᵗ = 1.5, zₒ = 0.5. Compute f, i, g, o, cᵗ and hᵗ.
f = σ(2) = 1/(1 + e⁻²) = 0.8808 i = σ(−1) = 1/(1 + e¹) = 0.2689 g = tanh(1.5) = 0.9051 o = σ(0.5) = 1/(1 + e⁻⁰‧⁵)= 0.6225 cᵗ = f·cᵗ₋₁ + i·g = 0.8808(2.0) + 0.2689(0.9051) = 1.7616 + 0.2434 = 2.0050 hᵗ = o · tanh(cᵗ) = 0.6225 × tanh(2.0050) = 0.6225 × 0.9645 = 0.6003

Read what the gates decided. The forget gate at 0.8808 keeps 88% of the old memory; the input gate at 0.2689 admits only 27% of the new candidate. So this cell is in remembering mode: the state barely moved, from 2.0000 to 2.0050. Reverse the two pre-activations and it would overwrite instead. That the two gates are separate — unlike the GRU, where keeping and admitting must sum to 1 — is the LSTM's extra degree of freedom.

P5.4.2 (variation) — A sequence task needs information from step 1 at step 60. Estimate the surviving gradient for a plain RNN with wₕ = 0.95 and tanh′ ≈ 0.6, and for an LSTM with f = 0.98. What does each imply?
PLAIN RNN: each step multiplies by wₕ · tanh′ = 0.95 × 0.6 = 0.57 across 59 steps: 0.57⁵⁹ = 4.0 × 10⁻¹⁵ LSTM: each step multiplies by f = 0.98 across 59 steps: 0.98⁵⁹ = 0.30

The plain RNN retains about four parts in 10¹⁵, which is indistinguishable from nothing. The update to the step-1 weights from this dependency is swamped by every other gradient contribution, so the model will never learn the connection — and note that it will still train happily and report a decreasing loss, having simply learned to ignore the long-range structure.

The LSTM retains 30%, which is a perfectly usable signal. Same task, same length, and the difference is entirely whether the state is updated by multiplication or by addition.

The qualification from Worked 5.4b applies: f = 0.98 is realistic but not free — the network must learn to hold the gate that high on the relevant dimension, and it can only learn that because the gradient is strong enough to inform the update. Extend to 500 steps and even 0.98⁴⁹⁹ = 4 × 10⁻⁵, which is why attention's constant-length path matters at document scale.

P5.4.3 (interpretation) — A sentiment model on movie reviews scores 88% on short reviews and 61% on reviews over 300 words. It is a single-layer LSTM reading left to right. Diagnose and propose fixes.

The length-dependent gap is the signature of a memory limitation, not a modelling error. At 300 words even an LSTM's forget gate cannot hold early content: at f = 0.98, 0.98³⁰⁰ ≈ 0.002. Long reviews also tend to be structurally different — more qualification, contrast and late reversals ("...but the ending ruined it") — so the decisive evidence is often distant from wherever the model's attention effectively sits.

Check first that it is length and not confounding. Are long reviews rarer in training, so the model has seen fewer? Are they systematically more mixed in sentiment and therefore genuinely harder for any model? Plot accuracy against length in buckets, and compare against a bag-of-words baseline: if the baseline shows the same drop, the difficulty is in the data rather than the architecture.

The fixes, in rough order of effort. Make it bidirectional, so the end of the review is read by a backward pass and no position is 300 steps from the output — cheap, and often most of the gain. Add attention over the hidden states, so the classifier can look directly at any position rather than relying on the final state, which addresses the cause precisely. Or replace the model with a pretrained transformer and fine-tune it, per section 5.3, which is what practice would actually do.

What will not help: a larger hidden size, more layers, or more training. The bottleneck is the length of the path from an early word to the output, and none of those shortens it.

P5.4.4 (synthesis) — Using 4.2, 4.3 and 5.2, place the recurrent architectures in the wider pattern. What is the recurring idea?

Weight sharing, and the assumption behind it. Section 4.2's convolution shares one kernel across every spatial position, encoding the assumption that a pattern means the same thing wherever it appears. A recurrent cell shares one transition function across every timestep, encoding the assumption that the rule for updating a summary is the same at every point in the sequence. Both buy the same two things: a parameter count independent of input size, and the ability to generalise a pattern learned at one position to all the others. Both are hard constraints that are valuable exactly to the extent that they are true, which is 4.2's closing argument and 5.1's depth box.

The multiplicative-chain failure, and the additive fix. Section 4.3 showed a gradient crossing L layers is a product of L factors, and that a product of factors below 1 dies. Section 5.2's residual block answered it with y = F(x) + x, whose derivative is ∂F/∂x + 1. The LSTM answers the identical problem in time with cᵗ = f cᵗ₋₁ + i g, whose derivative is f. Both replace a transformation with an accumulation, and both give the signal a path whose local derivative is at or near 1. Depth and time are the same axis as far as the gradient is concerned, and the fix is the same fix.

What the pattern predicts. Once you see it, the next move is visible: if an additive path with derivative 1 rescues a chain of length T, a direct path of length 1 would rescue it entirely. That is attention, and it is why the depth box above belongs in this section rather than as an aside. The progression — multiply, then add, then connect directly — is the architectural history of the 2010s in three steps.


5.5

Multi-class Metrics and Convergence

Unit 2B's evaluation machinery extended past two classes — including a case where every AUC is exactly 1.0000 and accuracy is 0.8333.

The question

Section 2.4.3 built ROC and AUC for a binary problem: one score per example, one threshold, one curve. With three classes there are three scores per example and no single threshold. What replaces it, and what does the replacement actually measure?

Top-K accuracy

Credit if the true class is among the top K predictionsrank the K classes by predicted probability. top-1 accuracy = fraction where the true class ranks 1st (this is ordinary accuracy) top-5 accuracy = fraction where the true class is in the top 5 top-K rises monotonically with K and reaches 1 when K = number of classes.

Top-5 is quoted for ImageNet because with 1000 fine-grained classes — dozens of dog breeds — ranking the right one second is a nearly correct answer and a useful thing to measure. The number to compare against is that a random model scores K/1000, so top-5 chance is 0.5%.

Report top-K only where being close has value. For a three-class medical triage, "the right answer was our second guess" is not a partial success, and quoting top-2 there would be inflating the result.

Extending ROC and AUC

One-vs-rest, then averagedfor each class k, build a BINARY problem: positives = examples whose true class is k scores = the model's predicted p(class k) compute AUC as in 2.4.3 MACRO average = the unweighted mean of the K AUCs every class counts equally, however rare MICRO average = pool all K×n score-label pairs into one AUC every PREDICTION counts equally, so frequent classes dominate

Choose macro when rare classes matter as much as common ones, which in an imbalanced problem is usually the point. Choose micro when overall throughput is what you care about. Quoting one without saying which is a reporting failure, since they can differ substantially.

The worked example

Worked 5.5 — twelve predictions, and a metric that disagrees with itself
AUC 1.0000, accuracy 0.8333
A model predicts probabilities over ring, bar and hook for twelve validation images, four of each class. Compute top-1 and top-2 accuracy, the confusion matrix, per-class recall and precision, and the one-vs-rest AUCs.
The predictions. Bold is the argmax.
#truep(ring)p(bar)p(hook)predictedrank of true
1ring0.700.200.10ring ✓1
2ring0.550.300.15ring ✓1
3ring0.400.350.25ring ✓1
4ring0.800.100.10ring ✓1
5bar0.150.650.20bar ✓1
6bar0.250.500.25bar ✓1
7bar0.300.450.25bar ✓1
8bar0.100.750.15bar ✓1
9hook0.200.300.50hook ✓1
10hook0.300.350.35bar ✗2
11hook0.150.250.60hook ✓1
12hook0.250.400.35bar ✗2
Step 1 — accuracy and top-K
top-1 = 10/12 = 0.8333 top-2 = 12/12 = 1.0000 every true class is at worst second top-3 = 12/12 = 1.0000 trivial with only 3 classes
Step 2 — confusion matrix and per-class scores
predicted ring bar hook ring 4 0 0 t bar 0 4 0 r hook 0 2 2 u recall precision ring 4/4 = 1.0000 4/4 = 1.0000 bar 4/4 = 1.0000 4/6 = 0.6667 hook 2/4 = 0.5000 2/2 = 1.0000

The whole of the error is one confusion in one direction: two hooks called bars. So bar's precision suffers and hook's recall suffers, while every other figure is perfect. That asymmetry is exactly what a confusion matrix is for and what a single accuracy number hides.

Step 3 — one-vs-rest AUC

For each class, take that column of scores and ask whether it ranks the four true members above the eight others.

RING column: positives 0.70, 0.55, 0.40, 0.80 min = 0.40 negatives 0.15, 0.25, 0.30, 0.10, 0.20, 0.30, 0.15, 0.25 max = 0.30 every positive outranks every negative → AUC = 1.0000 BAR column: positives 0.65, 0.50, 0.45, 0.75 min = 0.45 negatives max = 0.40 → AUC = 1.0000 HOOK column: positives 0.50, 0.35, 0.60, 0.35 min = 0.35 negatives max = 0.25 → AUC = 1.0000 MACRO AUC = (1 + 1 + 1)/3 = 1.0000 MICRO AUC, pooling all 36 pairs = 0.9844
Every one-vs-rest AUC is exactly 1.0000. Top-1 accuracy is 0.8333 and one class has recall 0.5000.
Both are correct. They are measuring different things.

The reconciliation is worth stating carefully, because it is the point of the whole section. AUC asks a question within a column: does this class's score rank its own members above everyone else's? For all three classes the answer is yes, perfectly — hook's lowest positive is 0.35 and its highest negative is 0.25, so a threshold at 0.30 on the hook score alone would separate hooks flawlessly.

Argmax asks a question across columns: is this class's score the largest of the three? For images 10 and 12 the hook score of 0.35 is perfectly adequate in isolation and simply loses to the bar score of 0.35 and 0.40. Per-class AUC is blind to that competition, because it never compares one class's score against another's.

What this means in practice

A model with high per-class AUC and mediocre accuracy is telling you the ranking is good and the calibration between classes is not. That is a repairable problem, and the repair is cheap: adjust the per-class decision thresholds, or apply a per-class scaling to the scores before the argmax. Here, multiplying the hook column by 1.2 before comparing would fix both errors and cost nothing elsewhere.

So the diagnostic value is real. Accuracy alone would have said "83%, needs a better model". The AUCs say "the model already separates every class perfectly; you have a threshold problem", which is section 2.4.4's material and a very different afternoon's work.

Loss, and what a converged number should look like

Categorical cross-entropy on the same twelve predictionsL = −(1/n) Σᵢ ln pᵢ,ᵗᵣᵘᵔ = 0.6340 reference points: a uniform predictor over 3 classes: ln 3 = 1.0986 perfect confident predictions: 0 so 0.6340 is well below chance and well above perfect — consistent with a model that ranks correctly and is under-confident. for K classes the "learned nothing" value is ln K: K = 2 ln 2 = 0.6931 K = 3 ln 3 = 1.0986 K = 10 ln 10 = 2.3026 K = 1000 6.9078

Section 4.8 made the point and it is worth repeating because it is the fastest diagnostic in deep learning: a loss sitting at ln K means no learning at all, not slow learning. Recognising 0.693, 1.099 and 2.303 on sight saves a great deal of time.

Depth — reading a convergence curve, and the three shapes it takes

Section 4.8 covered the two learning curves. Three specific patterns recur often enough to name.

Flat at ln K from the start. Nothing is learning. Check the learning rate is not zero or absurdly small, that the labels are actually connected to the inputs, that the loss is the right one for the output layer, and — per 4.7 — that the initialisation is not degenerate. This is a bug, not a tuning problem.

Falls, then a sudden spike, then recovery or divergence. A single large gradient, per 4.5. Log the gradient norm, add clipping, and checkpoint every epoch so a run that destroys itself at epoch 21 does not also destroy epochs 1 to 20.

Smooth training curve, validation curve turning up. Ordinary overfitting. Early stopping with weight restoration is free and comes first; then the regularisers of 4.6, then more data.

And one non-pattern worth being relaxed about: a noisy validation curve is normal on small validation sets. A curve that jumps by a couple of points between epochs on 200 validation examples is measuring sampling noise, not model quality, and smoothing it or averaging the last few epochs is more honest than reading the single best point.

The visualization

The same predictions under four metrics
interactive — move a class threshold and watch them disagree
top-1 accuracy0.833the argmax
top-2 accuracy1.000true class in the top two
macro AUC1.000unchanged by scaling
hook recall0.500the class being missed
 

Scale the hook column up and top-1 accuracy climbs to 1.000 while macro AUC does not move at all, because multiplying one column by a positive constant cannot change the ranking within it. That is the demonstration in one gesture: AUC is a property of the ranking and accuracy is a property of the comparison, and a scaling changes only the second.

The pitfalls

Where marks are lost
  • Quoting top-K where being close has no value. Top-2 on a three-class decision is close to meaningless and inflates the result.
  • Reporting an average AUC without saying macro or micro. They differ — 1.0000 and 0.9844 on the very same predictions here.
  • Concluding from high AUC that the model is accurate. Worked 5.5: three perfect AUCs and 83% accuracy. AUC is blind to competition between classes.
  • Concluding from mediocre accuracy that the model is bad. Check the AUCs first. A threshold problem and a representation problem need completely different work.
  • Reporting accuracy without per-class recall. Here it conceals that one class in three is being found half the time.
  • Forgetting the chance baseline. Accuracy against 1/K, cross-entropy against ln K, top-5 on 1000 classes against 0.5%.
  • Reading a single best epoch off a noisy validation curve. On small validation sets that is sampling noise, and 4.8's rule about reporting a spread applies.

Practice

P5.5.1 (direct) — A 4-class model predicts (0.15, 0.35, 0.30, 0.20) and the true class is the third. Give the top-1 and top-2 verdicts, the cross-entropy loss, and the gradient at the logits.
ranking: class 2 (0.35) > class 3 (0.30) > class 4 (0.20) > class 1 (0.15) true class 3 ranks 2nd top-1: wrong top-2: correct L = −ln p₃ = −ln 0.30 = 1.2040 compare with chance: ln 4 = 1.3863 ∂L/∂z = p − y = (0.15, 0.35, 0.30 − 1, 0.20) = (0.15, 0.35, −0.70, 0.20) components sum to 0, as always.

A loss of 1.2040 against a chance value of 1.3863 says this prediction is barely better than a uniform guess, which the probabilities confirm — the top two are 0.35 and 0.30. The gradient pushes the true logit up and all three others down, hardest against class 2, the confident wrong answer.

P5.5.2 (variation) — For Worked 5.5's predictions, find a threshold on the hook score alone that classifies all four hooks correctly, and explain why this is possible when the argmax fails.
hook scores: true hooks (images 9-12): 0.50, 0.35, 0.60, 0.35 minimum 0.35 non-hooks (images 1-8): 0.10, 0.15, 0.25, 0.10, 0.20, 0.25, 0.25, 0.15 maximum 0.25 any threshold in (0.25, 0.35] separates them perfectly. take t = 0.30: all four hooks flagged, no false positives. recall 1.0000, precision 1.0000, and this is why AUC = 1.0000.

The argmax fails on images 10 and 12 not because the hook score is too low but because the bar score is higher — 0.35 against 0.35 on image 10, where the tie breaks the wrong way, and 0.35 against 0.40 on image 12. The hook evidence was perfectly adequate; it lost a comparison.

Which points at the practical fix from 2.4.4: the decision rule need not be argmax. Per-class thresholds, or a per-class scaling applied before the comparison, convert this from a modelling problem into a one-line calibration change. And note the caveat — thresholds must be chosen on validation data and reported as such, or you have tuned on the test set.

P5.5.3 (interpretation) — An 8-class model reports macro AUC 0.94 and micro AUC 0.99. Class frequencies range from 45% to 2%. What is happening?

The gap between the two averages is the finding, and it points straight at the rare classes. Micro pools every prediction, so the 45% class dominates it; macro weights all eight classes equally, so a rare class scoring poorly drags it down. A micro of 0.99 with a macro of 0.94 means the common classes are being handled superbly and at least one rare class is not.

What to do about it. Report the per-class AUCs rather than either average — the mean of eight numbers is hiding which one is the problem, and eight numbers fit in a table. Report per-class recall alongside, since a rare class can have a respectable AUC and still almost never be predicted by the argmax, exactly as hook did in Worked 5.5. And put confidence intervals on the rare classes: at 2% of a 2,000-example validation set that is 40 examples, so its AUC is estimated from very little and could move by several points on resampling.

And decide which average the task calls for before quoting one. If the rare classes are rare but important — a rare disease, a rare fault — macro is the honest headline and micro is close to misleading. If the goal is aggregate throughput, micro is defensible. Quoting whichever is higher is not.

P5.5.4 (synthesis) — Using 2.4.2, 2.4.3 and 2.4.6, state what carries over from the binary case unchanged, what needs a decision, and what is genuinely new.

Unchanged: everything computed from a confusion matrix. Per-class precision, recall and F1 are defined identically once you fix a class as positive and pool the rest; the confusion matrix simply becomes K×K instead of 2×2, and reading it by row gives recall and by column gives precision exactly as in 2.4.1. Cross-entropy generalises directly, with ln K replacing ln 2 as the chance baseline. Calibration and 2.4.6's temperature scaling apply without modification, since a single T divides all K logits.

Needs a decision: how to aggregate. Binary gave one number; multi-class gives K, and combining them requires a choice. Macro treats classes equally, micro treats predictions equally, and weighted averaging sits between. There is no default that is right for every task, so the choice must be stated and justified — and this is the same structure as 2.4.2's β in the F-score, where the metric embeds a value judgement that has to be declared.

Genuinely new: competition between classes. In a binary problem the score and the decision are the same thing up to a threshold, so AUC and accuracy could not disagree the way they do here. With K classes the decision is a comparison across K scores, and a class can be ranked perfectly within its own column while losing every comparison — which is exactly Worked 5.5's 1.0000 against 0.8333. Nothing in Unit 2B has this shape, and it is the one place where the binary intuition genuinely misleads.

The practical consequence closes the loop with 2.4.4: because the decision is a comparison rather than a threshold, the per-class thresholds become a tunable object in their own right, and adjusting them is often a far cheaper improvement than retraining.


R1

Cheat Sheet

Every formula in this unit, plus the spine's numbers.

5.1 DL vs ML

The difference is learned versus designed representations, not layer count.
Classical: human designs features, model fits weights.
Deep: model fits features and weights together, against the same loss.
Feature hierarchy: edges → textures → parts → objects.
Tabular data: gradient boosting still wins, because convolution's and recurrence's assumptions are both false there.
ImageNet 2012: 15.3% vs 26.2% top-5 error.

5.2 Architecture

Block: conv 3×3 → BN → ReLU, twice, then downsample.
Double the channels when you halve the resolution.
GAP instead of flatten: 25,089,000 → 513,000 on 7×7×512 → 1000. A factor of 49.
1×1 conv = learned mixing across channels. Bottleneck 256→64→64→256 costs 70,016 against 590,080 — an 88% saving.
Drop the conv bias when BN follows.

5.2 Residual connections

y = F(x) + x, so ∂y/∂x = ∂F/∂x + 1
The identity becomes the easy case, not a target.
Fixes degradation: a 56-layer plain net had higher TRAINING error than a 20-layer one.
Identity shortcut: 0 params. Projection when channels change: (Cᵢₙ+1)Cᶜᵘᵗ.
Receptive field: r ← r + (k−1)j, then j ← j·s.

5.3 Transfer learning

Feature extraction freeze all, train head — 1,539 of 14,753,155 = 0.01%
Fine-tune top unfreeze last blocks — block 5 alone is 48% of the network
Full fine-tune everything, low rate, lots of data
Head rate 10⁻³; fine-tune rate 10⁻⁵ to 10⁻⁴.
Train the head to convergence FIRST, then unfreeze.
Traps: BatchNorm still updating when "frozen"; wrong preprocessing.

5.3 Which strategy

similar + small → freeze all
similar + large → fine-tune everything
different + small → freeze early, retrain late (hardest)
different + large → fine-tune all, or from scratch
Early layers are generic and transfer; late layers are task-specific and do not.

5.4 Simple RNN

hᵗ = tanh(Wₕₓxᵗ + Wₕₕhᵗ₋₁ + b)
Same weights every step — weight sharing over time.
Params: h(d + h) + h, independent of sequence length.
BPTT = unroll, backprop, sum the shared gradients.
∂hᵗ/∂h₁ = ∏ wₕ·tanh′: at wₕ=0.5, 20 steps gives 1.9×10⁻⁶.
Only wₕ = 1 exactly is stable.

5.4 LSTM

f, i, o = σ(·)   g = tanh(·)
cᵗ = fᵗcᵗ₋₁ + iᵗgᵗ   hᵗ = oᵗ tanh(cᵗ)
∂cᵗ/∂cᵗ₋₁ = f exactly — the constant error carousel.
f = 0.99 over 100 steps: 0.366
plain RNN, same: 2.9×10⁻³¹ — a factor of 10³⁰.
Params: 4[h(d+h)+h]. GRU: 3[·]. Try GRU first.

5.4 The pattern

When a repeated multiplication destroys a signal, add instead.
Residual: y = F(x) + x for depth
LSTM: cᵗ = fcᵗ₋₁ + ig for time
Attention: a direct path of length 1, at O(T²) cost
Clipping fixes explosion only; it cannot inflate a vanished gradient.

5.5 Multi-class metrics

top-K: true class within the K highest. Rises with K; = 1 at K = classes.
One-vs-rest AUC, then macro (classes equal) or micro (predictions equal).
Confusion matrix: read rows for recall, columns for precision.
Loss = ln K means nothing was learned: 0.693, 1.099, 2.303, 6.908.

5.5 The trap

Every AUC can be 1.0000 while accuracy is 0.8333.
AUC asks a question within a class column: does it rank its own members first?
Argmax asks a question across columns: is it the largest?
A class can be perfectly rankable and lose every comparison.
Diagnosis: high AUC + poor accuracy = a threshold problem, not a model problem.

Convergence curves

Flat at ln K → nothing is learning; a bug, not tuning.
Sudden spike → one large gradient; clip and checkpoint.
Validation turning up → overfitting; early stopping first.
Noisy validation on a small set is sampling noise, not model quality.

Architectures by name

LeNet-5 1998, 60 K — convolution works
AlexNet 2012, 62 M, 15.3% — ReLU, dropout, GPUs
VGG-16 2014, 138 M, 7.3% — only 3×3, stacked
GoogLeNet 2014, 6.8 M, 6.7% — beat VGG with 5% of the parameters
ResNet-50 2015, 25.6 M, 5.25% — residual connections
ResNet-152, 60.2 M, 4.49%

The spine, end to end

Reproduce this column and you have the unit
QuantityValueSection
Row sums: ring, bar, hook2 4 4 4 4 2 / 4 4 4 4 4 4 / 0 4 4 4 4 45.0
Hand-crafted features: centre 2×2ring 0, bar 4, hook 45.1
The same after a one-pixel shiftring 2 — the rule breaks5.1
Bottleneck saving, 256→25670,016 against 590,080, 88.1%5.2
GAP against flatten, 7×7×512 → 1000513,000 against 25,089,0005.2
Residual block, 128 channels295,680; projection at 64→128 adds 8,3205.2
Small CNN for the three shapes387 parameters5.2
Backbone / head14,751,616 / 1,5395.3
Trainable under feature extraction0.01%5.3
Trainable when block 5 is unfrozen48.00%5.3
RNN separation of bar/hook at t=11.5232 = 2 tanh(1)5.4
The same at t=60.0000395.4
And at every wₕ from 0.3 to 1.0never above 0.000065.4
LSTM cell separation at every step1.52325.4
Carousel: f=0.99 vs plain RNN, 100 steps0.366 against 2.9×10⁻³¹5.4
LSTM params, d=100 h=256365,568 (GRU 274,176, RNN 91,392)5.4
Twelve predictions: top-1 / top-20.8333 / 1.00005.5
Macro AUC on the same predictions1.0000 (micro 0.9844)5.5
Per-class recall1.0000, 1.0000, 0.50005.5
Cross-entropy, against chance0.6340 against ln 3 = 1.09865.5

R2

Mixed Self-Test

Ten questions, unlabelled by section.

Q1. Count the parameters of a bottleneck block taking 512 channels to 512 via a 128-channel middle, with BatchNorm after each convolution. Compare with the direct 3×3.
1×1, 512 → 128: (1·1·512 + 1) × 128 = 513 × 128 = 65,664 BN: 2 × 128 = 256 3×3, 128 → 128: (3·3·128 + 1) × 128 = 1153 × 128 = 147,584 BN: 2 × 128 = 256 1×1, 128 → 512: (1·1·128 + 1) × 512 = 129 × 512 = 66,048 BN: 2 × 512 = 1,024 total = 280,832 direct 3×3, 512 → 512: (3·3·512 + 1) × 512 = 4609 × 512 = 2,359,808 (+1,024 BN) saving: 1 − 280,832/2,360,832 = 88.1%

The same 88% as Worked 5.2a at 256 channels, which is no coincidence: the ratio depends on the compression factor (4× here) and not on the absolute width. That is why the bottleneck pattern scales to any channel count and why every architecture after 2015 uses it.

Q2. A plain RNN has wₕ = 1.2. Give the gradient factor across 30 steps and say what will happen during training.
upper bound (taking tanh′ = 1 throughout): 1.2²⁹ = 197.8 — nearly 200× amplification with a realistic tanh′ ≈ 0.8: (1.2 × 0.8)²⁹ = 0.96²⁹ = 0.31

Which of the two happens depends on where the units sit, and that is the honest answer. Early in training, with small weights and pre-activations near zero, tanh′ is close to 1 and the gradient explodes — expect a loss spike or nan within the first epochs, per 4.4. Once the units saturate, tanh′ falls and the same network vanishes instead.

So a recurrent network can suffer both failures in one run, at different times, which is why wₕ > 1 is not a fix for vanishing gradients. Clip the gradients to handle the explosion; use gates to handle the vanishing. The two problems need different tools.

Q3. You have 500 satellite images in 6 classes and an ImageNet-pretrained ResNet-50 (25.6 M parameters). Give your strategy, the trainable count, and two domain-specific cautions.

Small dataset, different domain — the hardest quadrant. Freeze most of the backbone and retrain only the last block plus a new head, at a low learning rate, after first training the head alone.

head after global average pooling (2048-vector): (2048 + 1) × 6 = 12,294 feature extraction alone: 12,294 trainable of 25.6 M = 0.05% 500 images / 12,294 params = 0.04 examples per parameter → regularise the head and rely on early stopping

Caution 1: augmentation is different here. Satellite imagery has no canonical orientation, so rotations by any angle and both flips are valid and are unusually valuable — unlike photographs, where an upside-down car is not a normal input. This is close to free extra data.

Caution 2: the split must respect geography. Tiles cut from the same scene are near-duplicates, so a random split puts nearly identical images in train and test and inflates the score badly. Split by scene or region, which is 2.1's leakage rule in its satellite form.

And note that ImageNet features transfer less well here than for photographs — overhead imagery has different scale, texture and colour statistics — so consider a backbone pretrained on remote-sensing data if one is available, or self-supervised pretraining on your own unlabelled tiles.

Q4. An LSTM has cᵗ₋₁ = −1.5, f = 0.95, i = 0.10, g = 0.80, o = 0.60. Compute cᵗ and hᵗ, and describe the cell's behaviour in words.
cᵗ = f·cᵗ₋₁ + i·g = 0.95(−1.5) + 0.10(0.80) = −1.425 + 0.080 = −1.3450 hᵗ = o · tanh(cᵗ) = 0.60 × tanh(−1.3450) = 0.60 × (−0.8730) = −0.5237

The cell is holding on to something and largely ignoring the present. The forget gate at 0.95 retains almost all of the previous state, and the input gate at 0.10 admits only a tenth of a candidate that points the other way — so the state barely moves, from −1.500 to −1.345. The output gate at 0.60 then exposes about 60% of the (saturated) cell to the rest of the network.

This is exactly the configuration Worked 5.4b idealised: a unit that latched a value earlier in the sequence and is now protecting it. Over 30 more steps at f = 0.95 the retained fraction would be 0.95³⁰ = 0.21, so the memory is long but not permanent.

Q5. A 3-class model outputs (0.45, 0.40, 0.15) for an example whose true class is the second. Give the loss, the gradient at the logits, and whether top-1 and top-2 are satisfied.
true class is 2, so y = (0, 1, 0) L = −ln(0.40) = 0.9163 chance is ln 3 = 1.0986 ∂L/∂z = p − y = (0.45, 0.40 − 1, 0.15) = (0.45, −0.60, 0.15) sum = 0 ✓ ranking: 0.45 > 0.40 > 0.15, so the true class ranks 2nd top-1 wrong top-2 correct

A loss of 0.9163 against a chance value of 1.0986 says the model has learned something but very little on this example. Note that the gradient magnitude on the true class, 0.60, is larger than on either wrong class, so the update pushes hardest in the right direction — and that the near-tie between 0.45 and 0.40 is exactly the situation Worked 5.5 showed can produce perfect AUC with imperfect accuracy.

Q6. Compute the receptive field of a network with layers: conv 3×3, conv 3×3, pool 2×2, conv 3×3, pool 2×2, conv 5×5.
r = 1, j = 1. per layer: r ← r + (k − 1)j, then j ← j · s conv 3×3 s=1: r = 1 + 2(1) = 3 j = 1 conv 3×3 s=1: r = 3 + 2(1) = 5 j = 1 pool 2×2 s=2: r = 5 + 1(1) = 6 j = 2 conv 3×3 s=1: r = 6 + 2(2) = 10 j = 2 pool 2×2 s=2: r = 10 + 1(2) = 12 j = 4 conv 5×5 s=1: r = 12 + 4(4) = 28 j = 4

28 input pixels. The final 5×5 contributed 16 of those 28 on its own, because by then each of its inputs summarised a 4-pixel step. That is the general principle worth carrying: a kernel late in a network is worth far more receptive field than the same kernel early, which is why large kernels near the input are wasteful and why modern networks use 3×3 throughout and buy reach with downsampling instead.

Q7. A team fine-tunes a pretrained model and validation accuracy drops from 71% (feature extraction) to 44%. Training accuracy is 99%. Diagnose.

Two things are happening at once and both need fixing.

Catastrophic forgetting. Fine-tuning made things worse than freezing, which is the signature of a learning rate that destroyed the pretrained features. If they trained at the head's 10⁻³ rather than 10⁻⁵, the backbone moved far from its pretrained solution within the first epoch, and what remains is effectively a randomly initialised network trained on a small dataset. Check also whether the backbone was unfrozen from step one with a random head attached, which sends meaningless gradients into good weights.

Overfitting. 99% training against 44% validation is a 55-point gap, consistent with millions of newly trainable parameters against a dataset that only ever supported the head.

What to do. Return to feature extraction and confirm 71% reproduces, which establishes the baseline. Then unfreeze only the last block, at 10⁻⁵, after the head has converged, and check that validation improves rather than assuming it will. Verify the BatchNorm layers are genuinely in inference mode and the preprocessing matches the source model. And accept the possible conclusion: with a small dataset, feature extraction may simply be the better strategy, and 71% may be the honest ceiling until more data arrives.

Q8. Explain why a bidirectional LSTM helps on sentiment classification but cannot be used for real-time speech transcription.

Why it helps. A bidirectional layer runs two independent recurrent passes — one left to right, one right to left — and concatenates their states. Every position therefore has access to context from both directions, and no position is far from some output: a word at the start of a 300-word review is 300 steps from the end of the forward pass but only 1 step from the start of the backward pass. That halves the effective path length and, for classification tasks where the whole input is available, is usually one of the cheapest available improvements. It doubles the parameters and the compute.

Why it cannot stream. The backward pass starts at the last element, so it cannot begin until the sequence has ended. For live transcription there is no last element — the audio is still arriving — so the model would have to wait for the speaker to stop before producing any output at all. The latency is unbounded and the architecture is simply unavailable, however well it scores offline.

What is used instead. A unidirectional model, or a bidirectional one over a fixed lookahead window of a few hundred milliseconds, which buys some right-context at a bounded and acceptable latency cost. This is a good example of a constraint that comes from deployment rather than from the data, and it is exactly the kind of thing 4.8's reporting checklist should surface before a model is chosen.

Q9. A 5-class model reports accuracy 0.62, macro AUC 0.97, and per-class recalls 0.95, 0.93, 0.90, 0.22, 0.10. What is wrong and what would you do?

The pattern is Worked 5.5's, magnified. A macro AUC of 0.97 says each class's score column ranks its own members near-perfectly — so the representation is good and the model can see all five classes. Meanwhile two classes are recovered 22% and 10% of the time by the argmax. The scores are fine; the comparison between them is not.

The near-certain cause is class imbalance. If classes 4 and 5 are rare, cross-entropy training drives their predicted probabilities down across the board — the model learns that guessing a common class is usually right — so their scores, while correctly ordered, sit below the common classes' scores almost everywhere. Confirm by checking the class frequencies and the mean predicted probability per class.

The fixes, cheapest first. Per-class thresholds or a per-class scaling applied before the argmax, chosen on validation data — this is nearly free and, given AUC 0.97, should recover most of the loss. Then class weighting in the loss, which addresses the cause during training. Then resampling, or focal loss. Retraining the architecture is the last thing to try, because the AUCs say the representation was never the problem.

And report differently regardless. Accuracy 0.62 as a headline conceals that three classes work and two do not. Per-class recall in a table, with the class frequencies beside it, is the honest presentation — 2.4.2's argument, unchanged.

Q10. Explain in what precise sense a residual connection and an LSTM cell state are the same idea, and what the next step in that progression was.

Both replace a multiplicative chain with an additive one, for the same reason and with the same effect on the gradient.

A plain deep network composes transformations, so the gradient from the loss to layer 1 is a product of L local derivatives; section 4.3 measured what that costs. A plain recurrent network composes the same transformation T times, so the gradient across time is a product of T factors — and Worked 5.4a measured that as a separation of 0.000039 after five steps.

The residual block writes y = F(x) + x, giving ∂y/∂x = ∂F/∂x + 1. The LSTM writes cᵗ = f cᵗ₋₁ + i g, giving ∂cᵗ/∂cᵗ₋₁ = f. In both cases there is now a path whose local derivative is at or near 1 regardless of what the learned transformation does, so the product across many steps stays near 1 instead of collapsing. Worked 5.4b's cell holds a separation of 1.5232 at every step, against the plain RNN's 0.000039 — the same rescue the skip connection performs for depth.

The next step was to remove the chain altogether. If an additive path of derivative 1 rescues a chain of length T, a direct connection makes the chain length 1. Attention lets every position read every other position directly, weighting them by a softmax over similarity — so nothing has to survive a sequence of updates and, as a bonus, the positions can be computed in parallel rather than one after another. The price is O(T²) time and memory instead of O(T).

Stated as a progression: multiply, then add, then connect directly. Each step shortens the path from a signal to the place it is needed, and each was the dominant architectural idea of roughly half a decade.


R3

Where This Goes Next

One unit left, and it changes the problem rather than the model.

What Unit 5 established, in one paragraph

Deep learning is not defined by depth but by learning the representation rather than designing it — and section 5.1's hand-crafted rule, exact on the three shapes and broken by a one-pixel shift, shows both why that matters and why it is not always the right choice. Architecture is then a series of decisions about where parameters go: global average pooling instead of flattening saves a factor of 49, a 1×1 bottleneck saves 88%, and GoogLeNet beat VGG with 5% of the parameters. Residual connections made depth possible by turning a product into a sum. Transfer learning made small datasets viable by reusing a hierarchy somebody else paid for, with the whole decision reducing to where to draw the freeze line. Recurrence brought section 4.3's argument into the time axis, where a plain cell lost a first-step difference by a factor of 39,000 in five steps and a gate held it exactly. And multi-class evaluation produced the sharpest single result in the unit: three AUCs of exactly 1.0000 alongside an accuracy of 0.8333, which is a threshold problem wearing the costume of a model problem.

Unit 5 → Unit 6, and beyond the course
From hereReappears as
5.1 Learned representationsUnit 6's function approximation: deep Q-learning replaces a lookup table with a network, so the state representation becomes learned rather than enumerated.
5.2 Convolutional backbonesThe standard front end whenever a reinforcement-learning agent sees pixels rather than coordinates.
5.3 Transfer and pretrainingThe dominant paradigm outside this course: self-supervised pretraining then fine-tuning is how every current language and vision model is built.
5.4 Sequence models and gatingUnit 6's episodes are sequences, and the credit-assignment problem there — which earlier action caused this reward — is the same long-range problem in a new form.
5.4 Attention as a direct pathTransformers, which are outside this syllabus but are what the whole progression was heading toward.
5.5 Metrics that disagreeUnit 6 has no labels and no accuracy at all — reward replaces them — so the question of what a number is entitled to claim becomes sharper still.
Before you move on

Eight things you should be able to do from a blank page. Say what distinguishes deep learning from classical machine learning without mentioning layer count. Count the parameters of a bottleneck block and of a residual block. Compute a receptive field through convolutions and pooling. Choose a transfer-learning strategy from dataset size and domain similarity, and count what is trainable. Write the LSTM's four gate equations and the two state updates. Explain the vanishing gradient over time and why wₕ > 1 is not a fix. Compute top-K accuracy, per-class recall and a one-vs-rest AUC. And explain how a residual connection and a cell state are the same idea.

Unit 6 assumes none of the architecture material, but it does assume gradient descent and the habit of asking what a reported number actually measures.

Further reading

  • Géron, Hands-On Machine Learning, 3rd ed., ch. 14–16 — the prescribed textbook. Chapter 14 covers CNNs and the classic architectures, 15 covers RNNs, 16 covers sequence processing and attention. The closest match to this unit.
  • He et al., "Deep Residual Learning for Image Recognition" (2015) — the ResNet paper. Short, and the degradation experiment of P5.2.3 is on its first page, which makes the motivation unusually clear.
  • Olah, "Understanding LSTM Networks" — freely available online and still the clearest visual explanation of the gates. Read it if section 5.4's equations did not land.
  • Vaswani et al., "Attention Is All You Need" (2017) — outside the syllabus, but it is where the progression of Q10 arrives and it is worth reading once you can state why recurrence was a problem.
  • Yosinski et al., "How transferable are features in deep neural networks?" (2014) — measures layer by layer exactly how much transfers, and is the empirical basis for section 5.3's four-quadrant table.
  • Grinsztajn et al., "Why do tree-based models still outperform deep learning on tabular data?" (2022) — the careful version of section 5.1's depth box, with experiments rather than assertion.
CSUC301 Machine Learning · Unit 5 of 6 · Deep Learning Foundation · CO2, CO3
Spine: three 6×6 shapes — a ring, a bar, and a hook — read once as whole images by a convolutional network and once as sequences of row sums by a recurrent one. The bar and the hook differ only in their first row. Every numerical value in this file was computed rather than estimated, and every widget was driven through its range and checked against the printed worked examples.
Previous: Unit 4 — Neural Networks · Next: Unit 6 — Reinforcement Learning Fundamentals