Every transformer block, in every model, runs the same core operation to decide "which other tokens should this token pay attention to": score a query against a set of keys, turn those scores into a probability distribution, and use that distribution to mix the corresponding values. Given query, key and value matrices for a single attention head, compute this scaled dot-product attention output.
Implement scaled_dot_product_attention(Q, K, V, mask=None):
scores = Q @ K.T
scaled = scores / sqrt(d_k)
scaled[mask == 0] = -inf # only if mask is given
weights = softmax(scaled, axis=-1)
output = weights @ V
1/sqrt(d_k) where d_k is the last dimension of Q and K.-inf to positions where mask == 0, before the softmax, never after.As the head dimension d_k grows, q . k grows roughly like d_k in magnitude for unit-variance inputs. Large-magnitude scores push softmax into a near one-hot regime, which is brittle. Dividing by sqrt(d_k) keeps the pre-softmax variance close to 1 regardless of head size.
Do the masking on the SCALED logits, before the softmax — never after. Subtract the row-wise max before exponentiating for numerical stability; it doesn't change the softmax result, since softmax is shift-invariant.
Click "Run Tests" to test your implementation