DeepSeek-V4 高效长上下文注意力:FP4 混合精度与稀疏注意力解析

解析 DeepSeek-V4 在百万 token 长上下文下的注意力设计:专家权重 FP4 与其他参数 FP8 的混合精度存储、DeepSeek 稀疏注意力(DSA)降低注意力计算成本,以及 vLLM 保持 KV 缓存紧凑与 GPU 满载的实现手段。

DeepSeek-V4 的模型权重采用 FP4 + FP8 混合精度其占据显存大头的 MoE 专家权重(Expert)采用 FP4 精度存储,而其他参数(Attention / Norm / Router)则采用 FP8 精度存储;但在具体的注意力计算和推理核心路径中(如索引器),则直接应用真 FP4 精度进行运算

DeepSeek V4 注意力机制解析

长上下文推理面临两大主要挑战:

  • KV 缓存内存增长:标准 MHA / MQA 的 KV 随上下文线性增长, 多头潜在注意力(MLA)内存效率更高,但在 GPU 显存有限的情况下,扩展到一百万 token 仍然困难。
  • 注意力计算成本:即使采用 DeepSeek 稀疏注意力(DSA) 等现有技术,在长上下文上计算注意力开销巨大。
    V4 的解法是在 MLA 之上又叠了 4 层结构。
  1. 共享键和值向量(2 倍内存节省)。为保证正确性,对注意力输出应用逆 RoPE 操作。
  2. 跨多个 token 压缩 KV 缓存(4 倍至 128 倍内存节省),有两种实现方式:
  3. DSA 稀疏选择。即使使用 c4a 注意力压缩 KV 缓存后,一百万 token 的序列仍会有 25 万个压缩 token。为了加速注意力计算,使用DSA只关注 top-k 个压缩 token。
  4. 保留局部性:滑动窗口 SWA。使用大小为 128 的滑动窗口来处理局部信息,在未压缩的 token 上操作,使得查询 token 在到达压缩边界之前就能关注到局部信息。

DSACSAHSA 是为了处理超长文本,开发的三种创新的注意力机制(Attention Mechanism)。它们的共同目标是:在不牺牲模型理解能力的前提下,大幅降低计算量(FLOPs)和内存占用(KV Cache),解决传统注意力机制计算复杂度随文本长度呈二次方爆炸的问题。

  1. DSA:侧重于通过筛选(Top-k)来减少计算量,适合在高精度要求的局部上下文和推理任务中保留关键细节。
  2. CSA:属于压缩+筛选。先对数据进行温和的打包压缩,再通过稀疏机制挑选,在局部精度和计算效率上找到了极佳的平衡点。
  3. HCA:属于重度压缩,全量参与。对远处上下文进行极度压缩,不丢弃全局概览信息,主要负责极长序列的记忆并极大节省显存。
    CSA 结构:先压缩再稀疏,先把历史 KV 压缩 *m*  倍 → 用轻量索引器快速找 Top-k 相关压缩块 → 拼接最近原始 KV → 做高效注意力

HCA 结构:更重的压缩, 不做 Top-k 筛选,直接把**全部压缩后的历史 KV** 和**最近原始 KV** 拼在一起做注意力

c4a 注意力机制动画:展示压缩→稀疏选择→局部窗口的完整流程

这种高效的注意力设计带来了显著的 KV 缓存节省。使用 bf16 KV 缓存时,DeepSeek V4 在 1M 上下文下每个序列仅需 9.62 GiB 的 KV 缓存。这比 61 层 DeepSeek V3.2 风格堆栈估计的 83.9 GiB 小了约 88.5%。在实践中,对索引器缓存使用 fp4,对注意力缓存使用 fp8,与 bf16 估计相比,将 KV 缓存大小进一步缩减了约一半!

DeepSeek V3.2 与 DeepSeek V4 的每层 KV 状态对比

vLLM 对 DeepSeek V4 的实现

尽管结构上有节省,但该注意力机制仍然具有内在的复杂性,而在 vLLM 中高效地实现这些节省是一个涉及若干实现挑战的系统问题:

  • 与 DeepSeek V3.2 模型类似,注意力算子在 prefill 阶段使用 bfloat16 KV 缓存,在 decode 阶段部分使用逐 token 的 fp8。
  • 模型混合使用了 c4a 和 c128a 注意力,部分注意力层仅使用滑动窗口处理局部信息而不进行压缩。这些异构的注意力类型使 KV 缓存管理变得更加复杂。
  • 当对多个序列进行批处理时,它们相对于 KV 缓存压缩边界可能处于不同的状态。
  • 模型附带原生 fp4 MoE 权重,这需要 vLLM 进行特殊处理。
    vLLM 的优化分两条线:显存管理内核效率

保持 KV 缓存内存紧凑

