面灵AI→

腾讯混元 AI Infra 一面

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

  1. TP:Linear、Attention、FFN 分别怎么切?Column Parallel 与 Row Parallel 各切哪个维度、通信发生在哪一步?
  2. TP:QKV 与 Head 怎么分?FFN 的两层怎么组合?为什么常搭配 Column + Row?
  3. TP 是越大越快吗?
  4. 集合通信:为什么需要 All-Reduce、Reduce-Scatter、All-Gather?
  5. 给定 Shape 怎么算通信字节数?TP=2 与 TP=4 有什么变化?
  6. 通信量与 Batch Size、Seq Len、Hidden 的关系是什么?怎么判断是 Communication Bound?
  7. DP:与 TP 的区别是什么?什么时候该加 DP 而不是 TP?
  8. DP 是否复制完整模型?能不能提升吞吐、降低单请求延迟?单卡放不下怎么办?
  9. Serving 的 DP 与训练的 DP 有什么差异?
  10. PP:怎么切模型,为什么实现复杂?Stage 怎么划分、Micro-Batch 与 Bubble 的成因和优化方式是什么?
  11. PP:Stage 不均衡怎么处理?为什么它会增加延迟?你亲手实现过吗?
  12. CP:为什么适合长 Context?Sequence 切开之后 Attention 如何跨卡计算?
  13. CP 与 TP、Sequence Parallel 的区别是什么?引入了哪些通信?

《参考解析》

TP 怎么切,通信在哪一步:张量并行是把单层内部的权重矩阵切开。Transformer 里主要是两种切法:Column Parallel 按输出维度切权重,每张卡算出一部分输出列,输入是完整的,所以前向不需要通信、反向需要对输入的梯度做 All-Reduce;Row Parallel 按输入维度切,每张卡拿到的是部分和,必须在输出侧做一次 All-Reduce 才能得到完整结果。Attention 里的 QKV 投影属于 Column Parallel,输出投影属于 Row Parallel;FFN 的第一层升维是 Column Parallel、第二层降维是 Row Parallel,这样中间夹着的激活值天然是切分的,只在层与层之间各做一次通信。这也是「常搭配 Column + Row」的原因:一列一行的组合能让中间结果保持分片、把通信次数压到最低,如果全用同一种切法,每一层都要额外做一次 All-Reduce。Head 维度上,多头注意力天然适合按 Head 均分,每张卡算自己那几个头,只要头数能被 TP 整除即可;QKV 按列切时要注意每张卡只持有自己那部分头的参数。

集合通信量怎么算,怎么判断通信瓶颈:All-Reduce 在实现上是 Reduce-Scatter 加 All-Gather——前者各卡把自己那份数据的部分和归约好分发,后者再把分片拼成完整结果,这也是这三个原语经常一起出现的原因:需要规约、需要把结果摊开、或者两者都要。按字节数算的话有个常用结论:以 All-Reduce 传输 N 字节为例,环形实现的单卡通信量约为 2N(p-1)/p,p 是卡数,p 增大时它趋近 2N 但不会超过——所以 TP 从 2 到 4,单卡通信量上升但上升幅度递减,真正变化大的是通信次数与同步等待。通信量本身与激活张量大小成正比,也就是和 Batch Size、Seq Len、Hidden 都成正比;TP 的通信量还跟层数成正比。判断是不是 Communication Bound,看两个比值就够了:一是单层计算量与通信量之比(可以用 FLOPs 和字节数按硬件算力、带宽换算成时间),二是实测的通信耗时占单步总耗时的比例,占比随卡数上升而明显变高、且加大 Batch 后利用率上不去,就说明卡在通信上了。

