Sparse · SWA · Sinks
长上下文 · 注意力机制 · 4 篇主线 + 2 篇对照

滑窗省的是计算,sink 稳的是分布,FlashAttention 省的是搬运

Longformer 用局部窗口加少量 global token 把每层注意力从 O(n²) 压到 O(n·w);StreamingLLM 发现窗口丢掉开头几个 token 会让 Llama-2-13B 的 PPL 从 5.40 冲到 5158.07,于是保留 4 个 sink 再滚动窗口;Mistral 7B 则把 W=4096 的 SWA 写进预训练,用 32 层叠出约 131K 的理论跨度。 FlashAttention 不改变注意力模式,只用分块和重算把 GPT-2 medium 的 HBM 读写从 40.3 GB 压到 4.4 GB——四件事分别作用在「算哪些对」「留哪些 KV」「把数据放在哪」三个维度上。

TL;DR · 30 秒抓住核心

长上下文有三个独立的账本:注意力矩阵的计算量、推理时 KV cache 的大小、以及 HBM 与 SRAM 之间的数据搬运。 把三个账本混在一起,就会得出「FlashAttention 是稀疏注意力」或「滑窗等于长上下文」这类错误结论。

Longformer 改的是第一本账:每个 token 只算窗口内的 pair,再加少量 global token;计算 O(n·w),ℓ 层感受野 ℓ×w。 StreamingLLM 改的是第二本账:不训练、不改模型,只保留 4 个初始 token 的 KV 加最近窗口,Llama-2-13B 在 PG19 65K 上的 PPL 从 5158.07 回到 5.40。

Mistral 7B 把 SWA 写进预训练:W=4096、32 层,理论跨度 4096×32≈131K(W 与层数见 Mistral Table 1);rolling buffer 把 32K 序列的 cache 减少 8×。 FlashAttention 谁也不稀疏:它计算完整的 N×N 注意力,只是把中间矩阵留在 SRAM,靠 tiling 和重算减少 HBM 访问。

读这篇要分清「模式稀疏」「cache 策略」「IO 优化」三层;它们可以叠加,但任一层都不能单独解决另外两层的问题。

4096tokens
Mistral 7B 的 SWA 窗口 W(Mistral Table 1);32 层叠出约 131K 的理论跨度(Mistral §2)
4sink tokens
StreamingLLM 的 sink 数;Llama-2-13B 在 PG19 65K 上,0+1024 的 PPL 5158.07 回到 4+1020 的 5.40(StreamingLLM Table 1)
4.4GB
FlashAttention 在 GPT-2 medium 前向+反向的 HBM 读写;标准注意力为 40.3 GB(FlashAttention Figure 2)
01

长上下文的第一道墙不是显存容量,而是 O(n²) 的计算与无界的 KV

读完这节你应该知道:长上下文到底贵在哪三个地方,以及为什么「把窗口改小」只解决其中一部分。

标准自注意力先把 Q 和 K 乘成 N×N 的分数矩阵,再做 softmax、乘 V。Longformer 的 §3 直接指出, 这个操作的时间和显存都是 O(n²):序列翻倍,矩阵面积翻四倍。到了几万 token,矩阵不再是一个可以随手物化的中间量, 而是一堵墙。论文的解法不是把矩阵算得更快,而是只算其中一部分——滑窗、膨胀滑窗、global token。

推理侧是另一本账。StreamingLLM 的 §1 说,解码阶段缓存所有历史 token 的 Key/Value 会带来过高的显存占用和递增的解码延迟; 序列越长,KV cache 线性膨胀。解码又是 memory-bound 的:FlashAttention 的 §2.1 给出 A100 的层级—— HBM 带宽 1.5–2.0 TB/s,每个 SM 只有 192 KB SRAM, 108 个 SM,SRAM 带宽约 19 TB/s。 SRAM 比 HBM 快一个数量级,但小三个数量级;数据放在哪里、搬多少次,直接决定 wall-clock。

NSA 的 §1 给了一个量级:解码 64K 上下文时,softmax 注意力约占总延迟的 70–80%。 这解释了为什么长上下文优化会同时出现三条路线——改计算图、改缓存、改数据搬运。

计算模式

算哪些 query-key 对

全注意力算 N×N;滑窗只算对角线带;global token 额外连一些行和列。改变的是注意力矩阵的非零结构。

缓存策略

推理时留哪些 KV

