news 2026/10/16 16:40:56

大模型分布式训练:并行策略、显存优化与通信瓶颈全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大模型分布式训练:并行策略、显存优化与通信瓶颈全解析

第一次把训练脚本从一张卡改成多卡的时候,我天真地以为只要把 batch 切一半放到两张卡上就行。结果代码没改完,显存先不够了;改完显存,速度又上不去了;最后发现真正的瓶颈是通信。大模型的分布式训练,说白了就是在这三件事之间反复权衡:显存放不放得下、算力够不够快、通信跟不跟得上。这篇文章算是我在做大规模预训练时整理的基础理论笔记,面向的读者是已经会训单卡模型、但还没系统接触过分布式并行的人。我会把并行策略、显存优化、通信原语、工程落地这些内容按我实际踩坑的顺序写下来,尽量不讲废话。

1. 单卡到大模型之间,隔着两道墙

很多人以为分布式训练是为了“加速”,但真正的原因比加速更硬核:单卡根本装不下,也根本算不完。这两件事像两道墙一样横在中间,第一道叫显存墙,第二道叫算力墙,等翻过去之后才发现后面还有一道通信墙。

1.1 显存墙:为什么参数放不进一张卡

先说一组非常直观的数字。假设一个 10B(100亿)参数的大模型,在 BF16 精度下,仅权重参数就需要 10B × 2 字节 = 20GB。听着不多,一张 80GB 的卡好像能放进去,但这只是权重。

训练过程中还需要维护梯度,同样是 20GB 左右。而真正夸张的是优化器状态:混合精度训练常用的 Adam 优化器,每个参数要维护 FP32 主权重、一阶动量、二阶动量,总共 12 字节。10B 参数就是 120GB。三样加一起:20GB 权重 + 20GB 梯度 + 120GB 优化器状态 = 160GB,一张 80GB 的卡连存都存不完,更别提前向计算时产生的激活值了。

所以当你听到类似“某某 7B 模型单卡就能推理”时,那只是推理,只需要权重和 KV Cache。训练完全是另一回事,优化器状态是模型参数的好几倍,这是最容易忽略的一点。显存墙的本质就是:优化器状态 + 梯度 + 激活值让训练时的显存需求远大于模型文件大小。我们后面讲的 ZeRO、激活重计算、混合精度,全都指向这一道墙。

1.2 算力墙:单卡跑完需要多少年

显存可以靠优化硬塞,但算力不行。训练一个大模型的总计算量,业界有一个近似公式:

总 FLOPs ≈ 6 × N × D

其中 N 是模型参数量,D 是训练 token 总数。这个 6 的来源是:前向每个 token 每个参数约 2 次浮点运算,反向约 4 次。

拿一个 10B 模型、训练 300B token 来算:

总 FLOPs = 6 × 10¹⁰ × 3 × 10¹¹ = 1.8 × 10²² FLOPs

假设一张卡能达到 300 TFLOPS 的 BF16 稠密算力,这个值已经很乐观了:

单卡秒数 = 1.8 × 10²² ÷ (3 × 10¹⁴) = 6 × 10⁷ 秒,大约是 694 天。

也就是说,单卡训一个 10B 模型要将近两年。如果换成 100B 模型,二十年都不够看。所以分布式训练根本不是为了“快一点”,而是为了让一个本来不可能完成的任务变得可以完成。

1.3 通信墙:规模化之后真正卡住你的瓶颈

显存不够可以加卡,算力不够也可以加卡,但卡一多,新的问题来了:卡与卡之间要互相等数据和梯度,通信开销会随着并行规模的扩大而急剧增长。

我刚开始做多卡训练时犯过一个错误:以为 8 卡比 1 卡快 8 倍。实际跑出来只有 4 倍多。原因很简单,每一步训练结束,所有卡都要把梯度汇总一遍,这个汇总动作在 8 张卡之间有大量数据需要通过网络传输。卡越多,迁移次数越多,通信时间就越长,而计算时间被切得越来越短,两相对比,通信占比自然越来越大。

