第 5 课:IAW 模型 FA2 vs FA3 实测

理论说 FA-3 快 1.5–2×,实测里它真的总是更快吗?

本课基于一份真实模型的 kernel-trace 级性能分析(飞书文档原文)。它会把第 4 课的"Hopper 异步理论"拉回现实:在非 Hopper 平台上,FA-3 走的是另一条路。

1. 背景:IAW 模型的 attention 在算什么

IAW 是一个多模态模型(vision + LLM)。在 sequence packing 训练场景下,attention 的完整路径是:

输入: (B=1, total_len, H, D) 稠密张量(含 padding 位置)
  │
  ├─ unpad: 去掉 padding token,压成紧凑张量 (total_valid, H, D)
  │         ↑ 按 indices 取行(gather)
  │
  ├─ flash_attn_varlen_func: 在紧凑张量上做 attention(核心 kernel)
  │
  └─ pad: 把紧凑结果散回 (B, total_len, H, D)
          ↑ 按 indices 填回(scatter)

attention 分两块,开销占比悬殊:

关键观察

vit attention 占总 attention 耗时约 83%。LLM 部分总耗时占比很小——这会影响后面"升级 FA-3 收益多大"的判断。

2. FA2 vs FA3:unpad/pad 其实差别不大

一个常见误解:FA2 用 C++ 的 bert_padding 做搬运,FA3 用本地 index_select,所以 FA3 更快。kernel trace 打破了这个说法:

步骤FA2 (bert_padding)FA3 (本地)
unpadat::native::_scatter_gather_elementwise_kernelat::native::indexSelectLargeIndex
padvectorized_elementwise + index_elementwise相同
本质都是 PyTorch native op 的薄封装,差异很小

也就是说,FA2 的 bert_padding 并不是定制 CUDA kernel。性能差异的根源不在搬运,而在核心 flash kernel 的架构。

3. 核心差异:手写 CUDA vs CUTLASS

维度FA2FA3
框架手写 CUDA(flash::flash_fwd_kernelCUTLASS 模板(cutlass::FlashAttnFwdSm80
架构适配通用 kernel按 GPU 架构特化
tiling标准CollectiveMainloop 优化 tiling + pipeline

注意那个名字:FlashAttnFwdSm80。这是 CUTLASS 的 Sm80(Ampere)特化路径不是第 4 课讲的 Hopper (Sm90) 异步路径。

4. 平台对照:PPU810E 与"可移植性边界"

这份实测跑在 阿里自研 PPU810E 上——一个 CUDA 兼容的非 NVIDIA 平台(torch.cuda 可用,kernel 以 cutlass:: / at::native:: 名字出现)。CUTLASS 在它上面选中了 Sm80 路径

理论 vs 实测的裂缝

第 4 课的 WGMMA / TMA / warp-specialization / pingpong 全是 Hopper Sm90 专属,在 PPU810E 上根本没启用。所以这里 FA-3 的加速 完全来自 CUTLASS kernel 质量提升 + varlen/packed 路径优化,与异步重叠无关

这揭示了一条边界:硬件针对性优化不可移植。FA-3 这个"包"在不同硬件上走完全不同的 kernel,性能来源也不同。

5. 实测数据:eager 模式 FA3 确实更快

LLM 变长 attention(packed),eager 模式:

配置FA2 eagerFA3 eagerFA3 加速
32×64(多短序列)0.254 ms0.128 ms1.98×
32×128(中等 packing)0.274 ms0.175 ms1.56×
1×2048(单长序列)0.378 ms0.233 ms1.63×
1×8192(单长序列)2.065 ms1.674 ms1.23×

短序列 packed 场景优势最大,长序列优势收窄。FA3 eager 全面领先,来源是 CUTLASS flash kernel。

6. 反转:compile 之后 FA3 反而变慢

torch.compile 加进来,故事变了:

配置FA2 compile 加速FA3 compile 加速
32×641.49×(变快)0.51×(变慢近一半)
32×1281.36×0.74×(变慢)
1×20481.46×0.86×(变慢)
1×81921.01×1.00×(持平)

定量拆解 FA3 compile 为什么亏(典型短序列):

FA3 eager:   3×native index_select(9μs) + FillFunctor(3μs) + cutlass(100μs) + 2×native pad(6μs) = 118μs
FA3 compile: 2×triton index_select(30μs) + FillFunctor(3μs) + cutlass(100μs) + 2×triton pad(30μs) = 163μs
                                                                                  ↑ 多 45μs

净效果:+30μs。短序列(118μs)时劣化 23%;长序列(1674μs)时仅 2%,可忽略。

7. Vision dense:FA3 反而最慢

vit 走的是 dense(非 packed)attention,而且实际跑的是 SDPA(PyTorch 内置 flash_sdp,不是 flash_attn 包)。三方对比(每层,12 heads MHA,seq=1024):

配置SDPAFA2FA3
B=10.0680.1240.095
B=149(trace 匹配)6.5446.0077.194

12 层总开销(B=149):SDPA 78.5ms / FA2 72.1ms(最快但不可用)/ FA3 86.3ms

反直觉结论

Vision dense 场景 SDPA 比 FA3 还快约 11%。FA-3 的优化点在 varlen/packed,dense 场景反而吃亏。这里的优化方向不是换 attention kernel,而是减少 tile 数 / 缩短 seq_len。

8. 选型建议

场景推荐路径是否 compile原因
LLM attention(packed)FA3 eager整体 compileCUTLASS kernel 最快;MLP(87% 计算量)的 compile 收益覆盖 attention 的劣化
Vision attention(dense)SDPA可选PyTorch 内置、免装包、比 FA3 快
评测 / 推理FA3 eager不 compile无需编译,FA3 eager 已最快

典型 packed 32×256 路径延迟:FA2 eager 0.353 → FA2 comp 0.255 → FA3 eager 0.257 → FA3 comp 0.253(compile 对 FA3 无额外收益)。

9. 一句话总结

FA-3 不是"永远更快"。平台、序列形状、是否 compile、dense 还是 varlen 共同决定胜负。这份实测最值钱的教训是:第 4 课的 Hopper 异步是 不可移植的 Sm90 专属,而真实工程里你常在别的平台上跑——这时 FA-3 的收益来自 CUTLASS kernel 质量,且 torch.compile 可能帮倒忙。

10. 快速测验

1. 这份实测里 FA-3 比 FA-2 快的根源是?
2. FA3 在 torch.compile 后短序列变慢,主要因为什么?
3. Vision dense attention 场景,哪个最快?

11. 延伸阅读

本课的全部数据与 kernel trace 来自 飞书文档:FA2 vs FA3 性能对比分析(IAW 模型 / PPU810E),含完整 benchmark 脚本与 Asight Systems 报告。

对照回看 第 4 课:FA-3 Hopper 异步执行与 FP8,体会"理论上的 Hopper 异步"与"实测中的 CUTLASS 通用路径"的裂缝。下节课预告:FlashAttention-4:Blackwell 重架构与 CuTe-DSL

有疑问?

FillFunctor 为什么在 graph break 之后、pingpong 时间线怎么读、Vision 为什么 dense 反而 SDPA 更快——随时问我。