Phase 4 - Sequence Models with RNNs
Everything before this phase assumed a fixed-size input. Sequences break that twice
over: their order carries meaning, and their length varies. A recurrent layer
handles both by walking the sequence one element at a time and carrying a state forward —
so its parameter count is independent of length (SimpleRNN(32) is 2,080 parameters for
20 timesteps or 20,000).
The measurements in this phase are unusually blunt about what that buys. On 5,000 IMDB
reviews, a SimpleRNN(32) scored 0.5856 while averaging the same embeddings and
throwing away order entirely scored 0.8004. Gated cells then took it to 0.8156.
Sequence modelling is a story about a mechanism that does not work until it is fixed
twice.
The pages
Section titled “The pages”| # | Page | The measured headline |
|---|---|---|
| 431 | Intro to RNNs | the cell in five lines of NumPy, matching Keras at 2.68e-07; order is worth +0.0744 to the RNN and +0.0000 to a bag of words — which still won |
| 431.5 | Padding, Masking and Variable-Length Sequences | post-padding without a mask scores 0.5036 — chance — with no error and a falling loss curve |
| 432 | LSTM & GRU Networks | gates re-derived in NumPy to 6.56e-07; +0.23 accuracy over a SimpleRNN, and at 80 steps MAE 0.0056 against 0.2984 |
| 433 | Time Series Forecasting | persistence 0.3253, noise floor 0.0965, Dense 0.1210 against GRU 0.1146 at a quarter of the cost |
| 434 | Advanced Recurrent Layers | of three refinements only dropout helped (+0.0104); recurrent_dropout cost 2.0× the wall-clock to lose 0.0080; stacking lost at every depth; Bidirectional’s +0.0188 fell to +0.0024 at matched width |
| 434.5 | Attention Before Transformers | the fixed-state bottleneck, measured: 0.0017 exact matches against 1.0000, and a per-position split showing the year at 1.0000 and the day’s last digit at 0.0908 |
flowchart TD A["431 The recurrence
h_t = tanh(Wx·x + Wh·h + b)"] --> B["431.5 Padding & masking
pre/post, mask_zero"] B --> C["432 Gated cells
LSTM, GRU"] C --> D["433 Forecasting
windows, baselines, horizons"] C --> E["434 Refinements
dropout, stacking, bidirectional"] C --> G["434.5 Additive attention
the bottleneck, removed"] D --> F["Phase 5: attention
replaces recurrence"] E --> F G --> F
Three things this phase measures that most treatments assert
Section titled “Three things this phase measures that most treatments assert”- A
SimpleRNNis not a working sequence model at 200 timesteps. It lost to embedding-averaging by 0.2148. The gap is not a tuning failure — it is the vanishing-signal problem that gated cells were invented for, and the phase measures it before fixing it. - The padding bug is silent. Identical code with
padding="post"and no mask converged smoothly to 0.5036 on a balanced binary task. Nothing warns you; the loss curve looks healthy; only the accuracy tells you, and only if you know what chance is. - A flattened
Denselayer is a serious forecasting baseline. It scored 0.1210 against the GRU’s 0.1146 in a quarter of the wall-clock, with the irreducible noise floor at 0.0965. Recurrence pays when the useful information is far back and order-dependent — not merely because the data has a time axis.
The habit this phase is really teaching
Section titled “The habit this phase is really teaching”Every page here compares against something that costs nothing:
| Task | The do-nothing baseline | What it exposed |
|---|---|---|
| sentiment | average the embeddings (0.8004) | the SimpleRNN was not working |
| masking | chance on a balanced task (0.5000) | post-padding scored 0.5036 |
| long-range recall | predict the mean sum (0.3324) | the SimpleRNN reached 0.2984 — a tenth of the way — while the GRU reached 0.0056 |
| forecasting | persistence (0.3253), noise floor (0.0965) | the GRU’s win over Dense was 0.0064 |
| date normalisation | the same model without attention (0.0017) | attention reached 1.0000 exact match |
A sequence model that has not been compared against one of these has not been measured. That is why the same discipline reappears in Phase 5, where the baseline for a transformer is often a bag of words, and in Phase 6, where the baseline for a generative model is the training data itself.
What carries forward
Section titled “What carries forward”| Idea from this phase | Where it comes back |
|---|---|
| padding, masks, and which layers honour them | attention masks in every transformer |
| additive state updates under a gate | residual streams, gated MLPs |
return_sequences and per-timestep outputs | seq2seq decoders, per-token losses |
| layer normalisation over features, not batch | every transformer block |
| chronological splits and leakage | any temporal evaluation, including RL |
-
A `SimpleRNN(32)` scored 0.5856 on IMDB while averaging the same embeddings - discarding order entirely - scored 0.8004. What does the gap show?
pch.quizShowAnswer
B — That the SimpleRNN is not functioning as a sequence model at 200 timesteps: it is losing signal across the chain faster than it gains from order
-
Identical code with `padding="post"` and no mask converged smoothly to 0.5036 on a balanced binary task. Why is this the most dangerous bug in the phase?
pch.quizShowAnswer
B — Because nothing signals it - no error, no warning, and a healthy-looking falling loss curve - so it is only visible if you know what chance-level accuracy is for your task
-
A flattened `Dense` layer scored 0.1210 on forecasting against the GRU's 0.1146, with the irreducible noise floor at 0.0965. What does the noise floor add?
pch.quizShowAnswer
B — It converts a 0.0064 gap into a judgement: both models are close to the best achievable score, so there is very little left to win and 4.3x the wall-clock buys almost none of it
-
Of three refinements, `recurrent_dropout` cost 2.0x the wall clock to LOSE 0.0080, and `Bidirectional`'s +0.0188 fell to +0.0024 once width was matched. What does the width-matching change?
pch.quizShowAnswer
B — A bidirectional layer doubles the parameters, so the naive comparison credits attention-to-both-directions for a gain that is mostly extra capacity
-
The LSTM held MAE 0.0152 at 100 timesteps but failed at 200, landing on the do-nothing baseline. Why report the failure column?
pch.quizShowAnswer
B — Because it bounds the claim: gates raise the length at which recurrence works rather than removing the limit, and the reader needs to know where the limit sits
pch.coffeeTagline
pch.coffeeCtapch.feedbackHeading
pch.feedbackSubheading