全量、最近 W 个、或 S 个 sink 加最近 W 个。改变的是decode 时能回看多远,不改变训练时的注意力公式。

IO 调度

数据在哪一级内存算

标准实现把 N×N 的 S、P 写回 HBM;FlashAttention 把它们留在 SRAM,只写 O 和统计量。

关键判断

窗口变小不等于上下文变长;sink 不恢复被丢掉的中间信息;FlashAttention 不减少 FLOPs

三者只能各管一段。把它们当成同一件事,就会在「为什么滑窗模型仍然记不住很远的 token」或「为什么 FlashAttention 没有把长上下文变便宜」上卡住。

02

把注意力变稀疏的路线很多,但窗口一滑就丢掉了开头的锚点

读完这节你应该知道:Longformer 的局部+global 解决了什么,窗口 KV cache 又为什么会在超过 cache 后崩掉。

Longformer 的 §2 把当时的长文档 Transformer 分成两类:从左到右分块处理的 ltr 路线,和定义稀疏注意力模式的路线。 前者不适合需要双向上下文的任务;后者里最接近的是 Sparse Transformer,它用 8×8 块的膨胀滑窗, 但模式固定、且依赖 BlockSparse 的 C++ 实现。Longformer 的改动是:保留滑窗,额外加任务驱动的 global attention, 并用自定义 CUDA kernel 把带状矩阵乘法做快(Longformer §3.2)。

滑窗的算术很干净。给定窗口 w,每个 token 只看左右各 1/2 w 个 token;一层注意力的计算量是 O(n×w), 随序列长度线性增长。多层堆叠会把感受野撑大:ℓ 层的顶层感受野是 ℓ×w;如果加膨胀率 d, 感受野变成 ℓ×d×w(Longformer §3.1)。Longformer 的预训练配置是 w=512、序列长 4,096, 论文说这相当于 RoBERTa 在 512 上的计算量,序列长度是 BERT 的 8 倍(Longformer §5)。

推理侧的窗口缓存是另一种做法:只保留最近 L 个 token 的 KV,cache 满了就丢最旧的。它在 cache 填满后显存恒定、解码速度稳定, 但 StreamingLLM Figure 1(b) 和 Figure 3 显示,一旦序列长度超过 cache、开头的 KV 被挤掉,语言模型会崩。 Llama-2-13B 在 PG19 65K 上的窗口注意力(0+1024)PPL 是 5158.07; 保留 4 个初始 token 后(4+1020)回到 5.40(StreamingLLM Table 1)。

Longformer:改计算图

局部窗口 + 少量 global token

每个 token 只算窗口内的 pair;global token 与所有 token 双向相连。复杂度 O(n·w),global 数量与 n 无关时仍是线性。

卡点:global token 是任务相关的先验;窗口和膨胀率是手工设计的,不是从数据里学出来的(Longformer §3.1)。

Window cache:改缓存

只留最近 L 个 KV

cache 填满后显存恒定,解码速度稳定;实现简单,适合流式生成。

卡点:开头 token 被挤掉后,softmax 的分母少了一大块,注意力分布整体偏移;PPL 从 5.40 量级跳到 5158.07 量级(StreamingLLM Table 1)。

所以「窗口」在训练时和推理时不是同一件事。训练时的滑窗是一个注意力模式,模型仍然看得到整个序列,只是每层只连局部; 推理时的窗口 cache 是一个淘汰策略,被淘汰的 KV 再也回不来。Longformer 解决前者,StreamingLLM 解决后者。

03

三种机制回答三个不同问题:算哪些对、留哪些 KV、把数据放在哪

读完这节你应该知道:Longformer 的窗口+global 怎么定义,StreamingLLM 的 4+sink 怎么滚动,Mistral 的 SWA 怎么叠出 131K,FlashAttention 的在线 softmax 怎么在不物化 N×N 的情况下算精确注意力。

Longformer:窗口内的 pair 加上少量双向 global token

双向注意力下,第 i 个 token 的可见集合是窗口内的邻居加上 global 集合 G:

V(i) = { j : |i − j| ≤ w/2 } ∪ G
cost = O(n · w + n · |G|)
Longformer §3.1:每个 token 看左右各 1/2 w 个位置;global token 对称地看所有 token,所有 token 也看它。|G| 与 n 无关时,总复杂度仍是 O(n)。

