腾讯混元 AI Infra 一面(同场重复投稿):张量并行/数据并行/流水线并行的连续追问
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 讲解张量并行 TP 的核心逻辑,如何对 Linear、Attention、FFN 完成权重切分?列并行、行并行分别切哪一维、通信发生在哪个阶段?
- 大模型 QKV 矩阵与多头注意力头,具体如何做张量并行切分?
- FFN 两层网络为什么通常采用「列并行 + 行并行」的组合方式?
- TP 并行规模越大训练速度一定越快吗?请说明瓶颈与限制。
- 张量并行中 All-Gather、Reduce-Scatter、All-Reduce 分别解决什么问题?如何根据 Tensor Shape 计算实际通信量?
- 如何判断大模型训练进入通信瓶颈?通信量和序列长度、隐层维度的关系是什么?
- 详细区分 DP 数据并行与 TP 张量并行的本质差异,集群扩容时如何判断该加 DP 还是 TP?
- 数据并行能否解决单卡放不下模型的问题?训练 DP 和推理 Serving-DP 有什么区别?
- 流水线并行如何切分模型 Stage?流水线 Bubble 气泡如何产生、怎么优化降低损耗?
- 为什么 PP 流水线并行会增加推理延迟?多 Stage 负载不均衡如何处理?
- 上下文并行为什么适配超长序列场景?序列切块后,跨卡如何完成完整的 Attention 计算?
- 简述 QQ 空间好友动态推荐开发思路,如何实现数据管理、行为仿真、内容打分排序、TopN 推荐全流程?
《参考解析》
张量并行的切分规则可以归纳成一句话:列并行切权重、行并行切输出,通信点一前一后。 对 Y = XW,列并行把 W 按输出维(列)切成 N 份,每张卡持有 W_i(形状 [in, out/N]),各卡用完整输入算出自己那部分输出的部分和不需要通信,得到 [batch, out/N];因为输出被切开了,后面接的行并行层正好需要完整的输入才能算,所以在进入行并行层前要做一次 All-Gather 把列并行的结果拼回完整激活。行并行反过来把 W 按输入维(行)切成 N 份,每张卡持有 [in/N, out],各卡用自己那部分输入算出完整维度的部分和,因此结果需要在行并行层之后做一次 All-Reduce 求和。这是 Megatron-LM 里最核心的一条规律,面试时能把这个「切什么维 → 通信什么操作 → 在哪个位置通信」讲清楚,后面所有追问都能顺着推。
Attention 的切分按头走,是最自然的一维。 多头注意力天然有 num_heads 这个可切维度:把 Q、K、V 的投影矩阵按头数均分到 N 张卡,每张卡负责 num_heads/N 个头,各自独立完成自己那部分 softmax(QK^T/√d)V,这一步完全不需要通信——这也是为什么 Attention 在 TP 里比 FFN 更省通信。QKV 打包成一个大矩阵时,列并行的切分是按输出维切,切出来的恰好对应不同的头(注意要保证每个头对应的三块 Q/K/V 落在同一张卡上,所以布局上要把 QKV 交错排列)。多头注意力的输出投影是行并行,得到部分和后再 All-Reduce。
FFN 用「列并行 + 行并行」组合是为了把整条链路里只留一次通信。 第一层 Y = GeLU(X A),A 是 [hidden, 4*hidden],按列切成 [hidden, 4*hidden/N]——各卡拿到中间维度的一部分,GeLU 是逐元素非线性、可以安全地在切分后独立作用(这一点很关键:如果把行并行放在前面,GeLU 就不能在部分和上直接算)。第二层 Z = Y B,B 是 [4*hidden, hidden],按行切成 [4*hidden/N, hidden],各卡算出 Z 的部分和,最后 All-Reduce 合并。中间那次 GeLU 之前不需要 All-Gather,因为在同一次前向里列并行的输出形状正好匹配行并行的输入形状——这就是组合的意义:一个 Transformer 层里前向只通信 2 次(Attention 后 All-Reduce 一次、FFN 后 All-Reduce 一次),反向对应再各一次。
TP 规模不是越大越快,通信量与计算量之比才是决定项。 每层 TFLOPS 计算量大致随 batch × seq × hidden² 增长,而通信量是 batch × seq × hidden 量级——也就是说计算量随模型宽度呈平方增长、通信量只呈线性增长,所以模型越宽、TP 越划算。反过来,当 hidden 比较小、batch 或序列比较短时,通信占比迅速上升,All-Reduce 的时延和带宽就会成为瓶颈,加卡反而变慢。另外 TP 是层内并行,每层都要通信、通信频次极高,因此强依赖机内 NVLink 这种高带宽低时延互联;跨机做 TP 通常得不偿失。
三种集合通信按「输入输出谁完整」区分,通信量都按传输的数据量算。 All-Gather:每卡持有一片、输出每卡都有完整的 N 片(通信量 N-1)/N × 数据量 也算作每卡发送 (N-1)/N × S)。Reduce-Scatter:每卡持有完整数据、输出是各卡拿到归约后的一片(每卡发送 (N-1)/N × S)。All-Reduce:所有卡归约后每卡都有完整结果,等价于 Reduce-Scatter + All-Gather,每卡约发送 2(N-1)/N × S。Ring 算法下通信量基本与卡数无关(每卡 2S 左右),这解释了为什么 All-Reduce 在 TP 里通常是通信量而不是卡数的瓶颈。计算时把 Tensor Shape 具体代入:例如 hidden=8192、batch×seq=16384、bf16,则 S ≈ 16384 × 8192 × 2B ≈ 268MB,All-Reduce 每卡就要搬 ~536MB。
判断是否进入通信瓶颈,看的是「通信时间占比」而不是绝对值。 实操手段有几种:用 profiling 工具(Nsight、torch profiler)打时间线,看 NCCL kernel 的累计占用比例,超过 20%~30% 就要警惕;看 MFU(模型浮点利用率),TP 增大后 MFU 明显下降往往就是通信吃掉了收益。通信量随序列长度和 hidden 维度的关系可以概括为:通信量与 batch × seq × hidden 成正比(线性),而计算量与 batch × seq × hidden² 成正比(按宽度平方)。所以序列变长对通信和计算的影响是同比例的,不改变比值;hidden 变大则计算量涨得更快,通信占比下降——这就是为什么大模型比小模型更愿意用大 TP。
DP 与 TP 的本质差异是「切数据还是切模型」。 DP 每张卡持有完整模型副本、吃不同的数据分片,梯度通过 All-Reduce 同步,它的通信量随参数量增长、但只在每步结束时通信一次,因此对带宽要求相对温和、可以跨机跑;TP 是切模型本身,每层都要通信,对互联带宽要求极高。扩容选择看两个约束:单卡放不放得下(放不下就只能上 TP 或 PP)、以及通信能不能被计算掩盖。工程上的常见组合是「机内 TP × 机间 DP」,再叠加 ZeRO/FSDP 把优化器状态和梯度分片,缓解 DP 的显存与带宽压力。
数据并行解决不了「单卡放不下模型」。 DP 的前提是每张卡都能装下一个完整副本(含权重、梯度、优化器状态),参数量超过单卡显存时 DP 直接无法启动——这正是 TP、PP、 ZeRO 这类模型并行方案存在的理由(ZeRO 严格说是「切分 DP 的状态」而不是切模型,它把优化器状态、梯度、参数分片存放,需要时 All-Gather,能在显存意义上救急,但每步要多一次参数聚合通信)。训练 DP 与推理 Serving-DP 的区别在于目的:训练的 DP 是为了扩大全局 batch、提高吞吐并让梯度更稳,需要反向与梯度同步;推理的 DP 只是为了把请求分散到多个副本上提升并发,副本之间不需要通信,是纯粹的水平扩展。所以推理侧更关心负载均衡、KV Cache 显存和首 token 延迟,训练侧才关心梯度同步开销。
流水线并行按层切 Stage,Bubble 来自「前向填充、后向排空」的天然空转。 切分原则是让各 Stage 的计算量尽量均衡(按层数或按显存占用),并把通信量小的边界作为切点。Bubble 的产生原因是:微批次串行流过流水线时,开头几个气泡在等待前面的 Stage 出结果,结尾几个在等待后向回传。经典优化有:提高微批次数(Bubble 占比近似 (p-1)/(m+p-1),m 越大越小,但微批太小会降低单批计算效率、增加通信次数)、1F1B 交织调度让前向和后向交错填满空转、交错式/虚拟流水线(把每个设备上的层再拆成两段 V 形排布,把 Bubble 减小到约 1/p)、以及 ZeRO 与 PP 的组合。负载不均衡的解法是调整切分点做重平衡,或者让通信更重的 Stage 少分计算量,也可以用 profile 按实测耗时而非层数来切。
PP 会增加推理延迟,因为它把一次前向变成了多跳。 训练里可以靠大量微批把流水线填满、换取吞吐;但推理的请求是延迟敏感的,尤其是单条请求只能一个个 Stage 串行往下走,每跳都要传激活(可能还要跨机),于是首 token 延迟随 Stage 数线性增加。减轻办法有:把 PP 只用在吞吐优先的离线批推理、在线服务优先用 TP、用 Continuous Batching 把多请求的 Stage 填满、把相邻 Stage 放在同一台机器上(NVLink 或共享内存通信)、以及在显存允许时减少 Stage 数。这些取舍也是为什么真实生产里「TP 在机内、PP 跨机」是最常见的拓扑。
上下文并行把序列维度切开,用环形通信补上跨块的注意力。 超长序列下,激活和 KV Cache 按序列维度太大,单卡放不下,所以把序列切成若干块分给不同卡(每卡持有 seq/N 的 token),FFN 和 LayerNorm 这类逐 token 的操作可以直接本地算。难点在 Attention:每个 token 的注意力需要看到全序列的 K/V,所以要跨卡交换。主流做法是 Ring Attention——各卡把自己的 KV 块沿环传给下一张卡,边传边算本卡 query 对自己收到的那块 KV 的注意力并在线累加(配合 online softmax 的 running max/sum,做到不需要一次性存下完整注意力矩阵),转满 N-1 圈就覆盖了全部 KV,通信量约等于把 KV 环传一遍,且能与计算重叠。此外还有 DeepSpeed-Ulysses 那类把 head 维和序列维互换的方案,通信走 All-to-All,适合 head 数较多的模型。
QQ 空间好友动态推荐的设计题,答的是「闭环」而不是模型。 可以按四段组织。数据层:离线数仓沉淀用户画像、好友关系、内容特征与历史行为(曝光、点击、点赞、评论、停留时长),线上明细日志回流;关键是样本构造要处理曝光偏差和位置偏差。仿真层:用历史日志回放或离线模拟环境评估策略,能在不打扰真实用户的前提下试新策略,注意要按时间切分而不是随机切分,避免未来信息泄漏。打分排序层:召回(多路:社交关系、协同过滤、内容热度、向量召回)→ 粗排 → 精排(CTR/CVR 多目标,用 MMoE 这类多任务结构平衡点击与互动)→ 重排(打散同一作者、控制相似内容的重复、老友新内容的探索配额)。最后是 TopN 输出与在线服务:特征实时化、模型增量更新、A/B 实验与指标看板,并把「用户长期满意度」这类滞后指标单独监控,避免只优化短期点击。补一句社交场景的特殊性会加分:好友动态里「关系强度」和「时效性」的权重远高于通用信息流,且要处理冷启动新好友与新内容。