Home / Attention

Query, Key and Value

Pick a word and follow its query through every step: score against each key, scale, softmax, then blend the values.

Overview

Quick Context

The previous module described attention as score, normalise, blend. That description works, but it leaves one thing vague: what exactly is being compared against what?

The query–key–value framing answers that, and it is worth learning properly because every transformer paper, diagram and implementation is written in it.

Lookup

4

d_k, used in the 1/√d_k scaling


untick to see softmax saturate


4

1 score · 2 scale · 3 softmax · 4 blend

One Attention Lookup

blend

Result

Strongest Match
Its Weight 0.00
Largest Raw Score 0.00
Weight Entropy 0.00

Three Roles

Query — what this word is looking for.

Key — what each word offers, used only for matching.

Value — what each word actually contributes once it has been matched.

Keys and values are separate on purpose: how findable something is need not equal what it says.

Query, Key and Value: A Practical Guide

The three projections every transformer is written in, and why there are three rather than two.

A soft dictionary lookup

Attention is easiest to read as a lookup that returns a blend rather than one entry.

In an ordinary dictionary you present a key and get back exactly one value. In attention you present a query, compare it against every key, and get back a weighted mixture of all the values — weighted by how well each key matched.

  • Query — what this position is looking for.
  • Key — the label each position advertises.
  • Value — what each position actually contributes when selected.

All three are linear projections of the same input, with separate learned matrices:

Q = XWQ   K = XWK   V = XWV

That is where every parameter in the mechanism lives. Attention itself has no weights — it is a fixed formula applied to these three projections.

Where they come from

All three are linear projections of the same input embedding:

Q = X WQ    K = X WK    V = X WV

The three weight matrices are learned. This is the part people find surprising: the same word produces three different vectors, because it plays three different roles. As a query it asks a question; as a key it advertises what it can answer; as a value it supplies content.

And the whole mechanism is one formula:

Attention(Q, K, V) = softmax( QKT / √dk ) V

Why keys and values are separate

It is reasonable to ask why we need both — why not match against the values directly and save a matrix?

Because how easily something is found is a different question from what it contains. A word might be highly relevant to a query while the information it should pass on is quite unrelated to why it matched. Splitting the two lets the model learn addressing and content independently, and in practice that separation is what allows different heads to specialise.

Why three separate projections

The obvious question: if all three come from the same input, why not use the input directly for all of them?

Because the three roles want different information. What a token is looking for is not the same as how it wants to be found, and neither is the same as what it should contribute.

Take "it" in "The cat sat on the mat because it was warm". As a query, "it" needs to search for a nearby noun that could be warm. As a key, "mat" needs to advertise itself as a warmable surface. As a value, "mat" contributes its full semantic content. Separate matrices let the model learn those three functions independently.

The clearest demonstration is that Q and K are used only to compute compatibility, and V only to produce output. A token can be highly attended to for one reason and contribute something quite different — which a single shared projection could not express.

The computation, step by step

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

For a sequence of 4 tokens with head dimension 64:

StepOperationShape
1QKᵀ — every query against every key4×4
2Divide by √64 = 84×4
3Softmax over each row4×4, rows sum to 1
4Multiply by V4×64

Row i of the 4×4 matrix holds token i's attention weights over all four tokens. Multiplying by V replaces token i's representation with the weighted mixture.

The √dₖ division is not cosmetic. Dot products of d-dimensional vectors grow with d, so without scaling the scores reach the tens or hundreds, the softmax becomes nearly one-hot, and the gradient through it approaches zero. Dividing by √dₖ keeps the variance of the scores near 1 regardless of dimension.

Why three projections and not one

Q, K and V are three different linear maps of the same input. Collapsing any two of them breaks something specific, and this shows exactly what.

example_01.pyNumPy
Output

Things to try

  1. Follow one lookup end to end. Set the Stage slider to 1 and step it up to 4. You see the raw dot products appear, get divided by the square root of the head dimension, become weights through softmax, and finally blend the value vectors into one output.
  2. Change who is asking. Set the Query Word to drank. The scores rearrange completely — the same six keys, a different question, a different answer.
  3. Break the scaling. Set the Head Dimension slider to 64 and untick Scale by 1/√d_k. The raw scores grow large, softmax saturates, and the weights collapse onto a single key with entropy near zero. In a real model that means a vanishing gradient and a layer that stops learning.
  4. Then fix it. Tick Scale by 1/√d_k again with the dimension still at 64. The scores come back into a sane range and the distribution is usable again. That single division is the entire reason the mechanism is called scaled dot-product attention.
  5. Check the low-dimension case. Set the Head Dimension slider to 1. Now the scaling barely matters, because there was never anything to blow up. The correction only earns its keep as dimension grows.

Why divide by √d k

If the components of the query and key are roughly independent with unit variance, their dot product is a sum of dk such products, so its variance grows with dk and its typical magnitude grows with √dk. At dk = 64 the scores are around eight times larger than at dk = 1.

