Attention 复杂度与 FlashAttention#
本页内容2 个部分
1. Self-Attention 的复杂度瓶颈#
对于序列长度 、隐藏维度 :
| 组件 | 计算复杂度 | 瓶颈来源 |
|---|---|---|
| Self-Attention | 的 矩阵乘法 | |
| FFN | 个 token 各做 矩阵乘法 |
1.1 为什么 Attention 是 ?#
假设序列有 4 个 token,, 和 各是一个 的矩阵。 就是让每个 token 的 Q 向量和每个 token 的 K 向量两两做点积:
token1 token2 token3 token4
token1 [ Q1·K1 Q1·K2 Q1·K3 Q1·K4 ]
token2 [ Q2·K1 Q2·K2 Q2·K3 Q2·K4 ]
token3 [ Q3·K1 Q3·K2 Q3·K3 Q3·K4 ]
token4 [ Q4·K1 Q4·K2 Q4·K3 Q4·K4 ]
结果是 个格子,每个格子算一次 维点积( 次乘法)。总运算量 。
token 数翻倍():格子数从 16 变成 64,运算量变 4 倍。这就是平方增长的含义。 时,这张矩阵有 128000 × 128000 ≈ 160 亿个格子。
1.2 为什么 FFN 是 ?#
FFN 对每个 token 独立做两层线性变换(),每个 token 约 次运算, 个 token 串联,总量 。token 数翻倍,运算量只翻倍——线性增长,和 无关的平方项。
谁更大?取决于 和 的关系。
- :FFN 更大()。这是早期 BERT/GPT 的情况。
- :Attention 更大()。这是现在长上下文模型的情况。
所以长序列处理是一个重要研究方向——Attention 的 在长文本上成为严重瓶颈。
2. Flash Attention(2022 → 现在几乎所有训练都在用)#
Flash Attention 不改变注意力的数学结果,只改变计算顺序——它是一个 IO-aware 算法。
核心问题:标准注意力实现需要把完整的 注意力矩阵写入 GPU 的 HBM(高带宽内存),然后读出来做 softmax,再写回去。GPU 的计算速度很快,但内存读写(IO)是瓶颈。
Flash Attention 的做法:把 分块(tiling),每次只处理一小块,在 SRAM(片上缓存,速度是 HBM 的 10-20 倍)中完成注意力计算,避免把完整的 矩阵写入 HBM。
2.1 标准 Attention 的 IO 问题#
标准实现要走三趟 HBM:
第一步:HBM → 读 Q, K → 算 S = QKᵀ → 写 S 回 HBM
第二步:HBM → 读 S → 算 softmax → 写 A 回 HBM
第三步:HBM → 读 A, V → 算 AV → 写结果回 HBM
时 矩阵有 万个元素。来回搬运的时间比计算本身还长。
2.2 关键:online softmax 修正#
分块的难点是 softmax 需要看到全局才能算分母 。Flash Attention 的解法是延迟除法——每块只算分子,记住局部最大值 和局部 exp 之和 ;新块来了之后用修正系数 统一基准,最后一次性除以总 。
以分数 、分两块处理为例:
第一块 [3, 1]
(先不除以 )
SRAM 记住 ,写 回 HBM
第二块 [4, 2],更新基准
修正旧结果:
总 ,最后除以 得正确 softmax
结果和一次性算完整行完全一样——数学等价,不是近似。
**效果:**速度提升 2-4 倍,显存从 降到 (不需要存完整注意力矩阵)。
💡 为什么 Flash Attention 重要?
它让 Transformer 可以处理更长的序列、用更大的 batch size,而不改变模型本身。几乎是"免费的午餐"。现在 PyTorch 2.0+ 内置了 scaled_dot_product_attention,底层就是 Flash Attention。