Self-Attention
Every token builds a query, a key, and a value, then scores its query against every key in the sequence to decide how much of each other token's value to blend in.
Why Does This Exist?
The attention that fixed translation had a decoder looking back at a separate encoder. One sequence read another. Yet nothing in score, weigh, blend demands two sequences. A sequence can attend to itself, with every token scoring itself against every other token including its own position.
That reframing matters because recurrence pays for distance. A recurrent net carries context about token 2 forward through dozens of sequential updates before token 50 can use it, and long trips degrade the signal. Self-attention lets every token read every other token in one step, near or far. Distance stops costing steps. The two sequence setup it grew from is in attention-mechanism, the multi head extension is in multi-head-attention, and the order signal it still needs comes from positional-encoding.
Think of It Like This
A room where everyone hears everyone
Picture a meeting where information moves person to person around a table. To learn what the first speaker said, the last speaker waits through every relay in between, and each retelling risks losing a detail.
Now let every person hear every other person directly and at once, with each listener turning up the volume on whichever voices matter for their current question. Someone resolving the word it listens hardest to the earlier phrase that fixes its meaning, without waiting for relays.
That is self-attention: every position hears every position and weights each by relevance to itself, right now.
Where it stops: people choose what to amplify with intent, while tokens amplify whatever the trained weights score highly. The mechanism also hears all positions at once with no sense of who spoke first, so order must be supplied separately.
How It Actually Works
Each token embedding is projected through three learned matrices into three roles:
Here is the query, what token looks for. The term is the key, what token offers to be found by. The term is the value, the content token contributes when found relevant. All three grow from the same token, but , and differ, so each role captures something different about it.
Score, scale, softmax, blend
Every query scores against every key at once:
The product holds every query key dot product in one table, one row per query and one column per key. Dividing by , with the key width, keeps scores from ballooning as widths grow. Unscaled large scores drive softmax toward a single spike and starve gradients. Softmax turns each row into weights summing to , and multiplying by blends the value rows by those weights.
Why it is called self
In cross-attention, queries come from one sequence while keys and values come from another. Here , and all come from the same sequence, every token attending over its own sequence including itself. One layer therefore builds each token a representation already mixed with its full surrounding context.
Worked example
Take one query facing three keys with raw scores . Exponentiate to , where is and is rounded to three decimals. The sum is . Divide to get weights , since , and . They sum to .
Now blend values with those weights: . The top score takes about two thirds of the weight without taking all of it, which is why attention blends rather than selects. The diagram draws these exact bars and the they produce.
Code
Scaled dot product attention reduced to one row, using only the standard library. It recomputes the worked example exactly.
import math
scores = [2.0, 1.0, 0.0]exps = [math.exp(s) for s in scores]total = sum(exps)weights = [e / total for e in exps]print([round(w, 3) for w in weights]) # -> [0.665, 0.245, 0.09]
values = [10.0, 20.0, 30.0]print(round(sum(w * v for w, v in zip(weights, values)), 2)) # -> 14.25The printed weights read , and , the last being with its trailing zero dropped by printing. The blend lands on , matching the hand computation.
Watch Out For
Dropping the root d scale and blaming the optimizer
The symptom looks like a learning rate problem. Loss barely moves from the start, and lowering the rate changes nothing. The real cause sits upstream: without division by , wide keys produce large raw scores, softmax saturates near a single , and gradients through it collapse toward zero almost everywhere.
Check for the scale factor before touching hyperparameters. It belongs inside the score computation, applied before every softmax.
Assuming the mechanism knows the order
The symptom is a model treating shuffled word orders as equivalent. Self-attention is permutation equivariant on its own: reorder the inputs and the same outputs return in the new order, because no position enters the dot products.
That is not a bug inside attention. Order has to be injected separately before attention runs, which is the entire job of positional encodings. If swaps go unnoticed, the position signal is missing rather than the attention broken.
The Quick Version
- Every token is projected into a query, a key and a value through three separate learned matrices.
- Each query scores against every key with a dot product scaled by , then softmaxed into weights that sum to .
- Those weights blend the value vectors, so scores become and values become .
- Self means , and share one sequence, unlike cross-attention across two sequences.
- The mechanism carries no order on its own, so position must be added separately before it runs.