想象一下,你走进一座巨大的图书馆。每位研究员(查询头 Q)都需要查阅一批参考书(Key 和 Value),来撰写自己的报告(注意力输出)。在传统的多头注意力机制下,每个研究员不仅要亲自去书架取书,还要把自己看过的每一页都复印一份带走,甚至每一组座位都配一套完全相同的复印本。结果,整座图书馆的复印机一刻不停地运转,书架被塞满,大家在走廊里挤来挤去,阅读速度慢得惊人。 后来,管理员想出了两个妙招。第一招叫 MQA:既然大家查的都是同一批参考书,那就干脆只留一套复印本,所有人排队轮流看——速度快了,但热门区域总是挤成一团,有人等得不耐烦,报告质量就打了折扣。第二招叫 GQA:把研究员分成几个小组,每个小组共享一套复印本,既不像原来那样人手一套浪费资源,也不像只留一套那样挤得水泄不通。Llama 2 等现代大模型正是采用了 GQA 这个折中方案,把推理吞吐量提升了 2~3 倍。

岗位关联

理解 KV 共享,是理解大模型推理性能优化的关键。掌握 GQA/MQA,你就能读懂 Llama 2、Mistral 等主流模型的架构选择,并为实际部署加速方案提供理论依据。

目录
  1. 可视化演示
  2. 背景动机
  3. MQA方案
  4. GQA分组
  5. KV缓存
  6. 性能收益
  7. 工程应用
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示SCAN电梯调度算法的磁头移动过程:磁头沿一个方向移动到端点后反向,依次处理请求队列中的磁道访问请求。

本节配有交互动效(进入视口后自动加载,约 3KB)。

SCAN\u7535\u68af\u8c03\u5ea6 \u8bf7\u6c42\u961f\u5217 \u5f53\u524d\u78c1\u5934 \u5df2\u5904\u7406 SCAN \u78c1\u5934\u6cbf\u65b9\u5411\u79fb\u52a8\u81f3\u7aef\u70b9\u540e\u53cd\u5411

背景动机

图书馆管理员的烦恼,从每一个研究员都要求“人手一套复印本”开始。在标准多头注意力机制中,模型有多个查询头,每个查询头都独立地对同一个序列进行注意力计算,相当于每个研究员都要为同一批参考书单独复印一套。这套“复印本”在推理时就是 KV 缓存——每个 token 的 Key 和 Value 向量都要被保存下来,供后续 token 查询。序列越长,复印本就越多,书架的负担就越重。

自回归推理是另一个放大器。大模型生成每个新 token 时,都要重新读取之前所有 token 的 Key 和 Value,这就像每写一句话,都要把前面写过的所有参考书重新翻一遍。当序列长度达到几千甚至几万时,KV 缓存的大小就会爆炸。

更深层的瓶颈在于内存带宽。解码阶段每次只生成一个 token,计算量比训练时小得多,此时真正限制速度的不是算力,而是把 KV 缓存从显存搬到计算单元所需要的时间——就像图书馆里最慢的不是复印机本身,而是来回搬书的走廊。KV 缓存越大,搬书时间越长,推理就越慢。这就是为什么缩小 KV 缓存体积成为优化推理性能的第一突破口。

CacheSize=2×L×Hkv×D×S\text{CacheSize} = 2 \times L \times H_{kv} \times D \times S
其中 2 代表 Key 和 Value 各一份,L 是层数,H_kv 是 KV 头数,D 是每个头的维度,S 是序列长度。
  1. 层数 LTransformer 有多少层,每层都要存储一份 KV 缓存。这相当于图书馆的每一层楼都有一套复印本。
    LL
  2. KV 头数 H_kv在标准 MHA 中,KV 头数等于查询头数;在 GQA 中则被分组缩减。这是最关键的压缩旋钮。
    HkvH_{kv}
  3. 头维度 D每个注意力头向量的维度,决定了单本“参考书”的厚度。
    DD
  4. 序列长度 S已经生成的 token 数量,每生成一个新 token,KV 缓存就多一行。这就是为什么长上下文场景下缓存猛增。
    SS
  5. 系数 2Key 和 Value 各占一份,复印了两套。
    2×L×Hkv×D×S2 \times L \times H_{kv} \times D \times S

