Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

~14 min readNeurIPS 2022

FlashAttention,
explained.

Everyone knew attention got painfully slow on long inputs, and everyone assumed the problem was too much math. This 2022 paper showed the arithmetic was never the bottleneck — the GPU was spending almost all its time shuffling data between fast and slow memory. Fix the shuffling, and attention gets several times faster while computing the exact same answer.

The delta

What changes against every attempt to make attention cheaper: the diagnosis

The years between the transformer and this rung produced a large literature on making attention cheaper, nearly all of it aimed at the quadratic number of operations — sparsify the pattern, approximate the softmax, low-rank the matrix. This rung's change is to point out that operations were never the bottleneck, and to fix the one that was.

The observation: a standard implementation computes the full score matrix, writes it to the accelerator's main memory, reads it back to apply the softmax, writes it again, reads it again to multiply by the values. On modern hardware, arithmetic is enormously faster than that memory traffic, so the kernel spends most of its time waiting on reads and writes of a matrix it only needs transiently. Attention was slow because it was memory-bound, and every method that traded accuracy for fewer operations was optimising the resource that was not scarce.

The fix is to never build the matrix. Process the sequence in tiles small enough to live in the chip's fast on-die memory, and accumulate the result tile by tile — which requires computing a softmax whose denominator is not known until the end, done by carrying a running maximum and running sum and rescaling the accumulated output as each new tile arrives. Stated in units: the output is the same exact attention, up to floating-point rounding, wall-clock time falls substantially, and memory use drops from quadratic in sequence length to linear, because the quadratic object is never stored.

01

The real bottleneck

Self-attention has every token compare itself to every other token, producing an N×N scores matrix. For a sequence of length N, that matrix grows with the square of N — at 8,000 tokens it's 64 million numbers. The standard implementation writes that whole matrix out to memory, reads it back to apply softmax, then reads it a third time to multiply by the values.

The paper's diagnosis: the GPU's arithmetic units were mostly idle, waiting on those reads and writes. Attention was memory-bound, not compute-bound. The field had been optimizing the wrong thing.

02

Fast memory, slow memory

A GPU has two very different kinds of memory. HBM is the big main memory — tens of gigabytes, but relatively slow. SRAM is tiny on-chip memory — only kilobytes to a few megabytes, but roughly an order of magnitude faster.

The GPU memory hierarchy
SRAM~20 MB, ~19 TB/s — tiny but blazing fast. Work here.
HBM~40 GB, ~1.5 TB/s — huge but ~10x slower. Touch as little as possible.

Standard attention parks that giant scores matrix in slow HBM and keeps trudging back to it. FlashAttention's entire strategy is to never put it there in the first place.

03

Tiling and the online softmax

Instead of computing the full matrix at once, FlashAttention breaks the work into tiles — small blocks of queries and keys that fit inside fast SRAM. It loads a block, computes its piece of attention entirely in SRAM, and moves on, never writing the intermediate scores back to HBM.

The tricky part is softmax, which normally needs to see a whole row at once to normalize it. FlashAttention uses an online softmax: it processes blocks one at a time and keeps a running total and running maximum, rescaling previous partial results as new blocks arrive — so it gets the exact normalized answer without ever holding the full row. All the attention operations are fused into a single pass over fast memory.

One query block walks the key/value blocks — only the amber tile is in SRAM
Q block stays put K·V ✓ K·V ✓ K·V now in SRAM next… carry (m, ℓ, O) forward — rescale them whenever a new block raises the max
04

The math, worked with real numbers

The rescaling trick is the whole paper, so let's do it by hand. Softmax is computed "safely" by subtracting the row's max m before exponentiating (so nothing overflows), then dividing by the sum ℓ:

Both m and ℓ look like they need the whole row. They don't. Take a row of scores s = [2, 1, 3, 0] and process it in two blocks — [2, 1] first, then [3, 0]:

StepRunning max mRunning sum ℓWhat happened
Block [2, 1]2e^0 + e^−1 = 1.3679Everything measured against max-so-far = 2
Block [3, 0] arrives3—New max! The old sum used the wrong max
Rescale old ℓ31.3679 × e^2−3 = 0.5033One multiply fixes every earlier term at once
Absorb new block30.5033 + e^0 + e^−3 = 1.5530Exactly what the full row gives: e^−1+e^−2+e^0+e^−3 = 1.5530 ✓

