C.W.K.
Stream
Lesson 03 of 13 · published

Scaled Dot-Product Attention: Q · K^T → softmax → · V

~14 min · scaled-dot-product, core

Level 0Token
0 XP0/94 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

The core attention computation is three steps. Memorize them.

  1. Score: scores = Q @ K.T / sqrt(d_k). Each entry (i, j) measures how much token i should attend to token j. Shape: (n, n).
  2. Normalize: weights = softmax(scores, axis=-1). Each row becomes a probability distribution that sums to 1. Token i's attention is now distributed across all positions.
  3. Weighted sum: out = weights @ V. Each row is a convex combination of the value vectors, weighted by attention. Shape: (n, d_v).

Three matmuls and a softmax. That is the entire mechanism. Multi-head, causal masking, RoPE, GQA, Flash Attention — every piece of complexity in modern attention is built on top of these three steps without changing them.

Code

Scaled dot-product attention from scratch·python
import torch, math

def scaled_dot_product_attention(Q, K, V, mask=None):
    # Q, K, V: (..., seq_len, d_k or d_v)
    d_k = Q.size(-1)
    scores = Q @ K.transpose(-2, -1) / math.sqrt(d_k)   # (..., n, n)
    if mask is not None:
        scores = scores.masked_fill(mask, float('-inf'))
    weights = torch.softmax(scores, dim=-1)              # row-wise softmax
    return weights @ V                                    # (..., n, d_v)

# Equivalent to torch.nn.functional.scaled_dot_product_attention,
# minus the optimized kernels.
Verify against PyTorch's optimized kernel·python
import torch.nn.functional as F

Q = torch.randn(2, 4, 16, 64)
K = torch.randn(2, 4, 16, 64)
V = torch.randn(2, 4, 16, 64)

ref = F.scaled_dot_product_attention(Q, K, V)
mine = scaled_dot_product_attention(Q, K, V)

print(torch.allclose(ref, mine, atol=1e-5))   # True

External links

Exercise

Implement scaled_dot_product_attention from scratch. Test on (B=2, n=8, d_k=32) random tensors. Compare to F.scaled_dot_product_attention. Then, without re-running, predict what happens if you remove the 1/sqrt(d_k) scaling. Test it. Did the model's outputs change in a recognizable way?

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.