DP、TP 与推理场景的差异:DP 是数据并行——每张卡持有一份完整的模型副本,各自吃不同的数据,反向只对梯度做 All-Reduce。它的优点是实现简单、通信量只跟参数量有关而与激活无关,缺点是显存里要放全量参数、优化器状态和梯度,单卡放不下就无解,同时它不降低单次前向的计算量。TP 相反:把参数和计算都摊到多卡上,单层延迟能降下来,但每层都要通信,卡越多通信占比越高。所以扩展顺序一般是先 TP 到能放下模型、延迟也能接受的范围(通常不超过单机 8 卡,因为要跑在高带宽的 NVLink 上),再往上叠 DP 提吞吐,跨机 PP 用来放更大的模型。能不能降单请求延迟要分开看:DP 只提吞吐,对单请求延迟基本没有帮助;TP 和 PP 才影响单请求延迟,但 PP 因为要串行过 Stage,反而会抬高单请求延迟。推理侧的 DP 和训练的 DP 看着一样,实际差别在于推理是持久化的服务:请求持续到达、Batch 是动态拼的、没有反向和优化器状态,所以显存省下不少,换来的是 KV Cache 和权重的显存占用,调度上还要考虑连续批处理、请求级负载均衡和 KV Cache 的分片。单卡放不下时推理侧通常走 TP 加 PP 的组合,并配合 KV Cache 量化、分页管理等手段。

PP 的难点与 Bubble:流水线并行按层把模型切成若干 Stage 分到不同卡上,卡之间只需要传边界处的激活值,通信量比 TP 小得多,可以跨机扩展。它实现复杂的地方在于调度:为了让所有 Stage 都忙起来,一个 Batch 要被切成多个 Micro-Batch 依次喂进去,前向和反向交错执行,还要手工管理激活值的保存与释放、跨 Stage 的梯度回传、以及与 DP、TP 的组合关系。Bubble 的成因是流水线的填充与排空:启动阶段只有第一个 Stage 有活干,收尾阶段反过来,中间还有各 Stage 耗时不同带来的等待。优化手段有几个方向——增加 Micro-Batch 数量(Bubble 占比近似与 (p-1)/m 相关,m 是 Micro-Batch 数)、把 Stage 划分得尽量均衡(按计算量而不是按层数切、必要时把 Embedding 和 Loss 单独拆出来)、以及用交错式调度让每张卡持有多个不连续的 Stage 提高填充效率。Stage 不均衡会直接放大 Bubble,木桶效应下最慢的 Stage 决定整条流水线的节奏。PP 增加延迟的原因是数据必须一趟趟穿过所有 Stage,Micro-Batch 越多、吞吐越高但尾延迟越长,所以训练追求吞吐、推理追求延迟时对 PP 的态度完全不同。面试官问「有没有亲手实现过」,是想区分读过论文和真正动手写过——如果只是用过 DeepSpeed、Megatron 这类框架的配置,就如实说清自己调到哪一层、观察过哪些指标。

CP 与长上下文:Context Parallel 是把序列维度切开,适合长上下文的原因很直接:Attention 的计算和 KV Cache 都随序列长度增长,当单卡连一条长序列的 KV 都放不下时,只能沿序列切。切开之后每张卡只持有自己那段序列的 Q、K、V,Q 与本地 K 做注意力得到局部结果,但每个 token 还要看到其他卡上的 K/V,所以需要跨卡交换 K、V——常见实现是用环形注意力,各卡之间按环依次传递 KV 块并累加部分注意力结果,配合在线 Softmax 保证数值稳定。它和 TP 的区别在于切的是序列而不是权重:TP 每层都要通信、通信量与激活同阶,CP 的通信主要集中在注意力的 KV 交换上,对 FFN 这类逐 token 计算的部分不需要通信。和 Sequence Parallel 的区别则在于后者的目标是省激活显存——它把 LayerNorm、Dropout 这类逐 token 操作按序列切分,与 TP 配合使用(在 TP 的通信空隙里顺带完成),并不解决单卡放不下整条长序列的问题。CP 引入的通信主要是 KV 的 All-Gather 或环形 P2P 传递,以及反向时对应的梯度规约,实际代价取决于序列长度、头数和是否用了 GQA 这类减少 KV 体积的结构。