Module 15 · Part IV · The Modern Architecture
The LLaMA Block
Rotary Position Embedding and Its Extensions, RMSNorm, SwiGLU, and Grouped-Query Attention
By the end you can turn the 2017 block into a 2024 block and justify each change.
Check yourself ▸
Before you start, can you already…
- ☐trace one token through a full transformer and name every tensor's shape along the way. (Module 7)
- ☐plan a pretraining run (data, optimizer, schedule, model size) and justify each choice. (Module 10)
If any is shaky, the linked module teaches it.
Between 2020 and 2024 the decoder-only Transformer of Modules 7 and 8 picked up changes that LLaMA 1 to 3, Mistral, Qwen, Gemma and almost every large open model now share:
- RoPE replaces the sinusoidal position vector that was added to the embeddings.
- RMSNorm replaces LayerNorm.
- SwiGLU replaces the ReLU or GELU feed-forward layer. (Gemma uses GeGLU, the same design with GELU in place of Swish.)
- Grouped-Query Attention (GQA) lets several query heads share one key head and one value head, which shrinks the KV cache.
The first three change what the model computes; the last changes the memory needed to generate. Section 15.6 sets all four beside the 2017 block. FlashAttention, which computes the same attention more cheaply, is in Module 16.
15.1 Rotary Position Embedding (RoPE)Run this section
Rotary Position Embedding (RoPE) (Su et al., 2021) does not add a position vector at the bottom of the model, as section 7.1 did. Inside every attention layer it rotates each query and key by an angle set by the token's position. In the dot product the two rotations combine into one rotation by the difference of positions, so the score depends on how far apart the tokens are, not where they sit.
In words. Query and key are each rotated by their own position's angle; in the dot product the rotations reduce to one rotation by the difference, so only the gap between the tokens matters.
The 2D Rotation Matrix
Picture a two-number vector as an arrow in a plane. Following the RoPE paper, this section writes vectors as columns. The matrix below turns the arrow counter-clockwise by , for position and fixed frequency :
A real query or key of numbers (say 128) is split into neighboring pairs, each rotated on its own, so the full matrix has rotations along its diagonal:
Each pair has its own frequency, shrinking geometrically:
The first pair turns one radian per token and the last about ten thousand times more slowly: fast pairs separate neighbors, slow pairs separate positions thousands apart. This is section 7.1's schedule, applied over the head width rather than .
RoPE: position as a rotation
RoPE (rotary position embedding) marks position by rotating each pair of numbers in a query or key by an angle proportional to its position. Move the two sliders: the attention score (the dot product) changes only when the distance n - m between the two positions changes, not when both move together.
Low-numbered pairs turn fast, so they tell nearby positions apart. High-numbered pairs turn slowly, so they still change over long distances.
The two scores match. Where the pair sits in the sequence drops out; only how far apart they are is left.
Rotate a query by its position and a key by its position . Before trying it, predict what happens to their dot product if you add 5 to both positions.
In words. A query pair and a key pair as arrows, rotated by position times frequency. Sliders move both positions and the frequency; the angle between the arrows and their dot product depend only on the position difference.
Why Only the Distance Survives
Rotate a query at position and a key at position (the tilde marks rotated vectors):
By , the rotations meet in the middle of the dot product:
Two facts finish it. The transpose of a rotation runs it backwards, (negating the angle flips each , exactly as transposing does). And consecutive rotations add their angles. So back by then forward by is one turn by :
Substituting that into the dot product:
The score depends on the two vectors' content and the gap , nothing else ( names "some function of these"). Move a passage 500 tokens later and every score inside it is unchanged. That does not mean the model works at any length, as section 15.2 explains.
Measured (lab 4a,
experiments/rope.py). The identity holds up to float32 rounding. For a single 2D pair, the score at a fixed offset stays the same as the pair slides to different positions, to within . Over a full 32-dimensional head with the published frequencies (the same schedule, counting from zero), it holds to about at offsets and .
Measured (lab 4a). Now use a learned table of absolute positions instead. Take the same two tokens at the same distance apart and move them to different absolute positions, and the score for that pair changes by . That is more than times larger than RoPE's rounding error. The table also has no entry at all for positions past the length it was trained on, while a rotation can be computed for any position and keeps every score consistent.
15.2 Stretching RoPE, and ALiBiRun this section
Train on tokens and run at , and beyond position 4096 the slow pairs reach angles never seen in training, so quality drops. (The fast pairs have gone round the circle many times, so every angle is familiar.) Four common fixes:
- Linear position interpolation. Shrink positions into the trained range, . Every angle is familiar, but neighbors now differ by smaller angles, blurring the fast pairs that encode local order, so some fine-tuning is usually needed.
- Raising the base, as LLaMA 3 did:
The first pair is unchanged (its exponent is zero) and the slowest stretch most, giving room for distant positions while keeping local detail. LLaMA 3.1, reaching 128k tokens, adds a further rescaling of the frequencies.introduces 1 notation
- NTK-aware scaling picks the new base from the extension factor (new length over old):
The exponent makes the slowest pair slow by exactly , as interpolation would, while leaving the fastest unchanged.
- YaRN (Peng et al., 2023) makes the split explicit per pair: pairs with wavelengths much shorter than the trained context are left alone, longer ones are interpolated fully, and those between are blended. It also scales the logits up slightly to counter the flatter attention of longer contexts. Qwen2.5 uses it for long-context versions.
A model trained on 4,096 tokens, run at 32,768. Each pair’s wavelength is how many tokens it takes to turn once. Pairs whose wavelength is longer than the training length never finished a turn in training, so at the new length they reach angles they have never seen.
The model was trained on 4,096 tokens and is run at 32,768. Before choosing a method, predict which RoPE pairs are in trouble: the fast ones, the slow ones, or all of them.
In words. Each RoPE pair's wavelength for a model trained on 4,096 tokens and run at 32,768. Unchanged, slow pairs reach unseen angles. Interpolation stretches every wavelength, crowding neighbors in the fast pairs. NTK-aware scaling stretches only the slow end, though some middle pairs still overshoot. YaRN stretches slow pairs fully, leaves fast ones alone and blends between, so no pair reaches an unseen angle.
A Different Route: ALiBi
ALiBi (Press et al., 2022) adds no position information to the vectors. It subtracts from each score a penalty proportional to how far back the key is:
The bracket holds one entry per key up to the query's position : for itself, for the token before, and so on. Each head has its own fixed slope , a geometric sequence such as for eight heads, so some heads focus nearby and others look far back. Depending only on distance, ALiBi degrades gracefully beyond its training length. BLOOM and MPT use it; most later models chose RoPE, whose extensions recover long-context quality with modest fine-tuning.
15.3 RMSNormRun this section
Zhang & Sennrich (2019) argued that LayerNorm's mean subtraction (section 7.3) is not what keeps training stable; the division that fixes the scale is. Dropping the mean, models trained about as well. The result is RMSNorm.
In words. Divide the vector by its own root mean square, then multiply by learned scales. Nothing is subtracted or added.
The RMSNorm Formula
The root mean square is what it says: the square root of the mean of the squares, a measure of size like the standard deviation but without subtracting the mean.
- No mean: one fewer pass over the numbers, often quoted as saving 10–15% of the normalization time.
- No shift : half the parameters.
Measured (lab 4b,
experiments/norm_and_gqa.py). The parameter claim is exact. LayerNorm has parameters and RMSNorm has , so at the tested width the saving is exactly . The two layers' outputs have a correlation coefficient of (1 would mean identical up to scale and shift).
Measured (lab 4b). The lab does not test the speed claim. PyTorch's
nn.LayerNormruns as a single optimized GPU routine (a "fused kernel"), while the experiment's RMSNorm is six separate operations, each a separate trip through memory, and it times slower. That compares how the two were written, not the pass saved, so it neither supports nor contradicts the – figure.
15.4 SwiGLURun this section
A gated linear unit (GLU) (Dauphin et al., 2017) makes two projections of the input and multiplies them, so one acts as a gate on the other. Shazeer (2020) tested gated variants in the Transformer's feed-forward layer; LLaMA uses SwiGLU:
- with (also called SiLU; this is unrelated to LayerNorm's shift), using the sigmoid of section 3.6. It passes large positive inputs almost unchanged, sends large negative ones to nearly zero, and bends smoothly between: , .
- is element-by-element multiplication.
In words. The input is projected twice; one copy goes through Swish, the two are multiplied element by element, and the result is projected back to model width. The multiplication makes it a gate: one branch controls how much of the other survives.
For one hidden unit: the gate branch’s value g goes through Swish, the up branch’s value u passes through unchanged, and the unit’s output is their product.
Set the gate input to a large negative value and move the up input around. Before you do, predict what the unit outputs, and how that differs from a plain GELU unit.
In words. One SwiGLU hidden unit: the Swish curve, with ReLU for comparison, marks the gate input, and the gate's output multiplies the up branch's value. Sliders set both inputs.
Keeping the Parameter Count Equal
SwiGLU has three matrices instead of two, so to keep the total the same the inner width shrinks from to:
Three matrices of hold weights, the same as two of , so parameters and arithmetic are unchanged. At this equal size SwiGLU still reached lower perplexity than ReLU and GELU in Shazeer's experiments. LLaMA rounds up to a convenient multiple: for in the 7B model.
15.5 Grouped-Query AttentionRun this section
In multi-head attention (MHA, section 6.6), each of the query heads has its own key and value head, so . Every generated token must read the whole KV cache (section 12.2), which grows with and takes much of each step's time.
Grouped-Query Attention (GQA) (Ainslie et al., 2023) splits the query heads into groups that each share one key head and one value head. The extreme, one pair shared by all, is multi-query attention (MQA).
In words. With four query heads: MHA gives each its own keys and values, GQA shares each pair between two queries, and MQA shares one pair among all four.
How Much Memory GQA Saves
LLaMA 3 8B has and , four query heads per key-value head. The cache holds one key and value per token, layer and key-value head, bytes for tokens (section 23.1), so instead of 32 gives:
- a cache a quarter the MHA size, a reduction;
- a quarter of the reading per step, so up to faster generation when reading the cache is the bottleneck;
- quality close to MHA and better than MQA, in Ainslie et al.'s experiments.
LLaMA 3 8B has 32 query heads. Choose how many key-value heads they share; each line joins a query head to the key-value pair it reads, and the cache shrinks in proportion.
Before switching from 32 key-value heads to 8, predict the new cache size at 8,192 tokens, and then for 1 head.
In words. LLaMA 3 8B's 32 query heads joined to the key-value heads they read. At 8,192 tokens the cache is 4 GiB with 32 key-value heads, 1 GiB with 8, and 128 MiB with one.
Measured (lab 4b). The arithmetic is exact. At query heads, KV heads, , and
fp16, the cache falls from GiB to GiB. That is exactly the stated in this section, and the same figure section 23.1 works out for LLaMA-3 8B.
Measured (lab 4b). The structural claim is stronger than "nearly as good". Set and GQA reproduces MHA bit for bit, with a largest difference of exactly . GQA is a generalization of MHA, not an approximation of it: MHA is the special case with one query per group. That is why an existing MHA model can be converted to GQA, as Ainslie et al. did, by averaging the key and value heads within each group and then training briefly. Parameter counts fall as expected, , as the number of KV heads drops from to .
15.6 The 2017 Block and the 2024 Block, Side by SideRun this section
The whole change from the 2017 block of section 7.6 to a 2024 LLaMA-style block:
| 2017 block (Module 7) | 2024 block (this module) | |
|---|---|---|
| position information | a vector added to each embedding, once (section 7.1) | queries and keys rotated by position inside every attention layer (15.1) |
| normalization | LayerNorm after each residual add (Post-LN) | RMSNorm before each sub-layer (Pre-LN), plus one at the end (15.3, 8.5) |
| feed-forward | ReLU or GELU, two matrices, | SwiGLU, three matrices, (15.4) |
| attention heads | one key and value head per query head | groups of query heads share a key and value head (15.5) |
| biases | in every linear layer | usually none |
| embeddings | tied to the output layer | often untied (section 7.5) |
None is large on its own, and the shape is unchanged: residual stream, alternating attention and per-token network, causal mask, next-token loss. Each detail makes training more stable, long contexts better behaved, or generation cheaper.
The same characters go through both models. Pick a stage to see it in each; the 2024 model has no separate position stage, because it rotates queries and keys inside attention.
Open the after attention stage of block 1 in both models. Before looking, predict which of the two has a residual stream whose values keep growing as more blocks add to it.
In words. The same input through small 2017-style and 2024-style models, both trained on Shakespeare, side by side, stage by stage. The 2024 model has no position stage, since it rotates queries and keys inside attention, and its heads share key-value heads in pairs.
Exercises
List the four changes from the 2017 block to the LLaMA block that change what the model computes or stores, and the module section for each.
For a single 2D pair, show that using the angle-difference formulas, where rotates by angle .
Using the rule, what is the SwiGLU inner width for , before rounding?
How many parameters does RMSNorm save over LayerNorm at , per normalization layer?
A model with 32 layers, and a 32,768-token context stores its cache in bf16. How many GiB does one sequence's KV cache take with 8 key-value heads?
Why does linear position interpolation hurt the fast RoPE pairs, and how do NTK-aware scaling and YaRN avoid that?
Core Academic References
- Su et al. (2021): RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864
- Press, Smith & Lewis (2022): Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation (ALiBi). ICLR 2022. arXiv:2108.12409
- Peng et al. (2023): YaRN: Efficient Context Window Extension of Large Language Models. arXiv:2309.00071
- Zhang & Sennrich (2019): Root Mean Square Layer Normalization (RMSNorm). NeurIPS 2019. arXiv:1910.07467
- Dauphin et al. (2017): Language Modeling with Gated Convolutional Networks (GLU). ICML 2017. arXiv:1612.08083
- Shazeer (2020): GLU Variants Improve Transformer (SwiGLU). arXiv:2002.05202
- Ainslie et al. (2023): GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. EMNLP 2023. arXiv:2305.13245
- Touvron et al. (2023): LLaMA: Open and Efficient Foundation Language Models. arXiv:2302.13971
- Grattafiori et al. (2024): The Llama 3 Herd of Models. arXiv:2407.21783
Measured labs
These labs test what this module says by running real code. Each card states the idea, what the experiment found, and what it does not prove. The numbers come from experiments/results.json, the output of running experiments/run_all.sh on the tiny-transformers reference code at version 137f7ef. The project checks fail if a measured number in the module text stops matching that file.
Lab 4a — RoPE depends only on distance; a learned table does not
What the module says
Section 15.1 shows that RoPE rotates each query and key by an angle set by its position. Because rotating by and then undoing a rotation by is a single rotation by , the attention score depends only on the distance , not on where the pair sits in the sequence.
What the experiment found
It holds up to 32-bit rounding. For one 2D pair the score for a given distance varies by at most 4.8e-07 as the pair moves. Across a full 32-number head with the standard frequencies, at distances 0, 1, 7, 63 and 200, it varies by at most 7.2e-06. Run the same test through a learned position table and the score for the same distance changes by 5.78, about 800,000 times more.
- 2D pair: score change when moved
- 0.0000004768
- full head: score change when moved
- 0.0000071526
- learned table: same test
- 5.77769
largest change for a fixed distance
largest change for a fixed distance
same tokens, same distance, shifted along the sequence
What this does not prove
The learned-table test is easy to get wrong. Shifting the whole input also moves the tokens, so a careless test passes for the wrong reason. This one keeps the tokens fixed and changes only their positions, which is what matters when a model meets sequences longer than it was trained on.
Run it yourself
cd tiny-transformers && .venv/bin/python experiments/rope.pyThe code being tested
Lab 4b — RMSNorm and GQA: two claims confirmed, one not tested
What the module says
Section 15.3 says RMSNorm skips the mean subtraction of LayerNorm and drops its shift vector β, which saves parameters, and quotes 10–15% as a common estimate of the time spent on normalization. Section 15.5 says grouped-query attention (GQA) with 32 query heads sharing 8 key/value heads cuts the KV cache by 75% at little cost in quality.
What the experiment found
The parameter saving is exact: LayerNorm has parameters (scale and shift) and RMSNorm has (scale only), so it saves per norm. The GQA memory arithmetic is also exact: at 8,192 positions in fp16 the cache falls from 4.00 GiB to 1.00 GiB, a 75.0% cut. With as many key/value heads as query heads, GQA gives exactly the same output as ordinary multi-head attention, so GQA extends it rather than approximating it. The speed claim was not tested (see below), and quality was not measured.
- parameters RMSNorm saves
- 512 per layer
- LayerNorm vs RMSNorm output, correlation
- r = 0.999032
- passes over the data
- 3 → 2
- GQA 32:8, 8,192 positions, fp16
- 75% smaller cache
- GQA with equal heads vs multi-head attention
- max |Δ| = 0
exactly : the shift vector
1 would mean the two outputs rise and fall in perfect step
33% fewer on paper; the 10–15% in section 15.3 is a quoted estimate of time spent on normalization, not measured here
bit-for-bit identical
What this does not prove
Timed directly, this RMSNorm is 2.8 times slower than nn.LayerNorm. That is because nn.LayerNorm runs as one optimized built-in kernel, while the RMSNorm here is several separate operations. The timing compares two implementations, not the saving in passes that section 15.3 describes, so it counts neither for nor against the claim.
Run it yourself
cd tiny-transformers && .venv/bin/python experiments/norm_and_gqa.pyThe code being tested