global attention 不是简单地把某些位置标成 global 就完事:论文用了两组投影 Qs, Ks, Vs 和 Qg, Kg, Vg,分别算滑窗注意力和 global 注意力,并把 global 投影初始化为滑窗投影的值(Longformer §3.1)。 这样做是为了让两类注意力有不同的表达空间,同时不破坏预训练权重的初始化。global 位置是任务相关的:分类用 [CLS],QA 用所有 question token。

StreamingLLM:4 个 sink 加滚动窗口,位置 ID 在 cache 内重编号

StreamingLLM 不改注意力公式,只改缓存里放什么。设当前解码到第 t 个 token,cache 由两段组成:

Ct = {0, 1, …, S−1} ∪ {t−W+1, …, t}
pos(j) = j 在 Ct 中的序号,0 … |Ct|−1
StreamingLLM §3.2 / Figure 4:前 S 个 token 是 attention sink,后 W 个是最近窗口。位置编码按 cache 内的相对位置重新编号,而不是原始文本位置。

sink 的作用不是「保留开头的语义」,而是「保留 softmax 的一个大分母项」。论文用 Llama-2-7B 的注意力图(StreamingLLM Figure 2)说明:除了最底下 2 层, 模型在几乎所有层和头上都强烈关注初始 token;把前 4 个 token 换成换行符 "\n",模型仍然关注它们, 重新引入后 PPL 也能恢复(StreamingLLM Table 1:4+1020 是 5.40,4"\n"+1020 是 5.60)。 这说明起作用的是绝对起始位置,不是 token 的语义内容。

位置重编号是容易被忽略的一步。论文举了一个例子:当前 cache 是 [0, 1, 2, 3, 6, 7, 8],正在解码第 9 个 token, 位置应赋成 [0, 1, 2, 3, 4, 5, 6, 7],而不是原始文本里的 [0, 1, 2, 3, 6, 7, 8, 9](StreamingLLM §3.2)。 RoPE 要缓存旋转前的 Key,再在每步对 rolling cache 里的 Key 施加位置变换;ALiBi 则用连续的线性偏置,而不是跳跃的偏置。 不做这一步,sink 保住了 KV,位置却对不上,模型仍然会退化。

论文在 400K token 的拼接 PG19 上给了不同模型的 PPL:MPT-7B 从 0+2048 的 460.29 降到 4+2044 的 14.99;Llama-2-7B 从 0+4096 的 3359.95 降到 4+4092 的 9.59(StreamingLLM Table 2)。4 个 sink 通常就够,继续加到 8 个只有边际收益。

Mistral 7B:W=4096 的 SWA 叠 32 层,rolling buffer 按 i mod W 覆盖

Mistral 7B 把滑窗写进了预训练。Mistral 的 Table 1 配置是 n_layers=32、window_size=4096、context_len=8192; 第 k 层的 hi 只看上一层 [i−W, i] 的隐藏状态。递归下去,顶层输入可以回看 W×k 个 token; 在 W=4096、32 层时,论文给出的理论注意力跨度约为 131K(Mistral §2)。

推理时用 rolling buffer:第 i 个位置的 Key/Value 存在 cache 的 i mod W 槽位。位置超过 W 后旧值被覆盖, cache 大小固定为 W。论文报告,在 32K 序列上这把 cache 显存减少 8×,且不影响模型质量; 在 16K 序列、W=4096 下,配合 FlashAttention 和 xFormers 的改动,相对 vanilla attention baseline 有 2× 加速(Mistral §2)。

FlashAttention:不是稀疏,是把 N×N 留在 SRAM

FlashAttention 的摘要和 FlashAttention §3.1 反复强调 exact attention:它算的是完整的 softmax 注意力,不丢任何 pair。 它改的是执行顺序。标准实现把 S = QKT 和 P = softmax(S) 写回 HBM,再读出来乘 V; FlashAttention 把 Q/K/V 切成块,逐块搬进 SRAM,用在线 softmax 累积结果,最后只把 O 和归一化统计量写回。

mnew = max(m, m̃)
ℓnew = em−mnew · ℓ + em̃−mnew · ℓ̃
Onew = diag(ℓnew)−1 · ( diag(ℓ) · em−mnew · O + em̃−mnew · P̃ · V )
FlashAttention Algorithm 1:m 是 running max,ℓ 是 running sum;每读一个 K/V 块就更新一次。反向传播不存 S、P,用 O 和 (m, ℓ) 重算,省掉 O(N²) 的中间显存。

