⌂ 全部教程⌂ All tutorialseasyaioffer.github.io ⭐ Star
Interview Prep · Transformer Block

Transformer Block Interview Cheat Sheet

Post-LN / Pre-LN / branch pre+post residual topologies · MHA/MQA/GQA/MLA as an independent design axis · Dense FFN vs MoE capacity axis · GPT-2→Llama-style evolution · 30 interview questions (L1 essentials · L2 advanced · L3 top-tier lab)

Source: docs/tutorials/transformer_block_tutorial_en.md SHA256: c509d423f8c6 Rendered: 2026-09-16 06:00 UTC

§0 The Basic Parts of a Block

A Transformer block organizes attention and FFN with residual connections. In the serial structure the FFN reads the residual stream after the attention update; in the parallel structure the two have no ordering dependency. The decoder layer of the original encoder-decoder also contains a cross-attention. Normalization, KV sharing, and model structure each have their own choices.

§1 A Modern Block: Forward, Parameters, and Code

1.1 Assemble a Llama-3-like block, then swap in MoE

A concrete, complete, runnable modern decoder-only block looks like this:

  1. Normalization: Pre-RMSNorm, twice — once before attention, once before the FFN.
  2. Attention: causal self-attn, RoPE applied internally to Q/K, $n_q$ query heads grouped to share $n_\text{kv}$ KV heads — that is GQA, degenerating to MHA when $n_\text{kv}=n_q$; K is cached after rotation, V is never rotated, no bias.
  3. FFN: SwiGLU gated FFN, $h \approx 8d/3$ rounded to a hardware-friendly multiple, no bias.
  4. Single-block assembly: $x=x+\text{Attn}_\text{RoPE,GQA}(\text{RMSNorm}(x))$, $x=x+\text{SwiGLU}(\text{RMSNorm}(x))$ — this is the complete definition of one block; repeat it $N$ times to get the whole decoder stack.
  5. Stack-level closure: after all $N$ blocks, apply one final RMSNorm before the LM head: $x_\text{out} = \text{RMSNorm}\big(\text{Block}_N(\cdots\text{Block}_1(x_0))\big)$. The final norm belongs to stack assembly, not to any block in steps 1–4.

Strictly this is a "Llama-3-like core block": exactly reproducing a given checkpoint also requires matching head count, KV-head count, intermediate size, RoPE base, bias settings, and dtype behavior. Compute the parameter count once with the teaching sizes $d=96$, $n_q=8$, $n_\text{kv}=2$, gated hidden $=256$: the GQA attention part has $2d^2(1+n_\text{kv}/n_q)=23{,}040$ matrix parameters, the SwiGLU FFN part has $3dh=73{,}728$ matrix parameters, and each of the two RMSNorms has only $d=96$ per-channel scale parameters. A single block totals about $23{,}040+73{,}728=96{,}768$ matrix parameters, with the FFN taking the vast majority. This is also why the FFN hidden size affects total parameters more than the KV-head count.

Swap the FFN for MoE and touch nothing else:

$$x=x+\text{Attn}_\text{RoPE,GQA}(\text{RMSNorm}(x)), \qquad x=x+\text{MoEFFN}(\text{RMSNorm}(x))$$

MoEFFN's external main-activation tensor interface is still [B,T,d] -> [B,T,d], and not a single line of ModernDecoderBlock changes; §1.4 [D09] verifies this directly. What changes are two other things: training usually returns extra router/load-balancing quantities, and distributed deployment usually introduces expert parallelism.

Which fields describe a block's recipe

normalization topology, i.e. Post/Pre-serial/Pre-parallel/branch pre+post; normalization type, LayerNorm or RMSNorm; positional-encoding scheme and its owning level, learned absolute outside the stack and RoPE inside attention; attention variant MHA/MQA/GQA/MLA, local window or not, QK-Norm or not, attention scale/temperature; FFN variant dense/gated/MoE and intermediate size; bias, dropout, norm epsilon, residual scaling such as LayerScale. This covers the coarse-grained fields common interviews need; finer-grained values such as head dim, RoPE base, and the exact activation implementation are not on this list.

1.2 End-to-end forward: the complete data flow of a modern decoder-only block

Take the teaching sizes $d=96$, $n_q=8$, $n_\text{kv}=2$, gated hidden $=256$. The complete forward data flow of a modern decoder-only block is:

$$x \in [B,T,d] \;\xrightarrow{\text{RMSNorm}}\; h_1 \;\xrightarrow{\text{Q/K/V projection + reshape}}\; Q\in[B,n_q,T,d_h],\;K,V\in[B,n_\text{kv},T,d_h] \;\xrightarrow{\text{RoPE}}\; Q',K' \;\xrightarrow{\text{GQA attention}}\; O\in[B,T,d] \;\xrightarrow{\text{residual add}}\; u = x + O$$

$$u \;\xrightarrow{\text{RMSNorm}}\; h_2 \;\xrightarrow{\text{gate/up projection}}\; \text{SiLU}(\text{gate}(h_2))\odot\text{up}(h_2) \;\xrightarrow{\text{down projection}}\; F\in[B,T,d] \;\xrightarrow{\text{residual add}}\; y = u + F$$

Repeat this block $N$ times and then apply one stack-level final RMSNorm to get the full decoder-only backbone: $y_\text{final} = \text{RMSNorm}\big(\text{Block}_N(\cdots(\text{Block}_1(x_0)))\big)$.

This data flow takes different concrete forms under three execution modes:

Execution modeQ/K/V lengthsmaskKV cacheTypical scenario
Training / full-forwardQ, K, V all span the full $T$one-shot lower-triangular causal mask $[T,T]$not usedtraining, teacher-forcing evaluation, scoring a full prompt in one pass
Prefill (first inference step)Q, K, V all span the full prompt length $S$causal mask $[S,S]$written to cache (K and V, $n_\text{kv}$ heads each, length $S$)first forward after receiving the user prompt, building the cache for subsequent decode
One-token decode (step-by-step inference)Q has length $1$ (new token); K, V grow from cached history length $t$ to $t{+}1$with a dynamic cache and no padding/packing, the new token sees all of $0..t$ (whole row True); static cache/left padding/packed sequences still need extra masking (see §9 Q25)read old cache + append new K/Vevery step of autoregressive generation

The three modes share the same RMSNorm→RoPE→attention→residual code path, differing only in the actual Q/K/V lengths, the mask shape, and whether the cache is read/written. That is why §1.4 [D04] can use one implementation to verify that full-forward and cached decoding agree numerically; if the two paths used different code, that test would lose its cross-validation meaning.

1.3 Parameter-count and KV-cache formula accounting

FFN parameters, ignoring bias: dense (ReLU/GELU) is $8d^2$ over two matrices; gated (SwiGLU/GeGLU) is $3dh$ over three matrices. Setting them equal gives $h=8d/3$ — a common default computed from parameter matching, not an architectural law. Real Llama-family implementations usually start from $4d$, multiply by $2/3$, then round to hardware-friendly multiples (with an optional multiplier), so the intermediate size can deviate noticeably from $8d/3$.

Attention parameters, ignoring bias: MHA's four Q/K/V/O projections total $4d^2$; GQA gives $2d^2(1+n_\text{kv}/n_q)$, degenerating back to $4d^2$ at $n_\text{kv}=n_q$ and reaching MQA's minimum at $n_\text{kv}=1$. Both formulas assume $d=n_qd_h$, identical head dim for Q/K/V, a $d\times d$ output projection, and no bias — adjust them accordingly when these assumptions fail.

