跳转到主要内容

DeepSeek MLA:低秩 KV Cache 与推理效率

· 约 9 分钟阅读

DeepSeek 的 MLA(Multi-head Latent Attention)不是把 full attention 改成 linear attention,也不是简单把 KV head 数量降下来。它保留 softmax attention 对完整历史 token 的访问语义,但把每个 token 需要常驻 KV cache 的内容从「完整 K/V 向量」换成「低维 latent KV + 少量 RoPE 位置向量」。

核心结论:

  • MLA 主要解决 decode 的 KV cache 常驻显存和读取带宽问题,不是取消 attention 的历史依赖。
  • GQA/MQA 减少 KV head 数量,MLA 压缩 KV 表示本身。两者作用点不同。
  • DeepSeek-V2 参数下,每 token 每层 cache 从 MHA 的 2 x 128 x 128 = 32768 个元素降到 512 + 64 = 576 个元素,约为同等 head 配置 MHA 的 1/57
  • RoPE 必须解耦。如果直接对从 latent 解压出来的 K 加 RoPE,矩阵吸收会失效,decode 会重新变慢。
  • Prefix cache / paged KV 的匹配语义通常不变:仍按 token、model、position 等前缀条件判断是否可复用;变的是 page payload layout、bytes/token、attention kernel。

1. MLA 要解决什么

标准 decoder-only Transformer 在 decode 阶段每生成一个 token,都要让当前 query 访问历史所有 token 的 key/value:

step t:
  q_t 与 K_1...K_t 做 attention score
  score 再加权 V_1...V_t

为了避免每一步重算历史 token 的 K/V,serving 系统会把它们缓存下来,这就是 KV Cache。问题是 cache 体积随 layers x seq_len x batch 线性增长。长上下文和高并发下,KV cache 很快成为显存和 HBM 带宽瓶颈。

MHA 的每 token 每层 cache 元素数是:

MHA KV elements = 2 x n_heads x head_dim

GQA/MQA 的思路是减少独立 KV head 数:

GQA KV elements = 2 x n_kv_heads x head_dim

DeepSeek-V2 论文认为,GQA/MQA 虽然减少 KV cache,但会损伤模型能力。MLA 的目标是同时保住多 head 表达能力和低 KV cache。

2. MLA 的核心:低秩 KV 联合压缩

MLA 先把 attention 输入 hidden state h_t 投影到一个低维 latent:

c_t^KV = W_DKV h_t

然后从这个 latent 恢复 no-RoPE 部分的 K 和 V:

k_t^C = W_UK c_t^KV
v_t   = W_UV c_t^KV

推理时不缓存完整 k_t^Cv_t,只缓存 c_t^KV。这就是「KV 联合压缩」:K 和 V 共享同一个低维 bottleneck,而不是分别缓存完整向量。

用 DeepSeek-V2 的参数看:

参数数值含义
n_heads128attention heads
head_dim128每个 head 的维度
d_c512KV latent 压缩维度
d_R64解耦 RoPE key 维度

如果按标准 MHA 缓存,每 token 每层要缓存:

2 x 128 x 128 = 32768 elements

MLA 实际缓存:

d_c + d_R = 512 + 64 = 576 elements

所以在这个同等 head 配置口径下:

32768 / 576 = 56.9x

这解释了为什么 MLA 对长上下文服务特别有价值:它不是把 cache 小幅量化,而是直接改 cache schema。

3. 为什么不是 MQA

MQA 只保留一组 K/V 给所有 query heads 共享:

很多 Q heads -> 同一组 K/V

它的 cache 非常小,但多个 head 的注意力表达被迫共享同一份 key/value 表示。GQA 是折中:几个 Q heads 共享一组 K/V。

MLA 的结构更像:

很多 Q heads -> 共享一个 latent KV -> 每个 head 通过上投影得到自己的 K/V 视角

因此 MLA 不是「只有一个 KV head」。它缓存的是一个共享 latent,但模型仍可以通过 W_UK / W_UV 生成多 head 的 K/V 子空间。DeepSeek-V2 的消融表也给出这个方向的证据:在 MoE 模型对比中,MLA 版本比 MHA 版本使用显著更少 KV cache,同时多个 hard benchmark 上表现更好。

