Knowledge BaseArchitectures

Attention & Transformers

Self-attention lets every element look at every other element and decide what matters — the mechanism behind Transformers, ViTs, and modern foundation models.

advanced#attention#transformer#qkv#self-attention

Start here — what this is really about

Forget the formulas for a moment. Attention is one small idea: to understand any one piece of an input, look at the other pieces and decide how much each one matters.

Read this sentence: "The animal didn't cross the street because it was too tired." What does it refer to — the animal or the street? You knew instantly: the animal. Your brain looked back at the surrounding words and decided animal was the relevant one. That act — scanning the neighbours and weighting them by relevance — is exactly what an attention layer does, with numbers instead of intuition.

How to read this page

The page adapts to you. By default it teaches from first principles — plain words, pictures, and worked examples first. Flip the Depth switch at the top (or complete the prerequisites) to reveal the formal notation and derivations. Nothing is hidden for good; the deeper material lives inside the "Go deeper" panels, ready the moment you're curious.

The problem attention solves — meaning depends on context

A word, or a patch of an image, rarely means anything on its own. The word bank is a riverbank or a place for money depending on the words around it. A patch of brown fur only means dog once you notice the ear and the leash nearby.

So a model needs a way to let each element gather information from the rest of the input before it decides what that element represents. The naive fixes are bad: reading strictly left-to-right (like older RNNs) forgets things far away, and looking only at fixed neighbours (like a small convolution) can't connect a word to another word ten positions away.

Let every element ask the whole room

Instead of a fixed reading order or a fixed window, give each element a way to look at every other element at once and pull in whatever is relevant. A pronoun can reach straight back to its noun; an image patch can consult a patch on the far side of the picture. That direct, all-to-all lookup is the whole reason attention took over.

A is what we call one such element. When every token looks at every other token within the same input, we call it — and it is the engine inside the .

Attention is a weighted average you learn

Here is the mechanical heart of it, stripped bare. Attention produces, for each token, a weighted average of other tokens' information — where the weights say how much to listen to each one.

Think of it like asking a room full of experts one question:

You have a question. You ask everyone in the room. Some answers are highly relevant, some are useless. You don't just take the loudest voice — you take a blend, weighting each person's answer by how relevant they are to your question. Attention does exactly this: the weights are the relevances, and the output is the weighted blend of everyone's contribution.

Two pieces make this work, and the rest of the page just builds them out:

  1. A way to score how relevant each token is to the one doing the looking.
  2. A way to turn those scores into weights that sum to 1, then take the weighted average.

The score in step 1 is a (the same operation from Linear Algebra): two vectors that point the same way score high, so similar tokens pay more attention to each other.

Try to recall

In one sentence, what does an attention layer compute for each token?

Hint: Think weighted blend, not single pick.

Queries, Keys, and Values — three roles for every token

To score relevance and then fetch information, each token plays three different roles. The model learns to project every token vector into three smaller vectors:

  • The q\mathbf{q}what am I looking for?
  • The k\mathbf{k}what do I contain, so others can find me?
  • The v\mathbf{v}what do I actually hand over if you pick me?
Think of it like searching a library:

Your query is the topic you want. Every book has a spine label — its key — that advertises what it is about. You compare your query to every label, and the books whose labels match best get most of your attention. What you actually read and take away is the book's content — its value. Query-key matching decides how much of each value you take.

Scoring one query against three keys, by hand

Suppose a query and three keys are these tiny 2-D vectors:

  • query q=[1,0]\mathbf{q} = [1, 0]
  • key1=[1,0]_1 = [1, 0], key2=[0,1]_2 = [0, 1], key3=[1,1]_3 = [1, 1]

