LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 177 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/8
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/11
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageClustering and PCACore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/24
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernanceData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/16
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/19
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning & Test-Time Compute
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnProject Deep DivesDeep Dive - FlashAttention
🚀HardInference Optimization

Deep Dive - FlashAttention

Read FlashAttention from first principles: exact tiled attention, online softmax, GPU memory traffic, kernel dispatch, version history, and production trade-offs.

20 min read
Learning path
Step 163 of 177 in the full curriculum
Deep Dive - SkyRLDeep Dive - FlashInfer

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

In full dense self-attention, each query compares with every key. Causal decoders mask future positions, but the number of allowed query-key pairs still grows quadratically. The arithmetic is familiar, but the GPU has a second problem: where each intermediate lives while that arithmetic runs. FlashAttention keeps exact attention while changing the order and location of those reads and writes.

This chapter reads the Dao-AILab implementation as an engineering project. It connects original papers to the source tree, works through a two-tile softmax by hand, then identifies when a production system should use FlashAttention, a framework backend, or a fallback. The earlier scaled dot-product attention lesson supplies the formula. Here the focus is the memory traffic around it.

Side-by-side memory paths for exact attention. The dense path keeps full S and P matrices of shape n by n beside HBM, while the tiled path streams Q_i, K_j, and V_j through one highlighted S_ij tile in SRAM, retains m_i, l_i, and O_i, then writes O_i and LSE_i. Side-by-side memory paths for exact attention. The dense path keeps full S and P matrices of shape n by n beside HBM, while the tiled path streams Q_i, K_j, and V_j through one highlighted S_ij tile in SRAM, retains m_i, l_i, and O_i, then writes O_i and LSE_i.
The left path pays for full score and probability matrices in HBM. The right path keeps one query tile and one key/value tile in SRAM, updates row state, and writes only output and compact statistics.

The memory wall behind exact attention

Scaled dot-product attention forms a score for every query-key pair. For sequence length nnn, that is n2n^2n2 scores per head before multiplying by values. A baseline implementation can write scores, read them for softmax, write probabilities, read them for the value multiply, and finally write the output. Each round trip crosses HBM (high-bandwidth memory), the large GPU memory pool.

HBM has high capacity and high aggregate bandwidth, but an on-chip SRAM (static random-access memory) workspace is much smaller and faster to revisit. GPU arithmetic units can perform many fused multiply-adds while a kernel waits for HBM transactions. Kernel analysis therefore needs both FLOPs and bytes crossing the chip boundary.

The original FlashAttention paper describes an A100-era gap between aggregate on-chip SRAM and HBM capacity and bandwidth.[1]Reference 1FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness.https://arxiv.org/abs/2205.14135 Exact values depend on the GPU and the available per-kernel budget. Treat those paper-era values as an explanation of the design pressure, not as a current hardware specification.

IntermediateShape for one headBaseline lifetimeFlashAttention lifetime
Query, key, valuen×dn \times dn×d eachRead from HBM as neededStreamed into SRAM tiles
Scoresn×nn \times nn×nWritten and reread in HBMOne tile, then discarded
Probabilitiesn×nn \times nn×nOften written and rereadNever materialized globally
Outputn×dn \times dn×dWritten to HBMWritten once after tile loop
Row max and normalizernnn eachOptional saved buffersCompact state, saved for backward

The asymptotic score calculation stays O(n2d)O(n^2d)O(n2d) FLOPs. The memory that must remain live for intermediate scores changes from quadratic to linear in sequence length. That distinction is why "memory efficient" doesn't mean "less attention math."

A size check before blaming weights

Suppose a training batch has 8 sequences, 32 heads, sequence length 8,192, and FP16 scores. One dense score tensor would need:

8×32×81922×2  bytes=34,359,738,368  bytes≈32  GiB.8 \times 32 \times 8192^2 \times 2\;\text{bytes} = 34{,}359{,}738{,}368\;\text{bytes} \approx 32\;\text{GiB}.8×32×81922×2bytes=34,359,738,368bytes≈32GiB.

That is only scores. Probabilities, model weights, activations, gradients, and allocator fragmentation still need space. The number is a sizing exercise, not a benchmark, and it assumes an implementation actually materializes that tensor.

score-matrix-size.py
1batch, heads, sequence, bytes_per_value = 8, 32, 8192, 2 2score_bytes = batch * heads * sequence * sequence * bytes_per_value 3print(f"score values: {batch * heads * sequence * sequence:,}") 4print(f"binary size: {score_bytes / 1024**3:.2f} GiB")

