Octonote AI
Make your own →

Self-attention in one page

Sunil Tiwari · Oct 12, 2026 · 2 min read

Queries, keys and values, scaled dot-product attention, and why the √d scaling matters — with NumPy code.

Self-attention lets every token in a sequence look at every other token and decide how much each one matters for its own new representation. It is the core of every Transformer.

Queries, keys and values

Each token embedding xix_i is projected three ways with learned matrices:

qi=xiWQ,ki=xiWK,vi=xiWVq_i = x_i W_Q, \qquad k_i = x_i W_K, \qquad v_i = x_i W_V
  • Query: what this token is looking for.
  • Key: what this token offers.
  • Value: what this token passes on if it is chosen.

Scaled dot-product attention

Stacking all tokens into matrices Q,K,VQ, K, V:

Attention⁡(Q,K,V)=softmax⁡ ⁣(QK⊤dk)V\operatorname{Attention}(Q, K, V) = \operatorname{softmax}\!\left(\frac{QK^{\top}}{\sqrt{d_k}}\right) V

Row ii of the softmax is a probability distribution over all tokens: how much token ii attends to each one.

Why divide by √dₖ?

If the entries of qq and kk have unit variance, their dot product has variance dkd_k. Large scores push softmax into regions with near-zero gradients. Dividing by dk\sqrt{d_k} keeps the variance at 1.

Var⁡(q⋅k)=∑j=1dkVar⁡(qjkj)=dk\operatorname{Var}(q \cdot k) = \sum_{j=1}^{d_k} \operatorname{Var}(q_j k_j) = d_k

The data flow

flowchart LR
  X[Token embeddings X] --> Q[Q = XW_Q]
  X --> K[K = XW_K]
  X --> V[V = XW_V]
  Q --> S[Scores QKᵀ / √dₖ]
  K --> S
  S --> P[softmax]
  P --> O[Output = PV]
  V --> O

In NumPy

import numpy as np

def softmax(x, axis=-1):
    x = x - x.max(axis=axis, keepdims=True)
    e = np.exp(x)
    return e / e.sum(axis=axis, keepdims=True)

def self_attention(X, Wq, Wk, Wv):
    Q, K, V = X @ Wq, X @ Wk, X @ Wv
    scores = Q @ K.T / np.sqrt(K.shape[-1])
    weights = softmax(scores)          # (tokens, tokens)
    return weights @ V, weights

Going further

  • Multi-head: run hh attentions in parallel on smaller projections and concatenate.
  • Causal mask: set future positions to −∞-\infty before the softmax for decoder models.
  • Cost: O(n2d)O(n^2 d) in sequence length nn, which is why long contexts are expensive.

Published with Octonote AI · Make your own