The quadratic bottleneck chapter counted compute: n² dot products, unavoidable if every query has to see every key. But GPUs don't run out of compute first — they run out of fast memory. What if the bottleneck isn't the n² multiplications at all, but the n² numbers you were about to write down?
A 4×4 attention matrix has 16 scores. Step through the tiles and only ever 4 are on screen at once — the rest are never computed and stored simultaneously as a full grid. Attention still gets built, tile by tile; it's just never all present at the same moment.
FlashAttention keeps a running max and sum per query row instead of a finished one, correcting past work whenever a new block changes the max:
- — the largest score seen for this query so far, across all blocks processed.
- — the running sum of , i.e. the softmax denominator built up so far.
- — one raw attention score in the current block being processed.
- Softmax only needs a max and a sum — not the whole row up front
. Any constant works as long as it's subtracted everywhere consistently — it doesn't have to be the true row max known in advance.
- Raising the max means rescaling what's already been accumulated
If a new block's scores beat the old max, every term computed under the old max is systematically too large relative to the new one. Multiplying the running sum and the running weighted-value total by exactly corrects for that, no re-visiting of old blocks required.
- One block's scores are all that's ever needed at once
Each block contributes its scores, updates and , then can be discarded. The final output, after every block, is exactly the same number naive softmax would have produced.
Naive attention's peak memory is the whole n×n matrix — it grows quadratically as the sequence gets longer. Tiled attention's peak memory is one block×block tile — fixed, flat, and the same at n = 128 as at n = 4. That gap between the bars is the entire reason FlashAttention scales to sequences naive attention can't fit in memory at all.
Query against four keys with scores (all tied), processed in two blocks of 2:
- Block 1: scores (1, 1)
. Since there's no previous accumulation, the rescale factor is 0. Running sum: .
- Block 2: scores (1, 1) — the max doesn't change
stays 1, so the rescale factor is — nothing to correct. New terms add more, so .
- Divide by the final sum — matches the naive computation exactly
Every score tied at 1 means every weight is exactly, whether computed all at once or in two passes: the output is the plain average of the four value vectors either way.
Find the smallest sequence length, among the candidates, where naive peak memory first reaches at least 1000x tiled peak memory.
FlashAttention computes exactly the same attention output as the naive softmax formula — nothing is approximated — by keeping a running max and sum per query and rescaling past work whenever the max changes, instead of requiring the whole row of scores up front. That collapses peak memory from the full n×n matrix down to one block at a time, flat regardless of sequence length. It's an algorithmic and memory-hierarchy trick, not a change to what attention computes — the next chapter looks at architectures that change the computation itself, mixing in layers that never touch an n×n matrix in the first place.