习慈羊xiciyang
联系
订阅
正在读取订阅状态…

优化技术该插在哪一格:一套三层坐标,与一个 KV Cache 推导

Qwen3-235B 的 num_key_value_heads 是 4。这个数字看起来只是模型配置里的一个小项——其实它决定了一件很贵的事:

当张量并行度(TP)超过 4 时,KV Cache 会被整份复制 [1]。

于是可用 KV Cache 减半、最大并发下降、吞吐跟着掉 [2]。而你并没有多出任何算力,只是把同一份数据在更多卡上各存了一遍。

优化技术之间的耦合,比单项技术的优劣更决定结果——你选的每一层,都在为下一层的瓶颈创造条件。

一、为什么技术清单没有用

优化技术的内容会不断更新,但”该看哪里”的结构是稳定的。所以与其维护一张越来越长的清单,不如先建立一套坐标。

这个坐标系有三个相互正交的轴:

三层坐标:任务流阶段 × 软硬件层级 × 技术维度

第一轴:任务流阶段。数据 / 训练 / 推理 / 验证 / 治理。它决定了你现在做的事属于哪一类问题。

第二轴:软硬件层级(L1–L7)。它决定了你要动的是哪一层。下表 L4 那一格会用到三个词,先各解释一次:量化(用更低比特表示权重与缓存,省显存)、蒸馏(让小模型学大模型的输出行为,以小代大)、剪枝(删掉影响小的参数)。三者都属于”用精度换资源”的算法层手段。

层级名称典型技术
L7业务与应用层Agent 系统、RAG 应用、提示工程
L6调度与编排层K8s、批调度、弹性扩缩容、负载均衡
L5推理引擎与服务层vLLM、TensorRT-LLM 等模型服务
L4模型与算法层模型架构、并行策略、量化/剪枝/蒸馏
L3框架与编译器层PyTorch、torch.compile、XLA、MLIR
L2编程与驱动层CUDA / ROCm / Ascend C、集合通信库
L1硬件与芯片层GPU/ASIC、HBM、CXL、InfiniBand

第三轴:技术维度。算力 / 存储 / 网络 / 调度 / 数据 / 能源——它决定了这个优化主要在改善哪一种资源。

三层各取一个坐标,就是一次优化动作的完整定位。比如”把 MatMul 与 AllReduce 融合成一个算子”,坐标是:推理阶段 × L2–L3 之间 × 网络维度(辅以算力)。

二、坐标的三个用途

坐标系不是为了分类好看,它有三个具体用途。

用途一:定位”该不该在这里找”。症状和层级之间是有对应关系的。生成阶段慢、显存吃紧,问题几乎不可能在 L7;反过来,端到端响应慢而各层指标都正常,就要往 L6 的调度与排队上找。先定层,再选技术。

用途二:判断代价落在谁身上。这是坐标最有价值的地方。任何优化都不是免费的,而代价几乎总是落在另一个维度上:

  • 计算通信融合 → 省网络时间,代价是算子融合带来的实现复杂度与兼容性约束;
  • KV Cache 量化 → 省存储,代价是精度与算子支持;
  • 增大批处理 → 提高吞吐,代价是单请求延迟与显存峰值。

用途三:回答”新技术该放哪”。新东西出现时,给它在三个轴上各取一个坐标,别先去清单里找同类——如果它落在某个已经有名字的格子里,说明它是替换项;如果落在一个空格里,那才是真正的新方向。

所以”这个优化该放哪一章”是错误的问题。正确的问题是:它在哪一层、主要动哪个维度、代价落在谁身上。

三、判据必须带阈值

坐标系说明”在哪里”,但还需要判据说明”是不是”。判据的关键在于必须是带阈值的量,否则会退化成感觉。

一套可用的判墙判据如下(阈值可按机器重标,但结构不变)[3]:

观测量阈值判到哪堵墙动作方向
显存占用率(权重 + KV Cache)> 90%显存墙降并发、压缩 KV、量化
计算利用率> 85% 且吞吐未达预期算力墙优化算子、检查并行度
计算利用率< 50% 且显存很高显存墙(表现成算力闲置)优先解决显存
显存带宽利用率> 70%带宽墙减少访存、KV 优化、量化

