Lab 3: Self-Attention by Hand
One head by hand, a heatmap, then a causal mask — and why zero is the wrong fill.
Work in a Jupyter notebook with PyTorch. Do notes 3.1–3.4 first.
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
The algebra is note 3.2. The causal mask is the GPT fork in note 3.4.
1. One head, by hand
Four tokens, . You will compute attention without nn.MultiheadAttention.
torch.manual_seed(0)
X = torch.tensor([
[1.0, 0.0], # The
[0.0, 1.0], # cat
[1.0, 1.0], # sat
[0.5, 0.2], # on
])
Wq = torch.eye(2)
Wk = torch.eye(2)
Wv = torch.eye(2)
-
Compute . With these weights they equal .
-
Scores . Print . Why , not ?
-
. Rows must sum to 1. Heatmap with token names
The, cat, sat, on. -
Output . Which token’s output is closest (cosine) to
cat? Guess before you compute. Confirm you mixed values, not keys.
2. A causal mask
-
Build a mask with on and below the diagonal and strictly above. Add it to before softmax. Print the new . The last token may see everyone; the first token may see only itself.
-
Briefly: replace by and softmax again. Why is that the wrong mask?
-
In one sentence: why would a GPT-style model be cheating without this mask?
3. Library check
attn = torch.nn.MultiheadAttention(embed_dim=2, num_heads=1, batch_first=True)
You do not need to train it. Copy attn.in_proj_weight is optional. The point of (1)–(2) is the algebra. Write four sentences: query vs key vs value, what a row of is, why Week 2’s hidden state is no longer the only memory, and whether this four-token map is GPT-style or BERT-style before you add the mask.