Score each key by the dot product with the query (multiply matching slots, add):

  1. qk1=1×1+0×0=1\mathbf{q}\cdot \mathbf{k}_1 = 1{\times}1 + 0{\times}0 = 1
  2. qk2=1×0+0×1=0\mathbf{q}\cdot \mathbf{k}_2 = 1{\times}0 + 0{\times}1 = 0
  3. qk3=1×1+0×1=1\mathbf{q}\cdot \mathbf{k}_3 = 1{\times}1 + 0{\times}1 = 1

So keys 1 and 3 look relevant (score 1) and key 2 does not (score 0). Next we turn [1,0,1][1, 0, 1] into weights that sum to 1 and take the weighted average of the three value vectors. That final step is the softmax, coming up next.

Scaled dot-product attention — the whole formula

Now stack every token's query into a matrix QQ, every key into KK, every value into VV, and do all the lookups at once. This single equation is the core of every Transformer:

Attention(Q,K,V)=softmax ⁣(QKdk)V\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right) V

Decoding every symbol, ELI5 — and why each part is there:

  • QQ, KK, VV — the stacks of all queries, all keys, all values (one row per token). Bundling them into matrices lets us score every token against every token in one matrix multiply.
  • QKQK^\top — every query dotted with every key. The superscript \top means transpose (flip the matrix on its side) so the shapes line up for multiplication. The result is an n×nn \times n grid of relevance scores: entry (i,j)(i, j) is how much token ii cares about token jj. This grid is the whole point — it is the attention pattern.
  • dk\sqrt{d_k} — the square root of dkd_k, the length of each key vector. Dividing by it keeps the scores from getting huge. Why it matters: without this, big vectors produce big dot products, the softmax saturates, and gradients vanish so the layer stops learning (full reason in the Depth panel below).
  • softmax()\text{softmax}(\cdot) — squashes each row of scores into positive weights that sum to 1, so every row becomes a proper weighted-average recipe.
  • multiply by VV — take that weighted average of the value vectors. Why it matters: this is the actual output — each token's new representation, blended from the tokens it decided were relevant.
Read it as one sentence

softmax(QK/dk)V\text{softmax}(QK^\top/\sqrt{d_k})\,V says: score every token against every token, turn the scores into weights that sum to one, and use those weights to average the values. Similarity in, weighted blend out — nothing more.

is the step that turns raw scores into a clean weighting:

softmax(z)i=ezijezj\text{softmax}(\mathbf{z})_i = \frac{e^{z_i}}{\sum_{j} e^{z_j}}

Decoding it, ELI5:

  • z\mathbf{z} — one row of raw scores (for one token, its scores against all tokens).
  • ezie^{z_i}ee (about 2.718) raised to each score. Exponentiating makes everything positive and stretches gaps, so a slightly higher score wins a lot more weight.
  • jezj\sum_j e^{z_j} — the Σ\Sigma ("sum") of all those exponentials; dividing by it forces the whole row to add up to exactly 1.
  • Why it matters: it converts "how relevant" into "what fraction of my attention," and it's smooth (differentiable), so gradient descent can train through it.
Turning scores into a weighted average

Take the scores [1,0,1][1, 0, 1] from the previous worked example and softmax them:

  1. Exponentiate: e12.72,  e0=1,  e12.72e^1 \approx 2.72,\; e^0 = 1,\; e^1 \approx 2.72.
  2. Sum: 2.72+1+2.72=6.442.72 + 1 + 2.72 = 6.44.
  3. Divide: weights [0.42, 0.16, 0.42]\approx [0.42,\ 0.16,\ 0.42] — and 0.42+0.16+0.42=10.42 + 0.16 + 0.42 = 1. ✓

Now the output is 0.42v1+0.16v2+0.42v30.42\,\mathbf{v}_1 + 0.16\,\mathbf{v}_2 + 0.42\,\mathbf{v}_3 — mostly values 1 and 3 (the relevant ones), a little of value 2. That blend is what this token becomes.

Why each output row is a weighted average

