The State of FP8 KV-Cache and Attention Quantization in vLLM
The State of FP8 KV-Cache and Attention Quantization in vLLM
发表时间: 2026-04 · Blog post by Jonas Kübler* (AWS), Eldar Kurtić* (Red Hat AI), Lucas Wilkinson (Red Hat AI), Matthew Bonanni (Red Hat AI), Michael Goin (Red Hat AI), Alexandre Marques (Red Hat AI), Kailash Budhathoki (AWS) (* Equal Contribution) (blog.vllm.ai)
原文: https://blog.vllm.ai/blog/2026-04-22-fp8-kvcache
作者/机构: Jonas Kübler (AWS), Eldar Kurtić (Red Hat AI), Lucas Wilkinson (Red Hat AI), Matthew Bonanni (Red Hat AI), Michael Goin (Red Hat AI), Alexandre Marques (Red Hat AI), Kailash Budhathoki (AWS) (* 共同一作)
速读
一句话结论 vLLM 团队通过修复底层算子精度丢失问题并引入混合精度层级策略,成功在 Hopper 和 Blackwell 架构上将长上下文大模型的 FP8 KV Cache 部署落地,在保持接近无损精度的同时,将解码阶段的显存占用和单 token 注意力计算延迟减半。
要解决什么问题 长上下文大模型推理在解码阶段严重受限于显存带宽,KV Cache 占据了绝大部分显存。虽然将 KV Cache 压缩为 FP8 格式能理论上显存减半,但在实际压测中遇到了两个致命卡点。第一是长上下文精度崩溃:在 Hopper 架构 GPU 上,当执行注意力得分与 V 矩阵的乘法时,收缩维度对应的是上下文长度。当这个维度达到 100K 以上时,张量核心内部的 FP32 累加器会发生严重的中间精度丢失。这导致 128K 长度的“大海捞针”测试准确率从 BF16 的 91% 暴跌至 13%。第二是局部注意力机制下的性能失效:对于包含滑动窗口注意力层的混合架构模型,由于窗口大小固定(如 128 个 token),KV Cache 的容量是有上限的。在这些层上强制使用 FP8,其带来的显存读取收益根本无法抵消数据格式转换的固定开销。这导致其解码延迟随长度增长的斜率与 BF16 几乎一致,使得 FP8 必须在超过 700K tokens 的极端长度下才能体现出速度优势,完全失去了实用价值。
怎么做的 为了彻底绕开上述硬件与架构卡点,作者在 vLLM 和底层注意力算子 Flash Attention 3 层面引入了多项核心设计。首先,针对长上下文精度丢失问题,引入了双层累加策略。在执行注意力计算时,强制将部分累加的结果写入真正的 FP32 寄存器中,从而避免了硬件默认行为带来的截断误差,成功将长上下文准确率拉回到了 89%。其次,为了解决滑动窗口层的性能倒挂,设计了层级跳过机制。允许模型在全局注意力层使用 FP8 格式,而在滑动窗口层保持 BF16 格式。因为滑动窗口的 KV Cache 占用本身就是恒定的,保持 BF16 既能避免无谓的量化开销,又不会在长上下文中造成显存瓶颈。此外,为了消除量化过程本身的开销,将 Query 的量化操作从注意力后端剥离,重写为简单的 PyTorch 实现,并通过 torch.compile 将其与周围算子融合,消除了每个 token 的固定延迟。同时,系统支持了更细粒度的每头缩放因子,并针对双层累加带来的寄存器溢出问题,重新调优了算子的分块大小。在评估注意力计算成本时,作者使用以下两个公式分别对解码阶段的词间延迟(ITL)和预填充阶段的首字延迟(TTFT)进行建模:
效果如何 实验在单张 H100(搭配 Flash Attention 3)和 B200(搭配 FlashInfer)上进行,对比的基线是未量化的 BF16 KV Cache 标准路线。在性能方面,对于 Llama-3.1-8B,单并发下 FP8 的 ITL 斜率降至 BF16 的 54%,解码速度的盈亏平衡点从 24K 提前到了约 7K tokens;在并发度为 8、输入 20K tokens 的高负载吞吐测试中,输出吞吐量提升了 14.9%。对于包含滑动窗口的 gpt-oss-20b 模型,采用跳过滑动窗口层的 FP8 策略后,ITL 斜率降至基线的 71%,盈亏平衡点降至 7.6K tokens。在精度方面,采用最极端的无校准(缩放因子全为 1.0)FP8 设置,Qwen3-30B 和 Qwen3.5-27B 在 AIME25 等推理任务上最多仅下降 1 到 2 个百分点;在高达 1M 长度的 openai/mrcr 长上下文测试中,Llama-3.3-70B 和 Qwen 系列均能恢复基线 94% 到 98% 的 AUC 分数。该方法也存在明确的代价与局限:由于双层累加增加了寄存器压力,对于注意力头维度较大的模型(如 head_dim = 256 的 gemma-4-E2B),预填充阶段的 TTFT 会变慢约 1.6 倍;此外,在短上下文(小于 7K tokens)场景下,FP8 的固定开销会导致其略慢于 BF16;最后,对于使用非标准注意力后端(如 FlashMLA 的 Kimi-K2.5)的模型,无校准的 FP8 会出现系统性的精度下滑,此时必须引入数据集进行校准。
1. 主要贡献
长上下文大语言模型(LLM)的推理服务正日益受到内存限制:对于标准的全局注意力解码器,当上下文长度达到128k及以上时,KV Cache通常会占据绝大部分的GPU内存,并且每个解码步骤都必须读取该缓存的很大一部分。因此,通过FP8格式将KV Cache的存储空间减半,在精度保持不变的前提下,可以在相同的硬件成本下实现大幅提高的并发量或支持更长的上下文。
vLLM通过--kv-cache-dtype fp8标志实现了KV Cache的量化,并在FP8格式(本文主要指e4m3格式)下运行整个注意力计算(包括QK和ScoreV矩阵乘法)。本文在解码器架构(decoder-only)和混合专家(MoE)模型上,跨Hopper和Blackwell架构进行了全面的压力测试和验证。研究团队发现并修复了Flash Attention 3 (FA3) 后端中关键的精度和性能问题。在验证的路径上,该方案在保留接近基线精度的同时,降低了解码成本和KV Cache内存使用量。在受内存限制的解码场景中,KV Cache的每Token成本在最佳情况下可降至BF16对应成本的54%。
主要注意事项在于:对于具有小滑动窗口层的混合注意力模型,跳过这些层的量化通常效果更好;对于具有大注意力头维度($head\_dim = 256$)的模型,预填充(Prefill)性能可能会退化。然而,对于$head\_dim = 64$和$128$的模型,FP8格式在预填充和解码阶段均提供了加速。
快速启动代码示例:
# 为所有层启用FP8 KV-cache vllm serve meta-llama/Llama-3.1-8B --kv-cache-dtype fp8 # 启用FP8 KV-cache,但跳过滑动窗口层(推荐用于混合注意力模型) vllm serve gpt-oss-20b --kv-cache-dtype fp8 --kv-cache-dtype-skip-layers sliding_window
2. 背景知识与关键发现
精度问题:在Hopper GPU上,FP8 Flash Attention 3内核在长上下文时遭遇了累加精度损失。在128k大海捞针任务中,FP8精度从91%(BF16基线)骤降至仅13%。该退化被追溯到Tensor Core中不精确的FP32累加问题(详见后续的双层累加修复方案)。
性能问题:对于具有滑动窗口注意力层的模型(例如gpt-oss-20b),FP8的Token间延迟(ITL)斜率与BF16几乎相同(达到了BF16斜率的96%)。这意味着用户尽管将内存减半,却几乎没有获得任何解码速度的提升。其性能收支平衡点超过了70万个Token,这远远超出了大多数实际的上下文长度应用场景。
3. 方法细节
双层累加机制(Two-level accumulation):Hopper的FP8 Tensor Core在官方文档中被描述为会累加到FP32寄存器中,但在实际操作中,当收缩维度(contraction dimension)很大时,中间累加会丢失精度。这是一个已知的硬件级别问题,在DeepSeek-V3训练期间也曾遇到过(参见DeepSeek-V3技术报告中的图7(b))。当收缩维度达到10万或更高时,这种不精确的累加会导致剧烈的数值错误。具体而言,在长上下文推理中,在执行$Softmax(AttnScore) * V$矩阵乘法时,收缩维度对应于上下文长度。经验表明,这会导致长上下文大海捞针任务的精度从91%(BF16)下降到13%(FP8)。为了缓解这一问题,作者引入了双层累加策略(参考SageAttention2),将部分累加的结果写入真正的FP32寄存器中(flash-attention#104),从而将FP8精度恢复至89%。然而,从负面影响来看,这种双层累加增加了寄存器压力,并导致了预填充(Prefill)期间的速度减慢。作者通过优化的分块(tiling)配置部分解决了这个问题(flash-attention#125),但是,对于大于128的注意力头维度,预填充性能仍然落后于BF16。
层跳过机制(Skipping of Layers):在早期,vLLM仅允许用户为所有注意力层选择单一的数值格式。作者添加了--kv-cache-dtype-skip-layers标志(vllm#33695)以支持混合设置。像GPT-OSS这样的模型在某些层使用了滑动窗口注意力,其中Token仅关注固定大小的窗口(例如128个Token)。在这种情况下,FP8的开销无法被分摊。因此,将这些层保持在BF16格式实际上比量化它们更快。此外,如果某些特定层对量化特别敏感,该功能也允许跳过对这些层的量化。
逐头缩放因子(Per-Head Scales):Flash Attention 3内核允许为注意力操作的FP8量化指定一个缩放因子数组,其中每个缩放因子对应一个KV头。为了在vLLM中启用此功能,需要泛化对所有组形状(group-shapes)的静态量化支持(vllm#30833),并扩展reshape_and_cache_flash内核的作用域(vllm#30141),以使其能够处理缩放因子数组而不是单一标量。
Query量化融合(Query Quantization Fusion):作者将Query量化操作从注意力后端移出,转而使用一个简单的PyTorch实现,这使得torch.compile能够将其融合到周围的操作中,从而消除了固定的每Token开销(vllm#24914)。
优化的FA3 FP8分块大小(Optimized FA3 FP8 tile sizes):作者调整了$head\_dim = 64$和$head\_dim = 128$的预填充(Prefill)分块配置,以减少由双层累加引入的寄存器溢出(flash-attention#125)。此外,作者还为受内存限制的解码工作负载添加了专门调整的配置,这些配置大幅降低了依赖于上下文的ITL增加量(即ITL斜率)(flash-attention#96, flash-attention#91)。
4. 实验环境
-
数据集与基准测试:
- 长上下文(重Prefill):128k大海捞针任务;
openai/mrcr任务(测试高达1M的序列长度,评估指标为pass@1和AUC)。 - 推理(重Decode):AIME25, GPQA:Diamond, MATH500, LiveCodeBench-v6(评估指标为pass@1,采用模型创建者建议的非贪婪采样参数)。
- 长上下文(重Prefill):128k大海捞针任务;
-
模型架构:Llama-3.1-8B, gpt-oss-20b (混合注意力, 窗口128), gemma-4-E2B ($head\_dim = 256$, 窗口512), Llama-3.3-70B-Instruct, Qwen3-30B-A3B-Instruct-2507 (MoE), Qwen3-30B-A3B-Thinking-2507, Qwen3.5-27B, Kimi-K2.5。
- 硬件配置:单张H100 GPU (Hopper架构);B200 GPU (Blackwell架构)。
- 软件配置:vLLM (版本v0.10.2对比v0.19.1);FlashAttention-3 (FA3,通过vLLM的fork版本提供原生FP8 KV-cache支持);FlashInfer (用于B200);FlashMLA (用于Kimi-K2.5)。所有精度评估均采用每张量未校准的量化缩放因子(scale = 1.0)作为最严格的下界测试。性能测试使用
vllm bench serve。
5. 实验结果
5.1 单请求基准测试 (Single Request Benchmarking)
通过并发度为1的测试分离ITL(Token间延迟,线性模型:$ITL = slope \times input\_len + intercept$)和TTFT(首Token时间,二次模型:$TTFT = a \times input\_len^2 + b \times input\_len + c$)。
-
Llama-3.1-8B (H100):FP8的拟合ITL斜率从$4.37 \times 10^{-5}$降至$2.37 \times 10^{-5}$ ms/token(为BF16的54%),而截距仅从$6.44$变为$6.58$ ms。收支平衡点降至约7k tokens。即使启用了双层累加,在长上下文下FP8的TTFT也有轻微加速。
-
gpt-oss-20b (H100,混合注意力):BF16斜率为$8.94 \times 10^{-6}$ ms/token。全FP8斜率为$7.14 \times 10^{-6}$(BF16的80%)。跳过滑动窗口(skip-SW)的FP8变体表现最佳,斜率降至$6.34 \times 10^{-6}$(BF16的71%),截距保持在$4.03$至$4.07$ ms之间。跳过滑动窗口变体是明显的赢家。
表3:两种模型和KV-cache变体改进前后的总结。
| 模型 | 版本 | FP8 变体 | 收支平衡点 (tokens) | FP8 斜率 (% of BF16) |
|---|---|---|---|---|
| Llama-3.1-8B | 改进前 (v0.10.2) | FP8 | 24,889 | 63% |
| Llama-3.1-8B | 改进后 (v0.19.1) | FP8 | 7,010 | 54% |
| gpt-oss-20b | 改进前 (v0.10.2) | FP8 | 741,565 | 96% |
| gpt-oss-20b | 改进后 (v0.19.1) | FP8 | 22,109 | 80% |
| gpt-oss-20b | 改进后 (v0.19.1) | FP8 skip-SW | 7,659 | 71% |
5.2 负载下的吞吐量 (Throughput under Load)
测试条件:150个请求,并发度8,输入~20k tokens,输出~2k tokens。
- Llama-3.1-8B:FP8实现了14.9%的输出吞吐量提升,总运行时间缩短13.0%,中位数ITL降低14.8%。
- gpt-oss-20b:FP8 skip-SW变体实现了4.8%的输出吞吐量提升,总运行时间缩短4.6%,中位数ITL降低4.8%。收益较小是因为滑动窗口层限制了内存节省。
表4:Llama-3.1-8B在重吞吐量负载下的性能结果。
| 配置 | 中位数 TTFT (ms) | 中位数 ITL (ms) | 总耗时 (s) | 输出 tok/s |
|---|---|---|---|---|
| BF16 | 763.6 | 15.18 | 672.6 | 450.3 |
| FP8 | 742.8 | 12.93 | 585.2 | 517.5 |
表5:gpt-oss-20b在重吞吐量负载下的性能结果。
| 配置 | 中位数 TTFT (ms) | 中位数 ITL (ms) | 总耗时 (s) | 输出 tok/s |
|---|---|---|---|---|
| BF16 | 468.9 | 8.09 | 364.2 | 831.6 |
| FP8 | 451.7 | 7.90 | 355.1 | 853.0 |
| FP8 skip-SW | 456.4 | 7.70 | 347.4 | 871.8 |
5.3 大注意力头维度的限制 (Limitations for Large Head Dimensions)
对于gemma-4-E2B($head\_dim = 256$,滑动窗口大小512)。FP8的ITL斜率降至BF16的68%,解码优势明显。然而,TTFT二次项系数从$6.93 \times 10^{-7}$升至$1.12 \times 10^{-6}$ ms/token²。由于双层累加带来的寄存器压力,长上下文下的预填充(Prefill)显著变慢。
5.4 Blackwell (B200) GPU 上的性能
B200使用FlashInfer后端,不存在累加问题,因此无需双层累加。
-
Llama-3.1-8B:ITL斜率降至BF16的约54%,截距惩罚极小,解码收支平衡点约为4k tokens。
-
gpt-oss-20b:ITL斜率降至$2.06 \times 10^{-6}$ ms/token,收支平衡点约为13k tokens。
5.5 推理评估精度 (Reasoning Evaluations)
测试短Prefill后接长Decode任务。
-
Qwen3-30B-A3B-Thinking-2507:启用FP8 KV-cache和FP8注意力最多引入1-2个百分点的精度下降,最低恢复率在GPQA:Diamond上为97%。
-
Qwen3.5-27B:精度影响可忽略不计(最多0.7个百分点),最低恢复率在AIME25上为99%。
5.6 长上下文评估精度 (Long-Context Evaluations)
测试重Prefill后接短Decode任务(openai/mrcr)。
-
Llama-3.3-70B-Instruct (最高128k):恢复了基线AUC@128k得分的97-98%。
-
Qwen3-30B-A3B-Instruct-2507 (最高256k):整体AUC@256k恢复率在94%(BF16模型设置)到98%(FP8模型设置)之间。
-
Qwen3.5-27B (最高1M):完全恢复了聚合的AUC@1M指标。
5.7 Blackwell (B200) GPU 上的精度
-
Qwen3-30B-A3B-Instruct-2507 (MRCR):AUC恢复率约为93%(BF16模型)至96%(FP8模型)。
-
Qwen3-30B-A3B-Thinking-2507 (推理):在两种模型设置中,平均差异大致在一个百分点或更少。
6. 结论
FP8 KV-Cache量化目前已经完全具备条件成为许多长上下文vLLM部署和硬件环境的默认起点。如果工作负载是重解码(decode-heavy)且受内存限制的,FP8可以在带来微小或可忽略的精度损失的情况下,提供有意义的延迟降低和容量提升。主要的例外情况包括:在$head\_dim = 256$时预填充占主导地位的工作负载;混合注意力模型(应将其较小的滑动窗口层保留为BF16);以及表现出持续未校准精度损失的模型或后端(在这些情况下进行校准仍然很重要)。
此外,为了在特定部署中更好地恢复精度,研究团队还实现了两个额外功能:1)允许使用vllm-project/LLM-Compressor通过用户提供的数据集启用缩放因子校准;2)支持更细粒度的逐注意力头量化缩放因子。
7. 补充细节
未校准FP8缩放因子的局限性:并非所有模型都能在未校准的FP8缩放因子下良好运行。作者在H200 GPU上测试了使用Flash MLA注意力后端(这与上述模型使用的内核路径不同)的Kimi-K2.5模型,并采用了未校准的FP8 KV-cache量化。
需要校准的经验法则:Fig 14显示了在不同序列长度桶中一致的向下偏移。虽然聚合AUC下降幅度不大且标准误差带有所重叠,但这种退化是系统性的而不是随机的。实际的建议是:从简单且通常足够好的未校准FP8开始,但如果在实际工作负载中观察到这种持续的系统性下降(而不是孤立的噪声桶),那么进行校准是值得的。这对于使用非标准注意力后端(例如FlashMLA)的模型尤为重要,因为在这些后端中,FP8内核的行为可能与经过充分验证的FA3和FlashInfer路径不同。
避免使用FP8 KV-Cache的场景:FP8 KV-cache量化并不总是正确的选择。在以下情况中,建议考虑保持使用BF16:
- 上下文较短(< ~7k Tokens):FP8具有较小的固定开销(截距差距),因此在短上下文中,BF16在ITL上可能略快。
- 模型使用$head\_dim = 256$且关注Prefill延迟:双层累加开销在长上下文时使TTFT增加了约1.6倍。禁用双层累加可以恢复速度,但需要进行仔细的精度验证。
- 在目标工作负载上未校准精度降至95%以下:某些模型(例如使用FlashMLA的Kimi-K2.5)在未校准缩放因子下表现出一致的退化,可能会受益于在目标数据集上的校准。
- 模型具有许多小滑动窗口注意力层:FP8的开销在这些层上可能无法很好地分摊;对于混合注意力模型,建议使用
--kv-cache-dtype-skip-layers sliding_window。
💬 评论讨论
欢迎在这里分享您的想法和见解!