复杂度分析在 FlashAttention §3.2:标准注意力需要 Θ(Nd + N²) 次 HBM 访问,FlashAttention 需要 Θ(N²d²M−1), 其中 M 是 SRAM 大小。FLOPs 仍是 O(N²d),额外显存是 O(N);减少的是 HBM 访问,不是计算量。 论文在 FlashAttention Figure 2 的 GPT-2 medium 上把这一点量化得很直接:FLOPs 从 66.6 升到 75.2 GFLOPs,HBM 读写却从 40.3 GB 降到 4.4 GB,时间从 41.7 ms 降到 7.3 ms。

交互:窗口 + sink 的 KV cache 与覆盖率

下面的计算器把三种参数放在一起:滑窗 W、sink 数 S、序列长度 L、层数 layers。 它算两个量:cache 大小(decode 时实际保留多少 token 的 KV)和有效感受野(顶层理论上能回看到多远)。 公式是页面按 StreamingLLM §3.2 的 cache 结构、Longformer §3.1 / Mistral §2 的层间递推做的组合模型,不声称原文给出「sink + 窗口」的感受野公式。

cache = min(L, W + S)
ERF = min(L, W × layers + S)
cache 是 decode 时保留的 KV 数;ERF 是顶层理论感受野。ERF 是上限,不代表模型真的检索到或利用到窗口外的 token。
512 · 1024 · 2048 · 4096 · 8192 · 16384
0 · 1 · 2 · 4 · 8
2K · 8K · 32K · 128K · 1M
8 · 16 · 32
cache 内 / 覆盖 cache 外 / 未覆盖
当前配置

KV cache 4100 tokens · 占全量 12.5% · 省下 87.5% (默认 W=4096 + S=4,按 cache=min(L,W+S) 的页面公式计算)

每 token 可见 4100 keys · 有效感受野 32768 tokens(覆盖 100.0%) (ERF=min(L,W×layers+S):默认 W=4096、layers=32 时上限为 131076,再与 L 取 min;这是页面按 Longformer §3.1 的 ℓ×w 感受野递推做的组合模型,不是原文读数)

中间 28668 个 token 的 KV 不在 cache 里;每 token 只能看到 sink 与最近窗口。

手算:两组参数的 cache 与感受野 W=4096/S=4/L=1M 与 W=1024/S=0/L=32K

口径:cache = min(L, W+S);cache 占比 = cache / L × 100%;省下 = (L − cache) / L × 100%;每 token 可见 = cache;有效感受野 = min(L, W × layers + S)。这是页面按 StreamingLLM §3.2 的 cache 结构、Longformer §3.1 / Mistral §2 的层间递推做的组合模型,不声称原文给出「sink + 窗口」的感受野公式。

组 1:W=4096,S=4,L=1,048,576,layers=32。cache = min(1048576, 4100) = 4100;占比 4100 / 1048576 = 0.390625% → 0.4%;省下 (1048576 − 4100) / 1048576 = 99.609375% → 99.6%。有效感受野 = min(1048576, 4096×32 + 4) = min(1048576, 131076) = 131076 → 131076 / 1048576 = 12.5004% → 12.5%。JS 在同样参数下输出 4100 / 0.4% / 99.6% / 131076 / 12.5%。

组 2:W=1024,S=0,L=32,768,layers=32。cache = min(32768, 1024) = 1024;占比 1024 / 32768 = 3.125% → 3.1%;省下 (32768 − 1024) / 32768 = 96.875% → 96.9%。有效感受野 = min(32768, 1024×32) = 32768 → 100.0%。JS 输出 1024 / 3.1% / 96.9% / 32768 / 100.0%。

组 1 说明:即使 cache 只占全量的 0.4%,32 层滑窗的理论感受野仍能覆盖 12.5% 的 1M 序列;组 2 说明:在 32K 序列上,W=1024 的 32 层刚好覆盖全序列,但 cache 只有 1024 token。这里的「覆盖」是理论上限,不等于模型真的检索到或利用到那些 token。

交互常量:W=4096、layers=32 取自 Mistral Table 1;S=4 取自 StreamingLLM §3.2;序列长度是页面给的可调参数。 读数随滑块变化,不是论文报告值。

04

