推理阶段的显存大头往往不在参数,而在 KV 缓存——对话越长、并发越多,这块越撑。多查询注意力(MQA)的思路很直接:让所有查询头共用一套键值,缓存从几十份砍成一份。智谱清言、DeepSeek 等模型的不少版本采用这类结构,本文讲它的省法与取舍。
一套键值全场共用:MQA 的省法
注意力是怎么算 QKV 的那篇讲过,多头并行意味着每组头都背着一份独立的 Key 和 Value。MQA 把这份开销合并:查询头保留多个,各查各的;键值只剩一套,全场共用。缓存体积从「头数乘序列长度乘维度」缩成「一份乘序列长度乘维度」,几十个头就是几十倍的差距。省下的不只是显存,还有解码时每步从显存搬运数据的带宽——那才是逐字生成速度的瓶颈所在。缓存瘦了,同样的显存就能同时接待更多会话。
| 项目 | 共享之后的变化 | 说明 |
|---|---|---|
| KV 缓存体积 | 从几十份缩成一份 | 头数乘长度乘维度缩成一份乘长度乘维度 |
| 解码带宽 | 每步搬运的数据变少 | 逐字生成速度的瓶颈在这里 |
| 注意力打分次数 | 不变 | 打分的平方账原封不动 |
| 回答质量 | 可能略有回退 | 查询头失去独立的键值视角 |
折中方案:GQA 分组共享
全共用有代价:查询头之间失去独立的键值视角,回答质量略有回退。分组查询注意力(GQA)折中——比如三十二个查询头分八组,每组共享一套键值,缓存省四倍、质量损失更小,当前是主流选择。两者怎么选没有定论,以官方技术报告为准。注意它省的是缓存体积,注意力的计算量为什么随长度平方涨那笔打分的平方账原封不动,两回事别混为一谈。
三种头配置对照表
- 标准多头:质量基准,缓存占用也高
- MQA:缓存省到底,质量略降
- GQA:分组折中,当前多数新模型的选择
- 挑模型看显存预算时,先对照这张表再查它的头配置
省下的是什么:一笔显存账
逐字生成时每一步都要把历史键值从显存读一遍,序列越长读得越多。KV 缩到几分之一,同等显存就能服务更多会话,或塞下更长的上下文——这就是为什么注意力掩码是什么、logits 是什么这些讲基础机制的文章,常把 KV 结构当作部署前提来提。EOS 是怎么判定的讲的停止判定与缓存回收也配合工作:会话结束,缓存清空,显存归还给下一个请求。
关于多查询注意力的三个常问问题
- MQA 会让回答变笨吗?:键值共享确实压缩了每个查询头的独立性,但配合训练调优后差距很小;更实际的收益是同等显存下能跑更长上下文或更高并发。
- GQA 和 MQA 是竞争关系吗?:GQA 是 MQA 的温和版,分组共享介于全独立与全共用之间,多数新模型选它做平衡点。
- 为什么训练时感觉不到 KV 缓存的存在?:训练一次性并行算完整段序列,缓存按表分摊;推理是逐字生成,缓存每步都在长大,问题才凸显出来。
归结成一句:MQA 省的是缓存与带宽,不是打分本身,理解这点就不会被宣传词带偏。还要提醒一点:共享键值不是没有代价——所有查询头共用一份键值,意味着这一份表示要同时伺候多个提问角度,表达能力上限被压低,训练不当时容易出现质量回退,这也是早期这类方案在某些任务上掉点的原因。后来的分组方案把查询头分成若干组、组内共享,就是在省钱和保质量之间找平衡点,现在主流开源模型大多采用分组设计。看模型说明时如果看到键值头数字段,指的就是共享的粒度。选型时的判断很简单:显存与带宽紧张、并发量大的服务端场景优先考虑共享方案;单机跑小模型、显存富余时,多头独立的表达力更值得留。