Because every row of weights is positive and sums to 1, each output is a convex combination of the value vectors — it can never be larger or wilder than the values themselves. This statement matters practically: it keeps activations bounded and stable as you stack dozens of attention layers, instead of letting them explode.

Let's actually run it. This cell implements scaled dot-product self-attention in pure NumPy on a tiny 4-token sequence — no deep-learning library needed — and confirms each attention row sums to 1.

Python · runs in your browser
Try to recall

What are the three steps inside softmax(QKᵀ/√dₖ)V, in order?

Hint: Score, normalize, blend.

Multi-head attention — several viewpoints at once

One set of Q/K/V projections can only track one kind of relationship at a time. Language and images have many at once: grammar, meaning, position, object parts. So we run several attention operations in parallel, each with its own projections, and combine them.

Think of it like a panel of specialists reviewing the same document:

Give the same paragraph to a grammar expert, a fact-checker, and a tone analyst. Each notices different connections. You then merge their notes into one richer summary. Each expert is an attention ; multi-head attention is the panel plus the merge step.

gives each head its own small slice of the representation, so heads can specialize instead of competing.

MultiHead(X)=Concat(head1,,headh)WO\text{MultiHead}(X) = \text{Concat}(\text{head}_1, \dots, \text{head}_h)\, W^O