MQA方案

管理员的第一个激进方案是 MQA,把复印本从人手一套缩减为全馆共享唯一一套。MQA 的核心理念是:既然所有查询头查询的是同一个序列,为什么不让它们共享完全相同的 Key 和 Value?于是,所有查询头“排队”查阅同一组 KV。这一改动将 KV 缓存压缩到原来的 1/H(H 为查询头数)。

缓存体积的压缩直接解除了显存焦虑。以前需要 32 套复印本,现在只需要 1 套。在批处理大小为 B 的场景下,MQA 的显存优势更加明显,因为每个 batch 都只需要维护一套 KV。这意味着可以塞进更大的 batch,吞吐量随之提高。

然而,MQA 的激进换来了质量的下降。当所有查询头被迫共享同一组 K 和 V 时,模型表达不同“关系”的能力被削弱了——就像所有研究员都必须在同一本参考书上做笔记,但每个人的笔记重点不同,挤在一起难免互相干扰。实践中,MQA 在部分任务上会出现精度下降,尤其在需要精细区分多种关系的场景里。

MQA 的另一个问题是训练不稳定和实现复杂。虽然推理时缓存大幅缩小,但训练时多个查询头共享 K 和 V 会让梯度传播路径变得复杂,影响收敛速度。因此,MQA 虽然提出来得更早,但在实际大模型中的采用率远不如后来提出的 GQA。

MQA: O=softmax(QWQ(KWK)⊤dk)VWV\text{MQA: } O = \text{softmax}\left(\frac{Q W^Q (K W^K)^\top}{\sqrt{d_k}}\right) V W^V
在这个公式中,Q 来自每个查询头,而 K 和 V 是所有查询头共享的同一组。1/√d_k 起到缩放作用,避免点积过大导致 softmax 进入饱和区。
  1. 查询投影 QW^Q每个查询头将自己的输入投影成“问题向量”,相当于每位研究员写下自己的问题。
    QWQQ W^Q
  2. 共享键投影 KW^K所有查询头复用同一个 Key 投影,相当于全馆只保留一份目录索引。
    KWKK W^K
  3. 缩放点积将问题与目录做匹配,除以 √d_k 控制数值范围。
    QWQ(KWK)⊤dk\frac{Q W^Q (K W^K)^\top}{\sqrt{d_k}}
  4. Softmax 归一化把匹配度转成权重,决定每个 token 被关注多少。
    softmax(⋅)\text{softmax}(\cdot)
  5. 共享值投影 VW^V用同一份 Value 加权求和,产出最终输出。
    VWVV W^V

GQA分组

GQA 是管理员深思熟虑后的折中方案:与其让 8 个研究员挤 1 本参考书,或者每人复印 1 本,不如把他们分成小组,每组共享一套复印本。具体来说,GQA 将查询头分成 G 组,每组共享一组独立的 K 和 V 头。当 G = 1 时退化为 MQA,当 G = H 时等价于 MHA,因此 GQA 是两者之间的连续插值。

\begin{aligned}

O &= \text{softmax}\left(\frac{Q G^Q (K G^K)^\top}{\sqrt{d_k}}\right) V G^V \\

\end{aligned}

1. 分组重塑 Q:将查询头按组规整成新的形状,组数为 G。

Q∈RB×G×(H/G)×S×dQ \in \mathbb{R}^{B \times G \times (H/G) \times S \times d}

2. 广播 K 和 V:让每组共享同一套 K 和 V,通过 expand 操作实现零拷贝广播。

K,V∈RB×G×S×dK, V \in \mathbb{R}^{B \times G \times S \times d}

3. 组内注意力:每个查询头只与所在组的 KV 做缩放点积注意力,把计算限制在小组内部。

分组数 G 是一个超参数,直接决定了“多人共享程度”。G 越大,KV 缓存越大,模型表达能力越强;G 越小,KV 缓存越小,速度越快。Llama 2 70B 选择了 G = 8、H = 64,将 KV 缓存压缩为原来的 1/8,获得了速度与质量的双赢。

