Tokens, Embeddings, and Attention
The attention mechanism
How a model decides what matters in context
Instead of cramming a whole sentence through one fixed vector, let every word look back at every other and keep a weighted blend of what actually matters.
Early translation models read an entire source sentence, squeezed it into one fixed-length vector, and then tried to write the translation out of that single summary. It worked for short phrases and fell apart on long ones - the vector was a bottleneck, a funnel everything had to pass through. Attention removes the funnel. It lets each output position reach back and look at every input position directly, decide how relevant each one is, and take a weighted blend of them. That one idea - score, normalise, blend - is the engine inside every modern language model.
The one-line idea
The bottleneck it fixes
A sequence-to-sequence model without attention has a hard job: an encoder compresses "the cat that the dog next door had chased all afternoon finally climbed the tree" into a single vector of, say, 512 numbers, and a decoder must reconstruct the meaning from only that. The longer the sentence, the more gets lost - earlier words get overwritten by later ones. Attention lets the decoder skip the summary and consult the original words on demand: when it is about to translate "climbed," it can look straight back at "cat" and "tree," wherever they sit in the sentence.
Three steps: score, softmax, blend
Give every position three roles. A query is what position is looking for. A key advertises what position offers. A value is the content position will hand over if chosen. (Lesson 32 shows how are actually produced; here we just need their shapes.)
Step 1 - score. How well does query match key ? Use the dot product from Lesson 9 - big when the two vectors point the same way - divided by to keep the numbers from blowing up as the dimension grows:
Step 2 - softmax. The raw scores can be any size, positive or negative. Exponentiate each one (forcing it positive) and divide by the row's total, so the weights for one query are all in and sum to exactly - a genuine probability distribution over the keys:
Step 3 - blend. The output for position , its context vector, is the weighted sum of every value, using those attention weights as the mixing proportions:
Do this for all positions and you have filled an grid of weights - the alignment matrix. Row says where word looked; it always sums to 1. Play with it below.
Attention alignment matrix
pick a row - drag the temperature
Rows = the word doing the looking (its query). Columns = the words being looked at (their keys). A brighter cell means more attention. Hover a row's word, or any cell, to inspect it.
saw (pos 3) looks mostly at bird (70%), then cat (26%).
Both words spelled the sit in the sentence, yet position 1 leans on cat and position 4 leans on bird - same token, different context, different attention.
Temperature: how peaky is the blend?
Scale every score by a temperature before the exponential, . A small magnifies the gaps between scores, so the largest one runs away with almost all the weight - the distribution sharpens onto a single key (in the limit it becomes a hard pick, one-hot). A large shrinks the gaps, and the weight spreads toward a uniform average over every key. Standard attention runs at ; the in the score is a fixed temperature that keeps the softmax from saturating too early.
The aha: a soft, differentiable lookup
Attention is a dictionary lookup with soft edges. A hard lookup would return the single value whose key best matches the query. Softmax replaces that hard "argmax" with a smooth, weighted average - so instead of grabbing one value it returns a blend, tilted toward the best matches. Because a weighted average is differentiable, gradients flow back through the weights and the model can learn what to pay attention to. That is the whole trick: retrieval you can train with gradient descent.
The three steps in NumPy
import numpy as np
def softmax(z, T=1.0):
z = z / T
z = z - z.max() # subtract max: numerically stable, same result
e = np.exp(z)
return e / e.sum() # nonnegative, sums to 1
# Q, K, V come from Lesson 32; d is the key/value dimension.
scores = Q @ K.T / np.sqrt(d) # (n, n): every query dotted with every key
weights = np.stack([softmax(r) for r in scores]) # softmax along each row
context = weights @ V # (n, d): each row is a weighted blend of values
# one position alone - the verb "saw" looking back at the 5 words
row = np.array([1., 5., 3., 1., 6.]) # saw vs [the, cat, saw, the, bird]
w = softmax(row, T=1.0) # [.005, .257, .035, .005, .699]
c_saw = w @ V # ~70% bird + 26% cat + a little of the restCheck yourself
Softmax converts a row of raw alignment scores into:
Lowering the softmax temperature makes the attention distribution:
Recall the three steps that turn one position's queries and keys into its context vector - and what temperature does.
Nail down the score-normalise-blend pipeline. Try to state it, then check.
Lock it in
- Attention removes the fixed-vector bottleneck: every position can look back at every other and take exactly what it needs.
- Three steps: dot-product scores, softmax to get weights that sum to 1, weighted blend of values to form the context vector.
- Temperature controls peakiness: small T sharpens onto one key, large T spreads toward uniform.
- The whole mechanism is a soft, differentiable dictionary lookup - retrieval you can train with gradient descent.
Primary source
For the visual intuition - why a query "asks a question" and a key "answers" it - watch 3Blue1Brown's Attention in transformers (Chapter 6). For a build-it-up-from-vectors walkthrough with the exact matrices, read Jay Alammar's The Illustrated Transformer. Between the two you will see the same softmax-weighted blend drawn two complementary ways.
Ask your teacher
Attention is the beating heart of every modern LLM - GPT, Claude, Llama are all towers of the blend you just built. Notice the connections: the relevance score is exactly the dot product from Lesson 9, and the whole weight grid is a weighted graph over the tokens - each cell is an edge saying how strongly one word points at another (that is the graph view you will meet in Lesson 47). Ask me why we scale by , how "self-attention" makes queries, keys, and values all come from the same sentence, or how stacking many attention "heads" lets a model track several relationships at once.