Packed projection: fusing the three Q/K/V Linears, or SwiGLU's gate/up Linears, into one big Linear is a kernel-level equivalent rearrangement — with row-wise concatenated weights the results should agree at the corresponding precision, changing no architectural semantics.

KV cache: the table below gives element counts per token per layer, not bytes. Full memory usage further multiplies by batch size $B$, sequence length $L$, layer count $N_\text{layer}$, and bytes per element — usually 2 bytes for fp16/bf16, 1 byte for fp8.

VariantCache size (elements/token/layer)
MHA$2 n_q d_h$
GQA$2 n_\text{kv} d_h$
MQA$2 d_h$
MLA$d_c + d_h^R$ (latent dim + shared RoPE component; no "$\times 2$" because K/V share one latent)

1.4 From-scratch implementation and executable verification: code/transformer_block.py

The full runnable script is code/transformer_block.py (pure PyTorch; all 9 demos [D01]–[D09] finish in seconds on CPU). Four entry classes correspond to this tutorial's four "block eras": VanillaEncoderLayer2017, VanillaSeq2SeqDecoderLayer2017 (§2), GPT2StyleDecoderLayer (§3), ModernDecoderBlock (§4/§1.1, with ffn= swappable among DenseFFN/GatedFFN/MoEFFN). The body shows the three most central snippets; the remaining demos are standalone functions in the script.

[D02] Residual-topology test (zero out the sublayer output: Pre-LN must return exactly $x$, Post-LN must return $N(x) \ne x$):

def zero_sublayer(_x):
    return torch.zeros_like(_x)

post_ln_out = ln(x + zero_sublayer(x))       # y = N(x + F(x)) -> y = N(x)
pre_ln_out  = x + zero_sublayer(ln(x))       # y = x + F(N(x)) -> y = x

assert torch.allclose(pre_ln_out, x, atol=1e-6)          # Pre-LN: exact identity
assert torch.allclose(post_ln_out, ln(x), atol=1e-6)     # Post-LN: exactly N(x)
assert not torch.allclose(post_ln_out, x, atol=1e-4)     # and generally != x

[D04] Full forward vs cached decoding (under eval() with no dropout, the full-sequence forward and token-by-token incremental decoding must agree numerically — jointly checking the causal mask, RoPE position offset, and cache append):

causal = build_causal_mask(torch.arange(T), torch.arange(T))
out_full = block(x, cos, sin, mask=causal)                  # compute the whole sequence at once

cache = KVCache()
outs = []
for t in range(T):
    q_pos, k_pos = torch.tensor([t]), torch.arange(t + 1)
    mask_t = build_causal_mask(q_pos, k_pos)                 # new token sees all of 0..t
    outs.append(block(x[:, t:t+1, :], cos, sin, mask=mask_t,
                       kv_cache=cache, start_pos=t))
out_cached = torch.cat(outs, dim=1)
assert torch.allclose(out_full, out_cached, atol=1e-4)
assert cache.k.shape[1] == n_kv_heads                        # cache head count never grows to n_q_heads