GQA 的巧妙之处在于它几乎不牺牲质量。研究发现,组内共享 KV 带来的表达力损失远小于全部共享,因为多数注意力模式在组内就能被充分表达。这个结果像极了图书馆的“小组讨论区”——几个人的小组共享参考书,互相补充笔记,效率和质量都有保障。

KV缓存

KV 缓存是 GQA 的直接受益者。在推理时,每生成一个新 token,模型都需要把新 token 的 Key 和 Value 追加到缓存中,并在下一次生成时读取全部缓存。这个“写入 + 读取”的过程是内存带宽的主要消费者。KV 缓存的大小直接决定了单条请求的显存占用,进而决定了显卡能同时容纳多少条请求(batch size)。

应用 GQA 后,KV 头数从 H 降到 G,缓存体积相应变为:

压缩效果有多显著?以 Llama 2 70B 为例,该模型有 80 层、每层 8 个 KV 头、每个头 128 维。一条 4096 token 的序列,其 KV 缓存大约是 2 × 80 × 8 × 128 × 4096 ≈ 670 MB。如果不采用 GQA 而是用标准 64 个 KV 头,这个数字会膨胀到约 5.4 GB——一张 A100 80G 的显卡瞬间被吃掉了一小半。

KV 缓存的缩小还带来一个连锁收益:推理引擎可以在缓存中容纳更长的上下文。长上下文场景(如多轮对话、文档分析)是 KV 缓存压力的重灾区,GQA 让这些场景从“显存爆掉”变为“勉强可跑”甚至“流畅运行”。这也是为什么当前主流大模型几乎全部采用 GQA 而非 MHA。

Ratio=GH\text{Ratio} = \frac{G}{H}
KV 缓存压缩比例等于 GQA 的 KV 头数与原始查询头数之比。当 H = 32、G = 4 时,缓存缩小到原来的 1/8。
  1. 原始缓存MHA 的缓存体积正比于查询头数 H。
    CacheMHA∝H\text{Cache}_{MHA} \propto H
  2. GQA 缓存GQA 的缓存正比于分组数 G。
    CacheGQA∝G\text{Cache}_{GQA} \propto G
  3. 压缩比两者相除,得到压缩比例 G/H。
    GH\frac{G}{H}

性能收益

共享 KV 的最终目标不是省显存本身,而是把省下来的资源转化为吞吐量。推理吞吐量 = 每秒生成的 token 数,它受到两个因素制约:单次请求的延迟和并发请求的批处理规模。GQA 在这两个维度上都有贡献。

从延迟维度看,KV 缓存变小意味着每个生成步骤需要从显存搬运的数据量减少,内存带宽瓶颈被显著缓解。自回归解码本质上是“内存受限”任务,计算量只是附属,搬运 KV 缓存的时间常常占了大头。缓存缩到 1/8,搬运时间也近似缩到 1/8,单次生成延迟大幅下降。

这个 2~3 倍的吞吐量提升,是实测数据支撑的结论。Google 的 PaLM、Meta 的 Llama 2、Mistral 7B 等模型在采用 GQA 后,都报告了相似的收益。对于服务提供商而言,吞吐量翻倍意味着同样的显卡可以服务两倍的用户,成本直接减半。

GQA 的均衡策略还体现了一个重要理念:性能优化往往不是“快就好”,而是在多个目标之间寻找最佳平衡点。MQA 最快但质量受损,MHA 质量最好但速度受限,GQA 选择了中间地带,用略高一点的 KV 缓存换来了接近无损的质量,这才是工业界最需要的方案。

Throughput≈B×Ltcompute+tmemory\text{Throughput} \approx \frac{B \times L}{t_{\text{compute}} + t_{\text{memory}}}
吞吐量取决于批大小 B、序列长度 L、计算时间 t_compute 和内存访问时间 t_memory。GQA 压缩 KV 缓存,主要减小 t_memory,同时允许更大的 B。
  1. 批大小 B单次推理同时处理的请求数。KV 缓存越小,显存越宽裕,B 可以开得越大。
    BB
  2. 计算时间矩阵乘法和注意力计算本身的时间,在 GQA 中基本不变。
    tcomputet_{\text{compute}}
  3. 内存访问时间读取和写入 KV 缓存消耗的时间,GQA 大幅削减了这个分量。
    tmemoryt_{\text{memory}}
  4. 整体吞吐在计算时间不变、内存时间缩短、批处理变大的三重作用下,吞吐量获得 2~3 倍提升。
    B×Ltcompute+tmemory\frac{B \times L}{t_{\text{compute}} + t_{\text{memory}}}

