周末你负责操办一场 100 桌的婚宴,每桌要上 10 道菜。一个人显然做不完——灶台不够、人手不够、时间更不够。怎么办?第一种办法:多开几个厨房,每个厨房都按同一本菜谱做,一桌派一个厨房负责。第二种办法:一个厨房内部按上菜顺序切成几个工位——备菜台只管凉菜、炒锅位只管热菜、蒸箱只管汤羹,菜一道接一道流过工位。第三种办法:某一道硬菜,比如一整只烤全羊,单个灶台放不下,干脆让四位厨师围着同一个烤炉,一位切配、一位调味、一位看火、一位装盘,互相递料配合得天衣无缝。 今天的难题是:菜谱有 175 道,每桌还全是硬菜,任何单一办法都不够。真正的大型饭店必须三招齐上:厨房复制、工位切菜、硬菜合做。本文要讲的,就是把“按菜切流程”和“同一道菜分多人做”这两招组合起来的方法——什么菜该给哪个工位、几位厨师怎么配合、料怎么传不打架、闲下来的厨师怎么安排。看完你就能看懂主流大模型训练框架里的并行配置文件了。
学会流水线与张量并行组合,你就能独立设计千亿级模型的多卡训练方案,看懂 3D 并行配置,并在实际训练中快速定位显存与通信瓶颈。
可视化演示
展示BST的插入构建、查找路径和中序遍历过程,切换模式查看核心操作的不同执行流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
BST 插入构建过程 紫色为已构建节点,金色为当前插入路径 左子树<根<右子树 每个新节点从根开始比较,小于根走左子树,大于根走右子树
组合背景动机
回到婚宴的比喻。100 桌宴席、每桌 10 道菜,你发现光有“按菜切流程”还不够:有一道硬菜本身太大,单独一个工位的厨师也端不动。此时必须再叫几位厨师围在同一道菜前,一人切肉、一人配菜、一人掌勺、一人装盘——这就是“同菜分人做”。也就是说,流水线负责把菜谱切成段落,张量并行负责把某一道巨型硬菜再切成小块分给多人。两个维度叠加,才装得下真正的满汉全席。
技术世界里,这一幕每天都在发生。大语言模型的参数从 10 亿涨到 1750 亿(如 GPT-3),单张 A100 显卡只有 80GB 显存,而 1750 亿参数仅权重一项用 FP16 存储就需要约 350GB,单卡连参数都放不下,更别提训练还要存梯度和优化器状态。于是训练框架引入了三种切分:数据并行复制多个完整模型、流水线并行按层切段、张量并行把每一层的权重矩阵切开。当模型大到“层数很多”和“单层很大”两个问题同时出现时,流水线和张量并行就必须组合上场。
组合并行在业界常被称为“3D 并行”,因为三个并行维度像一个三维立方体,每个维度管一件事。要算总共需要多少张显卡,只需把三个维度的并行度乘起来:
回到比喻:饭店最终的总人手,从来不是简单相加,而是“几个厨房 × 每厨房几个工位 × 每工位几位厨师”。理解了这三个维度各自的角色,下面就能看清它们各自负责切什么了。
- GPU 总数 N_GPU整个训练集群可用的显卡总数,相当于饭店动用的厨师总人数。
- 数据并行度 P_data把整套宴席复制几份,同时开几套流水线处理不同的客人订单。
- 张量并行度 P_tensor同一道菜由几位厨师围着同一个灶台协作,对应权重矩阵被切成的份数。
- 流水线并行度 P_pipeline按上菜顺序把厨房分成几个工位,对应模型按层切成的段数。
并行维度对比
假设你现在当上了这家大饭店的厨师长,手里有一本 32 层的菜谱。三种分工方式各有各的切法:按“菜”切,是把第 1 到第 8 道菜分给工位一、第 9 到第 16 道菜分给工位二——这是流水线并行,切的是模型的“层序列”;按“菜里的原料”切,是让四位厨师同时做同一道菜,一个切肉、一个切菜、一个掌勺、一个装盘——这是张量并行,切的是某一层内部的“权重矩阵”;整间厨房复制一份,搬到隔壁再开一套同样的流水线——这是数据并行,切的是“数据的批次”。
从技术上看,三个维度有着本质区别。流水线并行把 Transformer 的层序列切成 P_pp 段,每张卡只持有其中一段的完整参数,工位之间只传递“半成品”(每层的输出激活张量),通信稀疏。张量并行则把每一层内的 QKV 投影矩阵、MLP 全连接矩阵按行或列切开,同一层的多张卡需要频繁同步彼此的中间结果,通信密集。数据并行不减少任何一张卡的模型显存——每个副本都拿着完整模型,它只负责用不同数据喂出梯度再互相平均。
三种切法对显存的影响也可以直接算出来。模型参数被流水线和张量两个维度同时分摊,每张卡存放的模型参数占比为:
一句话回扣:储物柜的存货,被“分段”和“分块”两个动作共同摊薄;但要小心,张量并行摊薄显存的同时,也带来了每层都要发生的沟通成本——这正是下一节要平衡的重点。
- 每卡模型显存 M_每卡单张 GPU 需要常驻的模型参数量,相当于每位厨师手边的工作原料量。
- 模型总显存 M_模型全部模型参数的存储占用,好比整本菜谱所有食材的总量。
- 张量并行度 P_tensor权重矩阵被切成的份数,分母里出现它,表示每张卡只拿矩阵的一块。
- 流水线并行度 P_pipeline模型层被切成的段数,每张卡也只持有其中一段的完整权重。
切分组合策略
既然两个维度要一起上,先切哪个?回到厨房:你得先确定每道菜属于哪个工位(流水段),再决定这道菜由几个人合作(张量切分)。顺序不能反——如果先让四位厨师围着一道菜切好料,却发现这道菜被分到了两个不同的工位,料就白切了。同理,组合并行必须“先划层、后切权”:先把 N 层模型均匀分给 P_pp 个流水级,再把每个流水级内部的每一层权重矩阵按 P_tp 切块。
具体操作上有两条硬性规则。第一,层的总数必须能被流水线并行度整除,否则各工位分到的层数不均匀,层数少的工位会提前完工空转,层数多的工位拖垮整个流水线。第二,每一层的注意力头数必须能被张量并行度整除,因为多头注意力是按“头”分组的——张量并行把 32 个注意力头分给 4 张卡,每卡负责 8 个头;如果头数除不尽,某些卡就会多分到半个头,权重形状直接对不上。
这两个维度分别决定了“每一级有几层”和“每张卡有几个头”,可以用两个式子同时刻画:
回到比喻:菜单要先排好菜序,再给每道菜分人手;同理,先定流水段边界(哪些层在哪个工位),再在段内做张量切分(矩阵怎么分块)。切分方案落定之后,下一个绕不开的问题是:料怎么传?
- 每级层数 L_stage每个流水工位负责的 Transformer 层数量,要求是整数且各工位相等。
- 总层数 N_layers 与流水线并行度 P_pipelineN_layers 必须被 P_pipeline 整除,否则无法做到均匀分配,会人为制造瓶颈。
- 每卡头数 H_local张量并行时每张卡实际负责的注意力头数量,对应每个厨师分到的那几份配料。
- 总头数 H_heads 与张量并行度 P_tensor总头数必须被 P_tensor 整除,多头注意力才能按完整“头”为单位切分,不产生残缺计算。
通信拓扑设计
四位厨师围着同一个烤炉做烤全羊,切配师傅每切下一块肉就要递给掌勺师傅,一来一回极其频繁——这是张量并行:同层的多张卡每算一小步就要做一次 All-reduce 全量同步,频率极高。而工位之间传菜就从容得多:备菜台把装好盘的凉菜用手推车推到下一个工位,一桌只推一次——这是流水线并行:只在工位边界传递一次激活张量,频率低得多。
这种频率差异直接决定了硬件选型。张量并行的 All-reduce 发生在每一层的前向和反向中,一个 Transformer 层大约要同步 4 次,而且必须等到同步完才能继续算下一步,属于“卡着算”的同步通信,必须走 GPU 之间的 NVLink 高速互联。因此张量并行度绝不能超过一个节点内的 GPU 数量——节点内 NVLink 是全互联的,跨节点只能走慢得多的 InfiniBand 或以太网。流水线并行则不同:它只在工位边界做点对点传输,单次数据量大但次数少,可以搭配异步流水线做“边算边传”,用通信与计算重叠来隐藏延迟。
把通信量写成公式,能直观看到两者量级差异。设层数为 N_layer,批次、序列长度、隐藏维度乘积为 bsh:
回到厨房画面:调料小碟要放在伸手可及的地方(NVLink 同节点),传菜推车可以走远路(IB 跨节点)。搞清了这个主次关系,下一步就要算一算:分工带来的显存节省,和等人等料造成的空转,到底怎么权衡?
- 分子 4 × N_layer每层前向反向各做两次 All-reduce,共 4 次;层数越多,张量并行同步次数线性增长。
- 分母 2 × (P_pp − 1)流水线有 P_pp − 1 个边界,每个边界前向反向各传一次激活,共 2 次。
- 比值含义分子对应“同灶台递料”次数,分母对应“手推车传菜”次数,比值越大说明组合方案越依赖高速节点内互联。
显存计算平衡
储物柜和灶台的矛盾来了。分工越细,每位厨师手边要放的原料越少(显存越省),但互相递料的次数越多(通信越贵);流水段切得越多,工位之间传菜越频繁,而且一道菜在上下游之间的等待时间也越长——这就是“气泡”。气泡指的是流水线上某些工位没活干、干等着的时间,好比婚宴上宾客还没吃完凉菜,热菜工位的厨师只能站在灶台边看着火发呆。
更精确地说,显存账单由三部分构成:模型参数与梯度、优化器状态、激活值(每层的中间输出,相当于做菜过程中的半成品)。流水线和张量并行组合能显著压缩第一部分——参数按两个维度分摊。但第二部分激活值有个特点:它不随张量并行度线性下降(LayerNorm、Dropout 等算子仍然需要全量激活),而是主要和“同时有多少个微批次在流水线上”成正比。至于第三部分,优化器状态也要按参数占比同步分摊。
于是工程上真正要权衡的是“流水线级数”和“微批次数量”对气泡的影响。当有 P_pp 个流水级、把一个大批次切成 M 个微批次时,气泡占比有一个经典的估算公式:
一句话回扣:省下来的储物柜空间,有一部分被“等人等料”的时间悄悄吃掉了。为了不让空转太难看,业界发明了错峰上菜的调度办法——这正是下一节的主角。
- 分子 P_pp − 1流水线刚启动和即将结束时,首尾工位必须等待的空闲槽位数。
- 分母 P_pp + M − 1完成 M 个微批次理想上需要经历的总时间段数,等于级数加批次数减一。
- 微批次 M 的作用M 越大,分母越大,气泡占比越小;但 M 太大又会撑爆激活值的显存。
- 级数 P_pp 的作用级数越大,分子分母同时变大,气泡率整体上升——多切段省了参数显存,却赔了利用率。
调度分配策略
婚宴上菜不能等第 1 桌的 10 道菜全部做完再上第 2 桌,那样第 2 桌客人要饿到半夜。聪明的厨师长会错峰:第 1 桌的凉菜刚端出去,备菜台就开始备第 2 桌的凉菜;第 1 桌的热菜下锅时,第 2 桌的凉菜已经上桌。训练大模型也是这个道理,把一个大的训练批次切成 M 个微批次(micro-batch),让它们像流水一样一个接一个涌进流水线。
最早的 GPipe 方案是“先全部前向、再全部反向”:所有微批次先从前到后做完前向,攒下一大堆激活值,然后再从后到前做反向。这样做实现简单,但所有微批次的中间结果必须同时存活,显存峰值极高——相当于把 100 桌的半成品菜全堆在厨房台面上。后来提出的 1F1B(One-Forward-One-Backward)调度则规定:每个工位做完一个微批次的前向,只要条件允许就立刻做反向,前向反向交替进行。这样流水线上同时存活的微批次数量被压到大约一个流水线级数 P_pp,显存峰值大幅下降。
1F1B 的显存占用可以概括为:常驻的参数、梯度、优化器状态(M_参数),加上最多 P_pp 份微批次激活值:
回到宴席:1F1B 的精髓是“随做随清”,不让半成品堆满整个后厨。前向、反向交错推进,显存峰值被压住,气泡也被微批次填掉大半——调度方案定好了,最后一步就是把这一切写进训练框架的配置文件。
- 参数类显存 M_param当前卡持有的模型权重、梯度和优化器状态,数值由 TP×PP 分摊决定。
- 单微批次激活显存 M_act一个微批次在一层中产生的中间激活值,相当于一份菜在某个工位的半成品台面。
- 流水级数 P_pp1F1B 下同时存活的微批次数量约为 P_pp,因此激活显存要乘上这个系数。
- 对比 GPipeGPipe 需要同时保留全部 M 个微批次的激活,若 M 远大于 P_pp,其显存峰值会远高于 1F1B。
工程配置实践
现在你已经是这家大饭店的厨师长了,手里攥着一份排班表。最流行的开源框架 Megatron-LM 里,排班表就两行参数:--tensor-model-parallel-size 控制张量并行度(几位厨师合做一道菜),--pipeline-model-parallel-size 控制流水线并行度(几个工位接力)。下面是一个 TP=8、PP=8 的典型配置:
配置时记住三个口诀。第一,“TP 不出节点”:张量并行度上限是单节点 GPU 数,8 卡的节点最多 TP=8,因为张量通信必须走节点内 NVLink。第二,“PP 受整除约束”:流水线并行度必须能整除模型层数,32 层模型可以 PP=8(每级 4 层),但不能 PP=12。第三,“DP 最后补足”:确定 TP 和 PP 后,用数据并行度把剩余 GPU 填满,即 N_GPU = DP × TP × PP。经验上,训练千亿模型常用 TP=8、PP=8、DP 视集群规模取 2 到 16。
排查问题时也按这个顺序来:先看整除约束是否满足,再看 TP 是否跨了节点,最后用性能分析工具(如 PyTorch Profiler、Nsight Systems)看通信时间占比。两个整除约束是配置文件能跑起来的前提:
回到厨房:排班表最终要回答三个问题——几个厨房(DP)、几个工位(PP)、每工位几个人(TP)。口诀“TP 不出节点、PP 看层数、DP 补位”就是所有大模型训练团队的共同经验。组合并行的原理与配置,到此闭环。
- 层数整除 PP流水线按整层切分,每级分到整数层,否则有的工位多一层,变成全局最短木板。
- 头数整除 TP按整“头”切分注意力,头数除不尽就会产生无法合并的残块。
- 工程意义这两个条件相当于排班表的基本纪律——先满足“每工位层数一致、每厨师头数一致”,再谈优化吞吐。
--tensor-model-parallel-size 8 \--pipeline-model-parallel-size 8 \--micro-batch-size 1 \--global-batch-size 256
AI 应用场景
场景 1:千亿参数 LLM 的预训练部署
阶段:模型训练(预训练)
解决的问题:175B 参数的模型单卡根本放不下,仅权重 FP16 就需要约 350GB 显存,传统单卡训练直接 OOM。通过 TP=8、PP=8、DP=N 的组合,把权重、梯度、优化器状态摊到几十上百张卡上,显存问题迎刃而解。
具体案例:某团队用 64 张 A100-80G 训练类 GPT-175B 模型。8 卡一个节点,节点内 NVLink 全互联,因此 TP=8 限制在节点内;8 个节点之间用 InfiniBand 组流水线,PP=8;节点间再叠加数据并行。配置 --tensor-model-parallel-size 8 --pipeline-model-parallel-size 8 --micro-batch-size 1 --global-batch-size 512,配合 1F1B 调度与激活重计算,最终将每卡显存控制在 70GB 以内。
场景 2:多节点集群的算力规划与选型
阶段:算力规划与成本预算
解决的问题:租用云上 GPU 集群时,面对不同实例规格(8 卡节点、16 卡节点),不知道该怎么组合并行参数才能既满足显存、又不浪费带宽。组合并行的约束(TP ≤ 节点卡数、层数整除 PP)能直接指导选型。
具体案例:某公司要微调 70B 模型,有 8 卡 A100 节点。先按整除约束枚举可行方案:70B 模型 80 层、80 注意力头,TP 可取 8,PP 可取 8(80/8=10 层每级、80/8=10 头每卡),剩余 GPU 用 DP 填满。最终选定 TP=8 + PP=8 + DP=2 共 128 卡,气泡率约 7%,比盲目选 TP=4+PP=16 的方案吞吐高 18%。
场景 3:训练过程中的显存 OOM 排障
阶段:训练调优与故障排查
解决的问题:TP+PP 组合训练时频繁出现 OOM,传统做法是盲目缩小 batch 导致吞吐骤降。正确排查顺序是:先用显存账单公式判断是参数、优化器还是激活值超限,再针对性调整 TP、PP 或微批次数量。
具体案例:某 13B 模型训练时 OOM,通过 profiler 发现激活值占显存 60%。团队将微批次从 4 降到 2、开启 1F1B 和激活重计算,显存占用立刻下降 40%,吞吐只损失 5%;若当初直接增大 TP 反而会因为跨节点通信更慢。此排查流程已成为该团队的标准化排障手册。
Python 演示
"""Demo of 3D parallel plan enumeration: check divisibility and bubble ratio""" class ParallelConfig: def __init__(self, layers, heads, gpus_total, gpus_per_node, n_microbatches): self.layers = layers self.heads = heads self.gpus_total = gpus_total self.gpus_per_node = gpus_per_node self.n_microbatches = n_microbatches def find_plans(self): """Enumerate feasible (data_parallel, tensor_parallel, pipeline_parallel)""" plans = [] for p_tp in (1, 2, 4, 8): if self.heads % p_tp != 0: continue if p_tp > self.gpus_per_node: continue for p_pp in (1, 2, 4, 8, 16): if self.layers % p_pp != 0: continue if self.gpus_total % (p_tp * p_pp) != 0: continue p_data = self.gpus_total // (p_tp * p_pp) plans.append((p_data, p_tp, p_pp, self.bubble_ratio(p_pp))) return plans def bubble_ratio(self, p_pp): """Bubble ratio = (pp - 1) / (pp + microbatches - 1)""" return (p_pp - 1) / (p_pp + self.n_microbatches - 1) def main(): config = ParallelConfig(layers=32, heads=32, gpus_total=64, gpus_per_node=8, n_microbatches=32) print("64 GPUs / 8 per node: feasible 3D parallel plans") for p_data, p_tp, p_pp, bubble in config.find_plans(): print(" data=%2d tensor=%d pipeline=%2d bubble=%.1f%%" % (p_data, p_tp, p_pp, bubble * 100)) if __name__ == "__main__": main()
if self.heads % p_tp != 0:注意力头数必须能被张量并行度整除,否则多头注意力无法按整“头”均分。if p_tp > self.gpus_per_node:张量并行度不能超过单节点卡数,否则 All-reduce 要走慢速跨节点网络。if self.layers % p_pp != 0:层数必须能被流水线并行度整除,保证每个工位分到的层数一致。p_data = self.gpus_total // (p_tp * p_pp)用总卡数反推数据并行度,凑满 N_GPU = DP × TP × PP 的 3D 组合。return (p_pp - 1) / (p_pp + self.n_microbatches - 1)气泡率公式:级数越大气泡越大,微批次越多气泡越小(但显存会涨)。for p_data, p_tp, p_pp, bubble in config.find_plans():遍历所有可行方案并打印气泡率,便于对比选型。
常见误区
误区“TP 切得越细,每卡显存越小,那我把 TP 调到 32 甚至 64,不就能训练更大的模型了吗?”
正解TP 的通信发生在每一层、且必须等 All-reduce 完成才能继续计算;TP 超过单节点卡数后,通信从 NVLink 降级到 InfiniBand,带宽下降一个数量级,算力利用率可能跌到 50% 以下。TP 的上限由通信拓扑决定,而不是由显存决定。就像四位厨师围一个灶台还能递料,32 位厨师围着同一个灶台只会互相撞手,传料的功夫比做菜还久。
为何常见:人们直觉认为“切得越细分摊的人越多”,却忽略了合作本身的同步开销随人数超线性增长。
误区“流水线只是把层分到不同卡上,每张卡各算各的,应该不需要通信吧?”
正解每个微批次在流水级之间传递的是完整激活张量(hidden states),前向和反向各传一次;对 175B 模型,一批数据的激活就有几百 MB,单次传输量很大。此外还有等待上下游产生的“气泡”时间开销。准确说法是:流水线通信是“低频率、大包”,张量并行是“高频率、中包”,两者都有通信成本。
为何常见:流水线的切分单位是“层”,看起来层级之间天然独立,人们容易忽略层与层之间必须传递中间结果的数据依赖。
误区“气泡公式里微批次数量在分母上,切得越多气泡越小,那把 1 个 batch 切成 1000 份不就好了?”
正解微批次越多,同时“挂”在流水线上的激活值越多(1F1B 下约为 P_pp 份),激活显存随之上涨;且微批次过小会导致每个 GPU kernel 的矩阵太小,算力利用率下降。实践中微批次数量取流水线级数的 1~2 倍即可,例如 PP=8 时取 16~32,让气泡和显存同时处于可接受区间。
为何常见:只盯着气泡公式的单调递减性质,忽略了公式背后的激活显存和计算效率约束。
误区“反正都是把模型拆开,先设 TP 还是先设 PP,结果应该一样吧?”
正解正确顺序是“先定 TP(受单节点卡数约束),再定 PP(受层数整除约束),最后用 DP 补足 GPU 数量”。TP 要求同节点内的 NVLink 高速互联,PP 可以跨节点。如果先把 PP 定得很大、再发现 TP 必须跨节点,通信就会频繁穿越慢速网络,性能断崖式下跌。三个维度在公式里地位对称,但在硬件拓扑中完全不对称。
为何常见:公式 N_GPU = DP × TP × PP 里三个维度看起来是纯乘法关系,让人误以为它们互相独立、顺序随意。
面试题
Q1. 流水线并行切分模型的基本单位是?
- A.按词的维度切开词表
- B.按层序列切分给各级← 正确答案
- C.按样本批次切分数据
- D.按优化器状态切分
答案:B。流水线并行把模型按“层”为基本单位切成连续的多段,每段分配给一个流水级;词表切分属于张量并行,样本切分属于数据并行,优化器状态切分不属于模型结构切分。
Q2. 某模型注意力头数为 40,下列哪个值能作为张量并行度?
- A.TP=4 可整除 40← 正确答案
- B.TP=6 可整除 40
- C.TP=9 可整除 40
- D.TP=11 可整除 40
答案:A。张量并行按整“头”切分注意力,头数必须能被 TP 整除。40 只能被 4 整除(40÷4=10),6、9、11 均不能整除 40,所以答案为 A。
Q3. 与 GPipe 相比,1F1B 调度最大的优势是?
- A.参数显存占用减半
- B.激活显存峰值更低← 正确答案
- C.通信总次数降为零
- D.不需要切分微批次
答案:B。GPipe 要等所有微批次前向完成再统一反向,激活值全部存活;1F1B 前向反向交替,同时存活的微批次约为流水级数 P_pp,激活显存峰值显著下降。参数显存由 TP/PP 决定,通信不会归零,微批次仍然要切。
Q4. 关于张量并行与流水线并行的通信特征,正确的是?
- A.张量通信稀疏且包小
- B.流水线通信每层发生
- C.张量通信每层多次发生← 正确答案
- D.两者频次完全相同
答案:C。张量并行在每一层的前向和反向都要做多次 All-reduce,因此“每层多次”;流水线通信只发生在工位边界,不是每层都发生,频次远低于 TP,两者完全不同。
Q5. 单节点有 8 张 A100 且节点内 NVLink 互联,设置张量并行度时推荐上限是?
- A.2(照顾小 batch)
- B.4(折中显存与带宽)
- C.8(充分利用 NVLink)← 正确答案
- D.64(跨节点扩展)
答案:C。张量并行通信密集,必须限制在 NVLink 节点内。单节点 8 卡时 TP 上限就是 8;超过 8 就要跨节点走慢速网络,All-reduce 延迟暴增,因此 D 是错误选项。
Q6. 常见的 3D 并行包含下列哪些维度?
- A.数据并行(复制完整模型)← 正确答案
- B.张量并行(切分权重矩阵)← 正确答案
- C.流水线并行(按层切分)← 正确答案
- D.算子融合并行(合并计算)
答案:ABC。3D 并行 = 数据并行 + 张量并行 + 流水线并行,对应文章开头的“厨房复制、工位切菜、硬菜合做”。算子融合是单卡上的计算优化手段,不属于并行维度。
Q7. 流水线训练中“气泡(bubble)”出现的根本原因是?
- A.显存不足触发换页
- B.前后级工位忙闲不均← 正确答案
- C.网络延迟导致丢包
- D.学习率设置不合理
答案:B。流水线启动和收尾阶段,首尾工位没有输入数据只能空等;即使稳态运行时,级数越多,启动/收尾等特时间占比越高,这就是气泡。它源自前后级之间的依赖与等待,与显存、丢包、学习率无关。
Q8. 设计流水线与张量并行组合方案时,必须满足哪些约束?
- A.层数能被流水线并行度整除← 正确答案
- B.注意力头数能被张量并行度整除← 正确答案
- C.张量并行度不超过单节点卡数← 正确答案
- D.微批次必须大于总层数
答案:ABC。A 保证每级层数均匀,B 保证多头注意力按整“头”切分,C 保证 TP 通信走 NVLink。微批次数量只需能整除全局批次即可,与总层数没有必须的大小关系,D 错误。
Q9. 模型参数共 70B(不含梯度与优化器),TP=8、PP=2、DP=4 时每卡模型参数约为?
- A.约 8.75B(仅按 TP 分摊)
- B.约 4.38B(TP 与 PP 分摊)← 正确答案
- C.约 35B(仅按 PP 分摊)
- D.约 1.09B(三维全分摊除)
答案:B。模型参数只被 TP 和 PP 两个维度分摊,DP 复制完整模型不参与分摊。所以每卡参数 = 70B ÷ (8 × 2) = 4.375B,选 B。D 把 DP 也除了进去是常见错误,DP 的每份副本都持有完整 70B。
Q10. 下列哪些做法可以有效缓解 TP+PP 组合训练的通信压力?
- A.计算与通信相互重叠调度← 正确答案
- B.把张量并行度调至 32
- C.梯度压缩并延迟同步← 正确答案
- D.删除流水线边界传输
答案:AC。通信与计算重叠能隐藏大部分传输延迟,梯度压缩则减少 All-reduce 的数据量,两者都有效。把 TP 调到 32 会迫使通信跨节点走慢速网络,反而加剧压力;流水线边界传输是数据依赖的必经之路,不能删除。