JJoeven

Curriculum/Neural Nets & Transformers

Residuals and LayerNorm

Add the delta back. Normalize so depth does not explode. That highway is why 96 layers can train.

intermediate19 min9 / 24

A residual connection means:

output = input + layer(input)

The layer is allowed to be “almost zero.” Then the output is almost the input. Depth does not have to reinvent the representation at every step. Slopes have a highway back to the first tokens.

Without residuals, stacking many nonlinear maps tends to smash the signal (or blow it up). With residuals, a 96-layer model can still look like “the embeddings plus a pile of patches.”

LayerNorm rescales a vector so its numbers have a stable size (zero mean, unit variance, then a learned scale and shift). RMSNorm is a cheaper cousin: no mean subtraction, divide by the root-mean-square, then a learned scale. Neither is a knob you set per request. They explain why a 2-layer toy you write by hand can explode while a deep trained model does not.

This lesson is the same residual you saw inside the block, slowed down, plus the size-taming step that makes depth possible.

A wrong picture

A wrong picture is: “residual means skip the layer.” The layer still runs. Its output is added, not used instead of the input. Both paths exist.

Another wrong picture is: “LayerNorm is dropout” or “LayerNorm is temperature.” Dropout exists in training; at inference it is off. Temperature is decoding (later). Norm is “make this vector a civilized size so the next matmul does not explode.”

A third wrong picture is: “if numbers become inf in my toy, the idea of transformers is wrong.” You are seeing the problem LayerNorm was hired to prevent. Print the size of the vector. Then divide. That is the move.

Highway for slopes

Training needs slopes (gradients) to reach early tokens and early layers. A long chain of multiplies can shrink those slopes to zero (vanishing) or grow them to inf (exploding). Adding the input every time gives a path whose local slope is “1 + whatever the layer did.” If the layer is small, that path is about 1. Signal and slope can travel.

This is why residual nets trained when very deep plain nets did not. Transformers borrowed that idea. The residual stream is the running total of all those patches. Interpreters who read models talk about writing into and reading from that stream. You do not need that vocabulary to use an agent. You need: do not smash the first embeddings.

Norm in words

For a vector v of length d:

LayerNorm: subtract the mean of the d slots, divide by the standard deviation (plus a tiny eps), then multiply by a learned gain and add a learned bias.

RMSNorm: skip the mean. Compute sqrt(mean of squares + eps). Divide v by that. Then a learned gain.

Both make the size predictable. Direction stays roughly the same if you only rescale. Adding a delta, then normalizing, is “nudge, then tame.”

eps is a tiny number so you never divide by zero. You will not tune it in production prompts.

Add a delta, then tame the size

Lists of numbers. RMSNorm by hand. Print sizes.

Residual skip: add the delta back
InputLayerAddOutput

The layer still runs. Its output is added, not used instead of the input. Depth can learn a small patch.

Residual skip: add the delta back
Live PythonOpen full playgroundpython
Output
Run to execute this in your browser. Nothing is sent to a server.

The sum still points a similar way. The size is pulled back. rmsnorm(10*x) should match rmsnorm(x) in this toy because RMSNorm cares about direction and relative slot sizes, not global scale. That is what lets the next block see a civilized vector.

If delta were huge, the sum would point a new way, then get tamed to unit-ish size. Norm does not undo a bad layer. It only stops the fire from spreading as magnitude.

When a toy net’s numbers become inf, print mag(v) before the next multiply. That print is the debugging habit LayerNorm automates.

Train vs run

Dropout randomly zeros slots during training so the net cannot rely on one path. At inference (generation) dropout is off. If a vendor “temperature” feels like dropout, it is not. Temperature reweights logits. Dropout was regularization.

You cannot peel LayerNorm off a hosted model. You can only change the first x. If the first embeddings are a duplicated stack trace, every residual patch is a patch on junk. Norm will still tame the size of junk.

Pre-norm vs post-norm (last lesson) is about where this taming sits relative to attention and the MLP. Pre-norm is the common modern default at depth.

Common mistakes

Removing the residual “to see what the layer really does” in a deep toy, then watching inf. You saw why the highway exists. Put it back.

Treating RMSNorm as a semantic operation: “it removes meaning so the model is fair.” It tames size. Direction mostly stays. Meaning lives in direction and in later mixes, not in the overall scale of one vector.

Matching dropout to temperature in a design doc. Dropout is a train-time coin flip on slots. Temperature is decode-time reweighting of logits. One is off at inference. Mixing the words makes the serving team turn the wrong knob.

Forgetting that the first x is your prompt’s embeddings. If you duplicate a stack trace, you did not “add context.” You added a loud junk direction that every residual patch will try to work around. Norm will keep it a civilized size of junk.

How agents use this

You cannot peel one block off a hosted response. You can only change the text that becomes the first x. If the first embeddings are a duplicated stack trace, every residual patch is a patch on junk.

When a local toy explodes, you are not failing “math.” You are missing the highway and the taming that production models have. Do not copy a 96-layer picture into 20 lines of Python and expect it to be stable without residuals and norm.

  • Add, do not replace: x + layer(x).
  • Tame size: LayerNorm or RMSNorm.
  • Dropout: train only; not a decode knob.
  • Junk in: junk patched 96 times is still junk.
  • Debug toys: print vector size when numbers blow up.
Tip:When a toy net’s numbers become inf, you are seeing the problem LayerNorm was hired to prevent. Print the size of the vector.

Check your understanding

Why add the layer output back to the input (a residual)?