vLLM 的 KV 缓存内存分配器必须将多种 KV 状态紧密打包在 GPU 内存中,同时仍要与前缀缓存、prefill/decode 分离、CUDA 图以及 vLLM 服务路径的其余部分协同工作。三项设计选择使这变得可管理。

(1) 统一逻辑块大小为 256 个原生 token

不同层以不同比率压缩(c4a 为 1/4,c128a 为 1/128,SWA 为 1/1)。一个直观的设计是将每层的块大小设置为某个压缩后条目数的整数。但这样每层都会有自己的page layout,allocator 必须分别处理它们。

相反,我们对所有压缩层固定逻辑块为 256 个原生 token 位置。那么 c4a 块物理上存储 256 / 4 = 64 个压缩条目,c128a 块存储 256 / 128 = 2 个。分配一个块总是意味着为请求上下文预留接下来的 256 个原生位置,无论该块属于哪一层。槽位映射、调度器统计和前缀命中检测都可以使用相同的单位,而无需根据 compress_ratio 分支。

(2) 把压缩器残差状态当成 SWA

每个压缩器层每个请求维护一个滚动残差:c4a 是 8 个 token(带 overlap)的部分状态,c128a 是 128 个 token。直觉是放”每请求侧 buffer”里,但这样会让 prefix caching 要在每个可缓存边界做快照、PD 解耦要新增一条残差传输路径——又给系统多堆一层状态

vLLM 的做法是把压缩器状态注册成 sliding-window KV cache,sliding_window = coff × compress_ratio(c4 是 8、c128 是 128)。一来 prefix caching 直接复用块语义;二来 PD 解耦把残差当 SWA 传,省下来的传输大小不变;三来 CUDA graphs / MTP 跟 SWA 走同一条集成路径

(3) Page size 三桶归一

c4 indexer 块、c128a KV 块、c4a 压缩器状态块还是不一样大。如果每种都自己一个 block pool,跨池碎片化又回来了

vLLM 注意到 page size = block_size × compress_ratio × per_entry_size,三个因子都可控。仔细挑参数之后整个五路缓存栈被压成 3 个 page-size 桶,每个桶一个 block pool:

  • 最大桶:c4a 主 KV、SWA KV、c4a 压缩器状态、c128a 压缩器状态;
  • 中桶:c4 indexer KV、c4 indexer 压缩器状态;
  • 最小桶:c128a 主 KV

    保持 GPU 满载

vLLM 集成了 FlashMLA 和 FlashInfer,提供优化的注意力和 MoE 算子。但该模型需要许多小的、主要是内存受限的算子。需要避免额外的启动和 HBM 往返,否则会拖慢整个 decode 路径。

下图是 c4a decode 路径的完整算子图,彩色轮廓标出了三处融合,蓝色带是 default stream,琥珀色带是 indexer stream:

`c4a` decode 路径:算子图与算子融合(彩色轮廓)及多流分区(默认流 = 蓝色带,索引器流 = 琥珀色带)。

三个融合:

  • Compressor + RMSNorm + RoPE + cache 写入:压缩之后 K 立刻走 RMSNorm、RoPE、写入下一层 attention 的 KV cache(主 attention 或者 indexer),全是 elementwise,融成一个 kernel。indexer K cache 和主 attention K cache 仍保留各自的 kernel 以便对每个 head dim 单独调并行策略。1.4-3× 加速
  • Inverse RoPE + fp8 quant:主 attention 输出之后过 inverse RoPE,再进 o_lora 投影的 fp8 batched matmul。两步融了之后省一次 HBM 来回,算术强度抬上去。2-3× 加速
  • Fused Q norm + KV RoPE + K insert:主 attention 之前的 query 和未压缩 SWA key 那段 elementwise 工作,做 horizontal fusion,按 warpID 静态分派到 Q head 或 K head,不用跨 warp 通信。10-20× 加速

多流并发:

主 attention 之前可拆成三件事——indexer 计算、主 attention KV 压缩、SWA token 插入。投影之后这三条几乎独立,所以走多 CUDA stream 并发

  • c128a 层没有 indexer,主 KV 压缩跟 SWA token 插入并发;
  • c4a 层完整 indexer 流水线在自己的 stream 上跟主 KV 压缩、SWA 插入并发(后两者之间还是串行)
    实测低 batch 下端到端延迟降低 5-6%。叠加 CUDA Graph 把 launch 开销也压下去

参考资料

  1. https://vllm.ai/blog/2026-04-24-deepseek-v4
  2. https://github.com/ForceInjection/AI-fundamentals/blob/main/09_inference_system/vllm/module_analysis/vllm_deepseek_v4.md
  3. https://zhuanlan.zhihu.com/p/2031756562075739135
本文结束 感谢您的阅读