Before you move a control in the demo, say what you expect to change.
Foundation reference
Scaled Dot-Product Attention & Transformer Layers
Scaled dot-product attention uses query–key scores to compute a weighted average of value vectors. Published large language models such as GPT-3 and Llama are deep stacks of decoder-only transformer blocks with causal self-attention (Brown et al., 2020; Touvron et al., 2023).
Study guide
Where to start
What does a query–key dot product measure geometrically (the alignment and the lengths of the two vectors), and how does softmax turn those scores into weights over the positions to copy from?
How to study this pagePredict · Check · Generalize · Continue
Compare what the demo shows with the key equation and with the papers cited below.
Identify the part of the idea that survives a change of notation or model, so you can recognize it in another paper or system.
The newer notebook covers the same concept and has an interactive demo.
Why It Matters for Modern Models
- Scaled dot-product attention uses query–key scores to compute a weighted average of value vectors. Published large language models such as GPT-3 and Llama are deep stacks of decoder-only transformer blocks with causal self-attention (Brown et al., 2020; Touvron et al., 2023).
- Latent diffusion (the basis of Stable Diffusion) uses a U-Net with self-attention over image latents and cross-attention from the latents to text embeddings (Rombach et al., 2022).
- OpenAI describes its Sora video model as a diffusion model whose transformer operates on spacetime patches of compressed video (Brooks et al., 2024).
Questions to Think About
- In what sense is each attention head a learned, input-dependent kernel over positions, and how does that differ from a fixed convolution kernel?
Interactive Demos
Row 0 (A) · unmasked projection.
One query · three sources · one continuous example
Follow one query through attention
Drag q and watch three steps happen at once: match (how far q reaches along each key), share (softmax splits the attention) and mix (the output blends the values). You can explore before answering anything; go at your own pace.
Given vectors for one unmasked head, not learned word meanings.
q = [2, 1] · Compare the query with each key.
Drag anywhere in the plane, or focus q and use the arrow keys.
Softmax exponentiates each score, then divides by the total. Only differences between scores matter.
Coloured arrows add w·v for each source, tip to tail. The output can never leave the triangle. The view fits the values with equal units on both axes.
q lines up most with B’s key (score 1.414), so B takes 58% of the attention; C gets 28% and A gets 14%. Output o = [-0.004, 0.868].
Give source B more than 90% of the attention.
Watch Match → Share → Mix
A 31-second guided explanation of the starting A/B/C example. This is fixed, silent playback with captions; it does not follow or reset your experiment.
Read the same calculation
- Match: query (2, 1) meets keys A = (−1, 2), B = (1, 0), C = (0, 1). Their dot products are [0, 2, 1]. Divide by √2, the square root of the key width, to get [0, 1.414, 0.707].
- Share: softmax subtracts the largest score, exponentiates and divides by the sum. The weights, in A/B/C order, are [0.14, 0.576, 0.284]. They sum to one; a larger match receives more weight.
- Mix: multiply values A = (2, 0), B = (0, 2), C = (−1, −1) by those weights, then add their contributions. The output is [-0.004, 0.868]. The values carry the content; the query and keys determine its weighting.
Displayed numbers are rounded. This hand-authored, unmasked example explains one attention calculation; it is not a trace from a trained model.
Show every number, the formula and the Python
Shared normalization: m = 1.414; Z = 1.736.
- Source Aindex 0
- Dot
- 0
- Scaled
- 0
- Share
- 0.14
- Carry w_Av_A
- [0.28, 0]
- Source Bindex 1
- Dot
- 2
- Scaled
- 1.414
- Share
- 0.576
- Carry w_Bv_B
- [0, 1.152]
- Source Cindex 2
- Dot
- 1
- Scaled
- 0.707
- Share
- 0.284
- Carry w_Cv_C
- [-0.284, -0.284]
Output o = [-0.004, 0.868]
Compared with q = [2, 1]:
Scores same; shares same; output same.
Worked example, not a test or model run. Given vectors, not learned meanings. Match the query with keys; mix values, not keys. All three sources are allowed in this view.
sum(qj * kj for qj, kj in zip(q, k)) / sqrt(2)exps = [exp(s - max(scores)) for s in scores]weights = [e / sum(exps) for e in exps]sum(w * v[j] for w, v in zip(weights, values))m is the shared maximum scaled score; Z = exp(s_A − m) + exp(s_B − m) + exp(s_C − m). Subtracting the same maximum avoids large exponentials without changing the shares. Each carry is a weighted source value; sum the three contributions coordinate by coordinate for output o.
The reference uses the same current keys and values, with q = [2, 1]. Not every query edit changes the mixture. Solid amber borders mark numerical changes; dashed teal borders mark values unchanged within 1e-12. Labels round to three decimals, not the calculation.
- Source A · index 0
- k_A = [-1, 2]; v_A = [2, 0]
- Source B · index 1
- k_B = [1, 0]; v_B = [0, 2]
- Source C · index 2
- k_C = [0, 1]; v_C = [-1, -1]
Inspect precise numbers and input coordinates
Finite JavaScript numbers before display rounding; −0 is kept where supplied. Tiny allowed shares can underflow to zero; that is not a mask.
q = [2, 1] A: key=[-1, 2]; value=[2, 0]; dot=0; score=0; share=0.14002924504337802; contribution=[0.28005849008675604, 0] B: key=[1, 0]; value=[0, 2]; dot=2; score=1.414213562373095; share=0.575975345215362; contribution=[0, 1.151950690430724] C: key=[0, 1]; value=[-1, -1]; dot=1; score=0.7071067811865475; share=0.28399540974126003; contribution=[-0.28399540974126003, -0.28399540974126003] m=1.414213562373095; stable denominator=1.736185425829454 output=[-0.00393691965450399, 0.8679552806894639]
Read the same calculation in Python
This runnable Python uses the current controls and the same labels. No NumPy or random inputs are needed.
Float operands and left-to-right sums from 0.0 follow browser accumulation, not exact arithmetic. Cancellation can hide a nonzero exact change; exp/sqrt implementations and display rounding can differ across runtimes.
from math import exp, sqrt
labels = ["A","B","C"]
q = [2.0, 1.0]
keys = [[-1.0, 2.0], [1.0, 0.0], [0.0, 1.0]]
values = [[2.0, 0.0], [0.0, 2.0], [-1.0, -1.0]]
# Float operands and left-to-right sums from 0.0 follow browser accumulation.
# Cancellation can hide a nonzero exact change. This is not exact arithmetic;
# exp/sqrt implementations and display rounding can differ across runtimes.
def ordered_sum(terms):
total = 0.0
for term in terms:
total += term
return total
d_k = len(q) # key dimension, NOT number of sources or value width
raw_scores = [ordered_sum(qj * kj for qj, kj in zip(q, k)) for k in keys]
scores = [s / sqrt(d_k) for s in raw_scores]
exps = [exp(s - max(scores)) for s in scores]
total = ordered_sum(exps)
weights = [e / total for e in exps]
output = [ordered_sum(v[j] * w for w, v in zip(weights, values))
for j in range(len(values[0]))]
for label, raw, score, weight in zip(labels, raw_scores, scores, weights):
print(label, round(raw, 3), round(score, 3), round(weight, 3))
print("output", [round(x, 3) for x in output])
Browser reference output: [-0.004, 0.868] (rounded to three decimals).
Inspect key and value geometry
Step 1 of 4 · Vectors
What does this query have in common with each key?
A, B, and C name the same three sources throughout. Compare q with their keys in key space. Their values are payloads in a different space, not arrows to compare with q.
These are optional inspection controls. The connected scores, shares and mixture stay visible in the explorable above.
Read the current numbers
Shapes: q and each k have d_k = 2 coordinates. Each v and the output have d_v = 2 coordinates. Equal widths here do not make the spaces identical.
q = [q₁, q₂]; k_A = [−1, 2]; k_B = [1, 0]; k_C = [0, 1]
i names a source; j runs over A, B, C. s is a scaled score, w its share, and o the output. Displayed decimals are rounded; calculations are not.
| Source | Key k | q |
|---|---|---|
| A | [-1, 2] | [2, 1] |
| B | [1, 0] | [2, 1] |
| C | [0, 1] | [2, 1] |
Reset example restores the query and first value’s x coordinate only. All other held inputs stay unchanged.
All sources are allowed here; this is not a masked sequence output. Query edits return to row 0; value edits are shared. Other rows and the held mask stay unchanged.
Practice, help and export
A study detour counts as consultation for the attempt you leave. Clearing a response or resetting values keeps its help history.
Held example · 3 queries · 3 sources. Started from the A/B/C sequence.
Study history for this visit
These record which help you used, not completion or learning scores. Each attempt keeps its own feedback and help. Reloading the page clears this history.
- Guided attention notebook · worked study · sequence-abc-v1
Core Math
If you prefer intuition first, try the demos above, then come back for the math.
Single attention head:
where and is the number of coordinates in each query and key. If those coordinates are independent with mean 0 and variance 1, a dot product has variance ; dividing by keeps the scores at unit variance so the softmax does not saturate as grows (Vaswani et al., 2017). Multi-head attention runs several such heads in parallel and concatenates their outputs.
A pre-norm transformer block, as in GPT-2 and many later language models (the original Transformer applied LayerNorm after each residual addition instead):