这道题我会先把两个概念拆开。KV Cache 是自回归解码的通用优化:生成第 t 个 token 时,历史 token 的 Key 和 Value 已经算过,就按层缓存起来,当前步只对新 token 计算 Query、Key 和 Value,把新的 K/V 追加进缓存,再用当前 Query 对历史与当前 K/V 做注意力。这样省掉的是重复投影和历史部分的重复计算,但缓存会随层数、batch 和上下文长度线性增长。
比较缓存量时必须统一口径。假设每个头维度是 d_h,MHA 有 n_h 个 KV 头,那么单层、单 token 的 K 和 V 一共大约是 2 乘 n_h 乘 d_h 个元素;整段长度为 L 才再乘 L。GQA 把 KV 头数降成 n_kv,让多个 Query 头共享一组 KV;MQA 更进一步,只保留一个 KV 头。所以它们节省的是“头数”这一维。不能把表头写成每 token,公式里却又偷偷乘序列长度。
MLA 的思路不同。以 DeepSeek-V2 公开的结构为例,它先把隐藏状态投影成一个较小的联合 KV latent,也就是 c_t^KV,再通过上投影得到内容相关的 Key 和 Value。为了兼容 RoPE,它还保留了解耦的位置 Key 成分。推理时真正要缓存的不是只有一个 latent,而是 c_t^KV 加上解耦的 RoPE key。单 token 缓存维度应写成 d_c 加 d_h^R,最后再乘层数、长度、batch 和数据类型字节数。部分投影还能通过矩阵吸收放到 Query 侧计算,但具体收益取决于实现。
这里有两个容易说错的边界。第一,MLA 是训练时就确定的注意力架构,不是把一个训练好的 MHA 模型在部署时随手做有损压缩;因此也不能没有实验就说它会把关键轮次压模糊。第二,论文里某个配置的压缩比例不是通用的四分之一或八分之一,比例由头数、latent 维度、RoPE 维度和精度共同决定。
如果做工程选型,我会在同模型质量、同上下文、同 batch、同硬件下比较每层每 token 的缓存字节数、最大并发、TTFT、TPOT 和吞吐。GQA、MQA 和 MLA 都能降低 KV 压力,但一个靠共享 KV 头,一个靠联合低秩表示。把公式口径和实测条件讲清楚,比背一个压缩倍数更重要。
再做一层正确性验收:用同一批前缀比较改造前后的 logits、固定种子生成和长上下文任务,确认误差来自数值精度还是架构差异;同时抓取每层缓存张量的真实 shape 和 dtype,与理论字节数逐项对账。若只看到显存下降,却没有质量回归、最大并发和端到端延迟,就还不能证明这个 MLA 实现可上线。
若模型采用张量并行,还要确认 latent 与 RoPE key 的分片轴、all-gather 和通信量;缓存元素少不代表通信自动更少。这些条件必须写进 benchmark 报告。