FlashAttention 的“加速玄学”:为什么 A100 能快 2 倍,910 却只能快 1.5 倍?
FlashAttention 的“加速玄学”:为什么 A100 能快 2 倍,910 却只能快 1.5 倍?
之前有个做推理服务的朋友跟我吐槽:他在 A100 上测 FlashAttention,长序列推理快了 2.3 倍,结果把同样的代码搬到昇腾 910 上一跑,加速比竟然只有 1.5 倍不到。
他很困惑:“FlashAttention 不就是把 O(N²) 的显存读写省了吗?这跟硬件有什么关系?难道省下来的显存,在 910 上就不叫显存了?”
这个问题问到了点子上。FlashAttention 的加速比,其实极度依赖硬件的“脾气”。今天我们就用盖房子的逻辑,把这件事掰扯清楚。
1. 核心比喻:盖房子的“搬砖”与“和泥”
为了搞懂这个问题,我们先把硬件看成一个工地,把 Attention 计算看成盖房子。
盖一栋房子(完成一次推理),主要分两步:
- 搬砖(HBM 读写):把砖头(Key、Value 矩阵)从仓库(显存)搬到工地(缓存)。
- 和泥(矩阵计算):把砖头砌成墙(计算 QK^T 和 PV)。
FlashAttention 做了什么?
它发明了一种新工艺,不需要把所有的砖头都搬出来堆在地上,而是边搬边砌。这极大地减少了“搬砖”的次数。
那么问题来了:在什么情况下,这种新工艺最能省时间?
答案是:当“搬砖”特别慢,而“和泥”特别快的时候。
这就引出了两个关键的“工地指标”:
- 搬砖速度(HBM 带宽):每秒能搬多少吨砖。
- 和泥速度(算力 TFLOPS):每秒能砌多少平米墙。
2. 两个“工地”的硬指标对比
我们来看看 A100 和 Ascend 910 这两个“工地”的真实数据:
| 硬件型号 | 搬砖速度 (HBM 带宽) | 和泥速度 (FP16 算力) | 关键比值 (带宽/算力) |
|---|---|---|---|
| NVIDIA A100 | 1935 GB/s (超快) | 312 TFLOPS (快) | 6.2 |
| Ascend 910 | 1200 GB/s (快) | 256 TFLOPS (超快) | 4.7 |
注意看最后一列——带宽与算力的比值。
A100 的比值是 6.2,而 910 的比值是 4.7。这意味着,Ascend 910 的“和泥”能力相对于“搬砖”能力更强。
换句话说,在 910 上,计算(和泥)本来就很快,甚至快到很多时候要停下来等数据(砖头)搬过来。
3. 用数据算一笔账:为什么 910 的加速比更低?
假设我们要盖一栋很大的房子(序列长度 seq_len=4096)。
标准 Attention(老工艺):
- 搬砖量:超大(要先把所有砖头搬出来)。
- 和泥量:正常。
- 总耗时:主要取决于搬砖时间 +和泥时间。
FlashAttention(新工艺):
- 搬砖量:极少(只有原来的 2.5%)。
- 和泥量:不变(甚至因为在线 Softmax 修正,多了 0.5% 的计算)。
- 总耗时:主要取决于和泥时间(因为搬砖已经不花时间了)。
场景推演:
在 A100(搬砖相对慢)上:
- 老工艺:花了很多时间搬砖。
- 新工艺:省下了大量的“搬砖”时间,虽然“和泥”时间没变,但整体时间大幅下降。
- 结果:加速比极高(2.3x)。
在 Ascend 910(和泥相对极快)上:
- 老工艺:因为“和泥”太快,大部分时间其实就在等“搬砖”。
- 新工艺:FlashAttention 确实省下了“搬砖”时间,但因为 910 的“和泥”实在太快了,计算(和泥)瞬间就完成了。
- 瓶颈转移:优化完之后,你会发现瓶颈不再是搬砖,而是计算本身。既然计算量没变,那么加速比就被“计算时间”锁死了。
- 结果:加速比不如 A100 高(1.5x)。
一句话总结:
FlashAttention 是把“搬砖”省下来的。如果你的硬件(如 910)本来就是“大力士(高算力)”,搬砖对你来说本来就不算最累的活,那我帮你省了这点搬砖时间,对你整体进度的提升自然就没那么夸张。
4. 那个“神秘的 1.5 倍”是怎么算出来的?
我们来修正一下之前的计算模型,把“瓶颈锁死”考虑进去。
假设处理 4096 长度的序列:
标准 Attention 在 910 上:
- 计算时间:因为算力强,大概 3.0ms 就算完了。
- 但显存带宽有限,光是读写中间结果(QK矩阵)就要花 2.8ms。
- 总时间:因为要等数据,所以总时间是
max(计算, 搬砖)加上叠加时间,约为5.8ms。
FlashAttention 在 910 上:
- 计算时间:还是 3.0ms(计算量没变)。
- 搬砖时间:几乎为 0(只有微不足道的分块读取)。
- 总时间:现在没有了显存等待,直接就是计算时间3.0ms。
加速比:5.8ms / 3.0ms ≈1.93x。
注:实测的 1.5x 比理论值更低,是因为在短序列或特定 Kernel 调度上,910 的计算核心利用率可能没有完全跑满,或者存在其他的调度延迟,导致实际计算时间略高于理论值,从而拉低了加速比。
5. 昇腾 NPU 上的“破局”之道
既然算力强导致加速比“看起来”低,那是不是意味着在 910 上用 FlashAttention 没意义?大错特错!
虽然加速比数字不如 A100 惊艳,但 FlashAttention 在昇腾上的核心价值在于显存容量。它能把显存占用从 16GB 降到 4GB,这才是业务能跑起来的关键。
而且,想在 910 上把 FlashAttention 的性能压榨到极致,我有三个实战建议:
堆 Batch Size(并发):
- 单个请求(Batch=1)的时候,910 的算力太强,跑不满。
- 当你把 Batch Size 堆到 16 或 32 时,计算量大了,显存瓶颈也出来了。这时候 FlashAttention 的优势会重新显现,加速比能轻松回到 2.0x 以上。
开启 INT8 KV Cache:
- 利用昇腾 NPU 的 INT8 高吞吐特性。FlashAttention 配合 INT8 量化,相当于把“搬砖”的体积再减半,进一步释放带宽压力。
善用 PagedAttention:
- 结合 CANN 的
ops-transformer库,使用 PagedAttention 管理显存。这能让你在 910 上塞进更多的长文本,虽然单次推理加速比是 1.5x,但吞吐量(QPS)能翻倍。
- 结合 CANN 的
6. 总结与选型建议
FlashAttention 的加速比公式是:加速比 = 原始显存耗时 / (计算耗时 + 极少量显存耗时)。
- A100:显存耗时 >> 计算耗时,所以加速比极高(2.3x)。
- Ascend 910:计算耗时 ≈ 显存耗时,优化后主要剩计算耗时,所以加速比被锁死在 1.5x-1.8x。
最终结论:
不要因为 910 上的加速比数字低就放弃它。FlashAttention 在昇腾上的核心使命是**“显存换算力”**。只要你的业务涉及长文本(>2048 tokens),不管加速比是 1.5 倍还是 2 倍,它都是让你的模型从“跑不起来”到“跑得流畅”的唯一解。
相关代码与文档:
[CANN ops-transformer 项目仓库](https://atomgit.com/cann/ops-transformer