可以打个比方:一个团队合作写一本书,分工很容易,每个人负责几章。但如果你每写完一页都要等所有人的批注汇总,那写作速度就被汇总流程彻底锁死了。分布式训练里的“批注汇总”就是通信。通信墙不像显存墙那么显而易见,但它才是真正决定你集群能跑到多快的关键。

2. 并行策略的三种基本形态:DP、TP、PP

2.1 数据并行(DP):复制模型,切分数据

数据并行是最直观、最容易理解的一种并行方式:每一张卡上都存一份完整的模型副本,训练数据按 batch 维切成多份分发给各卡,每张卡独立完成前向和反向,算出梯度。然后通过 all-reduce 操作把所有卡的梯度求和,再用这个总梯度去更新每一张卡上的模型。

它的优点非常明显:实现简单,和单卡训练的逻辑几乎一样,模型结构完全不用改。只要显存能放下完整模型,数据并行几乎是最省事的起步方案。所以很多大模型框架在你刚开始并行训练时,默认路径就是数据并行。

但数据并行有两个致命缺点。第一,模型复制多少份,显存就翻多少倍。前面算了,10B 模型训练状态大概 160GB,哪怕你有 16 张卡,每张卡依然要各存 160GB,这显然不现实。第二,通信量随着模型参数量的增加线性增长,每一步都要把全套梯度同步一遍。模型越大,这个 all-reduce 的代价就越大。

所以数据并行适合“模型能装进一张卡”的情况,但大模型恰恰装不进去。这促使我们考虑第二种方式:把模型本身切开,分到不同的卡上。

2.2 张量并行(TP):切开一层算子的矩阵

张量并行是把一个层内部的矩阵运算拆到多张卡上。以 Transformer 里的 FFN(前馈网络)为例,它的核心计算是:

Y = W₂ × activation(W₁ × X)

我们可以把 W₁ 按列切开,让卡 1 和卡 2 各算一半的隐藏维度;W₂ 则按行切开,两卡分别做矩阵乘,最后通过 all-reduce 把两者结果相加,得到和单卡完全一致的输出。注意,这里每一步都会有大规模的矩阵计算在卡间“拼接”,TP 的通信非常密集。

举个例子,一个隐藏层 4096 维的 FFN,按 2 路张量并行切分,每卡只需要计算 2048 维的部分。但每层的前向和反向都要做通信,层数越多,通信次数越多。这也是为什么张量并行一般只被用在同一个物理节点内——节点内的高速互联带宽高、延迟低,才经得住 TP 这种“每层都通信”的模式。如果把 TP 跨到不同节点,网络延迟立刻成为灾难。

2.3 流水线并行(PP):把 Transformer 层竖着切开

张量并行是横向切一层,流水线并行则是纵向切层:把模型的第 1~10 层放在卡 1,第 11~20 层放在卡 2,以此类推。数据像流水线一样,从第一阶段流到最后阶段。

纯流水线并行最大的问题是“气泡”:当第一个样本还在第一张卡上计算时,后面的卡完全空闲。等到样本逐层传到最后的卡,前面阶段可能已经算完了,白白空等。

怎么解决?引入 micro-batch。把一个大的 batch 切成很多份小 batch,依次注入流水线。第一阶段算完第一个 micro-batch 后马上算第二个,不用等后面;第二阶段收到第一个 micro-batch 时就开始,这样各个阶段都能保持忙碌。气泡率的近似公式是:

气泡比例 ≈ (PP - 1) / (PP + micro-batch 数 - 1)

micro-batch 数量越大,气泡越小。但 micro-batch 也不能无限大,它受显存和梯度累计的逻辑限制。实践中,PP 的切分数一般不会太大,常见的是 4~8 段,再多就可能出现调度复杂、气泡难压的问题。

3. 混合并行:为什么是 DP+TP+PP 而不是只用一种

我最早有一个疑惑:既然三种并行各有玩法,那大模型训练到底用哪种?后来和各种框架打交道多了才发现,现实世界里的超大模型从来不是只用一种并行,而是按“三层嵌套”的思路把三种方式组合起来。理由不复杂:三种并行的通信特征完全不同,分开使用会各踩各的坑,组合在一起反而能扬长避短。

3.1 三种并行策略的通信特征对比

我把三种并行的关键特征列了个表,这个表我每次做集群方案时都会拿出来看:

并行方式通信频率单次通信粒度通信范围主要代价
数据并行 DP每步一次全量梯度全局所有卡显存复制、通信量随参数量线性增长
张量并行 TP每层多次中间激活同一节点内通信极其密集,无法跨节点
流水线并行 PP每个 micro-batch 一次相邻阶段激活和梯度相邻阶段流水线气泡、调度复杂度

只看这张表就能明白为什么实际方案都是混合的。只用 DP,模型大一点显存直接爆掉,梯度同步量还大;只用 TP,每层都要通信,节点一多延迟完全扛不住;只用 PP,虽然跨节点可行,但单卡上的计算量和显存压力没法有效分摊到更多维度。于是主流的思路就是:在节点内做 TP,在节点间做 PP,在最外层做 DP。

3.2 并行维度怎么排:先 TP,再 PP,最后 DP

很多框架在超大规模训练时,使用的并行维度顺序可以概括为:

DDP → PP → TP

也就是说,最靠近单卡的是 TP,然后往外是 PP,最外层是 DP。为什么这样排?因为 TP 的通信最频繁、最紧急,必须放在速度最快的节点内互联上;PP 的通信频率低,可以接受跨节点延迟;DP 虽然要全局同步,但每个训练步只有一次 all-reduce,频率最低,所以放最外层,哪怕走较慢的跨节点网络也划算。

我自己做集群排布时的经验是:先画出物理拓扑,标出节点内带宽和跨节点带宽,然后把 TP 放在节点内,能塞多少塞多少;PP 顺着节点之间排;DP 在全局范围分配。这个顺序不绝对,但绝大多数情况下它都是合理的。

3.3 一个可参考的配置:512 卡训 10B 模型

纸上谈兵容易,我们看一个实际配置。假设一个节点内有 8 张卡,用 512 张卡训练一个 10B 模型。

  • 节点内做 8 路 TP,单层计算被切成 8 份;
  • 模型层间做 4 路 PP,把 Transformer 层切成 4 段;
  • 一个“模型副本”占 8×4 = 32 张卡;
  • 512 张卡总共就是 512 ÷ 32 = 16 路 DP。

最终配置是 16 路 DP × 4 路 PP × 8 路 TP。这个配置的好处是:TP 完全不出节点,PP 只在 4 个节点之间流动,DP 则在 16 个模型副本之间做主梯度同步。通信压力被分散到不同维度,不会出现某一条链路被打爆的情况。

4. 显存优化:ZeRO、激活重计算与混合精度

并行策略解决的是“模型怎么拆”,但拆完之后还有一个更底层的问题:每张卡上的显存到底怎么省。这一节讲的是训练大模型几乎逃不掉的三板斧:ZeRO 分片、激活重计算、混合精度。

4.1 ZeRO:让每张卡只存一部分模型状态

前面算过一个 10B 模型,权重 20GB、梯度 20GB、Adam 优化器状态 120GB,总共 160GB。如果在数据并行下每张卡都存 160GB,那 8 卡就是 1280GB,巨大的浪费。

ZeRO 的核心思路是:把这些状态在数据并行的卡之间做分片,每张卡只存储自己负责的那部分。它分几个级别:

  • ZeRO-1:只分片优化器状态,显存大幅下降,通信量基本不变;
  • ZeRO-2:分片优化器状态 + 梯度,反向传播时梯度不再全量复制;
  • ZeRO-3:再分片参数,前向计算前通过 all-gather 把参数收集回来。

代价是通信模式从“一次全量 all-reduce”变成“reduce-scatter + all-gather”,通信量大约变成原来的 1.5 倍左右。但换来的是显存可以被多卡线性分摊,让超大模型训练成为可能。实际工程里,7B、13B 这类模型用 ZeRO-2 搭配数据并行就很常见,100B 以上则需要 ZeRO-3,甚至配合 CPU offload,把部分状态放到内存里。

4.2 激活重计算:拿算力换显存

模型参数和优化器解决了,但训练时还有一块隐形显存大户——激活值。Transformer 前向过程中每一层都要保存中间结果用于反向传播,保存的大小大约是:层数 × 序列长度 × 隐藏层维度 × batch size。