这也是 MLA 容易被误读的地方:缓存形态像 MQA 一样小,但表达路径不是 MQA 的简单共享 KV。

4. RoPE 为什么要解耦

RoPE 会把位置信息注入 Q/K。标准 attention 中可以直接对 Q 和 K 加 RoPE,但 MLA 里如果对 W_UK c_t^KV 生成的 K 加 RoPE,会破坏矩阵吸收:

q_t · RoPE(W_UK c_i)^T

这里 RoPE 和 token position 相关,不能简单把 W_UK 合并到 query 投影里。结果是 decode 时可能要为历史 token 重新恢复 K,失去 MLA 节省带宽和计算路径的关键优化。

DeepSeek 的做法是把 K 拆成两部分:

k_t = [k_t^C ; k_t^R]

k_t^C: no-RoPE 内容部分,从 c_t^KV 恢复
k_t^R: 位置部分,单独投影并加 RoPE

因此 cache 里除了 c_t^KV,还要存一个小的 k_t^R。DeepSeek-V2 中 k_t^R 是 64 维,所以实际 cache 是 512 + 64 = 576

直觉上,MLA 把「内容信息」和「位置信息」分开管理:

  • 内容信息压进 latent,供所有 heads 共享和恢复。
  • 位置信息保留一个小 key 分支,保证 RoPE 能继续工作。
  • attention score 同时使用内容项和位置项。

5. 矩阵吸收:decode 为什么不用显式解压全量 K/V

如果每一步 decode 都先从 c_t^KV 解压出完整 K/V,再做 attention,MLA 会把 cache 省下来的成本换成额外计算开销。关键优化是利用矩阵乘法结合律。

对 no-RoPE key 部分:

score = q_t · (W_UK c_i)^T
      = (q_t W_UK) · c_i^T

也就是可以先把 query 变换到 latent key 空间,再直接和 cached latent c_i 做 attention。这样不需要为历史 token 显式恢复 k_i^C

对 value/output 部分也类似:

output = AttnWeights · (W_UV C)
       = (AttnWeights · C) · W_UV

W_UV 可以和 output projection 组合进后续线性层路径。工程上这类「weight absorption」是 MLA decode 高效的关键。

vLLM 的 MLA 文档也把实现路径分成两类:

路径更适合原因
compute-friendlyprefillSq / Skv 较大,计算密度高,按 MHA 风格展开更容易吃满算力
data-movement-friendlydecodeSq / Skv 很小,瓶颈是读历史 cache,直接用 latent cache 更划算

这说明 MLA 不是单一公式能解释完的。prefill 和 decode 的最优 kernel 路径不同,scheduler、cache layout、quantization 都会影响最终收益。

6. KV cache 账怎么记

对 serving / simulator,MLA 最重要的是把 KV bytes/token 的公式换掉。

标准 MHA:

KV_bytes = layers x seq_len x batch x (2 x n_heads x head_dim) x bytes_per_element

GQA:

KV_bytes = layers x seq_len x batch x (2 x n_kv_heads x head_dim) x bytes_per_element

MLA:

KV_bytes = layers x seq_len x batch x (d_c + d_R) x bytes_per_element

以 DeepSeek-V2 的 layers=60, d_c=512, d_R=64 估算,一条 128K 上下文、batch=1、BF16 cache:

60 x 128000 x 576 x 2 bytes = 8.85 GB decimal ~= 8.24 GiB

如果同样 head 配置用 MHA:

60 x 128000 x 32768 x 2 bytes = 503.3 GB decimal ~= 468.8 GiB

这个口径下,MLA 才让 128K 长上下文在常规多卡 serving 中变得现实。DeepSeek-V2 论文摘要报告相对 DeepSeek 67B 的 KV cache 降低 93.3%,附录中大 MoE 消融表也显示 MLA 的 KV cache 约为对应 MHA 的 4%。这些数字的分母不同,但方向一致:MLA 把 cache 从主要容量瓶颈降成仍需管理、但不再按 MHA 爆炸的资源。

7. 对 prefix cache 和 paged KV 的影响

MLA 容易引出一个工程问题:既然 KV cache schema 变了,prefix cache、paged KV、P/D 分离还成立吗?

