Spot the error: 'I apply the causal mask by setting masked positions to 0 in the attention scores before softmax.'
Same topic, related formats. Practice these next.
Same topic, related formats. Practice these next.
Click any words you think contain an error. Click again to unmark.
Setting masked scores to zero leaves them with about one-over-N weight after softmax; the correct mask value is negative infinity, applied before softmax.
Picture a vote where every candidate's score gets converted into a vote count by a rule that turns even a zero into one vote, because the conversion exponentiates first. A candidate you tried to disqualify by giving them a zero score still ends up on the ballot with one vote. To actually remove them, you have to push their score down to 'negative infinity bad', which is the only score the rule turns into zero votes. The intuition that 'zero score equals zero influence' is wrong here, and that misunderstanding is exactly the masking bug we are spotting.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
5 min: domain confusion between score and weight; arithmetic for softmax of [1, 2, 3, 0]; correct additive masking with -inf; dtype-aware mask values; multiplicative masking equivalent bug; training inference mismatch signature; how to test for leakage.
import math
import torch
B, H, T, D = 1, 1, 4, 8
q = torch.randn(B, H, T, D)
k = torch.randn(B, H, T, D)
causal_mask = torch.tril(torch.ones(T, T)) # 1 at allowed, 0 at forbidden
# WRONG: set masked scores to 0
scores = q @ k.transpose(-2, -1) / math.sqrt(D)
bad = scores.masked_fill(causal_mask == 0, 0.0)
weights_bad = torch.softmax(bad, dim=-1)
# weights_bad has nonzero weight at future positions
# CORRECT: set masked scores to -inf
good = scores.masked_fill(causal_mask == 0, float('-inf'))
weights_good = torch.softmax(good, dim=-1)
assert weights_good[..., 0, 1:].sum().item() == 0.0 # row 0 attends only to col 0Real products, models, and research that use this idea.
What an interviewer would ask next. Try answering before peeking at the approach.
Red flags and common mistakes that signal junior thinking. Click to expand.
Conflating pre-softmax score with post-softmax weight. A score of zero exponentiates to one, so the masked position still claims a real slice of the probability mass.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.