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

kernel 2307.08691
attention-kernelparallelismwork-partitioninggpu-optimizationcausal-masking

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

§1 TL;DR #

在 FlashAttention 基础上通过三项优化——减少 non-matmul FLOPs、序列维度并行化、warp 间 split-Q 分工——将 A100 上 attention 前向吞吐从 25–40% 提升至 50–73% of peak,端到端训练达 225 TFLOPs/s(72% MFU)。

§2 痛点 / 方法 / 结果 #

Q1 痛点 #

FlashAttention 虽然将 attention 从 memory-bound 推向 compute-bound,但在 A100 上前向传播仅达理论峰值的 30–50%,反向传播仅 25–35%。而优化后的 GEMM 可达 80–90%。差距来自两个层面:

  1. Non-matmul FLOPs 开销:GPU Tensor Core 使 matmul 吞吐(312 TFLOPs/s FP16)比 non-matmul(19.5 TFLOPs/s FP32)高 16×。FlashAttention 每步对 $\mathbf{O}_i$ 做 $\text{diag}(\ell)^{-1}$ rescaling,产生不必要的 non-matmul 开销。
  2. Work partitioning 低效:FlashAttention 外层循环遍历 K/V block(列方向),并行度仅 batch × heads;对长序列小 batch 场景 GPU 占用率低。Warp 间采用 split-K 方案需要 shared memory 同步。
  3. Q2 方法 #

    改进 1——减少 non-matmul FLOPs(§3.1):

    • Tweak 1(延迟 rescaling):不在每步除以 $\ell^{(j)}$,而是维护"未归一化"的输出 $\tilde{\mathbf{O}}$,仅在循环结束后做一次 $\text{diag}(\ell)^{-1}$ 除法:

    $$\tilde{\mathbf{O}}^{(j)} = \text{diag}(e^{m^{(j-1)} - m^{(j)}}) \tilde{\mathbf{O}}^{(j-1)} + e^{\mathbf{S}^{(j)} - m^{(j)}} \mathbf{V}^{(j)}$$

    $$\mathbf{O} = \text{diag}(\ell^{(T_c)})^{-1} \tilde{\mathbf{O}}^{(T_c)}$$

    每次迭代省去一次 element-wise division。

    • Tweak 2(logsumexp 融合):反向传播只需 $L = m + \log(\ell)$ 一个统计量,不需分别存储 $m$ 和 $\ell$,减少内存和 non-matmul 操作。

    改进 2——序列维度并行化(§3.2):

    • 前向传播:外层循环改为遍历 Q 行 block(而非 K/V 列 block)——不同 Q block 之间无通信,可跨 thread block 并行。总并行度 = batch × heads × $T_r$。
    • 反向传播:外层循环遍历 K/V 列 block(不同 Q block 需累加 $\mathbf{dQ}$),使用 atomic add 通信。

    改进 3——Warp 间 split-Q 分工(§3.3):

    FlashAttention 采用 split-K:4 warps 分别处理 K 的不同切片,计算 $\mathbf{Q}\mathbf{K}^\top$ 后需写入 shared memory 同步再合并。FlashAttention-2 改为 split-Q:4 warps 分别处理 Q 的不同切片,各自独立计算 $\mathbf{Q}_{\text{warp}} \mathbf{K}^\top \to \tilde{\mathbf{P}}_{\text{warp}} \mathbf{V}$,无需 warp 间通信

    Causal masking 优化:(1) 跳过列索引 > 行索引的 block(约一半),获得 1.7–1.8× 加速;(2) 对非边界 block 无需 apply mask。

    核心技术壁垒:将 FlashAttention 的循环方向从外层-K/V 翻转为外层-Q——这一看似简单的改动解锁了序列维度并行化(Q block 间无依赖),同时使 split-Q warp 分工无需同步。循环翻转最早由 Phil Tillet 在 Triton 实现中提出。

    Q3 结果 #

    • Kernel 加速:比 FlashAttention 快 1.7–3.0×,前向达 230 TFLOPs/s(73% peak),反向 63% peak。
    • 端到端训练:GPT3-2.7B 8K context 达 225 TFLOPs/s / A100(72% MFU),比无 FlashAttention 基线快 2.8×,比 FlashAttention 快 1.3×。
    • H100(未优化):直接运行达 335 TFLOPs/s,不利用 TMA / 4th-gen Tensor Core。

    §3 架构 / 方法图 #

    flowchart TB subgraph Forward ["Forward Pass: Outer loop over Q blocks"] direction LR Q1["Q block 1
    Thread Block A"] --> |"inner loop K,V"| Out1["O block 1"] Q2["Q block 2
    Thread Block B"] --> |"inner loop K,V"| Out2["O block 2"] Q3["Q block 3
    Thread Block C"] --> |"inner loop K,V"| Out3["O block 3"] end subgraph Backward ["Backward Pass: Outer loop over K,V blocks"] direction LR KV1["K,V block 1
    Thread Block X"] --> |"inner loop Q,dO"| dKV1["dK,dV block 1"] KV2["K,V block 2
    Thread Block Y"] --> |"inner loop Q,dO"| dKV2["dK,dV block 2"] end subgraph WarpPartition ["Warp Partitioning (Forward)"] direction TB Ksm["K in shared memory
    (all warps read)"] Vsm["V in shared memory
    (all warps read)"] W1["Warp 1: Q slice 1"] --> |"QK^T → P → PV"| O1["O slice 1"] W2["Warp 2: Q slice 2"] --> |"QK^T → P → PV"| O2["O slice 2"] W3["Warp 3: Q slice 3"] --> |"QK^T → P → PV"| O3["O slice 3"] W4["Warp 4: Q slice 4"] --> |"QK^T → P → PV"| O4["O slice 4"] end

    Target operation #

    • 输入:$\mathbf{Q}, \mathbf{K}, \mathbf{V} \in \mathbb{R}^{N \times d}$,head dim $d \in \{64, 128\}$
    • 输出:$\mathbf{O} = \text{softmax}(\mathbf{Q}\mathbf{K}^\top)\mathbf{V}$
    • 精度:FP16/BF16 输入,FP32 accumulator
    • Mask:causal(可选),block-level skip 优化

    Hardware model #

    参数A100 值
    FP16 matmul peak312 TFLOPs/s
    Non-matmul FP32 peak19.5 TFLOPs/s
    Matmul / non-matmul 比16×
    SMs108
    Warps per thread block4 or 8
    Block sizes$\{64, 128\} \times \{64, 128\}$

    FLOPs 计算 #

    $$\text{FLOPs}_{\text{fwd}} = 4 \times N^2 \times d \times h$$

    其中 $h$ = heads。Causal mask 减半。Backward = forward × 2.5(5 matmuls vs 2)。

    §4 作者证明 #

    符号表 #

    符号含义
    $B_r, B_c$Q 行 block / K,V 列 block 大小
    $T_r, T_c$Block 数量
    $m^{(j)}, \ell^{(j)}$第 $j$ 步的 running max / running sum
    $\tilde{\mathbf{O}}^{(j)}$未归一化的累积输出
    $L$logsumexp $= m + \log(\ell)$
    $D$$\text{rowsum}(\mathbf{dO} \circ \mathbf{O})$,反向传播辅助量

    方程物理意义 #

    延迟 rescaling:原 FlashAttention 每步计算 $\mathbf{O}^{(j)} = \text{diag}(\ell^{(j)})^{-1}(\ldots)$,即每步除以当前归一化因子。FA2 改为维护 $\tilde{\mathbf{O}}^{(j)}$(不除),最后一步才除。数学等价但省去 $T_c - 1$ 次 element-wise division。

    logsumexp 融合:$L = m + \log(\ell)$ 将两个标量压缩为一个。反向传播用 $\mathbf{P} = \exp(\mathbf{S} - L)$ 直接恢复 attention weight(vs. FA1 分别用 $m$ 和 $\ell$),减少内存和计算。

    无独立性能模型:论文不含 throughput/latency 解析模型,所有效率论证基于 hardware specs(matmul vs non-matmul throughput 16× 差距)和实测 benchmark。

    6 项检查 #

    1. 正确性:Algorithm 1 输出 $\mathbf{O} = \text{softmax}(\mathbf{Q}\mathbf{K}^\top)\mathbf{V}$,证明与 FA1 相同(仅 rescaling 时机不同)。✔
    2. Non-matmul FLOP 减少:延迟 rescaling 省去每步 $\text{diag}(\ell^{(j)})^{-1}$;logsumexp 省去 $(m, \ell)$ 分存。✔
    3. 序列并行正确性:前向 Q block 间无依赖(embarrassingly parallel);反向 dQ 通过 atomic add 累加。✔
    4. Split-Q 无通信:每 warp 独立计算 $\mathbf{Q}_{\text{warp}} \mathbf{K}^\top \to \tilde{\mathbf{P}} \mathbf{V}$,无 shared memory 写回。✔
    5. Causal mask 加速:跳过全零 block + 仅边界 block apply mask,理论极限 2×,实测 1.7–1.8×。✔
    6. GQA/MQA 支持:多个 Q head 共享一个 K/V head 通过隐式索引实现,反向传播对 dK/dV 跨 head 求和。✔
    7. Design space #

      优化轴选择拒绝的替代方案约束
      循环方向外层 Q / 内层 K,V外层 K,V(FA1)Q block 间无依赖是并行化前提
      Warp 分工split-Qsplit-K(FA1)split-K 需 shared memory 同步
      Rescaling 时机延迟至循环结束每步 rescale(FA1)延迟增加少量寄存器但省 non-matmul
      Block size{64,128}²更大 block寄存器压力 / SRAM 溢出
      统计量存储logsumexp $L$分存 $m, \ell$(FA1)$L$ 合二为一减少 IO 和内存

      §5 实验与数据 #

      Kernel benchmark(A100-80GB) #

      配置FA2 TFLOPs/sFA1 TFLOPs/s加速
      Fwd, hdim 64, no causal, seq 16K~230~1301.8×
      Fwd, hdim 128, causal, seq 16K~200~1002.0×
      Fwd+Bwd, hdim 128, no causal1.7–3.0×

      前向达 73% peak,反向达 63% peak。对比 GEMM 80–90% peak,仍有差距(归因于 non-matmul 操作和反向传播的 SRAM 压力)。

      端到端训练(8× A100-80GB) #

      Model配置无 FAFA1FA2
      GPT3-1.3B2K ctx142189196 TFLOPs/s
      GPT3-1.3B8K ctx72170220 TFLOPs/s
      GPT3-2.7B2K ctx149189205 TFLOPs/s
      GPT3-2.7B8K ctx80175225 TFLOPs/s

      GPT3-2.7B 8K:FA2 比无 FA 快 2.8×(80→225),比 FA1 快 1.3×(175→225)。72% MFU。

      H100(未针对优化) #

      直接运行 FA2 在 H100 上达 335 TFLOPs/s,预计利用 TMA + 4th-gen Tensor Core 可再提升 1.5–2×。

      论文承认的弱项 #

      1. 前向 73% vs GEMM 80–90%:非 matmul 操作无法完全消除(softmax 涉及 exp / sum / max / rescaling)。
      2. 反向 63% vs 前向 73%:反向 5 个 matmul + 更多 SRAM 压力,优化空间有限。
      3. Causal mask 实测 1.7–1.8× vs 理论 2×:边界 block 仍需 mask 逻辑。
      4. §6 论证链 #

        步骤论点证据
        1FlashAttention 在 A100 上仅达 30–50% peak,远低于 GEMM 的 80–90%§1 para 3(实测数据,Fig. 5 / Fig. 6)
        2瓶颈是 non-matmul FLOPs 和 work partitioning,不是 IO§3.1(matmul vs non-matmul 16× 差距);§3.2–3.3(low occupancy + shared memory sync)
        3延迟 rescaling + logsumexp 减少 non-matmul 开销§3.1.1 算法对比(FA1 vs FA2 公式)
        4外层-Q 循环解锁序列维度并行§3.2 前向 embarrassingly parallel;Phil Tillet Triton 实现先验
        5Split-Q warp 分工消除 shared memory 同步§3.3 Fig. 3 对比 split-K vs split-Q
        6三项改进叠加达 2× kernel 加速,端到端 72% MFU§4 全部 benchmark 数据

        §7 实现 cross-reference #

        代码仓库flash-attention

        • Kernel:CUDA,手动管理 shared memory 和寄存器分配
        • Block size:{64, 128}² 四种组合,按 head dim 手动选择
        • Causal mask:编译时分支,跳过全零 block
        • GQA/MQA:隐式索引,不复制 K/V

        关键实现细节 #

        1. Split-Q 的寄存器布局:每个 warp 持有 Q slice 的 registers,K/V 在 shared memory 中广播。$\mathbf{Q}_{\text{warp}} \mathbf{K}^\top$ 的结果留在 registers 中直接进入 softmax + $\mathbf{P}\mathbf{V}$ 计算,全程不写 shared memory。
        2. Backward dQ atomic add:不同 thread block 处理不同 K/V block 但累加到同一 dQ,使用 atomicAdd。论文未讨论非确定性 / 精度影响。
        3. 可移植性 #

          • 当前仅支持 A100 / H100(NVIDIA Ampere / Hopper)
          • Triton 有独立实现(FA2 in Triton),性能略低但更易移植
          • 未利用 H100 特有指令(TMA, 4th-gen Tensor Core)——这成为 FA3 的动机

          部署上下文 #

          • Serving stack:可替代 FA1 成为 vLLM / SGLang / HuggingFace 的默认 attention kernel
          • Regime:prefill(大 batch,compute-bound)为主要受益场景;decode(单 token,memory-bound)收益较小
          • Launch shape:grid = batch × heads × $T_r$,block = 4 或 8 warps

          Software → Hardware 启示 #

          • 更高 non-matmul 吞吐:16× 的 matmul/non-matmul 差距是根本限制。若 ISA 提供更快的 exp / sum / max 指令,attention 可进一步接近 GEMM 效率。
          • 自动 block size tuning:当前 4 种手动选择,auto-tuning 可扩展到更多硬件配置。
          • Warp-level 同步原语:split-Q 成功消除同步,但反向传播仍需部分同步——更灵活的 warp-level 通信原语可进一步优化。