工程应用

GQA 在工程界的普及速度令人瞩目。Meta 在 Llama 2 系列中首次大规模应用 GQA,其 70B 版本采用 8 个 KV 头,而 7B 版本则用 32 个 KV 头(即接近 MHA)。这种“大模型更加需要压缩”的设计思路,恰好印证了 KV 缓存压力随模型规模增大而急剧上升的规律。

主流推理引擎对 GQA 的支持已经相当成熟。Hugging Face Transformers、vLLM、TensorRT-LLM 等都内置了 GQA 的实现,并且在 KV 缓存管理上做了精细优化:内存池化、连续显存分配、Cache Manager 动态调度。对于应用开发者而言,无需手动实现 GQA,只需在加载模型时指定正确的配置,引擎会自动构建共享 KV 的注意力计算图。

在长上下文部署场景中,GQA 的地位不可替代。例如部署一个支持 32K 上下文的对话模型,如果使用 MHA,KV 缓存可能占据超过 20GB 显存,导致 batch size 被压到个位数;而使用 GQA 后,缓存缩减使 batch size 可以扩大数倍,服务吞吐量实现质的飞跃。

除了 Llama 2,Mistral 7B 和 Mixtral 8x7B 也采用 GQA,其 7B 模型使用 8 个 KV 头,配合滑动窗口注意力(Sliding Window Attention),在长文本任务上取得了极佳的效果。这代表了当前大模型架构的一个明确趋势:在注意力机制上做“减法”,用结构优化换取效率。

对于 AI 工程师而言,理解 GQA 不仅是为了读懂模型配置,更是为了在实际部署中做出正确决策:何时选择 GQA(推理成本敏感型场景)、如何设置分组数(在质量预算内尽量压缩)、怎样配合其他优化手段(如 KV 量化、PagedAttention)形成组合拳。这些知识直接决定了推理服务的成本与体验。

AI 应用场景

高并发对话服务

阶段:推理部署

解决的问题:在线对话服务需要同时服务大量用户,每个用户都有多轮历史对话,KV 缓存占用巨大,导致单卡只能服务少量并发。传统 MHA 架构下,一条 2000 token 的对话请求就要占用数百 MB 显存,GPU 上只能同时跑几个请求,服务成本居高不下。采用 GQA 后,KV 缓存缩小到 1/8,单卡并发数提升数倍。

具体案例:某 AI 创业公司部署 Llama 2 70B 提供客服机器人服务。将模型的 KV 头从 64 缩减到 8 后,在同样的 A100 集群上,每张卡的并发请求数从 4 提升到 12,整体推理成本降低了约 60%,同时客服回答质量在人工评估中几乎没有差异。

长文档分析

阶段:模型应用

解决的问题:长上下文场景(如论文解读、合同审查)要求模型一次性处理数万 token,KV 缓存随序列长度线性增长,极易超出显存限制。GQA 压缩缓存后,长序列推理才能在消费级 GPU 上运行。

具体案例:一家法律科技公司需要处理平均 8000 词的法律合同,每个合同约 12000 token。使用 MHA 架构的模型需要 48GB 显存才能处理,而切换到 GQA 架构后,显存需求降到 16GB,公司得以使用更便宜的 GPU 完成同样任务,月成本从 20 万元降至 7 万元。

KV缓存服务

阶段:系统架构

解决的问题:在 Prompt Cache、前缀复用等高级推理优化中,KV 缓存是需要被跨请求复用的核心资产。GQA 缩小了缓存体积,使得缓存服务可以在相同显存下缓存更多的前缀,提高前缀命中率。