Why does one multiply fix everything? Every old term was e^s−2 but should have been e^s−3 — and e^s−3 = e^s−2·e^2−3. The correction factor is the same for every term, so it can be applied to their sum. That's the update rule the kernel runs per block:

The third line is the punchline: the output accumulator O (the weighted sum of values built so far) is corrected by the same factor. Final answer = O / ℓ. Finishing the example: with m = 3 and ℓ = 1.5530, the weights come out [0.2369, 0.0871, 0.6439, 0.0321] — identical to computing softmax on the whole row at once. No approximation anywhere; the N×N matrix simply never existed.

05

Exact, not approximate

This is what set FlashAttention apart. Earlier attempts to speed up attention approximated it — sparse patterns, low-rank tricks — trading accuracy for speed. FlashAttention changes only the memory schedule. The result is the same attention, exact up to floating-point rounding; you give up nothing.

Worth knowing

Because it never stores the N×N matrix, FlashAttention's memory grows only linearly with sequence length instead of quadratically. That's the door to long context windows — the reason models could suddenly handle tens of thousands of tokens.

How it works

How the FlashAttention kernel runs, forward and backward

The kernel takes Q, K and V for one attention head, each N × d and stored in the GPU's high-bandwidth memory (HBM), plus an on-chip SRAM budget of M elements. It returns the same output O = softmax(QK^T)V a standard implementation would, with the 1/√d scale, masking and dropout fused in, but never writes the N × N score or probability matrix to HBM. The forward pass:

HBM (large, slow) Q, K, V row stats m, ℓ O and dO dQ, dK, dV SRAM tile (small, fast) recompute tile S = QKᵀ P = exp(S − m) / ℓ dS = P ∘ (dO Vᵀ − D) add into dQ, dK, dV forward pass saved only O, m and ℓ S and P are discarded after each tile extra FLOPs, but HBM traffic stays Θ(N²d²/M) loop over every (i, j)
The backward pass rebuilds each score and probability tile on chip from Q, K and the two saved row statistics, uses it once and throws it away, so the N × N matrix never exists in HBM in either direction.
  1. Size the tiles from SRAM. Key and value blocks get Bc = ⌈M/4d⌉ rows and query blocks Br = min(⌈M/4d⌉, d) rows, so a query block, a key block, a value block, an output block and their Br × Bc score tile all fit on chip at once.
  2. Initialize running state in HBM. An output accumulator O = 0, a running row sum ℓ = 0 and a running row maximum m = −∞, one entry of ℓ and m per query row.
  3. Outer loop over key and value blocks. Load Kj and Vj into SRAM once each.
  4. Inner loop over query blocks. Load Qi, Oi, ℓi and mi. Compute the tile Sij = QiKj^T, its row maxima, P̃ij = exp(Sij − row max) and its row sums. Merge them with the running m and ℓ, rescale the old Oi by ℓold·exp(mold − mnew), add P̃ijVj rescaled to the new maximum, divide by the new ℓ, and write Oi, ℓi and mi back. Masking and dropout are applied to the tile while it is still in SRAM.
  5. Keep only O(N) extra state. After the last block, O is the exact attention output. What is saved for the backward pass is O plus the statistics ℓ and m (and the random-number state for dropout), not the N × N matrix.

The backward pass recomputes instead of reading

Standard backpropagation through attention reads the stored probability matrix P. FlashAttention never stored it, so it rebuilds each tile on chip: reload Qi, Kj and Vj, recompute Sij, and get Pij = exp(Sij − mi)/ℓi directly from the saved statistics. From there: dVj += Pij^TdOi, dPij = dOiVj^T, dSij = Pij ∘ (dPij − Di), dQi += dSijKj and dKj += dSij^TQi. The vector Di = rowsum(dOi ∘ Oi) stands in for the reduction the softmax gradient would otherwise need over a full row of P, and it is computed from N × d matrices. Recomputation costs extra arithmetic, but the backward pass makes the same Θ(N²d²/M) HBM accesses as the forward pass, which is why it beats the standard backward despite doing more FLOPs.

Block-sparse FlashAttention

