The cost that is not the arithmetic
A standard implementation writes that matrix to memory, reads it back for the softmax, writes the result, and reads it again for the multiply by .
With a sequence of 8,192 and 32 heads, the attention matrix alone is gigabytes, and every byte crosses the memory bus several times.
Attention is memory-bound, so the speedup does not come from doing less arithmetic. FlashAttention does slightly more and moves far less.
Tiling, and the problem it creates
Blocks of the three matrices are loaded into shared memory, where the arithmetic is an order of magnitude faster than in main memory.
The obstacle is that softmax needs the maximum and the sum over the whole row, and a tile only ever sees part of it.
Online softmax
Keep a running maximum and a running sum, and rescale them whenever a new block raises the maximum.
The output accumulator is rescaled by the same factor, so the result after the last block is exactly the softmax over the whole row.
It is not an approximation. The output is numerically identical to the standard implementation, which is why it could be adopted without retraining anything.
One block row, in order
- Load a block of into shared memory and initialise the accumulators.
- Loop over blocks of and , loading each into shared memory.
- Compute the scores for that tile and its local maximum and sum.
- Rescale the running statistics and the output accumulator, then add the tile's contribution.
- After the last tile, divide by the running sum and write the output once.
The attention matrix is never materialised, which is where the memory saving comes from and why context lengths that previously did not fit now do.
The backward pass
The trick is to recompute from and instead of storing it.
Backpropagation needs the attention weights, and storing them would undo everything.
They are recomputed inside the same tiling, which costs extra arithmetic and still wins, because arithmetic was never the constraint.
The later versions improve the work partitioning across warps and reduce the non-matmul operations, which matter because the matrix units are far faster than the general ones.
Nothing about the model changes. It is a different implementation of the same function, which is the cleanest kind of optimisation there is.