想象一家叫“聚智咨询”的公司:8 位资深分析师(Q 头)每天要处理堆积如山的客户来信,每位分析师配一位专属助理(K/V 头)。助理的工作是把过往资料的关键索引和内容记在便签本上——这本便签本在 AI 里叫 KV 缓存。8 位助理各记各的,报告质量很高,但便签本把档案室塞得满满当当,空间开销是单人的 8 倍。老板想省钱:只留 1 位全能助理,全体分析师共用一本便签——空间省到 1/8,可助理分身乏术,每位分析师拿到的资料几乎一样,报告开始“注水”(质量下降)。最后老板想出了折中方案:把分析师分成 2~4 组,每组配 1 位助理,组内共享便签、组间各记各的——空间省一半,报告质量几乎不减。这篇文章讲的就是这场“便签本保卫战”:MQA 的极致压缩、GQA 的性能折中,以及主流大模型如何选型。
理解 MQA/GQA 是掌握大模型推理优化(KV 缓存压缩)的入门钥匙。对模型部署、推理加速、大模型应用研发的从业者,这是面试和工程实践中的高频考点。
目录
可视化演示
动态演示MQA与GQA的核心机制,通过采集/分析/决策/反馈四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
MQA与GQA:MHA标 MHA标准注意力与KV缓存瓶颈 MQA单K/V头极端压缩机制 核心机制可视化 MQA与GQA整体架构与关键组件
注意力基础:Q 问、K 索引、V 内容
咨询公司里处理一封客户来信的流程是这样的:分析师手里拿着客户的问题(Q),走到档案室翻目录(K),找到写着相关关键词的索引卡,再顺着索引取出真正的内容档案(V),最后把几份档案揉成一份答复。Transformer 的注意力机制干的就是这件事:Q(Query)是当前词的查询向量,K(Key)是序列里每个位置的索引向量,V(Value)是每个位置携带的语义内容。三者一做加权组合,模型就知道“该重点参考哪些词”。
为了让模型同时关注“语法”和“语义”等多个侧面,人们发明了多头注意力(MHA):用多组 Q/K/V 并行地重复查资料,每组关注一个角度。可这样一来,每生成一个新词,模型都要重新参考前面所有词——聪明的工程师会把算过的 K/V 缓存下来避免重复计算,这就是 KV 缓存。它有多大?以 8 个头、32 层的模型为例,一句话 4096 个 token 就能吃掉数百 MB 显存,堪称档案室里最占地方的便签本。
1. 相似度打分:用查询 Q 与所有键 K 做点积,得到每个键与当前查询的相关分数。$QK^{\top}$ 的每一行对应一个查询与全部键的相似度。
2. 缩放稳定:除以 $\sqrt{d_k}$ 防止点积数值过大导致 softmax 进入饱和区、梯度消失。$d_k$ 是键向量的维度。
3. 归一化成权重:$\text{softmax}(\cdot)$ 把分数压成总和为 1 的注意力权重,越相关的键权重越大。
4. 加权取内容:权重与值 V 加权求和,得到“按相关性混合后的资料摘要”,即最终注意力输出。
既然“助理们的便签本”是撑爆档案室的元凶,省空间的思路自然诞生:少配几位助理、少记几本便签。于是有了 MQA。
MQA 原理:全公司只留一位助理
老板拍板:裁掉 7 位助理,只留 1 位全能助理。8 位分析师的 Q(问题)仍是各自独立的,但大家共用同一套 K/V(索引 + 内容)。这在 2019 年由 Google 提出,取名 Multi-Query Attention(MQA)——直译就是“多查询、单键值”:查询头(Q 头)数量不变,键值头(K/V 头)数量压缩为 1。
极致压缩带来了立竿见影的收益。K/V 投影矩阵从 n_h 份变成 1 份,KV 缓存从“8 本便签”变成“1 本便签”。以 8 个 Q 头的模型为例,单条序列的缓存显存直接降到原来的 1/8;算上 K/V 投影参数本身也缩减了约七分之七的规模,模型体积也跟着瘦身。解码阶段的每一 token 生成都要读取全部缓存,缓存变小,读写时间自然变短。
1. 首项系数 2:每一层都要同时缓存 K 与 V 两份张量,这是记忆两本账。
2. 层数与头数:$n_{layers}$ 是 Transformer 层数,$n_{kv}$ 是每层 KV 头数——MHA 中 $n_{kv} = n_h$,MQA 中 $n_{kv} = 1$。
3. 头维度:$d_{head}$ 是每个注意力头的向量长度,决定单本便签写多细。
4. 序列长度:$L_{seq}$ 是已生成的 token 数,每生成一个词缓存就加长一次,所以长对话特别费显存。
5. 末项字节数:半精度浮点数每元素占 2 字节,最终单位是字节。
MQA 的省钱效果立竿见影,但分析师们很快发现:助理给出的资料几乎一模一样,擅长抠细节的人拿不到专属笔记,报告开始同质化——这正是它的代价。
MQA 局限:一个人的助理忙不过来
单助理的时间就那么多,他只能把资料“泛泛地”记在一本通用便签上。擅长抓特定细节的分析师(比如做代码审查、指代消解这类任务)发现,自己能用的“专属笔记”没有了,报告质量明显下滑。把视角拉回数学:注意力头的表达能力,本质来自 K/V 子空间的可调节维度。MHA 里每个头都有自己的 K/V 投影,自由度高;MQA 所有头共享一份 K/V,自由度被压到最低。
1. 自由度含义:$\text{dof}$ 表示 K/V 子空间里能独立变化的维度数,自由度越大,各头越能“各记各的笔记”。
2. MHA 的自由度:$n_h$ 个头各有独立的 K/V 投影,自由度是 $n_h \times d_{head}$,8 个头就是 8 倍的表达空间。
3. MQA 的自由度:$n_{kv} = 1$,所有头共享同一份 KV 子空间,自由度只剩 $d_{head}$。
4. 收缩比例:自由度缩小 $n_h$ 倍,这正是 MQA 表达受限、质量下降的结构性根源。
GQA 论文(Ainslie et al., 2023)在 T5 系列上的实验显示:MQA 在多数任务上与 MHA 接近,但在部分 SuperGLUE 子任务上仍有可感知的差距;业界在 LLM 实践中还观察到,MQA 偶发“注意力坍塌”——所有头几乎关注同一批位置,幻觉率上升。于是问题变成:能不能只裁掉一半助理,而不是裁到只剩一个?
GQA 设计:组内共享便签本
老板换了思路:把 8 位分析师分成 4 组,每组 2 人共用 1 位助理,全公司配 4 位助理。组内共享一本便签,组间各记各的。这就是 Grouped Query Attention(GQA)——分组查询注意力。Q 头仍然各问各的,但 K/V 头按组共享,每组只有一份。极端的组数选择让 GQA 成为一个“可调节的旋钮”:每组 1 个头就退化成 MHA,全部头一组就退化成 MQA。
1. 分组大小:$G$ 是每组包含的 Q 头数量,等于 Q 头总数 $n_h$ 除以 KV 头数 $n_{kv}$;$G=1$ 时是 MHA,$G=n_h$ 时是 MQA。
2. 头编号:$i$ 是第 $i$ 个 Q 头的编号,从 0 开始计数,共 $n_h$ 个。
3. 向下取整:$\lfloor \cdot \rfloor$ 向下取整,把连续的编号“切”进同一个组,实现相邻合并。
4. 映射结果:编号 $0 \sim G-1$ 的头共享第 0 个 KV 头,$G \sim 2G-1$ 共享第 1 个,依次类推。
那么 $G$ 取多少?论文与工业实践的共识是:KV 头数取 $n_h/2$ 或 $n_h/4$(即每组 2 个或 4 个 Q 头)是性价比甜点。分组方式则默认“相邻合并”——实验证明,把远距离的头强行凑一组(交叉分组)收益微乎其微,而相邻分组只需一行取整公式、零额外开销,于是成了不二之选。便签本从 8 本减到 2~4 本,质量几乎不掉,“折中”的智慧就在这里。
模型采纳:从 Llama 2 到 Llama 3 的行业风向
咨询公司的省钱妙招很快传遍全行业。Llama 2 系列是第一个大规模吃螃蟹的:7B 和 13B 模型仍用 MHA,但 70B 率先采用 GQA——64 个 Q 头配 8 个 KV 头,每 8 个 Q 头共享一份 K/V。为什么小模型不用?因为 70B 的 KV 缓存大到已经威胁可用上下文长度,GQA 带来的收益具有压倒性;而小模型的缓存绝对量小,MHA 的质量优势更值得保留。
到了 Llama 3,GQA 成了全系标配:8B 模型 32 个 Q 头配 8 个 KV 头(每组 4 个),70B 模型 64 个 Q 头配 8 个 KV 头(每组 8 个)。此后 Mistral、DeepSeek、Qwen 等主流开源模型全面跟进,GQA 几乎成了新一代大模型的“出厂设置”。
1. 缩减比定义:$R_{kv}$ 表示采用了 GQA 之后,KV 缓存占原来 MHA 的比例。
2. 分子:$n_{kv}$ 是 GQA 实际使用的 KV 头数,由设计者决定(Llama 3 8B 取 8)。
3. 分母:$n_h$ 是 Q 头总数(Llama 3 8B 取 32)。
4. 代入算例:$8 / 32 = 1/4$,意味着 KV 缓存直接缩减 75%。
行业的“用脚投票”说明了一件事:GQA 不是理论上的最优,而是工程上的最优解——MQA 的极致压缩成了 GQA 在 $G=n_h$ 时的特例,MHA 则是 $G=1$ 的特例,真正的战场在中间那一小段旋钮上。
性能权衡:质量与成本的最终账本
把三种方案放到同一张账本上:MHA 质量最好、成本最高;MQA 成本最低、质量打折;GQA 则占据“省得多、掉得少”的黄金区间。GQA 论文给出 T5 上的对比:GQA(每组 2~4 头)与 MHA 差距通常在 0.1% 以内,而 MQA 的差距约 0.3%~0.5%;Llama 2 70B 的工程报告中,GQA 让 KV 缓存减少 87.5%,解码吞吐在带宽受限场景下获得近一个量级的改善。
为什么缓存大小与解码速度关系如此紧密?因为自回归解码是“逐词生成”的:每生成一个词,都要把全部 KV 缓存从显存搬到计算单元,这个过程由显存带宽决定,而不是由算力决定。搬的书越少,翻页越快——缓存减半,每词延迟在理想情况下也近似减半。
1. 缓存总量:$S_{KV}$ 是所有层 KV 缓存的总字节数,来自前面推导的 $S_{KV}$ 公式。
2. 读写两次:生成一个 token 要把缓存读进计算单元,还要把新结果写回,故近似乘 2。
3. 带宽分母:$B_{HBM}$ 是显存带宽(GB/s),带宽越大,搬缓存越快。
4. 瓶颈启示:只要 $S_{KV}$ 减半,$T_{decode}$ 就近似减半——这正是 GQA 加速解码的根本机制。
选型建议因此清晰:追求超长上下文且能接受微调成本,选 GQA(甚至每组 8 头);追求完全无损的质量,留在 MHA;服务端推理要压成本、压延迟,GQA 的 $n_h/2$ 或 $n_h/4$ 是最稳的起点。没有免费的午餐,但 GQA 把午餐的性价比拉到了最高。
AI 应用场景
大模型在线推理服务的 KV 缓存瘦身
阶段:模型推理优化 / 服务部署
解决的问题:多轮对话和长文档处理时,KV 缓存随序列长度线性膨胀,GPU 显存被迅速占满,服务端不得不缩小批大小,导致吞吐骤降。GQA 通过把 KV 头数从 32 压到 8,让单条请求的缓存占用直接降为原来的 1/4,同样的显存可以服务更多并发用户。
具体案例:某公司用 vLLM 部署 Llama 3 8B 提供 API 服务,切换 GQA(8 KV 头)配置并配合 PagedAttention 后,长对话场景下并发数提升约 3 倍,每 token 平均延迟从 45 ms 降到 28 ms。
端侧与边缘设备上跑大模型
阶段:模型压缩与端侧部署
解决的问题:手机、PC 等设备显存只有 8~16 GB,MHA 的 KV 缓存动辄数 GB,模型根本塞不进去。GQA 从结构上降低了缓存峰值,配合 4-bit 量化,让 7B~8B 级模型在消费级设备上流畅运行。
具体案例:某 AI 应用把 Llama 3 8B(GQA,32 Q 头 / 8 KV 头)量化后部署到 16GB 内存的笔记本上,上下文窗口拉到 32K,本地离线摘要和问答的响应时间在可接受范围内。
长文档智能审阅系统
阶段:应用开发与任务适配
解决的问题:法律合同、论文等长文本动辄几万字,KV 缓存随长度线性增长,MHA 下显存爆炸;MQA 又容易在长距离指代任务上“注意力坍塌”。GQA 让 128K 超长上下文的 KV 缓存占用减少 75%,同时保留足够的表达自由度完成指代消解。
具体案例:某法律科技产品用 GQA 版模型做 50 万字合同审查,单份文档推理显存峰值从 22 GB 降到 9 GB,关键条款召回率与 MHA 版本相差不到 0.5%。
Python 演示
import mathimport numpy as np def prepare_kv(x_kv, n_head, d_head, kv_count): """把 K/V 切出 kv_count 头, 再按相邻分组复制成 n_head 头. 这就是 GQA 的分组共享: 编号连续的 Q 头映射到同一个 K/V 头.""" B, T, _ = x_kv.shape kv = x_kv[:, :, :kv_count * d_head].reshape(B, T, kv_count, d_head) kv = kv.transpose(0, 2, 1, 3) # (B, kv_count, T, d_head) heads = [] for i in range(n_head): src = min(i * kv_count // n_head, kv_count - 1) heads.append(kv[:, src:src + 1, :, :]) return np.concatenate(heads, axis=1) # (B, n_head, T, d_head) def attention(q, k, v): d = q.shape[-1] scores = np.matmul(q, k.transpose(0, 1, 3, 2)) / math.sqrt(d) weights = np.exp(scores - scores.max(axis=-1, keepdims=True)) weights = weights / weights.sum(axis=-1, keepdims=True) return np.matmul(weights, v) def run(x_q, x_kv, n_head, d_head, kv_count): B, T, _ = x_q.shape q = x_q.reshape(B, T, n_head, d_head).transpose(0, 2, 1, 3) k = prepare_kv(x_kv, n_head, d_head, kv_count) v = prepare_kv(x_kv, n_head, d_head, kv_count) out = attention(q, k, v) return out.transpose(0, 2, 1, 3).reshape(B, T, n_head * d_head) def kv_cache_mb(n_layers, kv_count, d_head, seq_len): return 2 * n_layers * kv_count * d_head * seq_len * 2 / 1024 / 1024 if __name__ == "__main__": np.random.seed(0) B, T, d_head, n_head = 2, 16, 64, 8 x_q = np.random.randn(B, T, n_head * d_head).astype(np.float32) x_kv = np.random.randn(B, T, n_head * d_head).astype(np.float32) for name, kv_count in [("MHA", n_head), ("GQA", 4), ("MQA", 1)]: out = run(x_q, x_kv, n_head, d_head, kv_count) mem = kv_cache_mb(32, kv_count, d_head, 4096) print("%s: 输出形状 %s, 32 层 KV 缓存 %.1f MB" % (name, list(out.shape), mem))
src = min(i * kv_count // n_head, kv_count - 1)相邻分组合并的核心:第 i 个 Q 头映射到第i * n_kv / n_h个 KV 头。kv = x_kv[:, :, :kv_count * d_head].reshape(B, T, kv_count, d_head)只取前 kv_count 份的 K/V 投影,模拟共享前的压缩。heads.append(kv[:, src:src + 1, :, :])按映射关系把同一个 KV 头复制给同组的所有 Q 头。np.concatenate(heads, axis=1)把复制后的头重新拼成 n_head 份,形状与 Q 头对齐。scores = np.matmul(q, k.transpose(0, 1, 3, 2)) / math.sqrt(d)缩放点积注意力打分,除以根号 d 稳定 softmax。weights = np.exp(scores - scores.max(axis=-1, keepdims=True))先减最大值再取指数,数值稳定版 softmax 分子。return 2 * n_layers * kv_count * d_head * seq_len * 2 / 1024 / 1024估算 KV 缓存显存:K/V 两份 × 层数 × KV 头数 × 头维度 × 序列长度 × 2 字节。out.transpose(0, 2, 1, 3).reshape(B, T, n_head * d_head)把多头输出重新拼回序列形状,还原为标准输出。
常见误区
误区“MQA 和 GQA 都是共享 K/V 头的技巧,本质上一样,面试时随便换着说也没关系。”
正解它们是“极端”与“折中”的关系。MQA 强制所有 Q 头共享唯一的 K/V 头($n_{kv}=1$);GQA 允许 $n_{kv}$ 取任意中间值(如 $n_h/2$、$n_h/4$)。准确地说,MQA 是 GQA 在分组数 $G=n_h$ 时的特例,MHA 则是 $G=1$ 的特例。把 MQA 说成“组的个数为 1 的 GQA”才严谨。
为何常见:两者都是“减少 KV 头数量”,网上的科普常把 MQA 当作 GQA 的旧称,导致概念混淆。
误区“KV 头数越少,缓存省得越多,那为什么不直接每组 8 个甚至更多?分组越多越划算。”
正解分组越多意味着每组的 Q 头越多、KV 子空间越小,表达自由度随之收缩。实验与工业实践都表明,$n_h/2$ 或 $n_h/4$(每组 2~4 个 Q 头)是质量与成本的甜点;压到 MQA 级别(全模型 1 组)就会出现可感知的质量下降。省钱的前提是别把助理累垮。
为何常见:人们容易只盯着显存数字,忽略了注意力表达能力的结构性收缩。
误区“GQA 只是帮我省了点显存,推理速度该多快还是多快,没什么变化。”
正解自回归解码是带宽瓶颈型任务:每生成一个 token 都要把全部 KV 缓存从 HBM 读进计算单元,读取耗时与缓存大小成正比。因此缓存减半,每 token 延迟在理想情况下近似减半,吞吐随之大幅提升——这也是 Llama 2 70B 用 GQA 的核心动机之一。
为何常见:大家习惯性认为“速度由算力决定”,忽略了访存带宽在大模型推理中的主导地位。
误区“把语义相近的注意力头分到一组才合理,按编号相邻合并太粗糙了。”
正解GQA 论文专门做了对比实验:交叉分组(把远距离的头凑一组)与相邻分组的效果差异微乎其微。因为注意力头的分工并不是泾渭分明的,强行聚类带来的收益抵不过实现复杂度。相邻分组只需一行 floor(i/G),零额外开销,因此成为默认方案。
为何常见:直觉上认为“语义分组”更聪明,但实验数据告诉我们:简单的方案在工程上往往更优。
误区“MHA 模型想改成 GQA,只能推倒重来,之前的训练全白费了。”
正解GQA 论文提出了"upcycling"(升级复用)方法:把相邻的 KV 头参数取平均,合并成新的共享头,然后在原有权重上继续微调即可。实践中,从 MHA 升级到 GQA 的模型在少量微调后就能逼近原生 GQA 的效果,大大降低了迁移成本。
为何常见:人们默认“结构变了就要重新训练”,忽略了注意力投影权重的可复用性。
面试题
Q1. MQA 中所有 Q 头共用的 K/V 头数量是多少?
- A.与 Q 头数量完全相同
- B.等于分组数目的值
- C.整个模型只有一个← 正确答案
- D.等于层数乘头数值
答案:C。MQA 的极端之处就在于每层所有 Q 头共享唯一一份 K/V 头,$n_{kv}=1$。A 是 MHA 的配置,B 是 GQA 的配置,D 没有任何实际依据。
Q2. GQA 相比 MHA 最主要的改动是什么?
- A.所有查询头共享一份 K/V
- B.查询头分组后组内共享 K/V← 正确答案
- C.直接去掉注意力中的 V 投影
- D.将 Q 与 K 投影合并为一组
答案:B。GQA 的核心是把 Q 头分组,组内共享一份 K/V,组间独立;A 描述的是 MQA,C 和 D 是错误改造。GQA 恰好位于“一人一本”(MHA)与“全员一本”(MQA)之间。
Q3. 采用 GQA 后能获得哪些收益?
- A.KV 缓存占用的显存变小← 正确答案
- B.每个解码 token 的延迟降低← 正确答案
- C.训练损失函数立即收敛
- D.模型总参数量大幅缩减
答案:AB。KV 头数减少直接降低缓存占显存(A);解码是带宽瓶颈,缓存变小则每 token 读取量变小、延迟降低(B)。C 与压缩无关;K/V 投影只占总参数一小部分,谈不上“大幅缩减”(D)。
Q4. Llama 3 8B 有 32 个 Q 头和 8 个 KV 头,平均每几个 Q 头共享一个 K/V 头?
- A.两个查询头共享一个
- B.四个查询头共享一个← 正确答案
- C.八个查询头共享一个
- D.十六个查询头共享一个
答案:B。32 ÷ 8 = 4,即每 4 个 Q 头分到一组、共享 1 个 KV 头,对应论文推荐的 $n_h/4$ 档位。其余选项均与除法结果不符。
Q5. GQA 论文中“相邻分组合并”指的是什么?
- A.位置相邻的缓存片段合并
- B.编号连续的头分到同组← 正确答案
- C.把注意力头按内容聚类
- D.相邻层的头合并共享
答案:B。相邻分组合并指把编号连续(0、1、2、3…)的 Q 头放进同一组,实现上只需 floor(i/G) 这个取整公式。A 把“相邻”误读成缓存位置,C 是聚类思想,D 是跨层共享,均不是论文默认方案。
Q6. 单条序列的 KV 缓存大小与哪些因素成正比?
- A.模型的层数与 KV 头数← 正确答案
- B.每个注意力头维度大小← 正确答案
- C.序列长度与数据类型← 正确答案
- D.前馈网络隐藏层维度
答案:ABC。由公式 $S_{KV}=2 \times n_{layers} \times n_{kv} \times d_{head} \times L_{seq} \times 2$ 可知,层数与 KV 头数(A)、头维度(B)、序列长度与每元素字节数(C)都是正比因子;前馈网络维度(D)不参与注意力缓存的计算。
Q7. 8 个 Q 头的 MHA 改成 MQA 后,KV 缓存大约节省到原来的多少?
- A.二分之一左右
- B.四分之一左右
- C.八分之一左右← 正确答案
- D.完全保持不变
答案:C。MHA 有 8 个 KV 头,MQA 只有 1 个,其余全不变,缓存为原来的 1/8。A、B 分别是 4 组、2 组 GQA 的节省比例,D 完全错误。
Q8. 为什么减少 KV 缓存能显著加速自回归解码?
- A.显存变小可以放更大批次
- B.解码受显存带宽瓶颈限制← 正确答案
- C.计算量本身大幅下降
- D.模型的层数会自动减少
答案:B。自回归每生成一个 token 都要把全部 KV 缓存读入计算单元,耗时由显存带宽决定,故缓存减半近乎延迟减半。A 是间接收益,C 中计算量下降有限且非主因,D 显然错误。
Q9. 以下哪些模型采用了 GQA 结构?
- A.Llama 2 70B 大版本← 正确答案
- B.Llama 3 8B 小版本← 正确答案
- C.Mistral 7B 版本← 正确答案
- D.GPT-3 原始模型
答案:ABC。Llama 2 70B(64 Q 头 / 8 KV 头)、Llama 3 全系(8B 为 32/8,70B 为 64/8)、Mistral 7B 都采用 GQA;GPT-3 是较早的 MHA 结构,未使用 GQA。
Q10. 将已训练好的 MHA 模型转换为 GQA 的常用方法是什么?
- A.随机初始化 K/V 头重训
- B.相邻头参数取平均合并← 正确答案
- C.直接丢弃多余的 KV 头
- D.转成 GQA 要重头预训练
答案:B。"upcycling"做法是把相邻 KV 头的投影参数取平均,合并成新的共享头,再做少量微调,尽量保留原模型知识。A 浪费已有权重,C 丢失信息过多,D 夸大了迁移成本。