4.1.14 · D2Transformer Architecture

Visual walkthrough — Flash attention and efficient attention

2,449 words11 min readBack to topic

Step 1 — What are we even computing? Attention as a weighted average

Let us name the players, and never use a symbol before it is a picture.

  • — one query vector (a row). It is the token that is "asking".
  • — the key vectors, one per token. Each key is what a token "advertises".
  • — the value vectors, the actual content each token would contribute.
  • — how many tokens there are (the sequence length).
  • — how many numbers are inside each vector (the dimension).

The score between the query and key is their dot product . A dot product is big when two arrows point the same way — so a big means "this token matches what I'm asking for".

PICTURE. Below: the query arrow, four key arrows, and the weights they earn. The output is the amber blended arrow.

Figure — Flash attention and efficient attention

The trouble is hiding in plain sight: the denominator needs every score before you can finish. That is the whole problem of this page.


Step 2 — Why we can't just start summing: the denominator blocks us

WHAT we want instead: pour keys through one block at a time, and never hold more than a small tile in fast memory.

WHY it seems impossible: division by a total you haven't finished. If you commit to a weight now, a later key could change the total and make your weight wrong.

PICTURE. The full row of scores vs. the tile we are allowed to see. Everything greyed-out is what we are forbidden to store.

Figure — Flash attention and efficient attention

The escape: don't compute final weights early. Keep a running numerator and a running denominator, and fix them up whenever new information arrives. That fix-up is the heart of the algorithm.


Step 3 — The overflow danger, and the max-shift that defuses it

Before we tile, one hazard. Scores can be large; overflows a computer's float. So everyone uses the safe softmax: subtract the biggest score first.

(To keep symbols light we fold into the scores from here on: read as "already scaled".)

WHY this matters for tiling: each tile only knows the max of its own tile. Different tiles will use different reference points . When we merge tiles we must convert them to a common reference — that conversion is a single multiply, and it is the one clever line in Flash Attention.

PICTURE. Left: raw exponentials skyrocketing. Right: after shifting by every bar sits at or below .

Figure — Flash attention and efficient attention

Step 4 — Book-keeping per tile: three running numbers

For each tile of keys we compute exactly three things and carry them forward.

The final answer, once all tiles are done, is one division: . We delay the division to the very end — that is how we dodge the "need the total first" trap.

For a single fresh tile with its own scores :

  • — this tile's local reference point.
  • — this tile's local denominator.
  • — this tile's local value-blend (not yet divided).

PICTURE. One tile arriving; the three quantities it produces shown as a max-marker, a sum-bar, and a small blended vector.

Figure — Flash attention and efficient attention

Step 5 — The merge, derived symbol by symbol

Now the key move. We hold old state and a new tile . How do we combine them without re-reading old scores?

First, the new common reference is the bigger of the two maxima:

Now the crux. A sum measured against can be re-based to by multiplying by one factor. Watch why:

Every term picked up the same extra factor , so it factors out. That single multiply "moves" a whole sum to the new reference point — no old scores needed.

PICTURE. Two sums at different reference heights; the amber rescale arrow pulls the lower one up to the shared baseline before they add.

Figure — Flash attention and efficient attention

Step 6 — Run it: the full example, tile by tile

Take the parent note's numbers (, , tile size ), following query row only. Scores are already scaled by .

Tile 1 (keys 0,1): scores .

  • exponents , so

Tile 2 (keys 2,3): scores .

  • exponents , so

Merge: here , so both rescale factors are .

This equals what standard attention gives for row — but the matrix was never stored.

PICTURE. The two tiles' running state, then the merged answer, drawn as accumulating bars.

Figure — Flash attention and efficient attention

Step 7 — Degenerate and edge cases (never leave the reader stranded)

Real inputs are not always tidy. Every case still works — here is why.

PICTURE. Three mini-panels: uniform scores → flat average; one spike → single-token pickup; masked entry → zero contribution.

Figure — Flash attention and efficient attention

Step 8 — Backward pass: the recompute trade

Training needs gradients, which normally means storing (the weights). Flash Attention refuses. Instead it stores only the tiny per-row statistics and, in the backward pass, recomputes the score tiles from on the fly — the same idea as gradient checkpointing.

PICTURE. Standard path: fat matrix parked in slow HBM. Flash path: only slim stored, tiles recomputed in fast SRAM.

Figure — Flash attention and efficient attention

The one-picture summary

Figure — Flash attention and efficient attention

Read it left to right: keys stream in as tiles; each tile makes a local ; the merge rescales to a shared max and accumulates; one final division at the far right gives the exact same output as full-matrix attention — with linear memory.

Recall Feynman retelling — say it back in plain words

Imagine averaging exam scores, but the students hand papers in one class at a time and you're not allowed to keep the papers. You keep three sticky notes: the highest score so far, a running total of "weights", and a running total of "weight × value". Every time a new class arrives you note its own highest score, its own totals, then — because the two classes measured their weights against different high-score reference points — you shrink the lower-reference class's totals by one multiply so both use the same reference. Add them. At the very end, divide the weighted total by the total weight. You get exactly the answer you'd get if you'd kept every paper — but you never held more than one class's worth at once. Attention does this with keys instead of classes, in fast on-chip memory, and that is why it's both leaner and faster.

Recall Quick self-test

Why can't we compute a softmax weight before seeing all scores? ::: The weight divides by the sum over all scores; that total isn't known until the last score arrives — so we delay the division and keep a running numerator and denominator instead. What are the three running numbers Flash Attention keeps per query? ::: the running max , the running denominator , and the running un-normalised output . Why is a rescale factor needed when merging two tiles? ::: The tiles measured their sums against different maxima; multiplying by re-bases a whole sum to the shared reference in one step. Both and get rescaled by the same factors — why? ::: They are the denominator and numerator of the same fraction; if only one were rescaled they'd be measured against different references and the final division would be wrong. Why is the backward pass's extra recompute worth it? ::: It avoids reading/writing the matrix from slow HBM; saving that memory traffic outweighs the small arithmetic cost, so it's a net speedup.