Scaled dot-product attention

8 tokens·dₖ = 4·causally maskedAll algorithms

AlgoLab runs no language model. The vectors here are four numbers per token, typed in by hand so that every dot product on this page can be checked with a pencil, and you can read all of them in the Vectors tab. A real model’s queries, keys and values have hundreds or thousands of dimensions, learned from data rather than chosen by a person.

Q vector for the, position 0, dimension 0: 11Q vector for the, position 0, dimension 1: 00Q vector for the, position 0, dimension 2: 00Q vector for the, position 0, dimension 3: 11Q vector for cat, position 1, dimension 0: 00Q vector for cat, position 1, dimension 1: 22Q vector for cat, position 1, dimension 2: 11Q vector for cat, position 1, dimension 3: 00Q vector for sat, position 2, dimension 0: 22Q vector for sat, position 2, dimension 1: 00Q vector for sat, position 2, dimension 2: 11Q vector for sat, position 2, dimension 3: 00Q vector for on, position 3, dimension 0: 11Q vector for on, position 3, dimension 1: 11Q vector for on, position 3, dimension 2: 00Q vector for on, position 3, dimension 3: 11Q vector for the, position 4, dimension 0: 11Q vector for the, position 4, dimension 1: 00Q vector for the, position 4, dimension 2: 00Q vector for the, position 4, dimension 3: 11Q vector for warm, position 5, dimension 0: 00Q vector for warm, position 5, dimension 1: 22Q vector for warm, position 5, dimension 2: 00Q vector for warm, position 5, dimension 3: 11Q vector for mat, position 6, dimension 0: 11Q vector for mat, position 6, dimension 1: 11Q vector for mat, position 6, dimension 2: 11Q vector for mat, position 6, dimension 3: 00Q vector for today, position 7, dimension 0: 00Q vector for today, position 7, dimension 1: 11Q vector for today, position 7, dimension 2: 22Q vector for today, position 7, dimension 3: 00Dimension 0, which has no meaning of its own0Dimension 1, which has no meaning of its own1Dimension 2, which has no meaning of its own2Dimension 3, which has no meaning of its own3Query 0, the token “the”the0Query 1, the token “cat”cat1Query 2, the token “sat”sat2Query 3, the token “on”on3Query 4, the token “the”the4Query 5, the token “warm”warm5Query 6, the token “mat”mat6Query 7, the token “today”today7↓ dimension→ query
Whole matrix

These are the 8 query vectors, one row of 4 numbers for each token. Every number was typed in by hand, not computed from the words.

These are the 8 query vectors, one row of 4 numbers for each token. Every number was typed in by hand, not computed from the words.
  1. 1Start with three tables: a query, a key and a value vector for every token.
  2. 2Score every query against every key by multiplying the two vectors element by element and adding up.
  3. 3Divide every score by the square root of the vector length.
  4. 4Where a position may not be used, replace its score with minus infinity.
  5. 5Turn each row of scores into weights that add up to one.
  6. 6Build each output row by adding up the value vectors, each scaled by its weight.
  7. 7Each output row is a weighted average of the value vectors, in the proportions that row gives.

What the division by √4 does

The largest weight in each row, as computed, beside what it would have been without the division.
RowDividedNot divided
the1.00001.0000
cat0.73110.8808
sat0.76620.9465
on0.29690.3189
the0.33910.4984
warm0.22490.2439
mat0.29450.4748
today0.21980.2853

Dividing a row of scores by anything greater than one cannot increase its largest weight, and strictly decreases it unless every score in the row is equal. Both columns above are computed from the numbers in the Vectors tab.

Dot products
0
Multiplications
0
Rows normalised
0
Positions masked
0

Complexity

BestO(n² · dₖ)
AverageO(n² · dₖ)
WorstO(n² · dₖ)
Extra spaceO(n²)

Scaled dot-product attention

AlgoLab runs no language model. The vectors here are four numbers per token, typed in by hand so that every dot product on this page can be checked with a pencil, and you can read all of them in the Vectors tab. A real model’s queries, keys and values have hundreds or thousands of dimensions, learned from data rather than chosen by a person.

Attention(Q, K, V) = softmax(QKᵀ / √dₖ) V