这里最容易误判的是第三行:算力利用率低,通常第一反应是”算力没用满,去优化算子”——但如果显存同时很高,真正的原因是”卡在显存上,算力只能等着”。两个观测量必须一起看,单看一个会把方向搞反。

另外,采集本身要有清单。一份可用的采集至少要覆盖三类共十几项:性能 KPI(吞吐、TTFT 分布、Token 间延迟分布、成功率)、系统资源水位(显存、算力、带宽、排队深度)、负载与配置上下文(请求长度分布、并发、关键配置)。第三类最容易被漏掉,但它正是归因所需的参照系——没有它,两组数字无法比较。

四、贯穿线:优化是耦合的,不是叠加的

把前面三节连起来,会得到一条比”哪个技术更好”重要得多的判断:

优化技术不是可叠加的独立选项,它们之间有耦合——你选的每一个,都在为下一个瓶颈创造条件。

这条判断有一个非常干净的实例。张量并行本身是”算得快”的优化(把计算摊到多卡),却在推理阶段制造了一个新的存储问题:

  • 为了让 KV 头能整除地分到各卡上,系统会复制 KV 头;
  • 复制的直接后果是每张卡上可用的 KV Cache 变少;
  • 于是最大并发与最大序列长度一起下降,吞吐反而受损。

也就是说:一个”算力维度”的优化,代价落在了”存储维度”上。这类跨维度的代价,只看单项技术的收益是看不见的——而这正是坐标系存在的理由。

耦合链:算力优化如何制造出存储问题,以及解法的代价落到网络维度

下面用一个完整推导把它算清楚。

五、一个完整推导:TP 复制了 KV,DCP 把它切回来

5.1 问题的来源:TP 超过 KV 头数

在 GQA 模型里,Key/Value 头的数量 H = num_key_value_heads 远小于 Query 头数。这个设计本身就是为了压缩 KV Cache——但它同时引入了一个约束:

KV 头必须能整除地分到各张卡上。当张量并行度 TP > H 时,这个整除条件无法满足,系统只能复制 KV 头来凑齐。

后果有两个,都很实在:

  • 每张卡可用 KV Cache 减少(极端情况下按 1/H 缩减),最大支持序列长度下降;
  • 最大并发批数下降,吞吐降低。

注意这里的因果:冲突发生在并行度与模型的一个配置项之间,训练或推理框架本身没有做错什么。 H = 4 这样一个数字,就这样决定了 TP 能开到多少而不再浪费显存。

5.2 解法:沿序列维再切一刀

既然冗余来自”沿头维切分无法再切”,那就换一个维度切:把同一个请求的 KV Cache 沿序列维度再切分到多张卡上——这就是解码阶段的上下文并行(DCP)。

它的存储方式是交错的:同一个请求的 KV Cache 被拆到不同卡上,每张卡只保存其中一部分 token 的 KV。

交错存储:偶数号 token 在 0 号卡、奇数号在 1 号卡,没有一份被重复保存

交错粒度由框架参数控制(默认按单个 token 交错)。这样切分之后,原来被复制的 KV 头不再需要复制——同一份序列数据被分摊到多张卡上,冗余被直接从根上消除。

5.3 它不增加设备,但增加通信

这是 DCP 与前缀阶段上下文并行(PCP)最关键的区别,也是坐标系能立刻说清的一件事:

Prefill 阶段上下文并行(PCP)Decode 阶段上下文并行(DCP)
目标摊薄 Prefill 计算,降 TTFT摊薄 KV Cache,提并发
是否增加设备是——它扩展了设备规模否——只在已有通信域内切分
代价全量 KV 的聚合通信 / 分块收发注意力计算时的跨卡通信

于是 DCP 的大小就有一个明确的有效范围:

dcp_size ∈ [1, tp_size / H],其中 H = num_key_value_heads。

  • 偏小 → KV 冗余较多,但通信少;
  • 偏大 → 冗余降到最低(理论上可到 1/H),但通信增加;
  • 超过 tp_size / H 在理论上仍可继续切分并加速计算,但会引入额外通信开销——是否值得,取决于你的瓶颈在存储还是在网络。

请注意最后这句的形态:它又把问题交回给了判据。坐标系告诉你这个手段在哪一层、动哪个维度;而”要不要用、用多大”仍然要回到第三节那组带阈值的观测。

六、什么时候该下到算子层

