FlashAttention
Standard attention writes a huge score matrix to GPU RAM and reads it back for the softmax — FlashAttention tiles the computation so the score matrix never leaves the small, fast on-chip cache, making attention faster without changing the result by a single bit.
Why Does This Exist?
Take the attention complexity page's finding seriously: the score matrix, for a sequence of length 4,096 and 32 heads, already measures tens of gigabytes per layer. That matrix has to be written to GPU memory (HBM) and then read back for the softmax — twice. On modern GPUs, HBM bandwidth is a more severe constraint than raw compute. A100 GPUs have roughly 312 TFLOPS of compute but only 2 TB/s of HBM bandwidth. Standard attention is memory-bound, not compute-bound, which means the attention arithmetic is fast but the data movement is the thing that costs time.
Dao et al. published FlashAttention in 2022 with a simple observation: A100 also has 20 MB of SRAM on-chip — much smaller than HBM but roughly 10× faster to access. If you could fit the relevant tiles of Q, K, and V into SRAM, run the attention math there, and accumulate the output without ever materialising the full score matrix in HBM, you'd cut HBM reads and writes dramatically. The FLOPs don't change. The result doesn't change. Only the data movement changes.
That's FlashAttention. IO-aware, exact, and now the default implementation in PyTorch, JAX, and every serious LLM training stack.
Think of It Like This
Doing maths at your desk instead of photocopying pages to the library
Imagine scoring 1,000 exam papers by printing all 1,000 answer sheets, taking them to a filing room, reading each one for scoring, carrying the scores back, then summing them. That's standard attention: compute the scores, write them all to memory, read them back for softmax, read them again for the weighted sum.
FlashAttention is scoring small batches at your desk without leaving the room. You pull a block of answer sheets, score them, note the running total, put them back, pull the next block. The final total is identical. But you never needed the 1,000-sheet pile in the filing room at once.
How It Actually Works
The memory-bandwidth problem
Standard attention does four large HBM operations per layer: write (the score matrix), read it for softmax, write the softmax weights, read them for the multiply. For N=4,096 and 32-bit floats, the score matrix alone is bytes ≈ 2 GB per layer. Even at 2 TB/s bandwidth that's a millisecond per read or write, and there are four of them.
Tiling and online softmax
FlashAttention processes the sequence in tiles of size chosen to fit in SRAM. For each tile:
- Load a tile of and from HBM into SRAM.
- Compute the tile's raw scores .
- Maintain a running maximum and running sum of softmax numerators using the online softmax recurrence — updating both as each new tile arrives rather than waiting for all scores to be computed.
- Load the corresponding tile, multiply by the current softmax weights, and accumulate into the output tile .
- Once all K/V tiles are processed, normalise by the final and write back to HBM.
The score matrix is never materialised. SRAM holds only the current tile. The online softmax recurrence, derived by Milakov and Gimelshein (2018), is what makes this numerically equivalent to computing the full softmax over all scores at once.
Recomputation in the backward pass
Backward pass needs the attention weights to compute gradients. Standard attention stores them during forward (another memory cost). FlashAttention instead stores only the softmax statistics ( and per query row) and recomputes the attention weights from tiles during the backward pass. This trades extra compute for drastically lower memory, which is the right trade on modern hardware.
The result
Memory usage drops from (the score matrix) to (the output). FLOPs are the same. HBM reads and writes drop dramatically. Wall-clock speedups of 2–4× on A100 were measured for N=1,024–4,096, growing as N grows because the score matrix that standard attention has to copy around gets larger.
Show Me the Code
Verifying that a tiled attention pass produces the same output as standard attention — the whole point of "exact".
import numpy as np
def standard_attention(Q, K, V): d = Q.shape[-1] scores = Q @ K.T / d**0.5 scores -= scores.max(-1, keepdims=True) # numerical stability weights = np.exp(scores) weights /= weights.sum(-1, keepdims=True) return weights @ V
def tiled_attention(Q, K, V, tile=2): """Simplified tiled attention; accumulates output without full score matrix.""" n, d = Q.shape O = np.zeros_like(Q) m = np.full(n, -np.inf) # running row-wise max l = np.zeros(n) # running row-wise softmax denominator
for j in range(0, n, tile): Kj = K[j:j+tile] Vj = V[j:j+tile] for i in range(0, n, tile): Qi = Q[i:i+tile] s = Qi @ Kj.T / d**0.5 # tile scores m_new = np.maximum(m[i:i+tile], s.max(-1)) e_old = np.exp(m[i:i+tile] - m_new)[:, None] e_s = np.exp(s - m_new[:, None]) O[i:i+tile] = O[i:i+tile] * e_old + e_s @ Vj l[i:i+tile] = l[i:i+tile] * e_old.squeeze() + e_s.sum(-1) m[i:i+tile] = m_new
O /= l[:, None] return O
rng = np.random.default_rng(7)Q, K, V = (rng.standard_normal((8, 16)) for _ in range(3))out_std = standard_attention(Q, K, V)out_tiled = tiled_attention(Q, K, V, tile=2)print("Max difference:", np.abs(out_std - out_tiled).max())# Max difference: ~1e-15 (floating-point rounding only, not approximation)The difference is floating-point rounding — the order of the operations differs slightly between tiled and standard, which shifts the last bits. There is no approximation.
Watch Out For
Assuming FlashAttention is an approximation
It's named differently from standard attention, it rewrites the computation, and it produces faster results — so it's easy to assume it's cutting a corner. It isn't. Given the same inputs, FlashAttention produces the same output as standard attention, to floating-point precision. The only thing it changes is the pattern of memory access. This is what the paper means by "exact": the algorithm is IO-aware, not approximate.
Expecting linear-time complexity
FlashAttention reduces memory from to and reduces HBM bandwidth dramatically. But it does not reduce FLOPs — the compute is still , the same as standard attention. If your bottleneck is pure arithmetic throughput rather than memory bandwidth (rare on current hardware, but possible on specialised accelerators), FlashAttention won't help there.
The Quick Version
- Standard attention writes the score matrix to HBM and reads it back multiple times; on modern GPUs, this memory movement is the real bottleneck, not the arithmetic.
- FlashAttention tiles Q, K, V to fit in fast SRAM, runs an online softmax recurrence to accumulate partial results, and never writes the full score matrix to HBM.
- Memory drops from to ; FLOPs are unchanged; the result is numerically identical to standard attention.
- Backward pass recomputes attention weights from tiles rather than storing them, trading a small amount of extra compute for large memory savings.
- FlashAttention is the default implementation in PyTorch (
F.scaled_dot_product_attention), JAX, and most training frameworks — you're almost certainly using it already.
What to Read Next
- Attention Complexity covers the cost FlashAttention's tiling addresses at the memory-access level.
- Self-Attention is the computation FlashAttention reimplements with smarter memory access.
- Multi-Head Attention runs FlashAttention per head in practice — the per-head tile sizes are what fit in SRAM.
- Sliding Window Attention changes which cells of the score matrix matter; FlashAttention changes how efficiently those cells are computed.
- Ring Attention extends FlashAttention's tiling logic across GPUs — the same IO-aware philosophy applied to multi-device sequence sharding.
- Mixed-Precision Training shares the same IO-aware philosophy — keep computations in fast lower-precision units; move only what has to move.