Scaled dot-product attention takes three tables of numbers — a query, a key and a value vector for every token — and produces one output vector per token. It scores every query against every key with a dot product, divides every score by the square root of the vector length, turns each row of scores into weights that add up to one, and builds each output row by adding up the value vectors in exactly those proportions. The whole of it is one expression: Attention(Q, K, V) = softmax(QKᵀ / √dₖ) V.

Why it matters, and what it costs

It is the operation a transformer layer is built from, which is the honest reason to understand it: it is the step that mixes information between positions, and every other part of the layer acts on one position at a time. Its cost is the thing to notice. Scoring every query against every key is n² dot products for n tokens — eight tokens here means 64 scores, and the tool counts them as it goes — so the work grows with the square of the sequence length, not with it. That is why a long context is expensive, and it is the whole reason techniques that avoid recomputing keys and values exist.

How it works

Worth noticing

Where the numbers come from

Every number this page computes with was typed in by a person. They are held attools/attention/src/data/examples.v1.json and shown in full in the tool’s Vectors tab: two eight-token examples, with a query, a key and a value vector of four numbers for each token. Entries are drawn from 0, 1 and 2, and that is a decision rather than laziness — it makes every dot product a small whole number, and since dk is 4 and √4 is exactly 2, every scaled score is a whole number or a half. The whole page can be checked with a pencil, which is the only reason it can promise its arithmetic is verifiable.

Nothing is derived from the words. The four dimensions are numbered, not named, and none of them means anything on its own; naming them would claim an interpretability this page cannot support. Exactly one structural constraint was imposed: a repeated token gets identical rows. So the two copies of the in the first example score identically against every query, which is a property of this hand-written data rather than of attention. Real implementations add positional information before the projections that produce Q, K and V, so two identical tokens would not have identical rows there.

What dividing by √dk does

This is the step the roadmap calls the one people least understand, so the tool gives it eight frames of its own and shows both versions rather than performing the division silently. On the first example, row 2’s largest weight comes to 0.7662 with the division and would have been 0.9465 without it; row 6 goes from 0.4748 to0.2945. Dividing a row of scores by anything greater than one cannot increase its largest weight, and strictly decreases it unless every score in the row is equal.

The reason the constant is √dk and not something else is about vectors much larger than these. For vectors whose entries are independent and average zero, the spread of a dot product grows as √d — measured over generated vectors, the standard deviation comes out at 0.499 × √d fromd = 4 to d = 4096 — and undivided, the softmax of those scores collapses onto one position as the dimension grows:

One query against eight keys, averaged over 4,000 draws of zero-mean vectors.
dLargest weight, undividedLargest weight, divided by √d
40.32600.2200
160.55020.2311
640.75320.2334
2560.86740.2320
10240.93470.2341
40960.96880.2342

Those numbers are measured over generated vectors, not over the hand-written ones on this page. The authored entries are not zero-mean, so their dot products do not grow that way, and the tool does not claim its own eight-token example demonstrates the rule. Both measurements are in tools/attention/test/attention.test.ts.

What this does not show

This is one attention head, computed once. It is not a transformer. There is no multi-head split, no stack of layers, no projection turning token embeddings into Q, K and V, no residual connection and no layer normalisation. The roadmap refuses a full forward pass on the grounds that it is a diagram rather than a trace, and cuts layer normalisation outright as a formula rather than a process. Those boundaries are named here so that nothing on this page is mistaken for the rest of a model.

Cost

Time
O(n² · dₖ)
Extra space
O(n²)
Steps recorded
100 masked, 92 unmasked

n is the number of tokens and dk the length of each vector. Then² term is the thing worth noticing: scoring every query against every key is 64 dot products for eight tokens, and the work grows with the square of the sequence length rather than with it.

Unlike every other tool here, this one has no ceiling and no input to refuse. There is no number a reader can raise: n and dk are fixed by the data file, so the step count is a constant and a refusal path would guard something that cannot vary. What is validated instead is the data file itself, at load, because that is the part a person can edit.

Source

Vaswani et al., “Attention Is All You Need” (2017), §3.2.1 for the formula and its name, §3.2.2 for the dimensions a real model uses, §3.5 for positional information.

Worth comparing

All algorithms