Attention, by hand

❓ Looking-at-everyone is still a slogan. What are the four steps, by hand, on three tokens?

Four steps of attention: compare, scale, normalize, combine.

Whiteboard: compare, scale, normalize, combine. Query is a slip, key is a spine, value is a book.

The last page said: drop the running summary; let every token look at the others. This page is that looking step, with three tokens and a pencil.

If you only take one chapter slowly, take this one. The rest of the transformer is this move, repeated.

Some words in a sentence depend on other words. Pronouns need nouns. not needs a verb. bank needs a clue.

A weighted average is not mysticism. If you have three numbers 10, 20, 30 and weights 0.5, 0.5, 0.0, the mix is 15. Attention is that, with the weights computed from the data.

Each token has a list of numbers (chapter 4). Those lists must talk, so it can become the animal, and so the last list can carry enough of the mystery novel to predict the murderer.

The looking step is four jobs: compare, scale, normalize, combine. We will do them on a 3-token toy. After that, the one-line formula is a caption, not a riddle.

Three tokens on a napkin

Imagine three tokens sitting in a row: it, was, tired. In a real model each would be a list of thousands of numbers. Here each is 2 numbers long, so the arithmetic fits on a napkin.

[
X=\begin{bmatrix}
1 & 0 \
0 & 1 \
1 & 1
\end{bmatrix}
\begin{matrix}
\leftarrow\text{it}\
\leftarrow\text{was}\
\leftarrow\text{tired}
\end{matrix}
]

So it is ([1, 0]), was is ([0, 1]), tired is ([1, 1]). This toy is not semantic. It is arithmetic you can check.

Three views of the same token

Whiteboard: query is a slip, key is a spine, value is a book.

In a real layer we multiply (X) by three different learned tables. That gives three views of each token.

The split exists so that matching and payload can be different learned views of the same token. A spine in a library is not the book. A search slip is not the spine.

Here, to see the geometry, take the question-table and the label-table to be “copy” (so query = key = the original list), and take the payload-table to be “double everything.” Then

[
Q=K=X,\qquad
V=\begin{bmatrix}2&0\0&2\2&2\end{bmatrix}.
]

(Q), (K), and (V) are just the matrices whose rows are those three views, stacked.

Think of a library.

You compare slip to spines (dot products). You turn those comparison scores into a set of mixing weights that sum to 1 (softmax). You take that mix of books. You do not go home with the labels. You go home with the pages.

Where the analogy breaks: every token is both patron and book, at the same time. That is the “self” in self-attention.

Why not use the same list for match and for payload?
You can, in a toy. The extra tables let “I match adjectives” be a different learned view from “here is the meaning I will hand over.”

Four steps

1. Compare

Dot-product every query with every key. That is (QK^{\top}), a 3×3 grid. Cell ((i,j)) is “how aligned is token (i)’s question with token (j)’s label.”

[
QK^{\top}=\begin{bmatrix}
1 & 0 & 1 \
0 & 1 & 1 \
1 & 1 & 2
\end{bmatrix}
]

tired matches itself hardest (score 2). it matches was not at all (score 0). Check one cell: it · it = ([1,0]\cdot[1,0]=1).

2. Scale

Divide by (\sqrt{d_k}). Here (d_k=2), the length of each query/key list, so (\sqrt{2}\approx 1.414).

[
\frac{QK^{\top}}{\sqrt{d_k}}\approx
\begin{bmatrix}
0.707 & 0 & 0.707 \
0 & 0.707 & 0.707 \
0.707 & 0.707 & 1.414
\end{bmatrix}
]

Why divide? Raw dot products get huge as lists get longer, and softmax then spikes — almost all the mix-weight lands on one token, and training sees a dead slope. Dividing by (\sqrt{d_k}) is a fixed recipe to keep typical scores near size 1. The probability cartoon is Math: why divide by (\sqrt{d_k}).

If we skipped the divide on long lists, what would softmax do?
Spike. Almost-one, almost-zeros. The mix would stop being a mix.

3. Normalize

Softmax each row (each query). Weights become positive and sum to 1. That row is the attention pattern for that token: how much it will take from each payload.

For the first row, (\mathrm{softmax}(0.707,\,0,\,0.707)\approx(0.401,\,0.198,\,0.401)).

Full grid, rounded:

[
A\approx
\begin{bmatrix}
0.401 & 0.198 & 0.401 \
0.198 & 0.401 & 0.401 \
0.248 & 0.248 & 0.504
\end{bmatrix}
]

Each row is a pile of chances. There is no remaining mystery in this step. It is the softmax you already have.

Do the three numbers in row 1 add to 1?
Yes, up to rounding. That is the whole point of this step.

4. Combine

Multiply (A) by (V). Each output row is a weighted sum of payload rows.

[
Z=AV\approx
\begin{bmatrix}
1.604 & 1.198 \
1.198 & 1.604 \
1.504 & 1.504
\end{bmatrix}
]

Row 1, the new it, is (0.401\cdot[2,0]+0.198\cdot[0,2]+0.401\cdot[2,2]). It has taken payload from itself and from tired, and less from was. That is attention. Information moved across positions.

The one-line caption, now that you have done the jobs:

[
\mathrm{Attention}(Q,K,V)=\mathrm{softmax}\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V
]

Do not peek: the causal mask

Whiteboard: hide the future so the present only mixes the past.

A causal mask hides future tokens so each position can only mix the past.

A next-piece model must not let token (t) see token (t+1) during training, or the test is a cheat. Before softmax, set the upper triangle of the score grid to (-\infty). After softmax those cells are 0. People call this a causal mask: a rule that hides the future so the present can only mix the past.

On our toy:

[
A_{\mathrm{causal}}\approx
\begin{bmatrix}
1 & 0 & 0 \
0.330 & 0.670 & 0 \
0.248 & 0.248 & 0.504
\end{bmatrix}
]

Now it can only look at it. was can look at it and was. tired can look at everyone. That triangle is the entire difference between “a bag of words” and “a language model that predicts the future without reading it.”

At inference, the generated tokens to the right of the current position do not exist yet, so the mask matches reality. During training, they do exist in the batch, so the mask is a rule.

On the no-peek version, why is the new it equal to ([2, 0])?
it can only look at itself. Its payload was ([2, 0]). Weight 1 on itself, weight 0 on the others.

Many heads

One set of question/label/payload tables learns one kind of match — for example, adjectives updating nouns. Language needs many kinds at once: grammar, “it = animal,” quotes, code indentation.

Multi-head attention runs several of these in parallel, each with its own tables, on a slice of the numbers. The 2017 paper used 8 heads with 64 numbers each, from a 512-number list. Glue the head outputs together and mix with one more table.

The compute is kept honest by shrinking each head. You pay about the same as one full-width head, and you get several independent looking-patterns.

You will not be able to narrate what every head does. Almost nobody can. You will be able to say what a head is: one compare-scale-normalize-combine with its own knobs.

What attention is not

It is not a pointer that selects one token. Softmax is soft. It is not “the model focusing” in the everyday sense, though the name invites that. It is not where facts are mostly stored — mix-clip-mix per position is the better current guess for that. It is the communication bus.

Close the notes. Write the four steps. Write the formula. On the toy, why does the no-peek version give it the output ([2,0])?

If you can answer, the black box of attention is gone. What remains is stacking, and the other half of the block.

What this still cannot do

Raw match-scores grow as the lists get longer.
Softmax then spikes. Why divide before we mix?

The next page is that divide.

← All at onceScale →