具体案例:某大模型 API 服务商观察到大量请求共享相同的系统提示词。在引入 GQA 并配合 Prefix Caching 后,系统提示词的 KV 缓存命中率达到 90%,有效生成时间缩短了 40%,用户感知的响应速度明显提升。

Python 演示

python57 行
import torchimport torch.nn as nnimport torch.nn.functional as F  class GroupedQueryAttention(nn.Module):    """分组查询注意力 GQA:分组共享 KV,可退化为 MQA/MHA"""     def __init__(self, d_model=512, h_q=8, h_kv=2, dropout=0.0):        super().__init__()        self.h_q = h_q        self.h_kv = h_kv        self.d = d_model // h_q        self.w_q = nn.Linear(d_model, d_model, bias=False)        self.w_k = nn.Linear(d_model, h_kv * self.d, bias=False)        self.w_v = nn.Linear(d_model, h_kv * self.d, bias=False)        self.w_o = nn.Linear(d_model, d_model, bias=False)        self.drop = nn.Dropout(dropout)     def forward(self, x, past_kv=None):        b, s, _ = x.shape        q = self.w_q(x).view(b, s, self.h_q, self.d).transpose(1, 2)        k = self.w_k(x).view(b, s, self.h_kv, self.d).transpose(1, 2)        v = self.w_v(x).view(b, s, self.h_kv, self.d).transpose(1, 2)        if past_kv is not None:            pk, pv = past_kv            k = torch.cat([pk, k], dim=2)            v = torch.cat([pv, v], dim=2)        # 核心:将 q 的 head 维度按组 reshape,再将 kv 扩展回原头数        group = self.h_q // self.h_kv        q = q.view(b, self.h_kv, group, s, self.d)        k_e = k.unsqueeze(2).expand(b, self.h_kv, group, -1, self.d)        v_e = v.unsqueeze(2).expand(b, self.h_kv, group, -1, self.d)        score = (q @ k_e.transpose(-1, -2)) / (self.d ** 0.5)        attn = F.softmax(score, dim=-1)        attn = self.drop(attn)        out = (attn @ v_e).transpose(1, 2).contiguous()        out = out.view(b, s, self.h_q * self.d)        return self.w_o(out), (k, v)  def main():    torch.manual_seed(0)    model = GroupedQueryAttention(d_model=64, h_q=8, h_kv=2)    x1 = torch.randn(1, 5, 64)    x2 = torch.randn(1, 3, 64)    out1, kv = model(x1)    out2, kv2 = model(x2, kv)    # 验证拼接后长度    assert kv2[0].shape[2] == 8, "KV 缓存应增大到 8"    print("GQA 单步输出:", out1.shape)    print("GQA 增量输出:", out2.shape)    print("KV 缓存形状:", kv2[0].shape)  if __name__ == "__main__":    main()
目的:实现一个简洁的 GQA 模块,并将 KV 缓存传入下一步完成增量解码。当 h_kv=1 时退化为 MQA,当 h_kv=8 时等价于 MHA。
  1. q = self.w_q(x).view(...).transpose(1, 2)将 Q 投影后拆成多个查询头,shape 变为 [batch, 头数, 序列, 维度]。
  2. self.w_k = nn.Linear(d_model, h_kv * self.d, bias=False)关键设计:仅投影出 h_kv 组 K(如 2 组),而不是 h_q 组,从源头压缩了 KV 缓存。
  3. torch.cat([pk, k], dim=2)在序列维度拼接历史 KV 和新 token 的 KV,这是缓存追加的标准操作。
  4. q.view(b, self.h_kv, group, s, self.d)将 h_q 个查询头按组 reshape,例如 8 个头 → 2 组 × 4 个头,为后续广播做准备。
  5. k.unsqueeze(2).expand(...)零拷贝广播 KV 到每个组内全部查询头。expand 不复制数据,这正是 GQA 高效的原因。
  6. (q @ k_e.transpose(-1, -2)) / (self.d ** 0.5)缩放点积注意力,计算每个查询头与其组内 KV 的匹配度。
  7. F.softmax(score, dim=-1)对最后一个维度归一化,得到注意力权重。
  8. return self.w_o(out), (k, v)返回输出与 KV 缓存,后者将在下一次生成时复用。