当序列长度到 8K、32K 的时候,激活值的显存会以恐怖的速度膨胀,甚至超过参数本身。这时最常用的手段是激活重计算(activation checkpointing / recomputation):前向时不保存所有中间激活,反向传播需要用激活时,临时再算一次前向来重放。

显存代价从 O(层数) 降到 O(1),代价是增加一次前向计算,整体算力开销通常多 30% 左右。这笔账在多数情况下是划算的,因为显存不够直接无法训练,花 30% 算力换来能训,比完全训不了强得多。我的经验是:只要是大模型训练,激活重计算基本一定要开,但要配合没有重计算的基线先做对比,避免过度重算导致 MFU 雪崩。

4.3 混合精度:BF16 为什么成了事实标准

混合精度训练的核心逻辑,是用 FP16 或 BF16 做前向和反向计算,用 FP32 保存优化器状态和主权重。好处很明显:显存减半、通信减半、GPU 上对应的计算单元吞吐更高。

FP16 的问题是:指数位只有 5 位,数值范围很小,梯度本来就小,前向稍微大一点就容易上溢,反向的梯度稍微小一点就容易下溢成 0。下溢意味着梯度信息直接消失,模型根本学不动。所以 FP16 时代要配合 loss scaling 把梯度整体放大,再在更新前缩小回来。

BF16 解决了这个问题,它有 8 位指数位,和 FP32 的范围一样,基本不会下溢,代价是尾数只有 7 位,精度差。但对大模型训练来说,保持范围远重要于保持精度,BF16 因此成为大模型训练的事实标准。如果你看到训练日志里 loss 突然出现 NAN,先怀疑混合精度相关的数值问题,这个习惯能省很多排查时间。

5. 通信是隐形天花板:从原语到通信计算重叠

我对分布式训练认知升级最快的一段经历,就是从“只看显存”变成“看通信”。这本质上是因为模型越大、并行规模越大,通信占整个训练 step 的比例就越高。你不可能优化掉通信,但你必须搞清楚通信发生在哪、规模多大、能不能和计算重叠。

5.1 常用通信原语:all-reduce、reduce-scatter、all-gather

分布式训练里所有网络传输最终都落到几个集合通信原语上:

  • all-reduce:所有节点把自己的数据发送出去,汇总后再广播回所有节点,数据并行里的梯度同步就是它。
  • reduce-scatter:数据先做 reduction,再按 rank 分发分片,每个 rank 只拿到结果的一小片,ZeRO 的梯度分片依赖它。
  • all-gather:把各 rank 持有的分片收集齐,最后每个 rank 都能拿到完整的张量,ZeRO-3 在每次前向时要收集参数就用它。
  • point-to-point:只在两个指定 rank 之间点对点传数据,流水线并行里相邻阶段传激活和梯度用它。

理解这些原语后,再去看训练日志里的通信时间就容易多了:DP 的 all-reduce 是“每步一次全量”,TP 的 all-reduce 是“每个算子来一次”,PP 的点对点是“每个 micro-batch 一次”。你看到的任何通信瓶颈,都能定位到具体是哪个环节在等哪类原语。

5.2 集群拓扑决定并行编排

通信不只是“带宽大就行”,拓扑结构同样重要。一个节点内的 8 张卡之间通常有极高的互联带宽和很低的延迟,但跨节点需要通过交换网络,带宽再高也有物理上限,延迟更是成倍增长。

所以拿到一个集群时,我第一件事就是画拓扑图:哪些卡在同一个节点,节点间几个上联口,交换机带宽多少。然后对照并行策略,把 TP 尽量锁在节点内,PP 放在节点间,DP 放全局。这个动作做不好,后面调优会非常痛苦。我见过不少人拿着一个理论最优的并行配置,跑到某个跨节点网络不好的集群上,速度反而比小规模还慢,根源就是拓扑和并行维度没对齐。

5.3 通信与计算重叠:一个真正的调优选重点

很多新手看通信占比高,第一反应是压缩通信数据,但更高效的思路是让通信和计算并行起来。比如数据并行的反向传播,传统方式是等到整张卡的反向全部结束,再一次性 all-reduce 梯度,这会导致每个 step 末尾出现一个明显的通信空洞。