Expected output is score values: 17,179,869,184 and binary size: 32.00 GiB. A fused kernel can avoid this allocation, but the pair count still matters for compute and data movement.

Tiling keeps the result exact

FlashAttention chooses a query tile QiQ_iQi​ and walks over key/value tiles (Kj,Vj)(K_j, V_j)(Kj​,Vj​). A tile is small enough for on-chip SRAM. The kernel computes Sij=QiKjTS_{ij}=Q_iK_j^TSij​=Qi​KjT​ there, applies mask and scale, updates a row-wise softmax state, and discards SijS_{ij}Sij​ before loading the next tile.

The control flow is easier to see than the CUDA code. Each row of QiQ_iQi​ carries three pieces of state:

  • mim_imi​: largest score seen so far, used for numerical stability.
  • ℓi\ell_iℓi​: sum of exponentials after shifting by that largest score.
  • OiO_iOi​: normalized output accumulated from the tiles seen so far.

m_i and \ell_i are running softmax statistics from which LSE⁡i=mi+log⁡ℓi\operatorname{LSE}_i=m_i+\log \ell_iLSEi​=mi​+logℓi​ is formed. They are small vectors, one entry per query row, not n×nn \times nn×n matrices.

Diagram showing Q tile Q_i rows × d, score tile Q_i K_jᵀ / √d, K tile K_j cols × d, and mask + row max m_new. Diagram showing Q tile Q_i rows × d, score tile Q_i K_jᵀ / √d, K tile K_j cols × d, and mask + row max m_new.
Q tile Q_i rows × d, score tile Q_i K_jᵀ / √d, K tile K_j cols × d, and mask + row max m_new.

The diagram's last edge is a loop in the kernel: the next tile reuses the same query tile and softmax state. Only after the final key tile does the kernel write the output row to HBM.

Online softmax recurrence

Normal softmax appears to need every score before it can compute a denominator. The online algorithm instead merges two partial summaries. Let a previous tile have state (mold,ℓold,Oold)(m_{old}, \ell_{old}, O_{old})(mold​,ℓold​,Oold​) and the new score tile have row scores sss. Compute:

mnew=max⁡(mold,max⁡(s)).m_{new}=\max(m_{old},\max(s)).mnew​=max(mold​,max(s)).

Then shift both old and new contributions to the same maximum:

ℓnew=emold−mnewℓold+∑kesk−mnew.\ell_{new}=e^{m_{old}-m_{new}}\ell_{old}+\sum_k e^{s_k-m_{new}}.ℓnew​=emold​−mnew​ℓold​+∑k​esk​−mnew​.

For values VjV_jVj​, update the numerator and normalize at the end:

Onew=emold−mnewℓoldOold+∑kesk−mnewVj,kℓnew.O_{new}=\frac{e^{m_{old}-m_{new}}\ell_{old}O_{old}+\sum_k e^{s_k-m_{new}}V_{j,k}}{\ell_{new}}.Onew​=ℓnew​emold​−mnew​ℓold​Oold​+∑k​esk​−mnew​Vj,k​​.

The exponential shift keeps exponents at or below one. When a later tile contains a larger score, the old accumulator is rescaled exactly instead of being thrown away. Milakov and Gimelshein describe this streaming normalizer, which FlashAttention uses as part of its tiled exact computation.[2]Reference 2Online normalizer calculation for softmax.https://arxiv.org/abs/1805.02867

Worked numbers across two tiles

Use one query row and four keys split into two tiles. The first tile has scores [1,2][1,2][1,2] and values [[10,0],[0,10]][[10,0],[0,10]][[10,0],[0,10]]. The second has scores [3,0][3,0][3,0] and values [[5,5],[9,1]][[5,5],[9,1]][[5,5],[9,1]]. We omit the common scale in this arithmetic so the state update stays readable.

For tile one, m1=2m_1=2m1​=2 and ℓ1=e−1+1=1.3679\ell_1=e^{-1}+1=1.3679ℓ1​=e−1+1=1.3679. Its numerator is:

e−1[10,0]+[0,10]=[3.6788,10].e^{-1}[10,0]+[0,10]=[3.6788,10].e−1[10,0]+[0,10]=[3.6788,10].

So O1=[2.689,7.311]O_1=[2.689,7.311]O1​=[2.689,7.311]. That output is provisional because key tile two hasn't been seen.

