This week we assemble all the components — embedding, positional encoding, multi-head attention, feed-forward networks, residual connections, layer normalisation — into a complete Transformer block, and then into full encoder-only, encoder-decoder, and decoder-only models.
A single Transformer block consists of:
x → LayerNorm → Multi-Head Self-Attention → + (residual) → LayerNorm → FFN → + (residual)
In PyTorch pseudocode:
def transformer_block(x, attn, ffn):
# Self-attention sub-layer with residual
x = x + attn(layer_norm(x))
# Feed-forward sub-layer with residual
x = x + ffn(layer_norm(x))
return x
Note: this is “Pre-LN” (layer norm before the sub-layer), which is more stable than the original “Post-LN” variant.
Covered in Week 4. Allows each token to gather information from all other tokens.
A position-wise (applied independently to each token) two-layer MLP:
FFN(x) = W_2 * GELU(W_1 * x + b_1) + b_2
The FFN has been described as a “key-value memory” — it stores factual associations learned during pre-training.
output = sub_layer(x) + x
Residual connections (He et al., 2016, from ResNets) allow gradients to flow directly to earlier layers, enabling training of very deep networks.
LayerNorm(x) = gamma * (x - mean(x)) / std(x) + beta
Normalises each token’s representation independently across the embedding dimension. Stabilises training.
Input: "The [MASK] sat on the mat"
Target: "cat"
Input: "The cat sat on the"
Target: "mat"
This is the architecture we focus on for the rest of the course.
Input token IDs
│
▼
Token Embedding (V × d_model)
+
Positional Encoding
│
▼
[Transformer Block 1]
[Transformer Block 2]
...
[Transformer Block N]
│
▼
Layer Norm
│
▼
Linear (d_model → V) ← weight-tied with token embedding
│
▼
Softmax → probability distribution over vocabulary
For GPT-2 small: N=12 blocks, d_model=768, d_ff=3072, 12 heads, vocab 50,257. For LLaMA-3 70B: N=80 blocks, d_model=8192, grouped query attention, vocab 128,256.
The token embedding matrix (V × d_model) is shared with the final linear layer that projects back to vocabulary size. This reduces parameters and also ensures the representation space is consistent between input and output.
At inference time, generating token t+1 requires the keys and values from all previous positions 1..t. Computing these from scratch each step would be O(n²) total. The KV cache stores previously computed K and V matrices and reuses them.
| Model | Layers | d_model | Heads | Parameters |
|---|---|---|---|---|
| GPT-2 small | 12 | 768 | 12 | 117M |
| GPT-2 XL | 48 | 1600 | 25 | 1.5B |
| LLaMA-2 7B | 32 | 4096 | 32 | 7B |
| LLaMA-2 70B | 80 | 8192 | 64 | 70B |
| GPT-3 | 96 | 12288 | 96 | 175B |
Modern large models also use:
See practicals/week05_practical.py:
[1_1]_Transformer_from_Scratch_(exercises).ipynb