Linear algebra for LLMsPart 5: Attention, one operation at a time
Multi-head attention
7 min
Many heads, in parallel
Instead of one wide head, use narrow ones, each with its own projections of width . Each head computes its own attention pattern: one might follow the previous token, another the subject of the sentence.
Write
One big projection, cut into heads
Code keeps one weight per projection. Its column blocks are the heads (Part 2), so a single matmul computes all heads’ queries, and view + transpose cut the result into heads (Part 4).
Concatenate, then mix with
The heads’ outputs are placed side by side, back to width , and one more matrix mixes information across heads. In block form that’s : every head writes its own contribution into the residual stream.
Write
Parameters: , whatever is
Splitting into heads doesn’t add parameters: heads of width use the same matrices as one head of width . That’s about 67 million parameters per layer for standard multi-head attention at , without biases.
Write
Each head is low-rank
From Part 3: each head compares tokens through a bilinear form of rank at most . Many narrow heads see many different low-dimensional “views” of the tokens, instead of one wide view.
✏️ Your turn
Size a GPT-2 small layer
Write and the number of attention weight parameters per layer (ignore biases).
Work it out on paper, then go to the next card to check.
Answer
About 2.4 million per layer, 28 million across GPT-2 small’s 12 layers.
In PyTorch
q = (x @ W_q).view(B, T, h, d_h).transpose(1, 2) # (B, h, T, d_h)
k = (x @ W_k).view(B, T, h, d_h).transpose(1, 2)
v = (x @ W_v).view(B, T, h, d_h).transpose(1, 2)
o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
o = o.transpose(1, 2).reshape(B, T, d) @ W_o # concat heads, mix📌 Recap
Multi-head attention in one card
- heads of width , each with its own attention pattern.
- One big projection, cut into heads by view + transpose.
- Concatenate and mix: .
- parameters regardless of ; each head has rank .
Write