The Full Block & the Residual Stream
MLPs, LayerNorm, RoPE — and the residual stream as the shared memory everything reads and writes.
- → Count a transformer's parameters and say where they live
- → Explain the residual stream and virtual weights views
- → Run a logit-lens decode and interpret per-layer predictions
One block, two writes
Module 1.2 gave you attention. A transformer block is attention plus one more sublayer, wired together in a specific way that turns out to matter more than either piece:
Look at what those two lines are not. Neither says . Both say . The sublayer never replaces the running vector; it computes a correction and adds it. That single design choice — the residual connection, borrowed from ResNets — is what this whole module is about.
LayerNorm
LayerNorm standardises a vector across its own features — not across the batch, not across the sequence — then applies a learned gain and bias:
It exists to keep the stream's scale in a range where gradients behave. But it has two consequences interpretability cares about enormously, and both come from what it throws away: subtracting deletes the component along the all-ones direction, and dividing by deletes the overall magnitude. Whatever a layer writes along is invisible to every later reader; and “how loudly” the stream is speaking is normalised away before anyone listens.
Where position comes from
Attention is permutation-equivariant: shuffle the tokens and the outputs shuffle with them. Something has to break that symmetry. GPT-2 uses learned absolute positional embeddings — a second lookup table with one vector per position, added to the token embedding at the very bottom. Simple, and it hard-caps the context at however many rows the table has.
Nearly every model since 2022 uses RoPE (rotary position embeddings). Instead of adding anything to the stream, RoPE rotates the query and key vectors inside each head by an angle proportional to position, in 2-D slices. The consequence is the whole point: after rotating by and by , their dot product depends only on — the attention score sees relative position for free, and there is no table to run off the end of.
The residual stream is the object
Unroll the recursion. A 12-layer model's final vector at some position is not the output of layer 12. It is a sum:
For GPT-2 small that is 1 embedding + 144 head contributions + 12 MLP contributions, all added into the same 768-dimensional vector. Nothing was ever overwritten. Every term is still, in principle, recoverable.
Virtual weights
Because the stream is linear and additive, there is an implied weight matrix between any two components, even though no such matrix appears in the checkpoint. If head in layer 1 writes and head in layer 4 reads through , then the composed map
is a real, computable matrix describing exactly how much 's output steers 's queries. Elhage et al. call these virtual weights, and the phenomenon composition (Q-, K-, or V-composition depending on which of 's inputs is affected). You can compute the virtual weight between any pair of components in a trained model without running it on a single token.
MLPs: two thirds of the parameters
The other sublayer is almost embarrassingly plain — one hidden layer, no bells:
with of shape and by convention. It acts on one position at a time, sees nothing else, and contains roughly two thirds of every parameter in the layer stack. Whatever a transformer knows, most of it is stored here.
The useful reframing — from Geva et al. — is to read the two matrices as a lookup table. Write as a stack of rows and as a stack of columns . Then
Geva et al. found the keys are often human-legible — neurons that fire on a topic, a template, a language — and the values frequently promote a coherent set of next tokens. Module 5.2 (ROME) uses exactly this picture to locate and rewrite a specific fact.
The logit lens: reading the stream mid-flight
Here is the payoff of additivity. The model's final step is LayerNorm and then multiplication by the unembedding matrix . But the residual stream at layer 5 lives in exactly the same space as the residual stream at layer 12 — same basis, same width, same units. So nothing stops you applying that final step early:
You get a distribution over the vocabulary for every layer: the model's prediction if you cut the remaining layers off. This is the logit lens (nostalgebraist, 2020), and it is the cheapest useful interpretability tool that exists — three lines of code, no training.
Read that shape. For six layers the model is not “gradually becoming more confident” — it has no idea, and its top guess is a generic function word. Then one MLP fires and the answer appears. The remaining layers sharpen and clean up. Prediction in transformers tends to be lumpy and event-like, not smooth.
The step-through widget below walks exactly this narrative, one sublayer at a time.
Play: watch the stream fill, then count the cost
The first widget follows one token position through a 4-layer model, one sublayer at a time: what reads, what writes, how the stream accumulates, and what the logit lens says at each step. The second answers the question every architecture diagram dodges — given a config, where do the parameters actually go?
embed + position — The stream starts as the token embedding of “of” plus its positional information. It knows what word it is and where it sits. Nothing else.
Each segment is one sublayer's contribution. The final stream is literally their sum — which is why you can subtract any one of them out and ask what the model would have predicted without it.
Apply the final LayerNorm and the unembedding to the partial stream, as if the remaining layers did not exist. The answer does not fade in smoothly — it arrives.
Two things worth noticing. Moving n_heads does not change the total — heads split a fixed budget of 4·d_model², they do not add to it. And inside the layer stack, MLP beats attention 2.00:1 — at the standard 4× expansion it is always exactly 2:1, before biases.
Things to try: (1) Step the flow widget through once and watch the “sum of writes” bar — notice that the embedding is a small fraction of the final stream by the end, which is why late-layer representations barely resemble the token that produced them. (2) In the calculator, drag n_heads from 1 to 32 and confirm the total does not move: heads split a fixed budget of rather than adding to it. (3) Set d_model to 256 and push n_layers to 48, then do the opposite — d_model 2048, n_layers 4. Same rough total, wildly different models. Watch what happens to the embedding's share in each case: for small models the vocabulary table dominates everything, which is why a 50k-token vocabulary is a real design constraint at small scale and an afterthought at frontier scale.
Problem set
The parameter count is the one to do properly, by hand, before touching the widget. Getting it exactly right — to the last of the eight digits — means you understand the architecture with no gaps, and there is no other exercise in Part 1 that checks that as ruthlessly.
GPT-2 small: , , , , , , . Every linear layer has a bias; there are two LayerNorms per block plus one at the end, each with a gain and a bias; the unembedding is tied to the token embedding.
Produce the exact integer, broken down by category. Then answer: what fraction sits in MLPs, and what fraction of the non-embedding parameters sit in MLPs? Check your answer against the published count for the released checkpoint.
Let (ignore ). Prove: (a) for any scalar ; (b) for any .
Then: what does (a) imply about a component that writes along the all-ones direction? What does (b) imply about trying to interpret the magnitude of a head's contribution? And why do interpretability libraries offer a “fold LayerNorm” option?
Head in layer 1 writes into the stream, where is and is . Head in layer 4 forms its queries with .
(a) Write the matrix describing the total effect of 's output on 's queries. (b) What is its maximum rank, for GPT-2 small numbers? (c) Ignoring LayerNorm, why is this map exact rather than approximate, even though layers 2 and 3 sit in between? (d) What is the name for a composition that changes 's keys instead?
Reusing your multi-head attention from Module 1.2, write block(x, params) implementing pre-LN GPT-2: LayerNorm → attention → add; LayerNorm → MLP (with GELU) → add. Then stack of them, add embeddings at the bottom, and finish with a final LayerNorm and a tied unembedding.
Success checks: (1) load the real gpt2 weights (HuggingFace transformers or transformer_lens) and reproduce the reference logits for a short prompt to within 1e-3; (2) assert your parameter count is exactly 124_439_808; (3) verify empirically that adding a constant vector to the residual stream before a block changes nothing downstream.
In TransformerLens, run gpt2-small on The Eiffel Tower is in the city of with run_with_cache. Pull resid_post for every layer, apply model.ln_final and then model.unembed, and plot against layer. Print the top-3 tokens at each layer.
Then two extensions. (1) Do the same for a prompt requiring syntax rather than a fact — e.g. subject-verb agreement across a clause — and compare the shapes of the two curves. (2) Use cache.decompose_resid() or accumulated_resid to check that the per-component contributions really do sum to the full stream.
Success check: your layer-12 distribution matches the model's actual output distribution exactly, and the sum of decomposed components matches resid_post[-1] to floating-point tolerance.
Open Neuronpedia and browse GPT-2 small MLP neurons (not SAE features — those come in Module 3.4). Pick three from different layers.
For each, record: the top activating text snippets, whether you can state a one-sentence hypothesis for what the key direction detects, and what the neuron's top positive logit contributions are. Then classify each neuron as monosemantic-looking, clearly polysemantic, or illegible, and count how many of each you found.
Check yourself
Go deeper
The Elhage framework is the one that changes how you see the architecture — read only the residual-stream sections now, and let Module 3.2 handle the rest. Karpathy is the do-along that makes all of Part 1 concrete.