Tile two contains a larger score, so m2=3m_2=3m2​=3. The old state must be rescaled by e2−3=0.3679e^{2-3}=0.3679e2−3=0.3679:

ℓ2=0.3679×1.3679+(1+e−3)=1.5530.\ell_2=0.3679\times1.3679 + (1+e^{-3}) = 1.5530.ℓ2​=0.3679×1.3679+(1+e−3)=1.5530.

The new numerator is:

0.3679[3.6788,10]+[5,5]+e−3[9,1]=[6.8014,8.7286].0.3679[3.6788,10] + [5,5] + e^{-3}[9,1] = [6.8014,8.7286].0.3679[3.6788,10]+[5,5]+e−3[9,1]=[6.8014,8.7286].

The final result is O2=[4.379,5.620]O_2=[4.379,5.620]O2​=[4.379,5.620]. Computing ordinary softmax over all four scores gives the same values up to rounding. No 1×41\times41×4 score row had to survive between tiles.

Read the implementation boundary

The official repository keeps Python wrappers and GPU kernels in separate layers.[3]Reference 3FlashAttentionhttps://github.com/Dao-AILab/flash-attention The public flash_attn_func interface accepts tensors shaped like (batch, sequence, heads, head_dim), normalizes optional arguments, and calls a compiled forward operator. The wrapper also exposes variable-length and key/value-cache paths.

The CUDA path registers custom PyTorch operators, returning output, row-wise softmax LSE, an optional probability or dropout-mask buffer, and RNG state. The LSE tensor is compact: it has one value per query row and head. It gives backward a stable summary without saving every probability.

The source has a ROCm branch selected by FLASH_ATTENTION_TRITON_AMD_ENABLE. On CUDA, the wrapper imports the compiled flash_attn_2_cuda extension. On ROCm, it can route to an AIter Triton implementation. This dispatch is part of the product: a fast algorithm still needs a kernel matching the device, dtype, head dimension, and layout.

dispatch-shape-check.py
1def choose_path(device: str, head_dim: int, use_rocm_triton: bool) -> str: 2 if device == "rocm" and use_rocm_triton: 3 return "aiter-triton" 4 if device == "cuda" and head_dim <= 256: 5 return "flash-attn-cuda" 6 return "framework-fallback" 7 8print(choose_path("cuda", 128, False)) 9print(choose_path("cuda", 320, False))

The expected output is flash-attn-cuda followed by framework-fallback. The snippet models a guard, not the full runtime selector. Real dispatch also checks GPU capability, dtype, sequence lengths, masks, dropout, and compiled extension availability.

Backward pass: recompute instead of save

Training needs gradients for QQQ, KKK, and VVV. A materializing implementation can save the full probability matrix for backward, but that repeats the quadratic memory problem. FlashAttention saves QQQ, KKK, VVV, output OOO, row-wise LSE, and any required random-number state, then recomputes score and probability tiles during backward.

For each tile, backward reconstructs the same shifted probabilities in SRAM, uses incoming gradient dOdOdO, and accumulates dQdQdQ, dKdKdK, and dVdVdV. Recomputing scores costs additional FLOPs and HBM reads, but it avoids storing and loading a full PPP matrix. This is a classic memory-compute trade-off, not a free speedup.

FlashAttention-2 adds work partitioning changes so more thread blocks can process long sequences and less serial work sits in each block.[4]Reference 4FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning.https://arxiv.org/abs/2307.08691 The repository exposes a deterministic option for backward. Deterministic backward uses more memory and can be slower, while forward remains deterministic according to the project interface.[3]Reference 3FlashAttentionhttps://github.com/Dao-AILab/flash-attention

A compact two-tile online softmax trace. Tile one contains scores 1 and 2 and produces m₁=2, ℓ₁=1.3679, and O₁=[2.689, 7.311]. The retained state is rescaled by α=e^(2−3)=0.3679 when tile two contains scores 3 and 0. The merged result is m₂=3, ℓ₂=1.5530, and O₂=[4.379, 5.620]. A compact two-tile online softmax trace. Tile one contains scores 1 and 2 and produces m₁=2, ℓ₁=1.3679, and O₁=[2.689, 7.311]. The retained state is rescaled by α=e^(2−3)=0.3679 when tile two contains scores 3 and 0. The merged result is m₂=3, ℓ₂=1.5530, and O₂=[4.379, 5.620].
The second score tile raises the row maximum from 2 to 3, so old state is multiplied by e^(2-3) before new values join. That rescale preserves exact softmax while each tile is discarded.