[D08] Parallel vs sequential dependency (use a forward hook to capture the FFN's actual input tensor and exactly match it against an independently recomputed expected tensor — not the fragile "two random numbers are unequal"):

captured = {}
seq_blk.ffn.register_forward_hook(lambda m, i, o: captured.setdefault("x", i[0]))
seq_blk(x, causal)
a, _ = seq_blk.attn(seq_blk.norm1(x), mask=causal)
assert torch.allclose(captured["x"], seq_blk.norm2(x + a), atol=1e-5)   # sequential: FFN sees the "updated" stream

captured.clear()
par_blk.ffn.register_forward_hook(lambda m, i, o: captured.setdefault("x", i[0]))
par_blk(x, causal)
assert torch.allclose(captured["x"], par_blk.norm(x), atol=1e-6)       # parallel: FFN sees the "original" stream

Key invariants the script must satisfy (one per [D01]–[D09], described here by "verification intent"; the exact assertions are as implemented in the script):

  1. [D01] Shape contract: all four entry classes preserve the [B,T,d] residual width; cross-attn still correctly returns length-$T$ output when $T\ne S$, and must verify that memory is actually read (changing memory changes the output), not just the shape.
  2. [D02] Residual-topology test: with sublayer outputs zeroed, Pre-LN-style blocks return exactly $x$; Post-LN-style blocks return $N(x)$, generally not equal to $x$; the two sublayers' LNs must be compared separately — one $N(x)$ must not be used to certify itself.
  3. [D03] No causal leakage: perturbing only tokens after position $t{+}1$ must leave outputs at positions $0..t$ untouched; confirm this invariant is actually contributed by the attention branch.
  4. [D04] Full forward vs cached decoding: under eval() with no dropout, the full-sequence forward and token-by-token incremental decoding agree numerically at all positions, and the cache head dimension stays $n_\text{kv}$ throughout — the most direct way to hunt causal-mask / RoPE-offset / cache-ordering bugs, though not the only test that must cover a nonzero attention-branch contribution.
  5. [D05] MHA/MQA/GQA degeneration: at $n_\text{kv}=n_q$ the general implementation matches an independently hand-written plain-MHA reference exactly; $n_\text{kv}=1$ (MQA) and intermediate values (e.g. $n_\text{kv}=2$) must each be compared against an independent repeat_interleave reference — testing only the $n_\text{kv}=n_q$ degenerate case is not enough.
  6. [D06] Parameter formulas: at $d=96$, dense FFN (hidden $=4d$) and gated FFN (hidden $=8d/3$) both have exactly 73,728 matrix parameters; GQA/MHA attention matrix parameters equal the $2d^2(1+n_\text{kv}/n_q)$ and $4d^2$ formulas exactly; illegal configurations where $d_\text{model}$ is not divisible by the head count must fail at construction time.
  7. [D07] Packed-projection numerical equivalence: packed QKV (and packed gate+up) with identical weights match three (or two) separate Linears numerically (numerically equivalent within tolerance, not necessarily bitwise identical).
  8. [D08] Parallel vs sequential: forward hooks capture both attention's and the FFN's actual inputs; the sequential block matches $N_2(x+\text{Attn}(N_1(x)))$ exactly, and both branches of the parallel block match $N(x)$ exactly.
  9. [D09] Backward smoke test: all dense-block parameter gradients are finite; the MoE-swapped block must iterate over all experts not unused in this batch and check nonzero gradients, while router/attention/norm and all other parameters also receive gradients normally.

The actual output of running python3 code/transformer_block.py (D10-D15 are targeted regression tests, covering constructor argument validation, KV-cache consistency, cross-attention combination restrictions, mask safety and broadcasting, default causal behavior, and RoPE-cache device/dtype handling):

[D01] shapes (enc/dec2017/gpt2/modern) = [torch.Size([2, 7, 96]), torch.Size([2, 7, 96]), torch.Size([2, 7, 96]), torch.Size([2, 7, 96])] (expect 4x (2,7,96)); cross-attn ran with Tq=7 != S=5; changing memory changes cross-attn output (memory is actually read, not ignored) = True  PASS
[D02] formula-level: Pre-LN(F=0)==x: True; Post-LN(F=0)==N(x): True (and != x: True); class-level: zeroed ModernDecoderBlock==x: True, zeroed Post-LN encoder layer != x: True, == ln2(ln1(x)) exactly: True  PASS
[D03] perturbing tokens after t=3: positions 0..3 unchanged = True, positions 4..5 changed = True; perturbing position 0 changes positions 1..5 (attention actually mixes forward, not a dead branch) = True  PASS
[D04] full-forward vs token-by-token cached decode: max|Δ| = 4.77e-07 (tol 1e-04, numerically equivalent, NOT bit-identical); cache CONTENT vs independently projected+rotated K/V: max|ΔK|=3.58e-07, max|ΔV|=4.77e-07; final cache shape head_dim=2 (expect 2) len=6 (expect 6)  PASS
[D05] GQA(n_kv=n_q) == independent reference MHA: max|Δ|=0.00e+00; GQA(n_kv=2, group=4) == independent repeat_interleave reference: max|Δ|=8.94e-08; MQA == same reference (n_kv=1): max|Δ|=8.94e-08, cache head_dim=1 (expect 1), output shape=(2, 5, 96), per-query-head outputs distinct (not collapsed) = True  PASS
[D06] FFN params: dense(4d)=73728, gated(8d/3)=73728 (both expect 73728); attn params: GQA=23040 (formula 2d^2(1+n_kv/n_q)=23040), MHA=36864 (formula 4d^2=36864)  PASS
[D07] packed QKV vs separate: max|Δ|=4.77e-07; packed gate+up vs separate: max|Δ|=0.00e+00  PASS
[D08] sequential: attn input == norm1(x): True, FFN input == norm2(x+attn_out) (updated stream): True (and != norm2(x) alone: True); parallel: attn input == norm(x): True, FFN input == norm(x): True, attn and FFN inputs are the literal SAME tensor: True  PASS
[D09] dense block: all grads finite = True, all non-zero = True; MoE tokens_per_expert=[1, 0, 2, 0] (<4 tokens, so >=1 expert unused by pigeonhole); touched experts non-zero+finite grad, untouched experts no/zero grad: True; router gate non-zero+finite grad: True; rest-of-block (attn+norms) non-zero+finite grad: True  PASS
[D10] d_model % n_q_heads != 0 raises ValueError: True; n_q_heads % n_kv_heads != 0 raises ValueError: True; RoPE + odd head_dim raises ValueError: True; MoEFFN(top_k=2) raises NotImplementedError (no silent top-1 downgrade): True  PASS
[D11] inconsistent start_pos vs non-empty cache raises ValueError: True; consistent start_pos does not raise: True; cache.reset() clears state: True; append() with mismatched batch/shape raises ValueError: True  PASS
[D12] cross-attention + RoPE raises ValueError: True; cross-attention + KV cache raises ValueError: True; plain cross-attention (no RoPE/cache) still works, shape=(1, 4, 32): True  PASS
[D13] fully-masked query row produces finite output (no NaN): True; key_padding_mask correctly isolated per-batch-sample when B==n_kv_heads (2): max|Δ| vs per-sample reference=1.79e-07 -> True; same check when B==Tq (3): max|Δ|=1.64e-07 -> True  PASS
[D14] GPT2StyleDecoderLayer: omitted causal_mask == explicit causal_mask: True, default is genuinely causal (no future->past leakage): True; ModernDecoderBlock: omitted causal_mask == explicit causal_mask: True  PASS
[D15] build_rope_cache(dtype=float64) produces float64 cos/sin: True; apply_rope auto-casts a mismatched (float32) cache to a float64 input's dtype (no crash, correct output dtype): True; matches a natively-float64-built cache: True (max|Δ|=0.00e+00)  PASS

all transformer block sanity checks passed ✓

§2 The Original Encoder-Decoder

The original Transformer (Vaswani et al., Attention Is All You Need, arXiv 1706.03762, 2017, NeurIPS 2017) is an encoder-decoder architecture: the encoder encodes the source sequence into a set of representations, and the decoder autoregressively generates the target sequence conditioned on them. Positional encoding uses fixed sinusoidal PE, added directly to the token embeddings before entering the encoder/decoder stacks; it belongs to no block and is input processing outside the blocks. The paper's original configuration is $d_\text{model}=512$, $d_\text{ff}=2048$ (4× expansion), 8 heads, 6 encoder + 6 decoder layers; this tutorial demonstrates with smaller sizes such as $d=96$, which is a teaching configuration, not the paper's — do not conflate the two.

The encoder layer and the decoder layer differ in both the number and the kinds of sublayers:

Encoder layerDecoder layer
Sublayer 1Self-attn (bidirectional, no causal mask, only an optional padding mask)Masked self-attn (causal)
Sublayer 2FFNCross-attn (Q from this layer's output, length $T$; K/V from encoder output, length $S$)
Sublayer 3—FFN
Norm topologyPost-LN per sublayer: $y=N(x+F(x))$Post-LN per sublayer, three times

The decoder's three sublayers run in the fixed order masked self-attn → cross-attn → FFN, each wrapped in its own Post-LN. Cross-attn's Q, K, V sources are asymmetric: Q comes from the decoder's own in-progress stream, length $T$; K and V come from the encoder output, length $S$, and $T$ and $S$ can differ.

Walking one concrete shape through, with teaching sizes batch $B=2$, source length $S=5$, target length $T=7$, $d=96$: the encoder input is [B, S, d] and remains [B, S, d] after several encoder layers, passed as memory to every decoder layer; the decoder input is [B, T, d], and in the masked self-attn stage Q/K/V are all computed internally from [B, T, d], with a causal mask of size $T\times T$; in the cross-attn stage Q is still [B, T, d] but K, V come from the encoder memory with shape [B, S, d], so the attention score matrix is $T\times S$ rather than square, with softmax along the $S$ dimension; after the output projection it returns to [B, T, d], matching the self-attn sublayer's output shape, so it can proceed into the FFN sublayer. $T \ne S$ does not affect this data path at all — this is what "cross-attn decouples Q length from K/V length" concretely looks like.

VanillaEncoderLayer2017 (2 sublayers) and VanillaSeq2SeqDecoderLayer2017 (3 sublayers) are two independent classes in §1's code. Writing them as one "generic block class + parameter switches" is workable engineering but hides the structural fact that the decoder has a whole extra cross-attn sublayer compared with the encoder.

§3 The Three Architecture Families and GPT-2→Llama

3.0 encoder-only / decoder-only / encoder-decoder

FamilyRepresentativesSublayer compositionAttention directionTypical training objectiveTypical use
Encoder-onlyBERT, RoBERTaper layer: self-attn + FFN (no causal mask)bidirectional (sees the whole sequence)denoising objectives such as masked language modeling (MLM)representation learning, classification, retrieval embeddings
Encoder-decoderoriginal Transformer, T5encoder layer: self-attn + FFN; decoder layer: masked self-attn + cross-attn + FFNencoder bidirectional; decoder unidirectional and conditioned on the encoderconditional generation (translation, summarization)two-sequence conditional generation tasks
Decoder-onlyGPT, Llama, Qwenper layer: causal self-attn + FFN (no cross-attn)unidirectional (causal)autoregressive language modelinggeneral-purpose generative LLMs

The core difference among the three is not "how many parameters" but that attention visibility, sublayer composition, and training objective change together as a bundle.

3.1 How decoder-only differs from the original decoder layer

At the single-layer structural level, a decoder-only block really is the original decoder layer with cross-attn removed: masked self-attn → cross-attn → FFN, three sublayers, becomes causal self-attn → FFN, two sublayers.

At the whole-model level an entire encoder/memory path is missing as well: source/prompt and target go from "two-stream conditional generation" to "single-stream causal modeling", with prompt and generated content concatenated into one causal sequence. What changes is the information-flow topology and the sequence factorization, not that the task was replaced by a different problem.

Some multimodal/retrieval-augmented models reintroduce cross-attention on a decoder-only backbone; every "decoder-only has no cross-attn" statement in this tutorial is restricted to the pure decoder-only block, i.e. the two sublayers causal self-attn + FFN.

3.2 GPT-2-style to Llama-style

GPT-2 (Radford et al., Language Models are Unsupervised Multitask Learners, OpenAI technical report, 2019, no arXiv id) is already Pre-LN, and puts a final LayerNorm, denoted ln_f, at the end of the stack. The complete GPT-2 block recipe:

$$x = x + \text{Attn}\big(\text{LN}(x)\big), \qquad x = x + \text{FFN}\big(\text{LN}(x)\big), \qquad \text{(GELU dense FFN, MHA, bias=True, no cross-attn)}$$

The learned absolute positional embedding is added to the embedding and sits outside the stack, the same as the original sinusoidal PE; neither lives inside a block. RoPE, adopted by the LLaMA family, is the opposite: it lives inside attention, acting only on the Q/K dot product. RoPE was first proposed by Su et al., RoFormer: Enhanced Transformer with Rotary Position Embedding, arXiv 2104.09864, 2021; LLaMA is a prominent adopter, not the proposer. Positional information is carried by an external embedding in GPT-2-style and by rotation inside attention in Llama-style; the two belong to different levels, so this is not a "seamless swap" between members of the same block. What actually changed is this:

DimensionGPT-2-styleLlama-style
Norm topologyPre-LN (already)Pre-LN (unchanged)
Norm typeLayerNormRMSNorm
Positional encodinglearned absolute (outside the stack, added to the embedding)RoPE (inside attention, acting only on Q/K)
FFNGELU dense (2 matrices)SwiGLU gated (3 matrices)
AttentionMHAMHA or GQA (per the specific checkpoint's spec)
biasbias in both Linear and LayerNormusually all bias removed
dropoutused in trainingusually removed or made tiny in large-scale pretraining
final normyes (ln_f, LayerNorm)yes (RMSNorm)

§4 RMSNorm, RoPE, SwiGLU, and Model Composition

Llama-style — the recipe of Llama 2 and Llama 3 — fills each component with the concrete implementations below; attention is written as MHA first:

$$x = x + \text{Attn}_{\text{RoPE}}\big(\text{RMSNorm}(x)\big), \qquad x = x + \text{SwiGLU}\big(\text{RMSNorm}(x)\big)$$

Where a design decision lives determines who assembles it:

LevelTypical decisionsOwned by
Inside the operatorQKV projections, RoPE, QK-Norm, head sharing (MHA/GQA/MQA/MLA), gated FFNthe attention/FFN module itself
Single blockserial/parallel dependency graph, norm placement (Pre/Post/branch pre+post), residual add, branch scaling/gatingthe block's forward
Stack schedulingfinal norm, local/global interleaving, which layers are dense vs. MoEthe stack-assembly code, not any single block
Model shelltoken embedding, external absolute PE, weight tying, LM head (incl. soft-cap)the whole model's input/output layers
Execution/adaptation overlayKV cache, FlashAttention, packed projection, quantization, LoRAdeployment/fine-tuning execution strategy; leaves the four levels above architecturally unchanged

Weight tying, embedding scaling, the LM head's soft-cap, and the global dropout switch are part of the "complete LM recipe" but live outside the block — the token embedding and LM head belong to no Transformer block:

Periphery fieldOne-sentence description
Weight tyingthe input token-embedding matrix and the LM-head projection matrix share one set of parameters, saving $Vd$ parameters
Embedding scalingsome implementations multiply the token embedding by a constant related to $\sqrt{d}$ before the first block
LM head soft-capsome models (e.g. the Gemma family) also apply a §7.2-style bounded transform to the final vocabulary logits — mechanically the same tool as the attention-logit soft-cap, applied to a different tensor
Global dropout switchwhether dropout is on, and the dropout rate, are usually model-wide training configuration; but the dropout operation itself typically executes inside attention weights, FFN outputs, and residual branches — "who configures it" and "where the operator actually runs" are two different things; do not lump them into "a property outside the block"

None of these four appears in the block classes of these examples: ModernDecoderBlock's forward receives only the residual stream x and never knows whether embedding scaling happened outside or whether the output head is tied.

§5 KV Sharing and MLA

Every step of autoregressive generation appends the new token's K, V to the cache and attends over the whole cache; the cache size directly determines how many requests one GPU can serve concurrently and how long a context it can hold. GQA/MQA reduce the KV-head count and simultaneously change the K/V projections' own parameter count and compute: the KV cache mainly affects inference memory/bandwidth, while K/V projection parameters are a fixed cost that also exists in training.

5.1 MHA / MQA / GQA: different compression ratios on the same axis

MHA is the baseline. **MQA (Shazeer, Fast Transformer Decoding: One Write-Head is All You Need, arXiv 1911.02150, 2019) predates GQA (Ainslie et al., GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints, EMNLP 2023), and GQA is the quality-memory compromise between MHA and MQA. MLA is DeepSeek's separate low-rank latent-compression branch**, not "reduce $n_\text{kv}$ once more". The four are coexisting design points on the "KV memory" design axis, not a historical ladder every model climbed in order.

VariantQ headsKV headsRelation
MHA$n_q$$n_q$baseline, $n_\text{kv}=n_q$
MQA$n_q$$1$all Q heads share one set of K/V
GQA$n_q$$n_\text{kv}$ ($1 \lt n_\text{kv} \lt n_q$, with $n_q \bmod n_\text{kv}=0$)each group of $n_q/n_\text{kv}$ Q heads shares one set of K/V

With vanilla MHA, LLaMA-2-70B would need about 10 GiB of KV cache per sample at a 4096 context; switching to GQA ($n_\text{kv}=8$) drops it to about 1.25 GiB — one of the important reasons many large models adopt GQA over MHA.

5.2 MLA: the low-rank latent branch

MLA (DeepSeek-V2, May 2024, arXiv 2405.04434) compresses along the hidden dimension via low-rank projection: each token's K/V is squeezed into a latent vector with $d_c \ll n_q d_h$. It must decouple RoPE into a separately shared small-dimension component to preserve the "absorb the up-projection matrix into the query side" inference speedup. MLA's cache format is "store the latent $c_t^{KV}$ + one shared RoPE key", not "store fewer K/V heads".

GQA compresses the head count, MQA is GQA's extreme case ($n_\text{kv}=1$), and MLA compresses each token's representation dimension. The three are not three points on one scale but two different compression ideas.

§6 MoE FFN

MoE replaces the FFN with $N$ experts plus one router, and each token passes through only $k \ll N$ experts: total parameters go up, per-token activated parameters stay flat.

Mixtral (Jiang et al., Mixtral of Experts, arXiv 2401.04088, 2024) activates about 12.9B parameters per token and matches or beats Llama 2 70B on most benchmarks reported in the paper. Total parameters are far above 13B, and per-token compute is close to a dense model in the low tens of billions, but not strictly FLOPs-equivalent. DeepSeek-V3's specific load-balancing mechanism comes from Wang, Gao, Zhao, Sun & Dai (arXiv 2408.15664, 2024).

The full routing formulas, capacity factor, load-balancing loss, and token dropping are in moe_tutorial.md §2–§4.

§7 Residual Structure, Attention, and Execution

Residual connections, normalization, and branch scaling determine a block's computation structure. Numerical control inside attention adjusts scale, and local or global attention determines the visible range. FlashAttention, quantization, and LoRA serve execution optimization or fine-tuning. Most of these mechanisms can be combined; the concrete configuration is influenced by training stability, kernel support, and compatibility with existing checkpoints.

7.1 Residual topology, norm placement, and branch scaling

$A$ and $M$ are the attention and FFN sublayers, and $N_1,N_2,N_A,N_M,N_1^{\text{pre}},N_1^{\text{post}},N_2^{\text{pre}},N_2^{\text{post}}$ are all normalization operators. The four topologies are all written at "whole block" granularity:

$$\text{Post-LN}:\quad u = N_1\big(x + A(x)\big),\quad y = N_2\big(u + M(u)\big)$$

Vaswani et al. 2017's original Transformer uses this one: the normalization wraps the residual sum, repeatedly squeezing the trunk.

$$\text{Pre-LN serial}:\quad u = x + A\big(N_1(x)\big),\quad y = u + M\big(N_2(u)\big)$$

Explicitly adopted at least by GPT-2 and later the common form in modern LLMs: the trunk keeps a pure identity-add path, and the FFN reads the updated stream $u$.

$$\text{Pre-LN parallel}:\quad y = x + A\big(N_A(x)\big) + M\big(N_M(x)\big)$$

GPT-J and PaLM use this one: the ordering dependency is removed, and attention and FFN read the same $x$.

$$\text{branch pre+post}:\quad u = x + N_1^{\text{post}}\big(A(N_1^{\text{pre}}(x))\big),\quad y = u + N_2^{\text{post}}\big(M(N_2^{\text{pre}}(u))\big)$$

Gemma-2/3 use this one: the second normalization wraps only the branch output, and the trunk stays pure addition — unlike Post-LN.

Norm placement and serial/parallel dependency are two dimensions, not one axis; §1.4 [D02]/[D08] gives executable positive and negative proofs of all four topologies. branch pre+post means one normalization before and after each sublayer branch, in single-sublayer form $y = x + N_\text{post}\big(F(N_\text{pre}(x))\big)$. Gemma-2 uses this topology together with attention-logit/final-logit soft-capping; Gemma-3 keeps this norm topology but replaces soft-capping with QK-Norm.

Parallel is defined as "no intra-layer ordering dependency"; it does not require attn and FFN to share one set of norm parameters: two independent normalization modules also satisfy the definition as long as both read the original $x$. GPT-J (Wang & Komatsuzaki, EleutherAI open-source release, 2021, no formal paper/arXiv id) implements it with a single shared LayerNorm; PaLM (Chowdhery et al. (Google), PaLM: Scaling Language Modeling with Pathways, arXiv 2204.02311, 2022) continues the same idea.

Residual/branch scaling is another independent, optional assembly position: multiply the residual branch by a fixed or learnable scale coefficient. LayerScale multiplies each branch output by a per-channel, learnable, small-initialized coefficient; DeepNorm multiplies the residual branch by a depth-dependent fixed amplification factor, paired with a specific initialization so deep networks train more stably. Whether to scale, whether the scale is a fixed constant or a learnable parameter, and which branch it acts on are chosen separately from norm placement, and can also be used together with it.

7.2 attention scale, QK-Norm, logit soft-cap

Three mechanisms act at different positions on the same computation chain:

The three act at different positions and control different quantities, and cannot be stacked blindly — enabling them together requires re-checking the overall scale, not simple addition.

7.3 local / sliding / global attention

This is the design axis of attention's connectivity structure / visible range (connectivity pattern) — not an "attention backend", and separate from positional-encoding schemes. Mistral (Jiang et al., Mistral 7B, arXiv 2310.06825, 2023) uses fixed-window sliding-window attention; Gemma-2 alternates local-window and global attention 1:1 across layers; Gemma-3 is closer to a periodic pattern of "several local layers then one global layer", about 5:1, not strictly one local layer then one global layer.

None of these change the block's outer residual interface; they only change "how far attention can see" inside. And the placement of "which layers are local, which are global" is itself a stack-assembly decision, not a single block's private attribute. Full sliding-window/StreamingLLM mechanics are in long_context_rope_yarn_mla_tutorial.md §10.

7.4 FlashAttention, quantization, and LoRA

These three mechanisms stack on top of an already-chosen architecture to accelerate it or adapt it to a deployment environment; they are not architectural components on the same level as GQA/MoE requiring a mutually exclusive choice:

§8 Model Comparison and Common Wrong Answers

8.1 Block-recipe comparison table for mainstream models

Conventions: "QK-Norm" refers strictly to explicit per-head Q/K normalization before the dot product (MLA's internal latent-projection normalization does not count); "branch pre+post" means $y=x+N_\text{post}(F(N_\text{pre}(x)))$, not the same as original Post-LN; the Attention column lists only the KV-head sharing scheme, with local/sliding/global patterns in the Notes column; final norm and local/global placement belong to stack assembly, and this table presents each model's overall recipe; none of these representative models' canonical recipes uses ALiBi as the primary positional scheme.

ModelNorm topologyNorm typePositional schemeAttentionFFN/expertsParallel attn+FFNQK-NormNotes
Llama-2Pre-LNRMSNormRoPEMHA for 7B/13B; GQA for 70BSwiGLU, densenonodo not write the whole Llama-2 family uniformly as GQA
Llama-3Pre-LNRMSNormRoPEGQASwiGLU, densenono"Llama-3-like" code still needs the specific checkpoint config for exact reproduction
Qwen2/2.5Pre-LNRMSNormRoPEGQASwiGLU; dense or MoE depending on checkpointnousually notext models only; do not write the whole Qwen family uniformly as dense or uniformly as MoE
MistralPre-LNRMSNormRoPEGQASwiGLU, densenonothe original Mistral dense recipe; also uses sliding-window attention; Mixtral is a separate MoE recipe
DeepSeek-V2Pre-LNRMSNormdecoupled RoPE within MLAMLASwiGLU-style; first layer dense, then mostly DeepSeekMoEnonoMLA has internal latent projection normalization, but that is not headwise QK-Norm
DeepSeek-V3Pre-LNRMSNormdecoupled RoPE within MLAMLASwiGLU-style; first 3 layers dense, then mostly DeepSeekMoEnonoblock backbone keeps MLA+MoE; training/load-balancing improvements must not be miswritten as a new attention type
GPT-JParallel Pre-LNLayerNormpartial RoPEMHAGELU, denseyesnocore form $x+A(N(x))+M(N(x))$; GELU falls outside the ReLU/GeGLU/SwiGLU trichotomy
PaLMParallel Pre-LNLayerNorm, bias-free recipeRoPEMQASwiGLU, denseyesnoparallel attn/MLP use a common normalized residual input
Gemma-1Pre-LNRMSNormRoPEMQA for 2B, MHA for 7BGeGLU, densenonodo not write the whole Gemma-1 series uniformly as GQA
Gemma-2branch pre+postRMSNormRoPEGQAGeGLU, densenono1:1 local/global attention alternation across layers, with attention-logit and final-logit soft-capping; the post norm sits inside the branch, before the residual add
Gemma-3branch pre+postRMSNormRoPE1B: MQA; 4B/12B/27B: GQA (per the checkpoint config's num_key_value_heads)GeGLU, densenoyeslocal/global attention pattern with roughly a 5:1 period (several local layers then one global layer, not strict 1:1 alternation); QK-Norm is one of the key differences from Gemma-2
GPT-2Pre-LNLayerNormlearned absolute positional embeddingMHAGELU, densenonoserial attn→MLP per layer, final LayerNorm at the end of the stack
GPT-3Pre-LNLayerNormlearned absolute positional embeddingMHAGELU, densenonocontinues the GPT-2-style block, with dense and locally banded sparse attention patterns varying across layers

Three regularities readable from this table: (1) "Norm topology" and "norm type" almost always come bound together — Pre-LN with RMSNorm, Parallel Pre-LN with LayerNorm, branch pre+post also with RMSNorm; (2) all four of MHA/MQA/GQA/MLA appear among this same batch of representative models, supporting §5's "coexisting design points, not a historical ladder"; (3) "Parallel attn+FFN" is "yes" only in the GPT-J and PaLM rows — niche but genuinely in use, not an abandoned dead end.

The modern recipe has not fully converged: Pre-RMSNorm + RoPE + gated FFN + inference-friendly GQA is only the more common combination; Post-LN variants, LayerNorm, MHA, MQA, parallel residual, dense FFN, and MoE are all still used in production.

8.2 The twelve claims most likely to backfire

High-frequency wrong answers and the more accurate claims:

Common claimMore accurate claim
Modern LLMs are what replaced Post-LN with Pre-LNGPT-2 is already Pre-LN; this step happened earlier (§3.2)
Decoder-only is just "the decoder with cross-attn removed"Correct at the single-layer structural level; at the whole-model level also add — the encoder/memory path disappears too, and two-stream conditional generation becomes single-stream causal modeling (§3.1)
The residual stream's variance inflates $\propto\sqrt l$ with depthVariance $\propto l$ (linear); it is the standard deviation/RMS that goes $\propto\sqrt l$ — under the independent-increment assumption (§4, §9 Q11)
A Pre-LN stack must have a final norm or the model cannot train wellA common configuration of the standard recipe, not a mathematical necessity; and it is a stack-level operation, not a block field (§1.1, §9 Q11)
MHA→MQA→GQA→MLA is one evolution chainTimeline MHA→MQA→GQA, compression strength MHA→GQA→MQA; MLA is an independent latent branch — there is more than one ordering dimension (§5, §9 Q27)
MLA is just GQA with harsher compressionMLA compresses the hidden dimension and needs decoupled RoPE; GQA compresses the head count/sharing relation — the two have different constraints (§5.2, §9)
SwiGLU's hidden size must equal $8d/3$A common default computed from parameter matching; real models round to hardware-friendly multiples and deviate noticeably (§4, §1.3)
Dense FFN will sooner or later be replaced by MoEAn independent capacity axis, not a mandatory stage; Llama 1–3/original Mistral/Gemma 1–3 remain dense, Mixtral/Llama 4 have gone MoE (§6)
"Sandwich norm" and original Post-LN are the same thingThe more accurate name is branch pre+post; the second norm acts only on the branch output, not on the residual sum (§7.1)
Pre-LN needs no warmup at allPre-LN only removes the hard warmup requirement caused by Post-LN's gradient imbalance; modern Pre-LN large models still commonly use warmup (with separate Adam-related motivations, see normalization_init_tutorial.md §5.2)
MQA/GQA reduce the Q projection's computeThey only reduce K/V projection parameters/compute and KV-cache memory/bandwidth; the Q-side head count and compute are unchanged (§5.1)
Parallel residual requires attn/FFN to share the same norm parametersParallel is defined as "no ordering dependency"; two independent norm modules also qualify as long as both read the original $x$ (§7.1, §1.4 [D08])

§9 30 High-Frequency Interview Questions

Three difficulty tiers; expand each for the answer key (the 10 questions that provide a discrimination action end with a pitfall note). L2/L3 are top-lab deep water (topology forks, assembly-axis independence, system correctness, cross-model recipe comparison).

L1 Must-Know

Q1. How do you write the complete forward for the four topologies: Post-LN, Pre-LN serial, Pre-LN parallel, branch pre+post?
  • Post-LN: $u=N_1(x+A(x))$, $y=N_2(u+M(u))$ — normalization wraps each residual sum
  • Pre-LN serial: $u=x+A(N_1(x))$, $y=u+M(N_2(u))$ — the residual trunk is pure identity addition; the FFN reads $u$ (the stream after the attention update)
  • Pre-LN parallel (GPT-J/PaLM): $y=x+A(N_A(x))+M(N_M(x))$ — both sublayers read the same $x$, no ordering dependency
  • branch pre+post (Gemma-2/3): $u=x+N_1^{\text{post}}(A(N_1^{\text{pre}}(x)))$, $y=u+N_2^{\text{post}}(M(N_2^{\text{pre}}(u)))$ — one norm before and after each branch; the residual trunk stays pure addition
  • A Pre-LN stack usually ends with one stack-level final norm, which is not part of any block formula above (§0, §1.1)
Q2. What is the fundamental difference between the original Transformer decoder and a decoder-only LLM block?
  • The original decoder has causal self-attn, cross-attn, and FFN per layer; pure decoder-only deletes cross-attn and the entire encoder/memory path with it, turning two-stream conditional generation into single-stream causal modeling
  • Boundary: multimodal/RAG models may insert extra cross-attn (§3.1)
Q3. What actually changed from the GPT-2-style block to the Llama-style block?
  • Both are already Pre-LN (GPT-2 is not Post-LN)
  • LayerNorm→RMSNorm; learned absolute PE (outside the stack)→RoPE (inside attention, acting only on Q/K; first proposed by Su et al. 2021's RoFormer — LLaMA is an adopter); GELU dense FFN→SwiGLU gated FFN; MHA→MHA/GQA per the specific spec; most bias/dropout removed
  • Both have a final norm, only the type differs (LayerNorm vs RMSNorm) (§3.2)
Q4. Why does attention divide by $\sqrt{d_k}$?
  • Dividing by $\sqrt{d_k}$ pulls the attention logits' variance back to $O(1)$, preventing premature softmax saturation
  • Derivation convention: if Q/K components are independent, zero-mean, unit-variance, then $\text{Var}(q\cdot k)=d_k$

You must be able to supply $\text{Var}(q\cdot k)=d_k$.

Q5. How do LayerNorm, RMSNorm, and BatchNorm differ? Why do Transformers usually not use BatchNorm?
  • LayerNorm: normalizes over the feature dimension per sample, per position (subtract mean, divide by standard deviation) — per-sample independent, never across the batch
  • RMSNorm: re-scale only (divide by the root mean square), no mean-centering — the mean-subtraction step is dropped
  • BatchNorm: normalizes each feature dimension across the batch; its statistics (running mean/var) depend on other samples in the batch
  • Transformer inputs are variable-length sequences, so cross-position/cross-sample batch statistics are unstable; inference is often variable-length, single-sample, token-by-token autoregressive decoding, where BatchNorm's running statistics mismatch the training distribution; LayerNorm/RMSNorm compute per sample independently, naturally fitting variable-length sequences and autoregressive decoding

Pitfall: saying only "BatchNorm works poorly in NLP" without naming the batch-statistics dependency and the variable-length/autoregressive-decoding mismatch as the concrete reason.

Q6. How do tensor shapes change through full attention? Why are multiple heads and $W_O$ needed?
  • Input $x\in[B,T,d]$ → after Q/K/V projection, reshape to $[B,n_\text{head},T,d_h]$ ($d=n_\text{head}\cdot d_h$)
  • score $=QK^\top/\sqrt{d_h}\in[B,n_\text{head},T,T]$ → add mask → softmax (along the last dim) → multiply with V to get $[B,n_\text{head},T,d_h]$
  • Concat heads back to $[B,T,d]$, then the output projection $W_O\in\mathbb{R}^{d\times d}$ gives the final output $[B,T,d]$
  • Multiple heads let the model learn different attention patterns in parallel subspaces; $W_O$ re-mixes and projects the heads' outputs — without $W_O$, head outputs are mere concatenation, and information across heads cannot recombine

Pitfall: omitting the reshape/concat steps; failing to say $W_O$'s role is "mixing multi-head information" rather than just "dimension alignment".

Q7. What is the key difference between self-attention and cross-attention?
  • self-attention: Q, K, V come from the same sequence
  • cross-attention: Q comes from the current stream (length $T$), K and V from another sequence/memory (length $S$); $T$ and $S$ are generally unequal
  • The original Transformer decoder uses cross-attn to condition the target sequence on the source encoding; the pure decoder-only LLM block structurally has no cross-attn (§2, §3.1; full mask/softmax formulas in attention_tutorial.md §4.1)

Pitfall: thinking cross-attention is just "self-attention plus a mask"; failing to note that Q length and K/V length can differ.

Q8. Which design axis of attention does local/sliding-window attention belong to?
  • It is the design axis of attention's connectivity structure / visible range (connectivity pattern) — not an "attention backend" (FlashAttention is the execution backend) and not a positional-encoding scheme
  • Mistral uses a fixed sliding window; Gemma-2 alternates local/global 1:1 across layers; Gemma-3 is closer to a periodic pattern of several local layers then one global layer (about 5:1, not strict 1:1)
  • Broadly combinable with any positional-encoding scheme, but extrapolation length, window boundaries, and compatibility with specific kernel implementations still need separate verification — not unconditionally "plug and play" (§7.3)

Pitfall: calling it an "attention backend", or conflating it with positional-encoding schemes like RoPE/ALiBi; assuming "broadly orthogonal" means "swap freely with no verification".

Q9. Do weight tying, embedding scaling, and the LM head belong inside the block or in the periphery recipe?
  • All belong to the "model shell" level and to no Transformer block — the token embedding and LM head are the whole model's input/output layers, not components of any block
  • Weight tying: input embedding and LM head share one parameter matrix; embedding scaling: token embedding multiplied by a constant related to $\sqrt{d}$; LM head soft-cap: some models also apply a §7.2-style bounded transform to the final logits (§4)
  • Mixing them into the block definition when asked "what does a block look like" easily makes the interviewer doubt your grasp of the "layer vs model" boundary
Q10. What is SwiGLU's complete formula, and what is the FFN's role?
  • The FFN is position-wise: it applies the same nonlinear transform independently to each position's vector, never mixing across positions (cross-position mixing is attention's job)
  • SwiGLU formula: $\text{down}(\text{SiLU}(\text{gate}(x))\odot\text{up}(x))$ — gate and up are two independent linear projections to the intermediate dimension $h$, multiplied elementwise, then projected back to $d$ by down
  • The SiLU on the gate branch acts as a gate, deciding "how much passes" per dimension of the up branch — the key difference from a dense FFN (two matrices, one activation)
  • Within the block, the FFN plays the "per-position feature transformation / information storage" role, complementary to attention's "cross-position information routing"

Pitfall: remembering only the count "three matrices" without the gate branch's gating semantics and the FFN's position-wise nature.

L2 Intermediate

Q11. Why is Pre-LN easier to train? Why does the stack usually end with a final norm?
  • ① Pre-LN provides an identity gradient path and improves the optimization landscape, but does not guarantee lossless total gradients
  • ② Under the independent-increment approximation, $\text{Var}=O(l)$ and RMS $=O(\sqrt l)$; actual growth depends on initialization and residual correlations
  • ③ The final norm is the common stack-level closure; alternative scaling/initialization schemes can omit it (derivation in normalization_init_tutorial.md §5.3)

Note: Pre-LN does not guarantee final quality always beats a well-tuned Post-LN — when Post-LN trains stably, deep-layer contributions are not diluted and the ceiling is sometimes higher.

Pitfall: writing the variance growth as $\propto\sqrt l$ (it is the standard deviation/RMS that goes as $\sqrt l$; variance itself grows linearly as $O(l)$); calling the final norm "mathematically required".

Q12. Where should RoPE be inserted, and what goes in the KV cache?
  • Standard path: RoPE acts only on Q/K; the cache stores K already rotated at each position; V is never rotated; GQA/MQA store only $n_\text{kv}$ heads
  • Note: caching unrotated K is also legal, but positions must be saved and rotation applied on read
  • MLA uses a different latent cache contract (§5.2; full rotation-matrix derivation in long_context_rope_yarn_mla_tutorial.md §2)
Q13. How do parameter counts and KV cache change across MHA, MQA, GQA?
  • MHA parameters $4d^2$; GQA parameters $2d^2(1+n_\text{kv}/n_q)$, degenerating back to MHA at $n_\text{kv}=n_q$ (§1.3 [D06])
  • KV cache: MHA $2n_q d_h$, GQA $2n_\text{kv}d_h$, MQA $2d_h$ elements/token/layer
  • Conventions: $d=n_qd_h$, identical Q/K/V head dim, $W_O$ is $d\times d$, bias ignored

State the conventions first, then convert element counts to bytes.

Q14. How do you compute a dense Transformer block's parameter count and FLOPs?
  • Parameters: attention about $4d^2$ (or GQA's $2d^2(1+n_\text{kv}/n_q)$) + FFN about $8d^2$ (dense) or $3dh$ (gated) + the two norms' per-channel parameters ($O(d)$, asymptotically lower-order than the matrix parameters) — per layer the FFN usually dominates (about 76% in §1.1's concrete example)
  • FLOPs: attention's QKVO projections are $O(Td^2)$, score-matrix computation + weighted sum are $O(T^2d)$ ($T$ is the sequence length), and the FFN is $O(Tdh)\sim O(Td^2)$
  • At small $T$ the projections dominate (the $O(Td^2)$ terms); at large $T$ attention's quadratic $O(T^2d)$ term gradually dominates — the direct reason attention compute becomes the bottleneck in long-context settings

Pitfall: memorizing only the parameter formulas without saying which of $O(Td^2)$ and $O(T^2d)$ dominates at which sequence lengths.

Q15. Why is SwiGLU's hidden size often close to $8d/3$?
  • Ignoring bias, a dense FFN (two matrices) has $8d^2$ parameters ($4d$ expansion); a gated FFN (gate/up/down, three matrices) has $3dh$
  • Setting them equal: $3dh=8d^2 \Rightarrow h=8d/3$ — a common default computed from parameter matching, not an architectural law that "gated FFN hidden size must equal $8d/3$"
  • Real Llama-family implementations usually start from $4d$, multiply by $2/3$, then round to hardware-friendly multiples (with an optional multiplier); the intermediate size can deviate noticeably from $8d/3$ (§4; §1.3 [D06] verifies 73,728 parameters on both sides at $d=96$)
Q16. Are serial attn→FFN and parallel attn+FFN equivalent?
  • No: in serial Pre-LN the FFN reads the residual stream after the attention update ($\text{FFN}(N_2(x+\text{Attn}(N_1(x))))$); in parallel, FFN and attention read the same normalized original input ($x$), independent of each other
  • The test should not be "do the two outputs happen to differ" (fragile) but reconstructing the FFN's actual input tensor for an exact match (§1.4 [D08] captures the input with a forward hook + compares against an independent recomputation)
  • The parallel structure removes this dependency chain and can cut some synchronization overhead during training (§7.1)
Q17. What problems do attention scale, QK-Norm, and logit soft-cap each solve?
  • scale controls dot-product magnitude (standard $1/\sqrt{d_h}$ or a learnable temperature)
  • original QK-Norm normalizes Q/K before the dot product and replaces the fixed scale with a learnable temperature
  • soft-cap bounds scores/logits after the dot product (bounded transforms like $c\tanh(z/c)$)
  • Combining them requires re-calibrating the scale; specific model implementations may differ (§7.2; full argument in normalization_init_tutorial.md §6.3)

Do not omit that original QK-Norm replaces the fixed scale.

Q18. How does a packed QKV projection differ from three separate Linears?
  • Packed and separate Linears are mathematically equivalent; with equivalent weights they agree within reasonable tolerance for the given dtype (§1.4 [D07])
  • Packed usually reduces kernel launches, but whether it is faster depends on sizes, quantization, and parallel layout
  • Same for SwiGLU's gate/up
Q19. What is the essential difference between MLA and GQA?
  • GQA compresses the KV-head count; MLA compresses KV into a low-dimensional latent ($d_c \ll n_qd_h$)
  • MLA's cache is latent + shared RoPE key, not "fewer heads of ordinary K/V"
  • To keep the absorbing trick, MLA must decouple RoPE; GQA has no such problem (§5.2; full derivation in long_context_rope_yarn_mla_tutorial.md §9)
Q20. Why do prefill and decode have different bottlenecks? How does the KV cache change the complexity?
  • Prefill processes the whole prompt with high weight reuse, so it is usually more compute-bound; decode processes one token per step but must read the weights and the growing KV, so at small batch it is more bandwidth-bound
  • What the KV cache saves is recomputing the historical K/V projections: at fixed model width, recomputing the K/V projections for the first $t$ positions grows linearly with length, while with a cache each step projects only the new token; $O(t^2)$ describes the cost of recomputing attention over the whole sequence, not the cost of the K/V projections ($t$ is the current position; full bottleneck analysis in llm_inference_serving_tutorial.md)
Q21. Which layer do FlashAttention, PagedAttention, and GQA/MQA each optimize?
  • FlashAttention: an IO-aware exact-attention kernel, optimizing "how to compute" — tiling/recompute to reduce HBM access, changing neither attention's mathematical result nor the model architecture (§7.4)
  • PagedAttention: a KV-cache memory-management mechanism, optimizing "how to store" — a page table maps logical KV to non-contiguous physical memory blocks, reducing fragmentation; serving-system level
  • GQA/MQA: model-architecture choices, optimizing "how much to store" — fewer KV heads shrink the cache itself
  • The three are optimizations at different levels and must not be conflated: the first two are execution/system engineering, the last is an architectural decision fixed before training; full mechanics in attention_tutorial.md (FlashAttention) and llm_inference_serving_tutorial.md (PagedAttention)
Q22. Why are bias and dropout gradually removed in modern large-model pretraining?
  • Large-scale, low-epoch pretraining commonly drops bias/dropout: bias's benefit is limited; massive data already provides strong regularization, and dropout can even slow convergence
  • This is an empirical recipe at that training scale, not a universal theorem (GPT-2-style keeps both; see the §3.2 bridge table)
Q23. What is inaccurate about the name "sandwich norm"? How should the formula be written?
  • "Sandwich norm" is an ambiguous colloquialism; the more accurate phrasing is "one normalization before and after each sublayer branch" (branch pre+post normalization)
  • Exact formula: $y=x+N_\text{post}(F(N_\text{pre}(x)))$ — the second normalization acts only on the branch output, not on the residual sum
  • This differs from original Post-LN's $N(x+F(x))$: Post-LN normalizes the whole summed stream, while branch pre+post closes off only the branch output, leaving the residual trunk pure addition (§7.1; Gemma-2/3 use this topology; full variant genealogy in normalization_init_tutorial.md §6.2)
Q24. How do MLA's and GQA's KV cache contracts differ?
  • GQA's cache is $n_\text{kv}$ heads of complete K/V (each of dimension $d_h$) — essentially still "multiple heads of ordinary K/V", just fewer than $n_q$
  • MLA's cache is one shared latent $c_t^{KV}$ (dimension $d_c$) plus one shared decoupled RoPE key (dimension $d_h^R$) — not "fewer heads of ordinary K/V", and K, V are no longer stored independently. The full absorbing trick, why RoPE cannot be absorbed directly, and the decoupling scheme's algebra are in long_context_rope_yarn_mla_tutorial.md §9, not repeated here
Q25. When hand-writing a KV-cached incremental-decoding causal self-attention, which correctness pits are easiest to miss?
  • ① The standard cache stores rotated K; the alternative contract must save positions (see Q12)
  • ② The cache always keeps $n_\text{kv}$ heads; broadcast results must never be written back
  • ③ Only under a dynamic dense causal setup with no padding/packing is the single-token mask all True
  • ④ Full-forward and cached decode must agree, but mask broadcasting and cache validation still need separate tests (§1.4 [D04])
Q26. Where does GQA's $n_q \bmod n_\text{kv} = 0$ constraint come from? Does it still hold in MLA?
  • Standard uniform GQA requires $n_q \bmod n_\text{kv}=0$: the $n_q$ Q heads split evenly into $n_\text{kv}$ groups of $n_q/n_\text{kv}$ each
  • MLA has no $n_\text{kv}$ grouping variable, so the constraint does not apply (§5)
  • Note: non-uniform head→KV mappings are definable in principle but are not a common model/kernel contract
Q27. Why is "MHA→MQA→GQA→MLA is one evolution chain" wrong? What is the correct way to organize the four?
  • Historical order: MHA→MQA→GQA (MQA predates GQA)
  • Compression strength: MHA→GQA→MQA — MHA ($n_\text{kv}=n_q$) and MQA ($n_\text{kv}=1$) are the two endpoints of the same uniform-GQA compression-ratio axis
  • MLA compresses the latent (hidden) dimension, is not on the KV-head-count axis, and should not be appended to its end (§5)

L3 Advanced

Q28. Given a Llama-3-like dense GQA block, how do you swap in MoE without changing the block interface? Which parts of the contract change, and which do not?
  • Replace only the FFN slot: the attention slot (GQA, RoPE) and normalization slot (Pre-RMSNorm) stay untouched
  • Three contract layers: ① main-activation shape unchanged — [B,T,d] -> [B,T,d], residual add stays in place; ② the training API may add router/load-balancing quantities; ③ distributed systems usually add expert parallel/all-to-all; report total and activated parameters separately
  • The backward pass only requires experts hit in this batch to receive gradients (§1.4 [D09]; full routing/capacity math in moe_tutorial.md §2–§4)
Q29. What systematic cost differences do parallel residual (GPT-J/PaLM) and serial Pre-LN have in training/inference?
  • Dependency chain: parallel allows attn/FFN to overlap; serial forces attn→FFN
  • Quality: both can train well; no unconditional winner
  • Norm overhead: shared-norm parallel (e.g. GPT-J) saves one norm; two-norm parallel only removes the dependency without reducing norm count (§7.1)
Q30. Given a new model's technical report, which block fields would you check first to determine its recipe?
  • Block: ① norm topology/type; ② positional encoding and its level; ③ attention: $n_q$/$n_\text{kv}$ or MLA latent/cache, QK-Norm, window; ④ FFN: dense/gated/MoE, activation, intermediate size, total/activated parameters; ⑤ bias/dropout/residual scaling
  • Stack: final norm, local/global, dense/MoE layer placement (checked separately, never mixed into block fields)
  • Fine details: head dims, scale/temperature, mask, cache layout

📚 References