The paper also gives a sparse version: given a fixed mask over blocks, the kernel skips every tile that is zero. Its IO cost falls in proportion to the fraction s of non-zero blocks, Θ(Nd + N²d²s/M). Unlike the dense kernel this one is an approximation, because it drops attention outside the mask, and it is the version that reached the 64K-token Path-256 task. Both versions are written as a single fused CUDA kernel, which is the practical reason the method has to be re-tuned for each GPU generation.

The math

FlashAttention's IO complexity, and the bound it meets

standard attention: Θ(N·d + N²) HBM accesses
FlashAttention: Θ(N²·d² / M) HBM accesses, for d ≤ M ≤ N·d
  • N — sequence length; d — head dimension; M — the SRAM available to the kernel, in elements.
  • N·d — reading Q, K and V and writing O once, which no method can avoid.
  • N² — the score and probability matrices the standard kernel writes out and reads back.
  • N²·d²/M — every K/V block is loaded once, but each one triggers a pass that streams Q and O through SRAM, and there are N/Bc = Θ(N·d/M) such passes, each moving Θ(N·d) elements.

The quadratic terms differ by a factor of M/d². For head dimensions of 64 to 128 and roughly 100 KB of SRAM, d² is many times smaller than M, so FlashAttention makes many times fewer HBM accesses. At the extremes: if M reached N·d, everything would fit on chip and the cost would fall to a single pass, Θ(N·d). If M shrank toward d, the bound would grow toward N²·d, worse than the standard kernel, so the method relies on SRAM being large compared with d². The paper also proves a matching lower bound: no exact attention algorithm can make asymptotically fewer HBM accesses than Θ(N²d²/M) over the whole range of SRAM sizes from d to N·d.

The evidence

What the FlashAttention paper measured

The main timings are on NVIDIA A100 GPUs. The paper trained BERT-large on the MLPerf 1.1 setup, GPT-2 small and medium on OpenWebText, and Transformers on the Long Range Arena and the Path-X and Path-256 tasks, against PyTorch, HuggingFace, Megatron-LM, Nvidia's MLPerf code and a range of approximate-attention methods.

BenchmarkBaselineFlashAttention
BERT-large to MLPerf target, 8 A100sNvidia MLPerf 1.1: 20.0 min17.4 min (15% faster)
GPT-2 small trainingHuggingFace 9.5 days; Megatron-LM 4.72.7 days
GPT-2 medium trainingHuggingFace 21.0 days; Megatron-LM 11.56.9 days
Attention only, GPT-2 medium, forward + backward66.6 GFLOPs, 40.3 GB HBM traffic, 41.7 ms75.2 GFLOPs, 4.4 GB, 7.3 ms
Long Range Arenastandard attention2.4× faster
Path-X, 16K tokensevery earlier Transformer at chance61.4% accuracy
Path-256, 64K tokens (block-sparse)no earlier result above chance63.1% accuracy

The GPT-2 runs reached the same perplexity as the baselines, so the speedups (about 3× against HuggingFace and 1.7× against Megatron-LM) came with no change in model quality. The attention-only row is the paper's central argument in numbers: the recomputing kernel did about 13 percent more arithmetic, yet moved roughly a ninth of the bytes and ran about 5.7 times faster, so runtime followed memory traffic, not FLOPs. Varying the block size told the same story: larger blocks meant fewer HBM accesses and lower runtime until arithmetic took over as the limit. Memory use grew linearly with sequence length, up to about 20 times less than the exact-attention baselines.

The negative result is about scale. Dense FlashAttention is still quadratic in arithmetic, and approximate methods such as Linformer overtook it somewhere between 512 and 1,024 tokens; only the block-sparse version was faster than every approximate method at every length. Longer context did pay off in accuracy: GPT-2 with a 4K context trained with FlashAttention was still faster than Megatron-LM at 1K and reached lower perplexity.

Since then

What the authors admit, and what happened next

The cost is that this is a hardware-specific kernel, not an algorithm you can express in a framework and have run everywhere. Its advantage comes from the ratio between on-die and main memory bandwidth on a particular accelerator, so it has to be rewritten per architecture, and successive versions exist largely to track new hardware. The paper is explicit that the analysis is about the memory hierarchy.

There is nothing to contest in the result — exactness makes it unusually unarguable — so what is worth noting instead is the opportunity cost the field paid for the wrong diagnosis. Several years of approximate-attention research was aimed at a resource that was not binding, and that line largely stopped being competitive the moment exact attention got fast.

