Attention weights for a single input token
All context vectors are computed with one matrix multiplication: attn_weights @ inputs.
Why One Multiplication Can Replace a Loop
Earlier in this chapter, a context vector was built for one input token at a time. That approach works, but it means repeating the same steps for every position in a sequence. This article shows how the attention weights you already computed can be applied to all of the inputs in one operation, producing a full set of context vectors together.
The central idea is that a single matrix product replaces a loop over tokens. Instead of asking, for each token in turn, how much it should borrow from every other token, you store all the attention weights in one matrix and all the input vectors in another, then multiply them. The result contains every context vector at once.
Tracing the Single Line of Code
The whole computation is one line. It takes the attention weight matrix named attn_weights, multiplies it by the inputs using the @ operator, and stores the result in all_context_vecs. A second line prints that result so you can read it.
The method the source recommends is to run the line first, read the printed tensor, and only then reason backward about the operation that produced it. When a result looks wrong, you need to know which operation produced which part of it, and reading the output before stepping through the execution gives you a concrete picture to test against.
What do you think happens?
If attn_weights has shape n × n and inputs has shape n × d, what is the shape of all_context_vecs?
Reveal answer
The result has shape $n \times d$. It takes its row count from attn_weights and its column count from inputs.
Matrix multiplication of an $n \times n$ matrix with an $n \times d$ matrix gives an $n \times d$ matrix. The inner dimensions (the $n$ columns of the weights and the $n$ rows of the inputs) must match and are consumed; the outer dimensions survive. Rows come from the weights, and columns come from the inputs.
Rows as Context Vectors
Each row of the output tensor holds one context vector. Row number one belongs to the first input token, row number two belongs to the second input token, and so on. The rows line up with the rows of the attention weight matrix, because each row of attention weights describes how much one token attends to every input token.
For a single row, the product forms a weighted combination of the input vectors. Each weight in that row scales one input vector, and the scaled vectors are summed. Written for a token $i$ with weights $\alpha_{i1}, \alpha_{i2}, \ldots, \alpha_{in}$ and input vectors $x_1, x_2, \ldots, x_n$, the context vector for that row is
The diagram shows the bookkeeping. Row $i$ of the weights is combined with the whole input matrix, and the result lands in row $i$ of the output. Nothing in the multiplication moves a row to a different position, so the index of a weight row is also the index of the context vector it produces.
Checking the Output Shape
The shape rule for matrix multiplication is the same one you use for any product. The number of columns in the first operand must match the number of rows in the second. The result takes the row count of the first operand and the column count of the second. Because the weights are square, the inner dimension matches the input token count automatically.
A three-token example worked by hand
Three input tokens each have a two-dimensional input vector. The attention weight matrix is $3 \times 3$. Compute the context vectors with attn_weights @ inputs, and check the result shape before reading the values.
- 1Write the operand shapes
The inputs have shape $3 \times 2$, one row per token with two features each. The weights have shape $3 \times 3$, one row per token with one weight per token.
- 2Predict the result shape
The inner dimensions are 3 and 3, so the product is defined. The outer dimensions are 3 (rows of weights) and 2 (columns of inputs), so the result should have shape $3 \times 2$.
- 3Set up the illustrative values
This example uses generated numbers, not values from the source. inputs has rows [1, 0], [0, 1], and [1, 1].
attn_weightshas rows [0.5, 0.5, 0.0], [0.0, 1.0, 0.0], and [0.2, 0.3, 0.5]. Each weight row sums to 1. - 4Compute row 1
Row 1 is 0.5 times [1, 0] plus 0.5 times [0, 1] plus 0.0 times [1, 1], which equals [0.5, 0.5].
- 5Compute row 2
Row 2 is 0.0 times [1, 0] plus 1.0 times [0, 1] plus 0.0 times [1, 1], which equals [0, 1]. This row copies token 2 exactly, because its weights put all attention on token 2.
- 6Compute row 3
Row 3 is 0.2 times [1, 0] plus 0.3 times [0, 1] plus 0.5 times [1, 1]. The first feature is 0.2 + 0.5 = 0.7 and the second is 0.3 + 0.5 = 0.8, giving [0.7, 0.8].
The result is a $3 \times 2$ matrix with rows [0.5, 0.5], [0, 1], and [0.7, 0.8]. The shape matches the prediction, and each row is one context vector aligned with one row of the weights.
Common Mistakes When Reading the Result
Common mistake Treating the columns of the result as tokens
What it looks likeReading the $3 \times 2$ result and concluding there are two tokens because there are two columns.
Why it failsRows of the result correspond to tokens. Columns hold the features of each context vector.
Do this insteadRead each row as one token's context vector, aligned with the matching row of attn_weights.
Common mistake Reordering rows when comparing against an earlier result
What it looks likeComparing context vector 2 against row 3 of the batched output.
Why it failsThe product keeps row positions fixed, so row $i$ of the output is the context vector for token $i$.
Do this insteadCompare row 2 of the batched result with the vector you computed for the second token.
Common mistake Assuming a wrong row means bad inputs
What it looks likeRebuilding the whole input matrix after only one output row looks off.
Why it failsIf a single row disagrees, the problem lies in the batched path for that token, and the inputs for the other rows are probably fine.
Do this insteadInspect the attention weights in the disagreeing row first. If every row disagrees, then suspect the shared inputs or how the weights were built.
Locating a Divergent Row
The source's debugging technique is to compare one row of the batched result with a context vector computed earlier by a different route. The earlier vector was built one token at a time, so if the batched and per-token paths agree, their values should match row by row.
Suppose the batched result for a four-token sequence matches the earlier per-token vectors in rows 1, 3, and 4, but row 2 differs. Which operand would you inspect first, and why?
Hints
- Rows of the result line up with rows of the attention weights.
- Only one row disagrees, so the shared inputs are unlikely to be the cause.
Extending to Trainable Self-Attention
The mechanism you have just run is a simplified version of attention. Its weights are fixed by the computation you already did. The next step is to add trainable weights, which let the model learn from data and improve its performance on specific tasks.
This extended mechanism is self-attention, also called scaled dot-product attention. The source notes that it is the self-attention used in the original transformer architecture, in GPT models, and in most other popular large language models. The simplified version and the trainable version share the same underlying idea: attention weights are applied to inputs through a matrix product to produce context vectors for all tokens together.
Key Takeaways
- All context vectors can be computed with one matrix multiplication,
attn_weights@ inputs, instead of a loop over tokens. - Each row of the result is one context vector, aligned with the matching row of the attention weights.
- For an n × n weight matrix and an n × d input matrix, the result has shape n × d; read the shape before trusting the values.
- Comparing a batched row against an earlier per-token vector locates where a computation diverged; a single bad row points to that token's path.
- Self-attention with trainable weights, also called scaled dot-product attention, extends this mechanism and underlies the transformer architecture and GPT models.