← Questions
Implement multi-head self-attention from scratch
0
I was asked this
No reports yet. Sign in to say where you were asked it.
Write masked multi-head self-attention from scratch, the layer at the core of a Transformer. Given a batch of token embeddings, project them to queries, keys and values, split them into heads, run scaled dot-product attention in each head, merge the heads and apply the output projection. Support a padding mask and a causal mask.
Requirements
- Functional: a module
MultiHeadSelfAttention(d_model, num_heads)withforward(x, padding_mask=None, causal=False).xhas shape(batch, seq_len, d_model)and the output has the same shape. - Separate learned projections for queries, keys and values, and one output projection.
d_modelmust divide evenly bynum_heads. - Scores are
Q·Kᵀ / sqrt(d_head), softmax over the key positions, then a weighted sum of the values. -
padding_maskhas shape(batch, seq_len)and marks padded keys that no query may attend to. Withcausal=True, positionimay attend only to positions<= i. - You may use tensor operations (matmul, softmax), but not a built-in attention layer.
- Non-functional: the cost in time and memory as
seq_lengrows, and numerical stability.
Clarifying questions
- Which framework, and may I use its built-in softmax and linear layers?
- Should a padding mask hide padded keys only, or padded queries as well?
- What should a query row return when every key is masked?
- Do you want dropout on the attention weights?
What a strong answer covers
- The shapes at every step:
(B, T, D) → (B, H, T, D/H)for the heads,(B, H, T, T)for the scores, then back to(B, T, D), and where the transposes and reshapes go. - Why the scores are divided by
sqrt(d_head): without it large dot products push softmax into regions with tiny gradients. - Masks applied before the softmax by setting blocked scores to a large negative value, and the fully masked row handled without producing NaNs.
- Cost:
O(T²·D)time andO(T²)memory per head for the score matrix. - A test: with one head and the projections set to identity, compare against a hand-computed softmax, and check that a causal output at position
idoesn't change when later tokens change.
Follow-ups
- Add a key-value cache for autoregressive decoding and say what it saves.
- Multi-query or grouped-query attention: what changes and why it helps inference.
- How do FlashAttention-style kernels avoid materializing the
T x Tmatrix? - Where do positional encodings such as RoPE enter this layer?
No official answer yet. Draw yours on the right; publish it and it shows under Community.
Nothing published yet. Publish your canvas and it shows here for others to open and remix.
Draw your answer hereBoxes, arrows and notes, saved for you to come back to.Sign in to start drawing