Masks and structured layouts

FlashAttention isn't limited to unmasked full-sequence attention. The same tile loop can skip or alter score elements before softmax.

Causal attention

Autoregressive decoders can't read future tokens. A causal tile masks positions above the diagonal, treating them as −∞-\infty−∞ before softmax. The wrapper aligns causal masks for unequal query and key lengths, which matters during decode when a short query attends to a long prefix.

Local or sliding-window attention

The window_size=(left,right) argument limits each query to nearby keys. Local attention reduces the number of allowed scores for long contexts, but it isn't automatically faster for every shape. Tile occupancy, mask shape, and GPU generation decide whether the work reduction outweighs branch and scheduling overhead.

Variable length and packed batches

Training batches often contain sequences with different lengths. The varlen interface uses cumulative sequence lengths (cu_seqlens_q and cu_seqlens_k) so padding doesn't force every row to the longest sequence. This changes indexing and launch metadata, not the online-softmax invariant.

Paged key/value cache

Decode systems may store K/V in fixed-size physical pages and map each request through a block table. The implementation accepts a page table for this mode. FlashAttention handles the attention math and page lookup; a serving engine still owns allocation, eviction, and request scheduling. Don't confuse the kernel's paged path with a complete KV-cache manager.

MQA and GQA

Multi-query attention (MQA) shares one K/V head across query heads. Grouped-query attention (GQA) shares K/V heads in groups. Passing fewer K/V heads than Q heads reduces cache traffic, provided the query-head count is divisible by the K/V-head count. This is an architectural choice with quality and bandwidth trade-offs; FlashAttention's interface supports it but doesn't choose the model's head layout.

ModeWhat changesMain production question
CausalMask future keysDoes mask alignment match query and cache lengths?
LocalKeep a bounded windowDoes the window preserve task quality and tile occupancy?
VarlenPack unequal sequencesAre cumulative lengths and max lengths correct?
Paged KVIndirect K/V pagesWho owns page allocation and eviction?
MQA/GQAFewer K/V headsIs cache bandwidth saved without unacceptable quality loss?

FlashAttention 1 through 4

Each release combines an algorithmic idea with a hardware target. Paper benchmark numbers are snapshots from specific GPU, dtype, sequence, and baseline conditions. They shouldn't be copied into a service SLO.

GenerationPrimary sourceHardware or software focusCore change
FA1FlashAttention paper, NeurIPS 2022[1]Reference 1FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness.https://arxiv.org/abs/2205.14135A100-era CUDAIO-aware tiling and exact online softmax avoid materialized intermediates.
FA2FlashAttention-2 paper, ICLR 2024[4]Reference 4FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning.https://arxiv.org/abs/2307.08691A100/Ampere CUDABetter parallelism, work partitioning, and lower non-matmul overhead.
FA3FlashAttention-3 paper, 2024[5]Reference 5FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision.https://arxiv.org/abs/2407.08608Hopper H100/H800Asynchrony, warp specialization, and low-precision paths match Hopper features.
FA4FlashAttention-4 paper, 2026[6]Reference 6FlashAttention-4: Algorithm and Kernel Pipelining Co-Design for Asymmetric Hardware Scalinghttps://arxiv.org/abs/2603.05451Hopper and BlackwellAlgorithm and kernel pipelining co-design for asymmetric hardware scaling.

The repository README describes FA3 as a beta path with H100/H800 and CUDA requirements, while FA4 is exposed through a CuTeDSL package for Hopper and Blackwell.[3]Reference 3FlashAttentionhttps://github.com/Dao-AILab/flash-attention Read those release notes as compatibility guidance. A paper name in a citation doesn't mean every installed wheel has that generation enabled.

Project identity

The team is best understood as an open research-and-engineering project. The Dao-AILab repository carries the implementation, tests, build scripts, and issue history; the papers identify Tri Dao and collaborators as authors. Downstream framework maintainers contribute integrations and backend work. That split explains why paper ideas, compiled kernels, and framework dispatch evolve on different schedules.