How it held up: it is in everything, and it is the single most-transferable lesson on this site for anyone who optimises anything. Measure which resource is saturated before redesigning the mathematics — the first-order win was available without giving up a single bit of accuracy, and it went unnoticed because the community was reasoning about complexity rather than about the memory hierarchy. Long context became practical as a side effect, since the quadratic memory term was what made it impossible.

SOLVE IT YOURSELF

Online softmax & tiled attention, for real

This is the paper's core algorithm in ~40 lines of plain Python, running in your browser through WebAssembly. naive_softmax needs the whole row; online_softmax streams it in blocks with the rescale trick; flash_attention extends the same trick to the full attention output. Run it and watch the tiled version match the standard one to 16 decimal places — then change the row, the block size, or Q/K/V and check it still does.

YOUR TASK

Write the body of flash_attention. Everything else in the file is already written; this is the function the paper is about. Press ▶ Run to check it against the 5 assertions below — they start red.

WHAT IT HAS TO SATISFY — 5 ASSERTIONS
  1. Online softmax == naive softmax
  2. Block size never changes the answer
  3. Flash attention == standard attention
  4. The online softmax is still a valid distribution (sums to 1)
  5. Tiled flash attention equals standard attention on the worked example
CPython · WebAssembly
07

Why it still matters

FlashAttention became a default building block baked into every major training and inference stack — PyTorch's scaled_dot_product_attention, vLLM, TensorRT-LLM, xFormers. If you've used a model with a long context window, you've almost certainly used it. And it grew into a lineage:

VersionYearWhat changed
FlashAttention2022Tiling + online softmax + recomputation; IO-aware exact attention
FlashAttention-22023Better parallelism & work partitioning between GPU thread blocks and warps — roughly 2× again, reaching 50–73% of A100 peak FLOPs
FlashAttention-32024Rebuilt for Hopper (H100): warp specialization, asynchronous TMA copies, FP8 support — another ~1.5–2×

Its deeper lesson is one every systems engineer learns eventually: on modern hardware, data movement is the cost, not arithmetic. The fastest code isn't the one that does the least math — it's the one that moves the least memory. FlashAttention is that principle, applied to the single most important operation in modern AI.

Questions

Questions people ask about FlashAttention

What is the IO complexity of FlashAttention?

FlashAttention makes Θ(N²d²/M) reads and writes to GPU high-bandwidth memory, where N is the sequence length, d the head dimension and M the size of on-chip SRAM. Standard attention makes Θ(Nd + N²), because it writes the N by N score and probability matrices out and reads them back. The quadratic terms differ by a factor of M/d², and for head dimensions of 64 to 128 with about 100 KB of SRAM that factor is large. The paper also proves that no exact attention algorithm can do asymptotically better than Θ(N²d²/M) across the full range of SRAM sizes, so the tiling is optimal in that sense.

How does the FlashAttention backward pass work without storing the attention matrix?

The forward pass saves only the output and two numbers per query row: the running maximum and the softmax normalizer. In the backward pass the kernel reloads blocks of Q, K and V into SRAM, recomputes each score tile, and rebuilds the exact probabilities from those saved statistics. It then forms the gradients for V, K and Q tile by tile, using a per-row term computed from the output and its gradient, D = rowsum(dO ∘ O), in place of a reduction over the full probability row. This trades extra arithmetic for far less memory traffic, and the backward pass ends up faster than a standard one that reads a stored matrix.

Is FlashAttention numerically identical to standard attention?

It computes exact attention in the mathematical sense: the dense kernel has no approximation, no sparsity and no low-rank shortcut. But it is not bitwise identical to a standard implementation. Floating-point addition is not associative, and FlashAttention sums the softmax normalizer and the output tile by tile with rescaling steps, while a standard kernel reduces each full row at once. In half precision the two therefore agree up to rounding error rather than in every bit, and some implementations accumulate backward-pass gradients with atomic additions, so even two runs of the same kernel can differ slightly. Training quality matches; individual values can differ in the last digits.

Why is FlashAttention faster even though it does more FLOPs?