常见误区

误区GQA 和 MQA 听起来都像“让多个查询头共享 KV”,很多人认为它们只是同一种技术的不同名字,用哪个都一样。

正解GQA 与 MQA 有本质区别。MQA 是“所有人共用一套 KV”的极限共享,8 个查询头全部指向 1 组 K 和 V;GQA 是“分组共享”,8 个查询头分成 4 组或 2 组,每组共享一套 KV。可以这样理解:MQA 是整座图书馆只有一套复印本,GQA 是每个小组各有一套。MQA 是 GQA 在分组数 = 1 时的特例,MHA 则是分组数 = 查询头数时的另一极端。

为何常见:两者名字中都带“查询”与“共享”,教程中也经常放在一起讲,初学者容易把“部分共享”和“全部共享”混为一谈。

误区既然 MQA 会掉点,那 GQA 作为“变小版的 MHA”也必然会明显损害生成质量,只是比 MQA 轻一点。

正解GQA 在多数任务上质量与 MHA 几乎持平。实验表明,当分组数 G 在 4~8 之间时,PPL(困惑度)仅增加不到 0.1%,这对于实际应用完全可接受。质量下降主要出现在极端压缩(如 G=1 的 MQA)或任务对多种关系建模特别敏感时。GQA 的设计哲学就是“以极小的质量代价换取巨大的效率收益”。

为何常见:人们容易从“MQA 掉点”线性外推,认为凡是共享 KV 都会掉点,忽略了分组带来的缓冲作用。

误区KV 头从 64 个减到 8 个,肯定省了很多参数,模型变小了,所以推理变快了。

正解GQA 减少的是 KV 缓存体积,而不是模型参数量。在标准实现中,KV 投影矩阵本身占比不大,真正的大头是 FFN(前馈网络)和 Embedding。GQA 提速的核心机制是:推理时 KV 缓存变小 → 每次生成 token 需要从显存搬运到计算单元的数据变少 → 内存带宽瓶颈缓解。这类似于图书馆真正拥挤的不是书架上的书本身,而是搬书的走廊。

为何常见:人们习惯于用“参数少=速度快”的直觉做判断,忽略了自回归推理实际上是内存带宽受限而非计算受限的事实。

误区论文说 GQA 能让吞吐量提升 2~3 倍,那我部署服务时直接用 GQA,所有场景的速度都会自动翻倍。

正解GQA 的提速效果受序列长度、batch size、硬件特性影响显著。短序列 + 小 batch 场景下,KV 缓存占比本来就小,GQA 收益有限;长序列 + 大 batch 场景下(如 4K 以上上下文、多用户并发),缓存压缩的收益才会充分显现。GQA 是“给系统创造提速条件”而非“无条件提速”,需要配合足够的并发负载才能兑现。

为何常见:2~3 倍是一个吸引眼球的数字,但它是特定配置下的实验结论,初学者容易把它当成普适常量。

误区KV 缓存缩小,最直接的好处就是显存占用变少,所以 GQA 的作用就是让模型能在更小的显卡上运行。

正解节省显存只是表层收益,更深层的价值是突破内存带宽瓶颈。自回归解码中,每个 token 的生成都要读取全部 KV 缓存,缓存越大,搬运时间越长。GQA 压缩缓存后,搬运时间缩短,单 token 延迟下降,同时显存腾出空间后可以增加 batch size,两者共同提升吞吐量。显存只是物理容器,带宽才是真正的速度瓶颈。

为何常见:显存占用是看得见的数字,而内存带宽是隐藏在系统深处的运行机制,初学者更容易关注前者。

面试题

Q1. MQA 的核心思想是什么?

单选题 · mid

  • A.所有查询头共享一组 K 和 V← 正确答案
  • B.所有查询头各自保留独立的 K 和 V
  • C.查询头分成多组共享 K 和 V
  • D.取消 Key 只保留 Value

答案:A。MQA 是极端的共享策略,所有查询头共用同一组 K 和 V。B 是 MHA 的做法,C 是 GQA,D 是无效设计。