优化方式是把梯度分成很多个“桶”,哪个桶算完哪个桶先发,不用等全部反向结束。这样通信和后续的反向计算天然重叠,整体 step 时间能显著缩短。流水线并行里的 micro-batch 调度,本质上也是让不同阶段的通信和计算重叠。实践里,我通常会看 profiler 输出的通信 gap,如果 gap 占比超过 10%,就说明通信还没被有效隐藏,优先去优化调度和梯度分桶,往往立竿见影。

6. 工程落地最容易踩的坑

理论层面了解并行策略和显存优化之后,真正拉开差距的是工程细节。分布式训练的项目代码跑起来容易,跑得快、跑得稳很难。我把自己踩过和帮别人排查过的坑整理成以下几个方面。

6.1 慢节点:木桶效应

分布式训练基本是同步训练的,每一个 step 都要等所有卡完成。只要有一张卡慢一点点,整个集群的吞吐就被它拖到那个水平。

我遇到过一次 64 卡训练,吞吐比预期低了 30%。查了很久才发现是 rank 7 的数据加载线程被 CPU 别的进程抢占,每 step 慢了几百毫秒。卡数越多,这个木桶效应越严重。排查慢节点的方法很简单:给每张卡记录每 step 耗时,拉出分布,找出离群值,再去看是数据加载问题、显存频率降频,还是网络故障。记住,分布式训练里“大部分卡快”没有意义,最慢的那张卡决定一切。

6.2 checkpoint 与容错:不能从头再来

大模型训练一个任务动不动就是几天甚至几周,进程崩掉、节点断网、显存 OOM 都太常见了。如果 checkpoint 设计得不好,一次故障就可能让你损失好几十个小时。

这里的核心原则是分布式保存分片 checkpoint:每张卡只保存自己持有的那部分参数分片、优化器状态分片,以及当前 step 序号,不要每个 rank 都 dump 一份全量模型。恢复时按照相同的并行配置直接加载。同时,checkpoint 写入本身也有开销,建议用异步方式,避免保存时整条流水线阻塞。我吃过一次大亏:把 checkpoint 都写在同一台机器的本地盘上,节点一挂,备份全丢。所以 checkpoint 存储至少要有冗余,最好写到独立存储。

6.3 调试与观测:从日志到 profiling

分布式训练的调试难度和卡数成正比。一个 128 卡的任务,出了问题根本没法像单卡一样直接加断点看。我的调试顺序基本固定:

  1. 先用极小的 batch 和极短的序列把链路跑通,确认 loss 能正常下降;
  2. 看 loss 曲线有没有 NAN、有没有突然抖动,重点查学习率、混合精度、数据顺序;
  3. 看每张卡的 GPU 利用率,有没有某张卡一直是 0% 或者明显偏低;
  4. 用 profiler 看每个 step 的 breakdown,找出通信占比、算子耗时、空闲 gap;
  5. 打印 grad norm,监控梯度是否爆炸或消失。

这些小技巧看着简单,但能帮你快速把“不知道哪出了问题”缩小到“计算、通信、数据、数值”这四类问题里。特别是 grad norm,很多人都不看,它往往是判断训练是否健康的最早信号。

6.4 数据加载管线:最容易被忽视的瓶颈

分布式训练时,GPU 算力很大,但 CPU 负责的 tokenizer、数据读取很容易跟不上。很多项目把 tokenizer 放在训练进程里实时处理,一旦数据量大起来,CPU 直接被拖垮,GPU 就开始空转。

我现在的基本做法是:所有文本预处理尽量离线完成,提前转成二进制数据格式,训练时只做读入和随机索引,不做重度计算。还要注意 num_workers 的设置,以及随机打乱时会不会破坏样本顺序导致缓存失效。数据管线的目标是“GPU 要什么,数据就在那里”,而不是“GPU 等数据算完”。

7. 怎么判断分布式训练做得好不好

配置一堆并行策略,最终要看效果。我觉得评估一个分布式训练方案,就盯三个数字:MFU、单卡实际算力、扩展效率。

7.1 三个核心数字:MFU、单卡实际算力、扩展效率

