DeepSeek MLA:低秩 KV Cache 与推理效率
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^C 和 v_t,只缓存 c_t^KV。这就是「KV 联合压缩」:K 和 V 共享同一个低维 bottleneck,而不是分别缓存完整向量。
用 DeepSeek-V2 的参数看:
| 参数 | 数值 | 含义 |
|---|---|---|
n_heads | 128 | attention heads |
head_dim | 128 | 每个 head 的维度 |
d_c | 512 | KV latent 压缩维度 |
d_R | 64 | 解耦 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-friendly | prefill | Sq / Skv 较大,计算密度高,按 MHA 风格展开更容易吃满算力 |
| data-movement-friendly | decode | Sq / 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_c | latent KV 维度,DeepSeek-V2/V3 常见为 512 |
qk_rope_head_dim / d_R | decoupled RoPE key 维度,DeepSeek-V2 常见为 64 |
num_layers | KV 总量线性乘数 |
kv_cache_dtype | BF16/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. 相关页面
- KV Cache:推理性能的命根子 — KV cache 公式、GQA/MQA/PagedAttention 基础。
- Token Flow 与 Hidden State — 从 hidden state 理解 Q/K/V、Attention、MoE 和 LM Head。
- 推理框架对比 2026 — MLA 模型在 vLLM/SGLang/TensorRT-LLM 选型中的位置。
- DeepSeek-V3 Technical Report:中英对照解读 — V3 架构、MoE、MTP、FP8 和部署策略。
- CSA/HCA 注意力:DeepSeek-V4 的混合压缩稀疏机制 — MLA 之后面向更长上下文的稀疏/压缩注意力方向。
12. 参考资料
- DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model — MLA 的原始技术报告,包含低秩 KV 联合压缩、RoPE 解耦、KV cache 对比和消融。
- DeepSeek-V3 Technical Report — V3 继续采用 MLA,并给出大规模训练、FP8、P/D 分离部署背景。
- vLLM MLA attention API docs — 实现视角:prefill/decode 两条路径、latent cache 形态和 cache update。
- SGLang v0.3 Release — 引擎侧 MLA 优化,包括 weight absorption、grouped decoding kernels、FP8 KV cache quantization。
← 被以下页面引用(2)
- Prefill Trace:Worker 供给、DSA/MLA 与 Chunked Prefillai-systems · synthesis
- GDN 与 Chunked Prefill:为什么 prepare_chunk_indices 会出现在 trace 里ai-systems · concept
修改历史2 次提交
- feat(wiki): strengthen discovery and content lifecyclexiaocheng··
92f3e8c - docs(wiki): publish July inference researchxiaocheng··
5d6504e