滑窗把每层压到 O(n·W),层数把感受野补回来,FlashAttention 把 HBM 访问压低

读完这节你应该知道:四种方案的计算/缓存/IO 复杂度各是什么,以及为什么 Mistral 的 131K 只是理论上限。

表 1:四种注意力方案的复杂度对照(公式来自 Longformer §3.1、StreamingLLM §3.2、Mistral §2、FlashAttention §3.2;页面整理)
方案每个 query 看多少 key计算 / 中间显存KV cache备注
Full attentionNO(N²) 计算;O(N²) 中间矩阵N精确,但长序列不可行
Longformer 滑窗 + globalw + |G|O(N·w + N·|G|)N(训练);推理可另配窗口global 是任务相关先验;ℓ 层感受野 ℓ·w
StreamingLLMS + W(稳态)O(N·(S+W)) = O(N)S + W只保 sink + 最近窗口;中间 KV 丢弃
Mistral SWAWO(N·W)W(rolling)预训练时写入;槽位 i mod W
FlashAttentionN(精确)O(N²·d) FLOPs;O(N) 额外显存NHBM Θ(N²d²/M);不是稀疏

这张表里最容易被误读的是最后一行。FlashAttention 的「每个 query 看多少 key」仍是 N,它没有把矩阵变稀疏; 它把标准实现里 O(N²) 的中间矩阵从 HBM 拿掉,换成 SRAM 里的分块计算。所以它的 FLOPs 甚至可能更多: FlashAttention Figure 2 的 GPT-2 medium 上,FLOPs 从 66.6 升到 75.2 GFLOPs, 绝对多 8.6 GFLOPs,相对多 12.9%(8.6 / 66.6); 但 HBM 从 40.3 GB 降到 4.4 GB, 绝对少 35.9 GB,相对少 89.1%(35.9 / 40.3), 比值 9.2×(40.3 / 4.4;论文摘要写 up to 9×,这里按 FlashAttention Figure 2 的表值算到 9.2×);时间从 41.7 ms 降到 7.3 ms,比值 5.7×(41.7 / 7.3)。

Mistral 的 131K 也要加限定词。论文写的是 theoretical attention span:它假设每层都把信息往前传满 W, 且模型真的学会利用这条链路。它不等于「模型能有效使用 131K 上下文」,也不等于「cache 里存了 131K 个 token」—— rolling buffer 的 cache 始终只有 W=4096。这两件事在页面上经常被混成一句「Mistral 支持 131K」。 推断(由 Mistral §2 的 W×k 递推与 rolling buffer 的 i mod W 覆盖规则对照得出)

反过来,StreamingLLM 的 cache 是 S+W,在稳态下与序列长度无关:4 个 sink 加最近窗口,序列到 4M token 时 cache 仍是常数。 这也是它能把 Llama-2 系列跑到 4M token 的原因(StreamingLLM Abstract / §4.1)。但常数 cache 的代价是中间 KV 全部丢弃, 见第 07 节。

口径

FLOPs、HBM 字节、cache token 数是三个不同的单位

FLOPs 衡量算术量;HBM 字节衡量数据搬运;cache token 数衡量 decode 时保留的历史。一个方案可以「FLOPs 更多、HBM 更少、cache 不变」(FlashAttention),也可以「FLOPs 更少、cache 更小、但中间信息丢失」(窗口 cache)。横比之前先确认单位。

05

模式写进权重,切块交给 kernel,缓存决定推理能回看多远

读完这节你应该知道:训练时的注意力模式、推理时的 cache 策略、kernel 的 IO 调度如何串在一次 decode 里。