Q2. GQA 中 KV 缓存压缩比例约为多少?

单选题 · easy

  • A.1(不压缩)
  • B.H/G(H 为查询头数,G 为分组数)
  • C.G/H← 正确答案
  • D.常数 2

答案:C。KV 缓存正比于 KV 头数。GQA 从 H 个 KV 头变为 G 个,缓存变为原来的 G/H。若 H=32、G=4,则压缩到 1/8。

Q3. 以下关于 GQA 的说法正确的有哪些?

多选题 · mid

  • A.G 等于查询头数时退化为 MHA← 正确答案
  • B.G 等于 1 时退化为 MQA← 正确答案
  • C.GQA 完全不损失模型质量
  • D.GQA 可缓解内存带宽瓶颈← 正确答案

答案:ABD。GQA 是 MHA 与 MQA 的连续插值,G=H 即每头独立共享(MHA),G=1 即全共享(MQA)。GQA 虽能大幅提升效率,但仍有可能造成轻微的精度下降,C 过于绝对。

Q4. Llama 2 70B 采用 GQA 后,推理吞吐量大约提升多少?

单选题 · hard

  • A.10%以内
  • B.50%
  • C.2~3 倍← 正确答案
  • D.10 倍以上

答案:C。官方报告与业界实测显示,采用 GQA 后 KV 缓存大幅压缩,内存带宽瓶颈缓解,推理吞吐量可提升约 2~3 倍。10 倍以上在纯软件层面很难实现。

Q5. 自回归解码阶段的主要性能瓶颈是什么?

单选题 · mid

  • A.矩阵乘法的计算量
  • B.内存带宽和 KV 缓存搬运← 正确答案
  • C.数据加载与预处理
  • D.网络通信延迟

答案:B。解码阶段每个 token 都要读取全部历史 KV 缓存,计算量相对小,但搬运量随序列长度线性增长,因此瓶颈在显存带宽而非算力。

Q6. KV 缓存大小的计算公式中,符号 H 代表什么?

单选题 · mid

  • A.模型总层数
  • B.序列长度
  • C.KV 头数← 正确答案
  • D.隐藏层维度

答案:C。缓存公式为 2×L×H×D×S,其中 H 是 KV 头数。L 是层数,D 是头维度,S 是序列长度。GQA 正是在 H 上做压缩。

Q7. 关于 GQA 分组数 G 的选择,以下哪些说法是正确的?

多选题 · hard

  • A.G 越大,KV 缓存越大← 正确答案
  • B.G 越小,表达能力越弱← 正确答案
  • C.分组数应当固定为 8,不可调整
  • D.G 的选择需在速度与质量之间权衡← 正确答案

答案:ABD。G 是超参数,并非固定值。G 越大,缓存越多、质量越好;G 越小,缓存越少、速度越快。工业界需要结合任务质量要求和算力预算做权衡。

Q8. 以下哪个模型架构明确采用了 GQA?

单选题 · mid

  • A.GPT-3
  • B.BERT
  • C.Llama 2 70B← 正确答案
  • D.T5 base

答案:C。Llama 2 系列是 GQA 的典型代表,其 70B 版本使用 8 个 KV 头。GPT-3、BERT、T5 base 都基于标准 MHA 设计。

Q9. GQA 相比 MHA 最主要的改进是什么?

单选题 · easy

  • A.增加注意力头数
  • B.减少 KV 缓存体积← 正确答案
  • C.增大模型参数量
  • D.改进激活函数

答案:B。GQA 将多个查询头分组共享 KV,直接减少了 KV 头数,从而压缩缓存体积,缓解显存和带宽压力。B 是 GQA 的设计初衷。

Q10. GQA 可以看作哪两种机制的插值?

多选题 · mid

  • A.MHA 每头独立 KV← 正确答案
  • B.MQA 全部共享 KV← 正确答案
  • C.线性注意力
  • D.滑动窗口注意力

答案:AB。GQA 在分组数 G=H 时等于 MHA,G=1 时等于 MQA,因此它是 MHA 与 MQA 之间的广义插值。C 和 D 是其他注意力变体,不属于 GQA 的定义范畴。