MLA 的 KV Cache 到底有多大:先把层数、字节和分片算清楚
同样写着“512 维潜变量加 64 维位置分支”有人算出 6.75 KiB/Token有人算出 67.5 KiB/Token。两者相差十倍通常不是算法突然进步了而是层数漏了一位。容量规划里最危险的错误往往发生在单位和统计范围上。MLA 以低维潜在状态保存注意力所需的信息是 DeepSeek-V2 已提出的设计并非 2026 年 10 月才出现的新概念。DeepSeek-V2 原论文先写公式再填配置以一种简化 MLA 缓存布局为例每层为每个 Token 保存潜变量与独立 RoPE Key 分支。若层数为 L两个维度分别为 dc、dr每元素占 b 字节未分片的缓存为KV_bytes L × (dc dr) × b × sequence_length × concurrent_sequences这是教学模型的存储公式。它没有包括页表、对齐、量化缩放因子、额外状态或共享层。真实引擎可能使用不同布局模型配置也不保证所有层完全相同。取 L60、dc512、dr64、FP16 每元素 2 字节单层单 Token 为 1152 B全层为 69120 B也就是 67.5 KiB128 KiToken 的单序列全层缓存为 8.4375 GiB。这里明确使用 1 Ki1024、1 GiB1024³ B避免把十进制 GB 与二进制 GiB 混在一张表里。把计算器写成可检查的代码下面的维度是人为指定的算术样例不代表某个现役模型的完整配置也不是实测显存。保存后用 Python 3 运行。from fractions import Fraction def mla_bytes(layers, dc, dr, element_bytes, tokens, sequences1): args (layers, dc, element_bytes, tokens, sequences) if any(x 0 for x in args) or dr 0: raise ValueError(invalid dimension) return layers * (dc dr) * element_bytes * tokens * sequences per_token mla_bytes(60, 512, 64, 2, 1) full mla_bytes(60, 512, 64, 2, 128 * 1024) assert per_token 69120 assert Fraction(full, 1024 ** 3) Fraction(135, 16) # 仅比较两个假设向量的元素数不是模型能力对比。 saved 1 - Fraction(576, 8192) print(bytes/token:, per_token) print(GiB/sequence:, float(Fraction(full, 1024 ** 3))) print(element reduction %:, float(saved * 100))最后一行得到约 92.97%不是 85.9%。但“8192 个元素变成 576 个元素”只是一组给定维度的比较不能直接拿来宣称某个模型相对另一个模型省了同样比例更不能据此证明精度无损。比较完整 MHA/GQA 缓存时还要把 Key、Value、KV 头数和 head_dim 一起写出来。TP8 不等于一律除以八一种缓存可能按头分片另一种潜在状态可能被复制。还有流水线按层分配、跨层共享以及不同 Attention 后端的差别。没有读引擎布局与分配日志之前直接把总量除以 TP 数会得到一个看似精确、实际无法使用的单卡容量。应当分别记录逻辑全局字节数、每张卡实际保存的状态、物理块取整后的分配量。权重、激活、CUDA Graph 和通信缓冲区另外列账不能把“KV 放得下”写成“模型可以运行”。10 月 7 日 vLLM 对 DeepSeek-V4.1-Flash 的说明已经涉及压缩状态、窗口状态及跨层共享。它提醒我们旧版 MLA 的简化公式不能自动覆盖新模型的全部缓存。vLLM 官方工程说明这份计算器只验证整数与单位未调用 GPU、未加载模型。落地时应从目标 checkpoint 的配置和实际后端入手再用分配日志核对公式。容量数字可以精确到字节前提是每个因子都有明确含义。