MFU(Model FLOPs Utilization)是大模型训练里最重要的效率指标之一,含义是实际完成的有效计算量除以 GPU 的理论峰值计算量。大模型训练在合理优化下 MFU 一般能到 40%~55%,再往上需要很强的调优。如果你看到 MFU 只有 15%,大概率是通信没重叠好、激活重算开太多,或者数据加载在卡脖子。

单卡实际算力可以看作 MFU 的另一种表达,单位是 TFLOPS。比如一张卡的峰值是 300 TFLOPS,实际跑到 150 TFLOPS,MFU 就是 50%。它比 MFU 更直观,能直接看出“这张卡到底干了多少活”。

扩展效率则反映加卡后的吞吐增益。理想情况下 64 卡应该比 32 卡快 2 倍,如果只快了 1.6 倍,说明扩展效率只有 80%,那 20% 去哪了,要么是通信太慢,要么是气泡太多,要么是负载不均。看到扩展效率低下,先按这个思路往下拆。

7.2 用 6ND 心算资源需求

最后分享一个我经常用的估算方法,基于前面的总 FLOPs = 6×N×D。

要估算一个任务需要多少卡时,可以用:

卡时 = 总 FLOPs ÷(单卡峰值 TFLOPS × MFU × 卡数)

举个例子:1B 模型训 100B token,总 FLOPs = 6×10⁹×10¹¹ = 6×10²⁰。假设 256 卡,单卡峰值 300 TFLOPS,MFU 0.4:

卡时 = 6×10²⁰ ÷(3×10¹⁴ × 256 × 0.4)≈ 1.95×10⁴ 秒 ≈ 5.4 小时

这个计算能让你在设计实验之前快速判断可行性:一个方案要跑多久、需要多少块卡、划不划算。虽然实际会有各种 overhead,但它给了一个很稳的底线预期,比凭空感觉靠谱得多。

写到这里,基本把我做分布式训练前的笔记倒了一遍。回想起来最想强调的还是那句话:先跑通小规模,再想大规模。很多并行配置在理论上是最优的,落到真实集群上会因为拓扑、数据管线、慢节点完全变样。我第一次做多卡训练时,以为卡数翻倍吞吐就能翻倍,结果只提升了四成,后来一步步定位才发现是通信没重叠好,外加数据加载拖后腿。这种挫败感,每一个搞分布式训练的人都经历过。希望这些笔记能帮你少走一点弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 16:36:48

IO控制器详解:信号类型、选型思路、控制方式与调试要点

刚开始接触工业控制系统的人,十有八九会被“IO控制器”这个词绕晕。我第一次搞现场项目时也这样:PLC、远程IO模块、继电器、传感器、变送器堆了一柜子,电脑上的点位表密密麻麻写着DI、DO、AI、AO,脑子里一团糨糊——这些东西到底是…

作者头像 李华
网站建设 2026/10/16 16:36:14

C语言第九周核心:指针偏移、结构体内存布局与文件缓冲机制

1. 这不是刷题攻略,而是一份C语言第九周编程题的“底层通关手册”如果你正卡在哈工大MOOC《C语言程序设计精髓》第九周练兵区——那个被不少学习者称为“指针风暴”“结构体迷宫”“文件操作断崖”的关卡,别急着翻答案、抄代码、搜解析。我带过三届线上C…

作者头像 李华
网站建设 2026/10/16 16:34:11

Python打包exe实战:PyInstaller从入门到避坑

1. 为什么你需要认真对待打包这件事很多刚接触 Python 的朋友都有过这样的经历:自己写了个小工具,比如批量重命名文件、自动整理桌面、定时抓取某些数据,在本机跑得好好的,想发给同事或者朋友用一下,结果对方一句“我电…

作者头像 李华
网站建设 2026/10/16 16:32:43

屏幕录像程序源代码工程化解析:采集、编码、音画同步与性能控制

简介:这份屏幕录像程序源代码面向具备一定C与Windows开发基础的程序员、软件专业学生及需要自研录屏工具的开发者,帮助其理解屏幕捕获、视频编码与文件管理的完整实现思路,可用于教程制作、游戏录制或软件演示等场景。资源包共58个文件&#…

作者头像 李华