Decoding the symbols, ELI5:

  • headi\text{head}_i — the output of the ii-th attention operation (its own softmax(QK/dk)V\text{softmax}(QK^\top/\sqrt{d_k})V using head ii's own projections).
  • hh — how many heads run in parallel (e.g. 8 or 12). More heads = more relationship types tracked at once.
  • Concat()\text{Concat}(\cdots) — stick the heads' output vectors side by side into one long vector.
  • WOW^O — a final learned matrix that mixes the concatenated heads back into the model's dimension. Why it matters: without this mix step the heads would stay in separate lanes; WOW^O lets the layer combine what different heads found.

What is the purpose of using multiple attention heads instead of one?

Order matters — positional encoding

Here is a subtle trap. Look again at softmax(QK/dk)V\text{softmax}(QK^\top/\sqrt{d_k})V: it is a sum of weighted values. If you shuffle the tokens, you shuffle the rows and columns but compute the exact same set of weighted sums — the output for each token is unchanged. Attention is .

Attention sees a bag, not a sequence

On its own, attention treats the input like a bag of tokens with no order — it cannot tell "dog bites man" from "man bites dog." For language and images, order and position obviously matter. So we must inject position information ourselves.

The fix is a : give every position its own distinctive pattern of numbers and add it to the token's vector before attention. The original Transformer used fixed sine and cosine waves of different frequencies.

The Transformer block — attention plus the plumbing

Attention is the star, but a working Transformer block wraps it with three supporting pieces, then stacks that block many times:

x = x + MultiHeadAttention(LayerNorm(x))   # look around, add the result back
x = x + MLP(LayerNorm(x))                   # think per-token, add the result back

The three helpers each earn their place:

  • The x = x + ... pattern is a (from CNNs): each sub-layer only learns a correction to add, which keeps gradients healthy through dozens of layers.
  • steadies the numbers going into each sub-layer.
  • The lets each token privately process what attention just gathered.
Mix, then think

Attention is the only place tokens talk to each other — it mixes information across positions. The MLP is where each token thinks on its own about what it heard. A Transformer is just this two-step — mix, then think — repeated many times, with residuals and LayerNorm keeping the deep stack trainable.

Here is a compact self-attention module in real PyTorch. It needs a GPU-class library, so it opens in Colab rather than running in your browser — but notice the shape is exactly the NumPy version above, just batched and multi-head.

Python · needs a GPU — run on Colab
import torch, torch.nn as nn

class SelfAttention(nn.Module):
    def __init__(self, dim, heads=8):
        super().__init__()
        self.h, self.dk = heads, dim // heads
        self.qkv = nn.Linear(dim, dim * 3)     # builds Q, K, V in one matmul
        self.proj = nn.Linear(dim, dim)        # the W_O mixing step

    def forward(self, x):                       # x: (B, N, D)
        B, N, D = x.shape
        qkv = self.qkv(x).reshape(B, N, 3, self.h, self.dk).permute(2, 0, 3, 1, 4)
        q, k, v = qkv[0], qkv[1], qkv[2]        # each (B, h, N, dk)
        att = (q @ k.transpose(-2, -1)) / self.dk ** 0.5   # scaled scores
        att = att.softmax(dim=-1)               # weights sum to 1 per row
        out = (att @ v).transpose(1, 2).reshape(B, N, D)   # weighted average of values
        return self.proj(out)

Why it matters for vision

The (ViT) makes one clever leap: chop the image into small square patches, flatten each patch into a vector (a token), add positional encodings, and feed the sequence into an ordinary Transformer. With enough training data it matches or beats CNNs, and because it speaks the same "sequence of tokens" language as text models, it unlocks unified multimodal systems like CLIP.

The catch is cost. Building the full n×nn\times n score grid means attention has in the number of tokens.

  • nn — the number of tokens (patches or words).
  • Why it matters: doubling the sequence roughly quadruples the compute and memory. This is the bottleneck for long documents and high-resolution images, and the reason for efficient variants — windowed attention (Swin), sparse and linear attention, and FlashAttention's memory-savvy implementation.

Why is plain self-attention expensive on long sequences?

Practice — and how to make it stick

Learn it the way that actually works

Three research-backed habits, built into this platform:
Retrieval practice: attempt the exercises below before rereading — pulling the answer from memory beats recognizing it on the page.
Spaced repetition: mark this topic complete and it joins your Review queue, resurfacing right before you'd forget.
Interleaving: mix these with problems from Linear Algebra and CNNs rather than grinding one topic — messier practice, sturdier memory.

Start hands-on. This lab gives you a working self-attention in NumPy and asks you to make the pattern visible — edit the code, run it (Ctrl/Cmd+Enter), and read the heatmap.

Python · runs in your browser

More to try, by hand and in code:

  1. By hand: given query [2,0][2, 0] and keys [2,0],[0,3],[1,1][2,0], [0,3], [1,1], compute the three dot-product scores, softmax them, and check the weights sum to 1.
  2. From scratch: add real learned projections WQ,WK,WVW^Q, W^K, W^V (random matrices) to the NumPy cell and confirm the output shape is unchanged.
  3. Multi-head: split the 4-D vectors into two 2-D heads, run attention in each, concatenate, and compare the pattern to the single-head version.
  4. Build a tiny ViT: patchify CIFAR-10, add a class token plus positional embeddings, and train a few Transformer blocks.
Explain it yourself

Explain self-attention to a curious friend using the room-of-experts or library picture — no formulas. Cover why each token needs a query, a key, and a value, and why we divide the scores before softmax. If you stall on any part, that is exactly the spot to reread.

Recap — the key ideas
  • Attention computes, for each token, a weighted average of the other tokens' information — the weights say how relevant each one is.
  • Every token plays three roles: a query (what I want), a key (what I advertise), and a value (what I hand over).
  • Scaled dot-product attentionsoftmax(QK/dk)V\text{softmax}(QK^\top/\sqrt{d_k})V — scores every token against every token, normalizes to weights that sum to 1, then blends the values. The dk\sqrt{d_k} keeps softmax gradients alive.
  • Multi-head attention runs several of these in parallel so different heads track different relationships.
  • Attention is permutation-invariant, so positional encodings add order back in.
  • A Transformer block = attention (mix across tokens) + MLP (think per token), wrapped in residuals and LayerNorm — the backbone of ViTs and modern foundation models. Its cost is O(n²) in sequence length.

Continue to Vision Transformers to see attention applied to images end-to-end, then Foundation Models for where this architecture leads.

Key papers