Because attention on a GPU is limited by memory traffic, not arithmetic. On the paper's GPT-2 medium benchmark, forward plus backward attention took 66.6 GFLOPs with the standard kernel and 75.2 with FlashAttention, the extra coming from recomputing tiles in the backward pass. But the standard kernel moved 40.3 GB to and from high-bandwidth memory against 4.4 GB, and runtime fell from 41.7 to 7.3 milliseconds. Softmax, masking and dropout do little arithmetic per byte, so when each of them reads and writes an N by N matrix the arithmetic units mostly wait. Fusing everything into one tiled kernel removes that waiting.

Does FlashAttention make attention sub-quadratic?

No. The dense kernel still does O(N²d) arithmetic; what it changes is memory. Extra memory becomes linear in sequence length because the N by N matrix is never stored, and HBM traffic drops by a large constant factor. The paper is explicit about the consequence: approximate methods such as Linformer became faster than dense FlashAttention somewhere between 512 and 1,024 tokens. For sub-quadratic cost the paper offers block-sparse FlashAttention, which skips the zero blocks of a fixed sparsity mask and was faster than every approximate method it was compared with, but which, like any sparse pattern, no longer computes full attention.

How does FlashAttention choose its block size?

From the size of on-chip memory. With M elements of SRAM and head dimension d, key and value blocks get about M/4d rows and query blocks the smaller of that and d, so that query, key, value and output blocks plus their score tile fit on chip together. Larger blocks mean fewer passes over Q and O and therefore fewer HBM accesses, and the paper's block-size sweep shows runtime falling with them until arithmetic becomes the bottleneck. Because the right size depends on each GPU's SRAM and on the head dimension, the kernel has to be tuned, and eventually rewritten, for each hardware generation.

Check yourself

4 questions to test what you just read

Work each one out before you open it — a number, a prediction or a reason, not a definition. Producing the answer is what makes it stick. Your progress is kept on this device.

In the GPT-2 medium benchmark FlashAttention did 75.2 GFLOPs against 66.6 for the standard kernel, yet took 7.3 ms instead of 41.7 ms. Using the HBM traffic figures (4.4 GB against 40.3 GB), which resource set the runtime?

Show answer

Memory traffic. FLOPs went up by about 13% (75.2 / 66.6), while bytes moved fell about 9.2× (40.3 / 4.4) and runtime fell about 5.7× (41.7 / 7.3). Runtime tracked the traffic, not the arithmetic, which is what memory-bound means.

At N = 16,384 tokens, how many entries does one head's N × N score matrix hold, how many bytes is that in fp16, and what does FlashAttention store instead?

Show answer

16,384² = 268,435,456 entries, about 537 MB (512 MiB) at 2 bytes each, per head and per sequence, and the probability matrix is the same size again. FlashAttention stores only the N × d output, which any method produces, plus two statistics per row: 2 × 16,384 = 32,768 numbers.

Why can the backward pass use D = rowsum(dO ∘ O) instead of reducing over the full row of P, and why does that matter?

Show answer

The softmax gradient needs rowsum(P ∘ dP) for each row. Since dP = dO V^T, that sum equals rowsum(dO ∘ (P V)) = rowsum(dO ∘ O). O and dO are N × d and already available, so D costs O(Nd) and never touches an N × N matrix, which is what makes recomputation cheap.

Predict: if a GPU doubled its SRAM while keeping HBM bandwidth the same, how should FlashAttention's HBM traffic change according to its IO bound?

Show answer

The bound Θ(N²d²/M) says the quadratic part of the traffic should roughly halve: key and value blocks get twice as wide, so Q and O are streamed through SRAM half as many times. The gain lasts only until arithmetic becomes the limit, the same pattern the paper's block-size sweep showed.

Where this sits

Serving it cheaply

Five papers about the bill. Each one buys throughput back from a different part of the stack: the weights, the memory hierarchy, the KV cache, the decode loop.

  1. 1Knowledge Distillation2014
  2. 2FlashAttention2022
  3. 3PagedAttention2023
  4. 4Speculative Decoding2023
  5. 5Medusa2024

All 110 papers, in 19 ladders →

FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness · Dao, Fu, Ermon, Rudra, Ré · NeurIPS 2022 · read the original paper on arXiv → · Vibe Engines · 2026
Finished this one? 0 / 110 Paper Breakdowns done
NextPagedAttention (vLLM) Next on the “Serving it cheaply” ladder · rung 3 of 5

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More Paper Breakdowns