The one operation that powers every transformer: each token looks at every other
token and pulls in what's relevant. It's just three matrices — Query, Key, Value — and the
formula softmax(Q·Kᵀ / √d)·V.
Tiny 2-D Q/K/V vectors keep the arithmetic legible. It opens on the first token's finished step — its Query scored against every Key, softmaxed, the Values blended. Press ▶ to replay, click a token to jump to its softmax, or type your own sentence.
① Scores = Q·Kᵀ, then ÷√d, then ② softmax → weights:
Full attention matrix (row = query, darker = more attention):
③ Output = Σ (weight × Value) — the context-mixed vector for the query token:
To understand a word you need its context. In "the cat ate the fish," the meaning of "ate" is tied to its subject ("cat") and object ("fish"), which sit several positions away. Older models pushed information along the sequence step by step (RNNs), which is slow and forgetful over long distances. Self-attention instead lets every token directly gather information from every other token in one parallel step — and learn which ones matter.
Attention reframes "understanding context" as a soft dictionary lookup. From each token's embedding, three small learned matrices produce three vectors:
To process a token, you compare its Query against every token's Key with a dot product — high when they align, the way two arrows pointing the same way have a large dot product. Those scores become attention weights (via softmax), and the token's output is the weighted sum of all the Values. A token that matches your query contributes most of its Value; irrelevant tokens contribute almost nothing.
√d? In high dimensions, dot products grow large, which makes
softmax razor-sharp (one token gets weight ≈1) and kills the gradient. Scaling by √d keeps
the scores tame so attention stays smooth and trainable. Toggle the checkbox to feel the difference.Multi-head attention just runs several of these in parallel with different learned projections, so one head can track syntax while another tracks coreference, then their outputs are concatenated. Stack that with a feed-forward network, add residual connections and normalization, and repeat — that's a transformer block.
Two things the walkthrough above skipped, because a real transformer needs both. First: not every
token may look at every other token. A decoder predicting token 4 must never see tokens 5 and 6 —
that would let training copy the answer instead of predicting it — so a causal mask sets those
scores to −∞ before the softmax, and a padding mask does the same for the
filler tokens a batch adds so every sequence in it has the same length. Second: real models don't run one
wide attention — they split the same total dimension into several narrower heads that each learn a
different kind of relation, then concatenate the results back together. Pick a mask below, then compare 1
head against 4 on the six-token sentence "the cat sat on the mat":
√d, softmax
into weights, and output the weighted sum of Values. It lets every token gather context from every other
token in parallel — the core of every modern LLM. Build the whole block in
BYO-8 (mini-GPT). For a real running model, poke the
Transformer Explainer.