The Transformer Architecture
A transformer block is four things stacked: layer normalisation, multi-head attention, a residual connection, and a small feed-forward network — with another norm and residual around it. The attention page measured the attention. This page measures everything around it, by removing one piece at a time.
The result is uncomfortable and worth confronting directly: at one block, every single ablation improved the score.
| Setting | Parameters | Best validation accuracy | vs full |
|---|---|---|---|
| full block | 328,577 | 0.8462 | — |
| no positional embeddings | 328,577 | 0.8405 | −0.0058 |
| no feed-forward | 324,321 | 0.8515 | +0.0052 |
| no residuals | 328,577 | 0.8562 | +0.0100 |
| no layer normalisation | 328,449 | 0.8665 | +0.0203 |
The full block was the worst configuration tested. Rather than explain that away, the page repeats the experiment at depth — where the answer changes for one component and does not for another.
What you’ll learn
Section titled “What you’ll learn”- Where a block’s parameters actually live: 95.54% of them are the token embedding.
- The measured comparison against recurrence, including a transformer that reaches its best accuracy in epoch 1.
- What each component contributes at one block — all of them negative except positions.
- What changes at four blocks: removing layer norm costs 0.0612, while removing residuals still does not hurt.
- Why the pooled-output design makes the positional ablation a measurement of the task, not the architecture.
The block, and where its parameters go
Section titled “The block, and where its parameters go”def block(x, width, heads):
normed = keras.layers.LayerNormalization(epsilon=1e-6)(x)
attention = keras.layers.MultiHeadAttention(num_heads=heads,
key_dim=width // heads)(normed, normed)
x = keras.layers.Add()([x, attention]) # residual
normed = keras.layers.LayerNormalization(epsilon=1e-6)(x)
hidden = keras.layers.Dense(width * 2, activation="relu")(normed)
return keras.layers.Add()([x, keras.layers.Dense(width)(hidden)]) # residual| Component | Parameters | Share |
|---|---|---|
| token embedding | 320,000 | 95.54% |
| position embedding | 6,400 | 1.91% |
| attention (Q, K, V, out) | 4,224 | 1.26% |
| feed-forward | 4,192 | 1.25% |
| layer norms (×2) | 128 | 0.04% |
| total | 334,944 |
This matters for reading the ablations below. Removing the feed-forward network deletes 1.25% of the parameters; removing both layer norms deletes 0.04%. These are not capacity experiments — they are experiments about optimisation.
Against recurrence
Section titled “Against recurrence”| Family | Parameters | Best validation accuracy | Seconds | Epoch 1 |
|---|---|---|---|---|
| bag of words | 320,033 | 0.8465 | 39.1 | 0.7303 |
| GRU | 326,369 | 0.8210 | 214.9 | 0.8018 |
| LSTM | 328,353 | 0.8415 | 264.9 | 0.8130 |
| transformer | 328,577 | 0.8462 | 383.5 | 0.8462 |
The transformer’s −0.0002 against a bag of words is the same lesson as the sentiment bake-off: on this task, at this scale, architecture is not the binding constraint. What is visible is convergence speed — one epoch against six.
The ablations, at one block
Section titled “The ablations, at one block”The positional ablation measures the task
Section titled “The positional ablation measures the task”Removing positions cost only 0.0058, and the reason is structural: this classifier ends
with GlobalAveragePooling1D. Averaging is permutation-invariant, so with no positional
information the whole model becomes a bag of words with an attention-weighted average
inside it — and the bag of words scores 0.8465. The ablation is therefore a measurement
of how much sentiment needs word order, which the
intro-to-RNNs page
put at +0.0744 for a recurrent model and +0.0000 for averaging.
For a generative transformer this ablation is not available: without positions a
language model cannot tell the cat sat from sat cat the, and its loss would reflect
that immediately.
The same ablations at depth
Section titled “The same ablations at depth”If residuals and normalisation exist to make deep stacks trainable, then the deep column should punish removing them. Same code, 1 block against 4:
| Setting | 1 block | 4 blocks | Deep − shallow |
|---|---|---|---|
| full | 0.8238 | 0.8090 | −0.0148 |
| no residuals | 0.8357 | 0.8190 | −0.0167 |
| no layer normalisation | 0.8515 | 0.7903 | −0.0612 |
Two conclusions, stated at the strength the data supports:
- Layer normalisation’s value is depth. At one block it is 128 wasted parameters; at four blocks it is the difference between 0.8090 and 0.7903. That is a direct confirmation, and it is why every transformer has it.
- Residual connections are not vindicated at four blocks. They remain slightly negative. The published argument for residuals concerns dozens of layers, where the gradient path length is the binding problem — the same claim the ResNet page also failed to reproduce at 12 convolutions. Two independent failures to reproduce at small depth, in the same direction, is consistent with the claim being about scale rather than being wrong.
flowchart TB A["tokens"] --> B["embedding + positions"] B --> C["LayerNorm"] C --> D["MultiHeadAttention"] D --> E["+ residual"] B --> E E --> F["LayerNorm"] F --> G["Dense -> Dense"] G --> H["+ residual"] E --> H H --> I["GlobalAveragePooling1D"] I --> J["Dense 1, sigmoid"] K["at 1 block: every removal helps"] -.-> H L["at 4 blocks: removing LayerNorm costs 0.0612"] -.-> H
Pitfalls
Section titled “Pitfalls”- Assuming every component raises accuracy. At one block, four of five ablations scored higher than the full block.
- Concluding the components are useless. Layer normalisation went from best-when- removed at 1 block to worst at 4, costing 0.0612.
- Reading an ablation as a capacity test. Both layer norms are 128 parameters — 0.04% of the model. What changes is optimisation, not capacity.
- Ablating positions on a pooled classifier and calling it an architecture result. Average pooling is permutation-invariant, so that ablation measures the task’s need for word order.
- Post-norm without warmup. This page uses pre-norm throughout;
Addthen normalise needs a learning-rate schedule to train at all. - Comparing architectures on accuracy alone. The transformer matched a bag of words (−0.0002) at 10× the cost, but reached its best score in epoch 1 against six.
- Calling this a transformer result. One block, width 32, trained from scratch on 8,000 reviews is not what the papers measure.
- A block is pre-norm → attention → residual → pre-norm → feed-forward → residual.
- At width 32 with a 10,000-word vocabulary, 95.54% of parameters are the token embedding; attention is 1.26% and both norms are 0.04%.
- Against recurrence: bag of words 0.8465, GRU 0.8210, LSTM 0.8415, transformer 0.8462 — but the transformer reached its best in epoch 1.
- At one block every ablation but positions improved the score, with no-layer-norm best at 0.8665.
- At four blocks removing layer norm cost 0.0612 against the full block’s 0.0148 — the component’s value is depth.
- Residuals stayed marginally positive-to-remove even at four blocks; that argument is about dozens of layers.
An encoder reads a sequence. Producing a different sequence needs a decoder, teacher forcing, and attention between the two: Sequence-to-Sequence Learning (Machine Translation).
-
At one block, removing layer normalisation improved accuracy from 0.8462 to 0.8665. At four blocks it dropped it to 0.7903 against the full block's 0.8090. What does that show?
This is why the ablation was repeated at depth instead of explaining the shallow result away: the prediction was specific and it held.
pch.quizShowAnswer
B — Its value is depth — it is 128 spare parameters in a shallow model and the difference between training and not training in a deeper one — This is why the ablation was repeated at depth instead of explaining the shallow result away: the prediction was specific and it held.
-
At width 32 with a 10,000-word vocabulary, what fraction of a one-block transformer's parameters is the attention mechanism?
Block parameters grow with width squared while the embedding grows linearly, so the ratio inverts in large models.
pch.quizShowAnswer
B — 1.26% — the token embedding is 95.54%, so at this scale the model is an embedding table with a transformer attached — Block parameters grow with width squared while the embedding grows linearly, so the ratio inverts in large models.
-
Removing the positional embeddings cost only 0.0058. Why is that not an argument against positional encoding?
A generative transformer cannot run this ablation at all: without positions it could not distinguish 'the cat sat' from 'sat cat the'.
pch.quizShowAnswer
B — Because the classifier ends in average pooling, which is permutation-invariant — so the ablation measures how much sentiment needs word order, not whether positions matter architecturally — A generative transformer cannot run this ablation at all: without positions it could not distinguish 'the cat sat' from 'sat cat the'.
-
The transformer scored 0.8462 and reached that in epoch 1, while the LSTM reached 0.8415 over six epochs. What is the real advantage on display?
On accuracy the transformer tied a bag of words at -0.0002 while costing ten times as much wall-clock.
pch.quizShowAnswer
B — Convergence speed — every token pair is one gradient step apart under attention, so there is no long credit-assignment chain to unroll — On accuracy the transformer tied a bag of words at -0.0002 while costing ten times as much wall-clock.
-
Residual connections were still slightly better removed even at four blocks. What is the appropriate conclusion?
Two independent failures to reproduce at small depth, both pointing the same way, is consistent with the claim being about scale rather than being false.
pch.quizShowAnswer
B — Four blocks is not deep — the published argument concerns dozens of layers, and this phase also failed to reproduce the ResNet claim at 12 convolutions, both in the same direction — Two independent failures to reproduce at small depth, both pointing the same way, is consistent with the claim being about scale rather than being false.
🧪 Try It Yourself
Section titled “🧪 Try It Yourself”pch.coffeeTagline
pch.coffeeCtapch.feedbackHeading
pch.feedbackSubheading