Softmax is exponential, so those larger gaps translate into near-one and near-zero weights. That is bad in itself — the layer stops blending — and worse for training, because softmax's gradient is almost zero once it saturates. Dividing by √dk cancels the growth exactly and keeps the scores in the range where softmax is still responsive.

The three kinds of attention

The same formula covers every attention in a transformer; only where Q, K and V come from changes:

KindQuery fromKey and value from
Encoder self-attentionthe inputthe input
Decoder self-attentionthe output so farthe output so far (masked)
Cross-attentionthe decoderthe encoder

Cross-attention is the classic encoder–decoder attention of the previous module. When query, key and value all come from the same sequence you get self-attention, which is the next module.

Traps worth knowing

  • Assuming Q, K and V are the same vector. They are three different projections of it, with three different learned matrices, and conflating them makes the rest of the architecture impossible to follow.
  • Dropping the scaling. It looks like a detail and is not. Without it, wide heads saturate and training stalls.
  • Thinking the weights are a similarity between words. They are a similarity between a query projection of one word and a key projection of another. Those projections are learned, so two synonyms need not attend to each other at all.
  • Forgetting the last multiply. Softmax gives weights, not output. The output is those weights applied to V, and V is a different projection again.

Summing up

Attention is a soft dictionary lookup: the query says what a position is looking for, each key says how well that position matches, and each value says what it contributes once matched, with all three being separate learned projections of the same input. Every key matches to some degree, so the output is a weighted blend rather than a single retrieved entry, and the whole mechanism is softmax(QKᵀ/√d_k)V. Keys and values are kept apart because findability and content are different things, and the √d_k division exists because dot products grow with dimension and would otherwise saturate the softmax into a hard, ungradient-able argmax.

Multiple heads, and where they come from

Multi-head attention runs several of these computations in parallel with different learned projections, then concatenates the outputs and applies one more projection.

import torch, torch.nn.functional as F

def attention(x, Wq, Wk, Wv, mask=None):
    Q, K, V = x @ Wq, x @ Wk, x @ Wv
    scores = Q @ K.transpose(-2, -1) / (K.size(-1) ** 0.5)
    if mask is not None:
        scores = scores.masked_fill(mask == 0, float("-inf"))
    return F.softmax(scores, dim=-1) @ V

With a model dimension of 512 and 8 heads, each head projects to 64 dimensions, so the total work is roughly the same as one 512-dimensional head — and the model gets 8 independent views instead of 1.

The masking line is how causal generation and padding are both handled: setting a score to negative infinity makes its softmax weight exactly zero.

Cross-attention, and the caching trick

In self-attention Q, K and V all come from the same sequence. In cross-attention the queries come from one sequence and the keys and values from another — a decoder querying an encoder's output, or a text query attending to image patches.

That asymmetry has a practical consequence during generation, and it is the basis of the most important inference optimisation in language models.

When generating token by token, the keys and values for all previous tokens do not change — only the new token's query is new. So they can be computed once and cached:

Without a KV cache, generating the 1,000th token requires recomputing keys and values for all 999 previous tokens. Generation is quadratic in output length.

With a KV cache, each new token computes its own K and V, appends them, and attends against the stored ones. Generation becomes linear.

The cost is memory: the cache holds two tensors per layer per token, which for a large model and a long context runs to many gigabytes. That is exactly what multi-query and grouped-query attention address, by sharing key and value projections across heads and shrinking the cache several-fold.

Questions people ask

Why is it called query, key, value? By analogy with a database lookup. The analogy is genuinely useful and the mechanism is soft rather than exact.

Are Q, K and V the same size? Q and K must match, since they are dotted together. V can differ in principle and is usually the same size in practice.

Do they have separate weight matrices? Yes — three per head, plus one output projection per layer.

What is dₖ? The dimension of a single head's key vectors, typically 64. It is what the scaling factor is derived from.

Why not use cosine similarity instead of a dot product? The dot product is cheaper, and the scaling plus LayerNorm already keeps magnitudes controlled. Some architectures do normalise the queries and keys.

Can K and V come from a different source than Q? That is precisely cross-attention, and it is how decoders read encoders and how multimodal models connect modalities.

Recap in one screen

  • Query is what a position seeks, key is how a position advertises itself, value is what it contributes.
  • All three are learned linear projections of the input; attention itself has no parameters.
  • Score with QKᵀ, scale by √dₖ, softmax, then weight the values.
  • The scaling prevents softmax saturation and vanishing gradients in high dimensions.
  • Keys and values do not change during generation, which is what makes KV caching — and linear-time decoding — possible.

Recall check

0 of 3

Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.

  1. What does this module say about “Quick Context”?

  2. What does this module say about “A soft dictionary lookup”?

  3. What does this module say about “Why keys and values are separate”?

Cheat sheet

Query, Key and Value

The previous module described attention as score, normalise, blend. That description works, but it leaves one thing vague: what exactly is being compared against what?

NLP · vizlearn.in/natural_language_processing/query_key_value.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.