三种长上下文注意力机制的对照 上带:Longformer 的局部窗口与 global token;中带:StreamingLLM 的 4 个 sink、被覆盖的中间 KV 与最近窗口;下带:FlashAttention 在 HBM 与 SRAM 之间分块搬运 Q/K/V、写回 O。 ① Longformer:局部窗口 + global token 每个 token 只看 ±w/2;global token 与所有 token 双向相连 G q w = 窗口 O(n·w);ℓ 层感受野 ℓ×w(Longformer §3.1) ② StreamingLLM:4 个 sink + 滚动窗口 sink 永远保留;中间 KV 被覆盖;位置 ID 在 cache 内重编号 q S = 4 evicted W cache = S + W;中间 KV 不参与注意力(StreamingLLM §3.2 / Figure 4) ③ FlashAttention:分块 + 在线 softmax,不物化 N×N Q/K/V 分块从 HBM 搬到 SRAM;O 和 (m, ℓ) 写回;反向重算 HBM Q K V O SRAM S_ij m, ℓ P̃·V 在 SRAM 内累加 load store O FLOPs 75.2 vs 66.6 GFLOPs;HBM 4.4 vs 40.3 GB(FlashAttention Figure 2)
三种机制的作用点不同:Longformer 改的是训练时的注意力模式;StreamingLLM 改的是推理时的 cache 内容;FlashAttention 改的是同一份精确注意力的执行位置。图中 token 数为示意,不代表具体实验配置。
global token 滑窗 / recent sink 被覆盖 / evicted
  1. 选模式。训练/预训练时决定注意力图:Longformer 的窗口+global;Mistral 的 causal SWA;Gemma 2 的 local/global 交替——每两层里一层用 4096 的 local window,另一层用 8192 的 global span(Gemma 2 §2)。模式在训练时写进权重,推理时不能仅靠改配置切换推断(依据:Longformer、Mistral、Gemma 2 的注意力模式都在预训练阶段确定,原文未给出推理时切换机制)。
  2. 切块。前向时按模式生成 mask 或索引。窗口模式只算对角线带;global 行/列单独算;FlashAttention 把任意 mask 切成块,在 SRAM 里做在线 softmax,块大小受 SRAM 容量约束(Algorithm 1 的 Bc、Br)。
  3. 定缓存。推理时决定保留哪些 KV:全量、rolling W、S+W。StreamingLLM 还要在 cache 内重编号位置;Mistral 用 i mod W 覆盖旧槽位(StreamingLLM §3.2 / Mistral §2)。
  4. 算反向。训练时 FlashAttention 不存 S、P,用 O 和 (m, ℓ) 重算;Longformer 的稀疏 kernel 只算非零带;两者的共同点是避免把 N×N 中间量写回 HBM(FlashAttention §3.1 / Longformer §3.2)。
  5. 看度量。比较方案时同时看 wall-clock、HBM 字节、cache token 数。只报 FLOPs 会漏掉 memory-bound 的大头;只报 cache 会漏掉计算模式的影响。
可以叠加,但别混为一谈

三种机制的组合关系

Longformer + FlashAttention:稀疏 mask 可以交给块稀疏 FlashAttention 执行;FlashAttention §3.3 的 block-sparse 版本就是把稀疏模式映射到块上,再按稀疏率减少 IO。

StreamingLLM + Mistral SWA:两者都保留最近窗口,但 Mistral 的 SWA 是训练时的注意力模式,rolling cache 是它在推理端的自然实现;StreamingLLM 是推理时对已训练模型加 sink,不改变模型权重。

FlashAttention + 全量 KV:它不减少 cache,只减少中间矩阵的 HBM 读写;要和窗口/sink 叠加,得另外改 cache 策略。

06

窗口+sink 把 PPL 从 5158.07 拉回 5.40;FlashAttention 用更多 FLOPs 换 9.2× 更少 HBM

读完这节你应该知道:每个机制在原文里的代表数字、测量条件,以及哪些数字不能直接横比。

先给一张总表,所有值都来自原文;不同论文的任务、模型、序列长度不同,只能在同一行内比较,不能跨行横比。

表 2:四篇论文的代表结果(Longformer Table 7;StreamingLLM Table 1 与 Table 2;Mistral §2;FlashAttention Figure 2。只转录与本页论点相关的行,条件见行内,均为原文报告值)
论文 / 模型设置指标结果
Longformer-base vs RoBERTa-baseWikiHop devaccuracy75.0 vs 72.4
Longformer-base vs RoBERTa-baseHyperpartisan devF194.8 vs 87.4
StreamingLLM · Llama-2-13BPG19 首本书 65K;0+1024 → 4+1020PPL5158.07 → 5.40
StreamingLLM · MPT-7B400K 拼接 PG19;0+2048 → 4+2044PPL460.29 → 14.99
Mistral 7B32K 序列;W=4096KV cache8× reduction
FlashAttention · GPT-2 mediumN=1024,d=64,16 heads,batch 64,A100;前向+反向HBM R/W40.3 → 4.4 GB
FlashAttention · GPT-2 medium同上runtime41.7 → 7.3 ms
FlashAttention · GPT-2 medium同上FLOPs66.6 → 75.2 GFLOPs