FieldCurrent project fact
OriginThe Stanford-centered FlashAttention paper names Tri Dao, Daniel Y. Fu, Stefano Ermon, Atri Rudra, and Christopher Ré.[1]Reference 1FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness.https://arxiv.org/abs/2205.14135
StewardshipDao AI Lab maintains the public repository, and its root author file names Tri Dao.[3]Reference 3FlashAttentionhttps://github.com/Dao-AILab/flash-attention[7]Reference 7FlashAttention Authorshttps://github.com/Dao-AILab/flash-attention/blob/c75d019dea9d910312974417bc28f190dfdda6d9/AUTHORS
Contributor modelThe project uses maintainer-led GitHub issues and pull requests. Framework teams contribute separate dispatch and integration work downstream.[3]Reference 3FlashAttentionhttps://github.com/Dao-AILab/flash-attention
Source licenseBSD-3-Clause for the pinned source snapshot.[8]Reference 8FlashAttention BSD 3-Clause Licensehttps://github.com/Dao-AILab/flash-attention/blob/c75d019dea9d910312974417bc28f190dfdda6d9/LICENSE
Commercial boundaryFlashAttention is a kernel implementation, not a hosted model service. A framework, API, or product that embeds it keeps its own support and licensing terms.
Asset boundaryThe repository doesn't license model weights or datasets, and its CUDA or ROCm dependencies retain their own notices.

Framework dispatch and application surface

PyTorch exposes scaled dot-product attention (SDPA), which can select among flash, memory-efficient, and math implementations based on input and device constraints.[9]Reference 9torch.nn.functional.scaled_dot_product_attentionhttps://docs.pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html A model library should call the framework API when it wants portability and let the dispatcher pick a valid backend. It should call the Dao-AILab package when it needs a feature or kernel version that the framework path doesn't provide.

The repository usage page lists integrations or adoption examples in PyTorch, Transformers, DeepSpeed, Megatron-LM, diffusion systems, and protein-structure models.[3]Reference 3FlashAttentionhttps://github.com/Dao-AILab/flash-attention Those examples cover two broad workloads:

  1. Training: reduce activation memory and improve attention throughput, allowing longer sequences or larger batches under a fixed memory budget.
  2. Inference: accelerate prompt processing and some decode attention, especially when the shape reaches the kernel's efficient regime. KV-cache layout and scheduler behavior still dominate many decode workloads.

Use the paper or a local benchmark for any speed claim. The measured gain depends on sequence length, batch shape, head dimension, dtype, dropout, mask, GPU generation, compiler version, and baseline backend. "Flash" is not a guarantee that a tiny or unusual tensor wins.

Strengths and weaknesses

DimensionStrengthCost or limit
ExactnessSame attention definition, aside from normal floating-point orderingDoesn't reduce quadratic score FLOPs for dense attention
MemoryNo global score/probability allocation; linear-size saved stateTile workspace and output still consume memory
TrainingRecompute can unlock longer context or larger batchBackward does extra work and deterministic mode may cost more
HardwareSpecialized kernels exploit SRAM, tensor cores, and async pipelinesBuild and dispatch are GPU, CUDA/ROCm, dtype, and shape specific
FeaturesCausal, local, varlen, paged, MQA, and GQA paths existEach feature combination has its own support and performance envelope
EcosystemPyTorch and model libraries can dispatch to compatible kernelsA framework may select another backend or fall back to math

The most important weakness is an operational one: a kernel can be correct but still be the wrong choice for a workload. Small batches, unsupported head dimensions, CPU or Apple MPS runs, unusual masks, and missing compiled extensions all need explicit fallback behavior.

A small correctness exercise

The following pure-Python check compares a full stable softmax with a two-tile streaming implementation. It uses one query row and scalar values so every intermediate can be inspected. This is a teaching model, not a GPU benchmark.

two-tile-online-softmax.py
1import math 2 3scores = [1.0, 2.0, 3.0, 0.0] 4values = [10.0, 0.0, 5.0, 9.0] 5 6def full(scores, values): 7 m = max(scores) 8 weights = [math.exp(x - m) for x in scores] 9 total = sum(weights) 10 return sum(w * v for w, v in zip(weights, values)) / total 11 12def tiled(tile_scores, tile_values): 13 m = float("-inf") 14 total = 0.0 15 numerator = 0.0 16 for current_scores, current_values in zip(tile_scores, tile_values): 17 tile_max = max(current_scores) 18 new_m = max(m, tile_max) 19 old_scale = 0.0 if m == float("-inf") else math.exp(m - new_m) 20 tile_weights = [math.exp(x - new_m) for x in current_scores] 21 total = old_scale * total + sum(tile_weights) 22 numerator = old_scale * numerator + sum(w * v for w, v in zip(tile_weights, current_values)) 23 m = new_m 24 return numerator / total 25 26print(f"full: {full(scores, values):.6f}") 27print(f"tiled: {tiled([[1.0, 2.0], [3.0, 0.0]], [[10.0, 0.0], [5.0, 9.0]]):.6f}")
Output
1full: 4.379542 2tiled: 4.379542