结论是:复用语义通常不变,存储和 kernel 变。

Prefix cache 判断的是一段 token 前缀在同一模型、同一参数、同一位置编码规则下是否已经计算过。MLA 没有改变这个语义。一个 prefix 命中后,复用的内容从 full K/V pages 变成 latent KV pages:

MHA page payload:
  K[block_tokens, n_heads, head_dim]
  V[block_tokens, n_heads, head_dim]

MLA page payload:
  c_KV[block_tokens, d_c]
  k_R[block_tokens, d_R]

Paged KV 仍然可以按 block 管理逻辑 token 到物理 cache page 的映射,但 page 的 bytes/token、stride、kernel 读取方式都要换。调度层仍关心 page 是否存在、是否可共享、是否可驱逐;attention kernel 则必须知道这是 latent cache。

对 P/D 分离也是类似:prefill 节点传给 decode 节点的不是完整 KV,而是 MLA cache payload。传输字节更少,但接收端的 decode kernel 必须和模型 MLA layout 对齐。

8. MLA 对性能的真实边界

MLA 最直接改善 decode:

  • 同样显存能容纳更长 seq_len 或更大 batch
  • 同样 batch 下,每 step 读 cache 的 HBM 字节更少。
  • P/D 分离、KV transfer、KV offload 的网络/PCIe 压力下降。
  • KV quantization 和 FP8 cache 还能继续叠加。

但它不把 attention 复杂度改成 linear attention:

  • Prefill 仍要处理 prompt 内 token 两两可见的 causal attention 区域。
  • Decode 每个新 token 仍要访问历史 token,只是访问的是压缩 cache。
  • 长上下文下,attention score 的长度维度仍随上下文增长。
  • 模型必须原生训练成 MLA,不能把任意 GQA checkpoint 直接开关切成 MLA。

因此 MLA 的定位应该是「保持 full attention 语义的 KV 表示压缩」,不是「新的线性注意力范式」。

9. 和 DeepSeek-V3 / serving 引擎的关系

DeepSeek-V3 技术报告继续采用 MLA 和 DeepSeekMoE,并明确说这两项架构已经在 DeepSeek-V2 中验证。V3 的重点新增在 auxiliary-loss-free load balancing、MTP、FP8 训练和 P/D 分离部署,但 attention 主线仍继承 MLA。

在 serving 引擎侧,MLA 需要专门优化。SGLang v0.3 的发布说明提到 MLA 相关优化包括 weight absorption、grouped decoding kernels、FP8 batched MatMul 和 FP8 KV cache quantization,报告在 H100 上相对 baseline 有 3x 到 7x 的吞吐提升。vLLM 的 MLA common components 也把 prefill/decode 分成 compute-friendly 和 data-movement-friendly 两条路径。

这说明一个实践结论:选择 DeepSeek 类 MLA 模型时,只看模型参数不够,必须确认引擎是否有 MLA 专用 kernel 和 cache layout 支持。 没有专用路径时,MLA 的理论 cache 优势可能被 naive 解压、低效 layout 或不匹配的 scheduler 吃掉。

10. 建模与排障检查表

做模拟器或线上诊断时,MLA 至少要单独建以下字段:

字段用途
attention_type=mla区分 MHA/GQA/MLA cache 公式
kv_lora_rank / d_clatent KV 维度,DeepSeek-V2/V3 常见为 512
qk_rope_head_dim / d_Rdecoupled RoPE key 维度,DeepSeek-V2 常见为 64
num_layersKV 总量线性乘数
kv_cache_dtypeBF16/FP8/INT8 直接决定 bytes/token
engine_mla_kernel是否走专用 MLA decode/prefill kernel

排障时把证据分成两层:

  • 配置证据:模型 config、runtime env、engine log 是否显示 MLA、FP8 MLA attention、blockwise quant 等路径。
  • 效果证据:KV cache bytes/token、max batch、TPOT、HBM read、decode kernel 时间是否符合 MLA 预期。

不要把 TPOT 变好直接等价为「MLA 已启用」。TPOT 还会受 batch、MoE EP、MTP、quantization、scheduler、网络和业务输出长度影响。

11. 相关页面

12. 参考资料

修改历史2 次提交