前面整套方法在宏观层就完成了大半。算子层是最后才去的地方,而且它有明确的前置条件。一条可用的三阶段路径是:

  1. 宏观参数——批大小、并行度、显存分配、序列长度上限;
  2. 应用与服务层——调度策略、缓存、请求编排;
  3. 算子与图模式——只有在前两层已收敛、硬件仍有余力时才进入。

第 3 步的进入条件必须写清楚,否则会变成”调不动就往下钻”。一个可判定的条件是:

计算利用率 < 85% 且显存 < 85%,但吞吐仍低于预期 → 说明硬件还有余力而瓶颈在实现细节,此时进算子层才有意义。

如果两个利用率都已接近上限,那说明宏观层已经到位,算子层也不会有大收益——继续往下钻只是浪费时间。先证明有余力,再往下走。

七、局限与边界

  • 阈值(90% / 85% / 50% / 70%)是运行经验值,不是硬性物理界线。它们的作用是给出”该看哪边”的判据,换硬件、换模型、换负载都要重标;把某一台机器上的阈值当作通用常数是误用。
  • DCP 的有效范围 [1, tp_size / H] 依赖”KV 头数按整除复制”这一实现前提。不同框架对 KV 头的切分实现不同,范围也可能不同——推导的形态可迁移,具体边界必须按所用框架复核。
  • num_key_value_heads = 4 是特定模型的值,这里用它是因为它足够小、冲突容易发生;换成 KV 头较多的模型,TP > H 这个条件可能永远不触发。
  • 坐标系的价值是”不找错层”,它不保证”找到最优”。它把搜索空间缩小,但格子里该选哪个技术,仍然要靠实测量化。
  • 不含本机实测数据:技术事实(GQA 的 KV 头复制、DCP 的交错切分与有效范围、三阶段路径)来自框架实现与公开资料;阈值来自运行经验。具体数值请以你自己机器上的测量为准。

结论:优化技术要插在坐标里,而不是堆在清单上

回到开头那个 4。

它之所以值得写在这里,是因为它示范了一件事:一个看起来只属于模型配置的小数字,可能会决定你的并行策略能开到多大、显存能装下多少并发。

所以我现在看一个优化时,顺序是固定的:

先给它取坐标(哪一层、动哪个维度、代价落在谁身上),再用量化判据确认瓶颈真的在那里,最后才比较具体技术。

顺序反了会怎样?你会得到一堆各自正确、合起来互相抵消的优化——换句话说,优化的顺序与耦合,比单项技术的优劣更决定结果;而坐标系的作用,就是让”代价落在谁身上”这件事在动手之前就可见。

参考文献

[1] Ainslie, J., Lee-Thorp, J., de Jong, M., Zemlyanskiy, Y., Lebrón, F., & Sanghai, S. (2023). GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245:https://arxiv.org/abs/2305.13245(2026-10-11 实测可达)—— 第五节 num_key_value_heads 这一配置项及其与并行切分冲突的来源。

[2] Kwon, W., Li, Z., Zhuang, S., Sheng, Y., Zheng, L., Yu, C. H., Gonzalez, J. E., Zhang, H., & Stoica, I. (2023). Efficient Memory Management for Large Language Model Serving with PagedAttention. SOSP ‘23. arXiv:2309.06180:https://arxiv.org/abs/2309.06180(2026-10-11 实测可达)—— KV Cache 分页管理与显存占用的公开出处。

[3] Williams, S., Waterman, A., & Patterson, D. (2009). Roofline: An Insightful Visual Performance Model for Multicore Architectures. Communications of the ACM, 52(4). —— “先判断被哪一类上限卡住(算力还是带宽)“这一思路的来源;第三节的判墙判据沿用其形态。

关于证据的核验说明:这是一篇定位方法文章,不含本机实测数据。技术事实(GQA 的 KV 头复制、DCP 的交错切分与有效范围、计算通信融合)来自框架实现与公开资料 [1][2];四个阈值(90% / 85% / 50% / 70%)与算子层进入条件来自运行经验,不是物理界线——换硬件、换模型、换负载都要重标。num_key_value_heads = 4 是特定模型的值;dcp_size ∈ [1, tp_size / H] 依赖”KV 头按整除复制”这一实现前提,推导形态可迁移,具体边界须按所用框架复核。

评论

填个昵称就能发,不需要注册或登录