Both lines print full: 4.379542 and tiled: 4.379542 to six decimals. Try moving score 3.0 into the first tile. The result should stay the same, which checks that state merging is independent of the tile boundary.

Production checklist

Before enabling a FlashAttention backend, record the exact workload and hardware:

  • Shape: batch, query length, key length, head count, K/V head count, and head dimension.
  • Numerics: FP16 or BF16 input, FP32 accumulation where supported, scale, dropout, and tolerance against a stable reference.
  • Mask: causal alignment, local window, padding, varlen offsets, and page-table indexing.
  • Device: GPU compute capability, CUDA or ROCm version, driver, PyTorch version, and compiled extension.
  • Dispatch: which backend was selected, whether a fallback occurred, and why.
  • Evidence: p50 and tail latency, memory peak, throughput, and correctness error on representative prompts.

PyTorch's SDPA documentation is a good first check for backend eligibility.[9]Reference 9torch.nn.functional.scaled_dot_product_attentionhttps://docs.pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html The repository tests are the next check for a direct package integration. A benchmark should compare the backend that production would otherwise choose, not a deliberately slow baseline.

If a release upgrades CUDA, PyTorch, GPU generation, or FlashAttention, rerun correctness and performance checks. Keep a fallback path in the service. A request should fail over to a framework implementation or a safe math path with an observable metric, rather than silently return wrong output or crash because a niche shape missed a kernel specialization.

⚠️ Common mistake: Treating "no quadratic allocation" as "constant-time attention." FlashAttention still computes dense query-key pairs, and long-context decode can remain dominated by KV-cache reads and scheduler effects.

Key takeaways

  • FlashAttention computes exact scaled dot-product attention while controlling HBM traffic.
  • Tiling keeps active Q, K, V, score, and value work in SRAM; online softmax preserves exact normalization with (m,ℓ,O)(m,\ell,O)(m,ℓ,O) state.
  • Backward recomputes score tiles to trade extra FLOPs for much smaller saved activation memory.
  • Causal, local, variable-length, paged, MQA, and GQA modes widen the application surface, but every mode has shape and dispatch constraints.
  • FA1 through FA4 pair the same core IO idea with different parallelism and hardware pipelines. Paper-era speedups are conditional measurements.
  • Production confidence requires correctness checks, dispatch observability, representative benchmarks, and a tested fallback.
Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.What does FlashAttention avoid materializing globally?
2.Why is the old accumulator multiplied by exp(m_old - m_new)?
3.What does backward recomputation trade for lower activation memory?
4.Which owner is responsible for evicting a paged KV cache?
5.Which result should be labeled paper-era and conditional?
6.What is a safe production response when a shape misses a specialized kernel?

6 questions remaining.

Next Step
Continue to Deep Dive - FlashInfer

FlashAttention teaches exact tiled attention inside one kernel; FlashInfer extends that IO-aware thinking to the broader decode, KV-cache, and serving-kernel surface.

PreviousDeep Dive - SkyRL
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness.

Dao, T., Fu, D. Y., Ermon, S., Rudra, A., & Ré, C. · 2022 · NeurIPS 2022

Online normalizer calculation for softmax.

Milakov, M. & Gimelshein, N. · 2018

FlashAttention

Dao-AILab · 2026

FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning.

Dao, T. · 2023 · ICLR 2024

FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision.

Shah, J., Bikshandi, G., Zhang, Y., Thakkar, V., Ramani, P., & Dao, T. · 2024

FlashAttention-4: Algorithm and Kernel Pipelining Co-Design for Asymmetric Hardware Scaling

Ted Zadouri, Markus Hoehnerbach, Jay Shah, Timmy Liu, Vijay Thakkar, Tri Dao · 2026 · arXiv

FlashAttention Authors

Dao AI Lab · 2026

FlashAttention BSD 3-Clause License

Dao AI Lab · 2026

torch.nn.functional.scaled_dot_product_attention

PyTorch Contributors · 2026

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.