Scaled Dot-Product Attention › Dot Product Similarity
Language AI HandbookAll chapters Scaled Dot-Product Attention › Dot Product SimilarityOne section · Sections in this chapter2 / 15 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
The first step in scaled dot-product attention is measuring how relevant each key is to each query. We need a similarity function that is fast to compute, works well in high dimensions, and integrates naturally with gradient-based learning. The choice of similarity measure is not obvious, and it is worth understanding why the dot product was selected over alternatives.
One alternative is Euclidean distance: we could measure how close two vectors are in space and use closeness as a proxy for relevance. But Euclidean distance is expensive to compute for all query-key pairs, and minimizing distance does not naturally integrate with the maximize-gradient training objective. Another alternative is cosine similarity, which normalizes vectors to unit length before taking the dot product. Cosine similarity is interpretable, but the normalization step is expensive and, more importantly, the model cannot learn to increase similarity by scaling the magnitude of its projections, which turns out to be a useful degree of freedom.
The dot product satisfies all three requirements: it is fast to compute via matrix multiplication, its geometric interpretation aligns naturally with learned representations, and it allows the model to control similarity through both the angle and the magnitude of projection vectors. For two vectors and of dimension , the dot product is:
where:
- : the -th component of the query vector
- : the -th component of the key vector
- : the shared dimension of queries and keys
Geometrically, the dot product measures how much two vectors point in the same direction. If and are unit vectors, the dot product equals their cosine similarity. For general vectors, it equals , where is the angle between them. Large positive values mean strong alignment; values near zero mean orthogonality; negative values mean the vectors point in opposite directions.
This geometric interpretation makes the dot product a natural fit for attention. During training, the model learns to align queries with relevant keys in the projected space. A position attending to relevant content will have its query vector pointing in a direction similar to the key vectors of those relevant positions. The projection matrices and are jointly trained to produce this alignment: shapes queries so they point toward relevant key directions, and shapes keys so they point toward the directions of queries that should attend to them. The learning process carves out a shared geometric space where relevance is encoded as directional alignment.
Why does this formula make sense? Notice that the dot product is bilinear: it is linear in holding fixed, and linear in holding fixed. This bilinearity is what makes the gradient flow back through both queries and keys cleanly during backpropagation. It is also what allows the score matrix to be computed as a single matrix multiplication, which modern hardware executes at peak efficiency.
The Score Matrix
In practice, we want to compute similarities between all queries and all keys simultaneously. Processing them one pair at a time would require separate dot product computations, which is slow and wasteful. Instead, we exploit the fact that all pairwise dot products can be expressed as a single matrix multiplication. This is a perfect job for linear algebra: the score matrix is:
where:
- : the query matrix, each row is one query vector
- : the transposed key matrix, each column is one key vector
- : the raw score matrix, where
Entry tells us how much position 's query matches position 's key. The entire matrix of scores is computed with a single matrix multiplication, which modern hardware executes very efficiently using BLAS routines that achieve near-peak floating-point throughput. This is one of the key reasons dot-product attention is so fast in practice: the score computation maps directly onto hardware-optimized matrix multiply.
The shape of also matters. For a sequence of tokens, has entries. Entry captures the directional alignment between token 's query and token 's key. The diagonal entries capture each token's self-similarity, while off-diagonal entries capture cross-token dependencies. Before any normalization, these are called "logits" (by analogy with classification logits): raw unnormalized scores that will be converted into probabilities by softmax.
import numpy as np
np.random.seed(42)
n = 5 # sequence length
d = 8 # input embedding dimension
d_k = 4 # query/key dimension
d_v = 4 # value dimension
# Simulated input embeddings
X = np.random.randn(n, d)
# Simulated projection matrices (normally trained)
W_Q = np.random.randn(d, d_k) * 0.3
W_K = np.random.randn(d, d_k) * 0.3
W_V = np.random.randn(d, d_v) * 0.3
# Project to Q, K, V
Q = X @ W_Q # (n, d_k)
K = X @ W_K # (n, d_k)
V = X @ W_V # (n, d_v)
# Compute raw scores
S = Q @ K.T # (n, n)Shapes: Q: (5, 4), K: (5, 4), V: (5, 4) Score matrix S = QK^T: (5, 5) Raw score matrix (entry [i,j] = similarity of query i with key j): [[-0.047 1.305 1.059 -1.327 2.064] [ 0.343 -0.085 -0.362 0.668 -0.201] [ 0.245 -0.748 -0.738 0.392 -0.534] [ 0.13 0.704 0.36 -0.434 1.3 ] [-0.321 0.48 0.57 0.277 -0.431]]
Each row of the score matrix corresponds to one token's query matched against all keys. Notice that the scores span a wide range and include negative values. These raw scores aren't attention weights yet; we need two more transformations before they are usable. In particular, the values here are on a scale where some entries are several times larger than others, which would cause softmax to produce extremely uneven weight distributions. Before we apply softmax, we need to address the scale problem.