Longformer 的 Table 7 是同一 backbone 的继续预训练+微调对比,不是和全注意力长上下文模型的横比。WikiHop 上 75.0 vs 72.4, 绝对 +2.6 个百分点,相对 +3.6%(2.6 / 72.4); Hyperpartisan 上 94.8 vs 87.4, 绝对 +7.4 个百分点,相对 +8.5%(7.4 / 87.4)。 指标口径按 Longformer Table 7 的表注:WikiHop 用 accuracy,Hyperpartisan 用 F1。

StreamingLLM 的 Table 1 条件是 Llama-2-13B、PG19 第一本书 65K token;0+1024 表示 0 个 sink 加 1024 个最近 token, 4+1020 表示 4 个 sink 加 1020 个最近 token。PPL 从 5158.07 降到 5.40,相对降幅 99.9% ((5158.07 − 5.40) / 5158.07)。把 4 个原始 token 换成 4 个换行符,PPL 是 5.60, 与原始 token 的 5.40 接近;这说明起作用的是起始位置,不是语义。

Mistral 7B 在 32K 序列上把 cache 减少 8×,论文的措辞是「without impacting the model quality」; 在 16K 序列、W=4096 下,配合 FlashAttention 和 xFormers 的改动,相对 vanilla attention baseline 有 2× 加速。这两个数字都是模型实现层面的报告,不是与全注意力模型的质量对比。

FlashAttention 的 Figure 2 条件最完整:GPT-2 medium、序列长 1024、head dim 64、16 heads、batch 64、A100、前向+反向。 FLOPs 从 66.6 升到 75.2 GFLOPs, 但 HBM 从 40.3 降到 4.4 GB, 时间从 41.7 降到 7.3 ms。 论文把原因归为 HBM 访问减少,而不是 FLOPs 减少。这个例子最能说明「省搬运」和「省计算」不是一回事。

还有两个容易混的加速数字。FlashAttention 的 Figure 1 报告 GPT-2 上注意力计算最高 7.6×; FlashAttention Figure 2 的 GPT-2 medium 前向+反向是 5.7×(41.7 / 7.3)。 前者是注意力 kernel 相对 PyTorch 实现的加速,后者是 GPT-2 medium 前向+反向的 attention 时间;引用时必须带测量对象。

StreamingLLM 的 22.2× 是相对 sliding window with re-computation 的每 token 解码加速 (StreamingLLM Abstract / §4.5),不是相对 full attention 的加速。它的质量基线是「窗口 + 重算」,不是「全量 KV」。

反直觉 1

FlashAttention 的 FLOPs 更多,但更快

75.2 vs 66.6 GFLOPs,时间却是 7.3 vs 41.7 ms。多出来的 FLOPs 来自反向重算;省下来的时间来自少读少写 HBM。在 memory-bound 的 attention 里,FLOPs 不是好指标。

反直觉 2

更大的 cache 不一定更低 PPL

在 400K 拼接 PG19 上,Llama-2-7B 从 4+2044 扩到 4+4092,PPL 从 9.08 升到 9.59(StreamingLLM Table 6)。论文的解释是模型不一定能充分利用更长的上下文;这也是「cache 大小」和「有效上下文」不能划等号的证据。

07

窗口不是记忆,sink 不是检索,FlashAttention 也没让注意力变便宜

读完这节你应该知道:每种方法的失效边界,以及什么时候不该用。

使用判断

什么时候用哪一种

值得用滑窗:长文档分类/QA,局部证据足够;训练预算有限;能接受 global token 的任务先验。

值得用 sink + rolling:流式对话/长生成,只关心最近上下文;显存和延迟敏感;不需要回查中间细节。

值得用 FlashAttention:需要精确全注意力;GPU 上 attention 是 memory-bound;训练和推理都想减少 HBM 流量。

不要期待:用窗口或 sink 做长距离检索;用 FlashAttention 降低渐近复杂度;用 4 个 sink 恢复被丢弃的中间信息。

最后回到三个账本:Longformer 和 Mistral 改的是「算哪些对」,StreamingLLM 改的是「留哪些 KV」,FlashAttention 改的是「把数据放在哪」。 它们可以组合,但每组合一次,都要重新量一次 wall-clock、HBM 字节和有效上下文;只报其中一个数,都会把另外两个账本的代价藏起来。