Attention Weights
A context vector is the weighted sum of all input vectors, where each input is multiplied by its attention weight for one chosen query.
Why Attention Weights Alone Are Not Enough
An attention weight tells you how strongly one input token should influence a chosen query token. On their own, though, attention weights are only numbers, and for a given query they sum to 1.0. A model cannot do much with a list of percentages. The step that turns them into something usable is the context vector: a single vector that blends the entire input sequence according to those weights.
In this article you will first run the computation that produces a context vector and trace why its output looks the way it does. Then you will see how the same procedure is repeated to produce a context vector for every token. Finally you will study dropout, a second kind of masking that is applied to the attention weight matrix during training, and learn how to check whether a dropout result is what you expect.
Building a Context Vector Step by Step
Write the context vector for the second token as z superscript 2. Its definition is a weighted sum over all T input vectors, where the weight is the attention that token 2 assigns to each input. In TeX form: $z^{2}=\sum_{i=1}^{T} a^{2}_{i}\, x^{i}$. Here x superscript i is the i-th input vector and a superscript 2 with subscript i is the attention weight that token 2 gives to input i. Every input contributes, including inputs that receive a very small weight.
Read this definition as a recipe with three ingredients. You need the full list of input vectors, the attention weight attached to each input for one chosen query, and a running total into which the weighted vectors are added. The order of the inputs does not change the recipe, with one requirement: each weight must stay paired with its own input vector.
The implementation follows the formula directly. It starts from a zero vector with the same shape as the query. Then it walks through the inputs one at a time. On each pass it scales the current input vector by its matching weight and adds the result into the running vector. Using enumerate, the index i selects the correct weight for the input at the same position. The zero start matters: the running vector must begin empty so that the first addition does not carry leftover values from anywhere else.
The example below uses one-hot inputs, meaning each input vector has a single 1 in its own slot. This makes each weight easy to see. With realistic embedding vectors every output value mixes contributions from all inputs, so the printed numbers look less tidy, but the mechanism is identical.
[0.2, 0.5, 0.3]- The running vector starts as a zero vector shaped like the query.
- enumerate gives the index i, which selects the weight that pairs with input i.
- Each pass scales the input by its weight and adds the result into the running total.
From One Query to Every Context Vector
Computing one context vector answers a single question: how should one token's representation be blended from the whole sequence? A model needs an answer for every token. The procedure does not change. Attention weights are first computed for every input token acting as a query, which produces a full table with one row per query. Each row is then used in the same weighted sum to produce that query's context vector.
So the same three steps repeat for every token: take the row of weights for that query, pair each weight with its input, and add the scaled inputs into a zero-started running vector. Producing the results one after another is the direct way to do this. A matrix formulation can perform the same work in one organized pass, but the underlying three steps stay the same.
Dropout as a Second Mask
Causal attention already restricts which tokens a model may look at: each position can draw information only from itself and earlier positions. That restriction is enforced with a mask that sets disallowed weights to zero. Dropout adds a second masking step on top of it. Instead of following a fixed rule about which positions are hidden, dropout chooses positions at random and zeroes them out. Its purpose is to reduce overfitting during training.
Dropout works as a two-part operation. First it generates a mask: a pattern of positions to drop, chosen at random. Second it applies that pattern to the matrix, zeroing the selected positions. Positions that are not dropped keep their values, although they are rescaled as described in the next section. Because the mask is random, the zeros do not fall in any fixed place you could predict from the rate alone.
Dropout is applied after the causal mask, so the causal zeros remain in place while additional weights are zeroed. The causal zeros are not undone by dropout.
Estimating zeros in a 6 by 6 matrix of ones
Apply dropout at a rate of 0.5 to a 6 by 6 tensor filled with 1s. Roughly how many of the 36 entries are zeroed, and why might two runs differ?
- 1Count the entries
A 6 by 6 matrix has 36 positions.
- 2Apply the rate
At a rate of 0.5, each position is dropped with about even odds, so about half, roughly 18, are zeroed on average.
- 3Explain the variation
The mask is random, so the exact positions and the exact count can differ from run to run. Counts a few above or below 18 are normal. Compare the approximate zero fraction, not the exact positions.
- 4Read the ones
Because the matrix is all 1s, any nonzero output must be a surviving 1 that has been scaled, so the zeros are easy to count.
About half of the 36 entries, roughly 18, are zeroed. The exact positions depend on the random mask and can vary.
Scaling the Surviving Weights
Zeroing half the entries would shrink the total influence of the attention weights if nothing else changed. To compensate, each surviving value is scaled up by the factor 1/dropout_rate. At a dropout rate of 0.5 the factor is $\frac{1}{0.5} = 2$, so every surviving value is multiplied by 2. This keeps the average influence of the attention mechanism consistent between training and inference.
weight row: 0.4, 0.3, 0.2, 0.1Original attention weights for one query
mask keeps 1, 0, 1, 0 then scale by 2: 0.8, 0.0, 0.4, 0.0
Two entries dropped and the two kept entries doubled
A surviving weight of 0.4 becomes 0.8, and a surviving weight of 0.2 becomes 0.4. The values that were dropped become exactly zero, and their original magnitude does not return. When you read a printed dropout result, the surviving entries will look larger than the originals, and that enlargement is the scaling step at work rather than an error.
Mistakes That Make Results Look Wrong
Common mistake Expecting dropout to remove the causal zeros
What it looks likeA position that was masked by the causal rule still shows zero after dropout is applied.
Why it failsDropout is applied after the causal mask and does not undo its zeros. It only adds further zeros.
Do this insteadCheck the causal zeros first, then look for the additional zeros that dropout introduced.
Common mistake Expecting exactly half the entries to be zero every run
What it looks likeTwo runs on a 6 by 6 matrix of ones zero slightly different numbers of entries.
Why it failsThe mask is chosen at random, so the count and the positions vary.
Do this insteadCompare the approximate zero fraction and the scaling, not the exact positions. Set a seed when you need reproducible results.
Common mistake Forgetting to scale the surviving values
What it looks likeA surviving 0.4 still prints as 0.4 after dropout at rate 0.5.
Why it failsWithout the 1/dropout_rate factor, the total influence of the weights shrinks.
Do this insteadMultiply each surviving value by 1/dropout_rate, which is 2 at a rate of 0.5.
Common mistake Pairing a weight with the wrong input
What it looks likeThe weight 0.5 is multiplied by input x0 instead of x1 because the loop index is off.
Why it failsEach weight must stay paired with its own input vector, or the weighted sum mixes the wrong contributions.
Do this insteadUse enumerate so the index selects the matching weight for the input at the same position.
Common mistake Starting the running vector from leftover values
What it looks likeThe accumulator is not reset and the first addition adds stale numbers.
Why it failsThe running vector has to begin empty so that only the weighted inputs contribute.
Do this insteadInitialize the accumulator as a zero vector with the same shape as the query.
Practice Tracing the Pipeline
A query has the weights 0.6, 0.1, 0.3 over three one-hot inputs. Trace the accumulation loop and state the context vector. Then say which step would be responsible if the printed result were 0.1, 0.6, 0.3.
Hints
- Start from 0.0, 0.0, 0.0 and add each scaled input in order.
- If the printed vector has the weights in the wrong slots, check the pairing of each weight with its input.
A row of four attention weights is 0.4, 0.3, 0.2, 0.1 and a dropout mask keeps entries 1 and 3 at a rate of 0.5. Compute the output row, then state which entries should be zero and the factor applied to the survivors.
Hints
- The factor is 1/0.5 = 2.
- Causal zeros would appear before dropout, so this row has none.
Key Takeaways
- A context vector is a weighted sum of all input vectors, with each input multiplied by its attention weight for one chosen query.
- The computation starts from a zero vector shaped like the query and adds each weighted input at its matching index, so the weight must stay paired with its own input.
- Computing all context vectors repeats the same three steps for every query, using one row of the attention weight table per query.
- Dropout randomly zeroes attention weights during training to reduce overfitting. At a rate of 0.5 about half the entries are zeroed, but the exact positions vary with the random mask.
- Surviving weights are scaled by 1/dropout_rate, which is 2 at a rate of 0.5, and the causal zeros remain in place. When results look wrong, check the query index, the weight pairing, the rate and seed, the scaling, and the order of the masks.