Interactive Explainer
Attention, Calculated
Pick an ambiguous word, drag its Query vector, and watch a Transformer figure out which neighbors to listen to—with every dot product, softmax weight, and value blend computed live as you move the arrows.
The ambiguity problem
A word in isolation is almost meaningless. Consider the word bank. Is it a river bank or a money bank? The word alone can't tell you—you have to look at its neighbors.
Self-attention is how Transformers let each word ask around. Every word in a sentence says to every other word: "Hey, how much should I care about you?" The answer comes back as a single number between 0 and 1. Then each word rebuilds itself as a weighted mix of its neighbors' meanings.
This page makes all of that explicit. By the end you'll have pushed raw scores through a softmax, watched a blended value vector form, and built the intuition for why Transformers beat every prior architecture at disambiguation.
Pick your sentence
We'll work through a handful of classic ambiguous words. Pick one and the whole page follows it:
The focus word bank needs to figure out whether it is water-related or money-related by listening to its neighbors.
Three roles for every word
In a Transformer, every word is associated with three separate vectors, each playing a different role:
- Query ($Q$): "What am I looking for?" This is the perspective of the word that wants to update itself.
- Key ($K$): "What do I offer?" Every other word advertises its flavor here.
- Value ($V$): "If you decide to attend to me, here is the actual meaning I contribute."
Queries and keys determine how much to attend. Values determine what gets mixed in. Keeping those two roles apart is what makes attention expressive.
Where Q, K, V actually come from
Step 1 painted Q, K, V as three roles a word plays. Where do those vectors physically come from? Each is a linear projection of the same input embedding $x_i \in \mathbb{R}^{d_{\text{model}}}$. Three matrices $W_Q, W_K, W_V$ are learned once, shared across every position:
Same input, three different rotations. The query rotation pulls out the "what am I looking for?" features, the key rotation pulls out the "what do I advertise?" features, and the value rotation pulls out "what do I deliver if attended to?". One word plays three roles because three separate matrices were trained to read it three different ways.
Worked example, real numbers
Click any token to see its raw embedding $x_i$ pushed through $W_Q$, $W_K$, $W_V$. We use $d_{\text{model}}=4$ and $d_k = d_v = 2$ so the matrices fit on screen — in GPT-style models they're 768 or 4096, but the recipe is identical. (Embeddings and projection matrices are pre-cooked here; in real training they'd be learned by gradient descent — see Step 8.)
Dot product = compatibility score
How do we measure how well a Query matches a Key? We use the dot product. If the two vectors point the same way, the score is large and positive. If they're perpendicular, zero. If they point opposite ways, negative.
Drag the orange Query arrow for the focus word, and the blue Key arrows for every other word. Watch the raw scores update live below. Drag the query so it aligns with one specific key and you'll see that word win.
| Word | Query vector | Key vector | Dot product |
|---|
Softmax turns scores into percentages
Raw dot products aren't weights—they can be negative, or gigantic. We need them to behave like probabilities that sum to one. Softmax does exactly that:
Exponentiating amplifies differences: a score that's just a bit higher than the others rockets upward, dominating the weights. This is why softmax is called "soft" argmax—it picks a winner, but still passes non-zero signal to everyone else.
Step-by-step calculation (live)
Here's the full pipeline applied to your current dragged arrangement. Every number comes from the canvas above:
| Word | Raw score | exp(score) | Weight (softmax) |
|---|
Blend the values into a new meaning
Now the payoff. The focus word rebuilds its meaning as a weighted sum of the Value vectors, with the softmax weights we just computed:
Below, the teal arrows are the value vectors for every word (drag them to simulate different "meanings"). The dashed orange arrow is $V_{\text{final}}$—the new contextual meaning for the focus word. Watch it slide toward whichever value has the highest attention weight.
All at once — the matrix view
Real Transformers don't loop over tokens one at a time. They stack all $N$ queries into a matrix $Q$, all $N$ keys into $K$, all $N$ values into $V$, and produce the entire layer output in a single matrix multiplication:
Here's that exact computation, run live on your current sentence. The score matrix $S$ is the table of every query against every key. Apply softmax to each row and you get the attention weight matrix $A$. Multiply by $V$ and you get the new embeddings $Y$ — one new vector per token, all in one matmul.
(row-wise)
Three knobs that shape every Transformer
The clean formula above hides three design choices that decide whether the layer is useful or broken. Here they are with quick interactives.
Knob 1 — Why divide by $\sqrt{d_k}$?
Dot products of two random $d_k$-dimensional vectors have variance $d_k$. As $d_k$ grows, raw scores get huge, softmax sharpens to one-hot, and gradients vanish. Dividing by $\sqrt{d_k}$ keeps the variance at 1 regardless of width.
Knob 2 — Causal masking
For a language model, the word at position $t$ must not peek at positions $t+1, t+2, \dots$ — or training would just teach it to copy the next token. We zero out those entries before the softmax by adding $-\infty$ to the upper triangle. After softmax, the future is exactly 0.
Each row's surviving weights are renormalised by the softmax, so an early token only sees itself, the next sees itself plus one predecessor, and so on. This single trick is what makes GPT-style models autoregressive.
Knob 3 — Multiple heads
One attention map can only express one relation at a time. Real Transformers run $h$ heads in parallel — each with its own $W_Q^{(h)}, W_K^{(h)}, W_V^{(h)}$ — then concatenate their outputs. Different heads learn to specialise (syntax, coreference, positional adjacency, topic).
Each head sees the same input but uses a different rotation of it (we simulate that here with four hand-picked rotations). Real heads are learned, but the visual story is the same: they notice different things.
Positions: the bug attention secretly has
Self-attention is permutation-invariant. Shuffle the order of the input tokens and the output is the same set of new vectors, just reshuffled. For language that is fatal — "dog bites man" and "man bites dog" should not be the same.
The fix — add a position signal
Before any attention runs, the model adds a position vector $p_t \in \mathbb{R}^{d_{\text{model}}}$ to each token's embedding. The classic Vaswani et al. choice is sinusoidal:
Each dimension is a sinusoid with a different wavelength. The short-wavelength dimensions distinguish nearby positions; the long-wavelength ones carry far-apart structure. Together they give every position a unique fingerprint — and crucially, a fingerprint where relative position can be linearly decoded.
With vs without — permute the sentence
Toggle the position signal on and off, then shuffle the words. With positions, "river bank" and "bank river" produce different attention; without, they're identical.
Watch a tiny attention head learn
Every Q, K, V in the article so far was hand-tuned to produce the "right" answer. Real Transformers don't get those for free — they discover them with gradient descent. Let's train one in your browser, end-to-end, with manually-coded backprop. Every parameter, every gradient, every step is in plain JavaScript — nothing imported.
The toy task — a soft lookup
We give the model a sequence of four tokens. The first three are candidates: each carries a one-hot identity in $\{A, B, C\}$ plus a random 3-dim payload. The fourth is the query: a one-hot saying which candidate's payload we want, with zeros for its payload slot. The model has to output that payload at the query position — a real "look-up by name" problem.
The only learnable parameters are the three projection matrices $W_Q$, $W_K$, $W_V$. We initialise them to small random Gaussians, run gradient descent on mean-squared error at the query position, and watch the loss fall.
What the model is learning
Two heads, two specialists
Step 7 said multi-head exists; Step 9 trained one head. Now watch two heads train side-by-side on a task that a single head cannot solve. Each head gets its own $W_Q, W_K, W_V$ (and a final linear that combines the two outputs). Loss flows through both.
The task: two compatible lookups
The sequence has four tokens: two type-A pairs $(\text{key}_A, \text{val}_A)$ and two type-B pairs $(\text{key}_B, \text{val}_B)$. Each token's input is $\bigl[\text{type}\ (2)\;|\;\text{key}\ (3)\;|\;\text{val}\ (3)\bigr]$. The query token (token 4) carries $\bigl[\text{type-A flag}\ (1)\;|\;\text{key}\ (3)\;|\;\text{type-B flag}\ (1)\;|\;\text{key}\ (3)\bigr]$ and we ask the model to output $\text{val}_A + \text{val}_B$ at the query position. One head can't disentangle the two lookups; two heads can.
Run it on all five sentences
Here's one more look at the pipeline, this time fully automated. The table below evaluates the same Q, K, V vectors (the pre-set "sensible" ones for each ambiguous word) through the entire attention formula and shows which neighbor dominates. Click a different sentence to see a different winner.
| Sentence | Focus word | Top-attended neighbor | Attention % | Interpretation |
|---|
Three things attention is not
"Attention is just a weighted average, nothing new."
The weights themselves are computed from the data
through $QK^\top$—they depend on every pair of tokens. No
static weighted sum gives you that. It's a function whose
coefficients are learned on the fly.
"Attention tells you what the model cares about."
Attention weights are one signal inside a deep model.
Cutting a low-weight neighbor doesn't necessarily change the
prediction, and the same logit can be reached via many weight
patterns. Reading them as explanations is risky.
"Every word attends to every other word equally in cost."
Self-attention is $O(n^2)$ in sequence length: doubling the
sentence quadruples the compute. That's why long-context models
use tricks (sparse, linear, sliding-window) to cut this down.
What we still swept under the rug
You've now seen every number of one head, one layer, with positions, with masking, with multi-head, and with training. A real Transformer keeps going:
- Many stacked layers. The output of one attention block becomes the input to the next. After a few layers, "bank" carries meaning shaped by chains of inference across the whole sentence. ViT-Base stacks 12, GPT-3 stacks 96, GPT-4 reportedly more.
- Residual streams + LayerNorm. Each block is wrapped in $x \leftarrow x + \mathrm{Attn}(x)$ followed by a LayerNorm and an MLP. The residual lets information skip unchanged through layers and is now believed to be the actual "memory tape" the model writes onto.
- Cross-attention. In encoder-decoder models (translation, T5, image-to-text), $Q$ comes from the decoder but $K, V$ come from the encoder — the decoder "asks the source" instead of itself. Mechanically the same formula.
- Efficient attention. $O(N^2)$ blows up at long context. FlashAttention reorders the matmul to fit in SRAM; sliding-window (Mistral), sparse (Longformer), state-space (Mamba), and linear-attention (Linformer) variants trade a little expressivity for $O(N)$ or $O(N \log N)$.
- KV cache for inference. When a chatbot generates text token by token, the keys and values of all previous tokens are cached and reused. That cache is most of what fills GPU memory in production deployments.