多张 GPU 分工协作。本文用类比的方式把三种最核心的并行策略讲清楚。先搞清楚GPU 显存里到底存了什么很多人以为训练模型只需要存「模型参数」其实不止。训练时显存里住着三类居民居民说明占用大小参数Parameters模型的权重矩阵1x梯度Gradients反向传播算出来的更新量1x优化器状态Optimizer States以 Adam 为例每个参数还要存两个历史统计量一阶矩 二阶矩2x还有一类容易被忽视的激活值Activations前向传播时每一层的中间计算结果反向传播求梯度时要用到所以必须暂存。激活内存的大小跟 batch size 和序列长度成正比——序列一长、batch 一大激活内存甚至比参数本身还大。策略一数据并行Data Parallelism, DP核心思路“模型复制数据分片”——每张 GPU 上都放一份完整的模型但每张卡只处理一部分训练数据。用工厂流水线打比方 你有 4 条一模一样的生产线4 张 GPU每条线上有完整的生产设备完整模型。今天有 1000 个订单训练数据每条线负责处理 250 个。下班前每个 step 结束4 条线开个会把各自的改进经验梯度汇总平均统一更新设备。这个汇总梯度的步骤叫做All-Reduce 操作每张卡把自己算出的梯度发给其他所有卡所有卡对梯度求平均保证 4 张卡上的模型副本始终保持一致。优缺点✅ 实现简单几乎所有框架都原生支持✅ 适用于各种模型架构❌每张卡都要存完整模型——模型太大、单卡放不下时直接失效❌ GPU 数量增多后通信开销会成为瓶颈ZeRO 优化为了解决每卡都存完整模型太浪费的问题微软提出了ZeROZero Redundancy Optimizer。ZeRO 的思路是把参数、梯度、优化器状态切碎分散存到各卡上需要用哪张卡的参数时临时通过 All-Gather 广播过来用完立刻丢掉。普通 DP8 张卡 每张卡存完整的 112GB → 显存爆炸 ZeRO-38 张卡 每张卡只存 112GB ÷ 8 14GB → 轻松装下 ✅ 代价需要频繁的卡间通信来临时凑齐参数 ZeRO 像图书馆借书——书分散在各分馆你需要哪本就借来用完还回去。策略二张量并行Tensor Parallelism, TP核心思路数据并行解决了数据太多的问题但解决不了激活内存太大的问题。张量并行的思路是把模型内部的矩阵运算本身切开分给多张卡并行计算。一个矩阵乘法A×B可以通过分别计算B的每一列或A的每一行然后组合结果来完成。数学依据是矩阵乘法的可切分性Y X · W 可以切成 GPU0Y₀ X · W₀ W 的前半部分列 GPU1Y₁ X · W₁ W 的后半部分列 最后Y [Y₀, Y₁] 拼起来就是完整结果以 Transformer 的 MLP 层为例第一个线性层按列切分每张卡负责计算输出的一部分第二个线性层按行切分每张卡拿到上一步的部分结果直接算算完之后做一次All-Reduce把各卡的结果加在一起为什么张量并行不能跨节点用每算完一层就必须做一次同步通信这个通信是阻塞式的——所有卡必须等通信完才能继续算。节点内NVLink 带宽 ≈ 600 GB/s → 每次通信约 3ms感觉不到 跨节点网络 带宽 ≈ 25 GB/s → 每次通信约 80msGPU 全在等三种关键通信原语理解张量并行绕不开这三个概念通信原语描述类比Broadcast广播一张卡的数据发给所有卡老师把答案念给全班同学All-Gather全聚合每张卡把自己那份发给所有人最终每卡都有完整数据全班同学互相抄笔记最后每人都有完整答案Reduce-Scatter散播归约先对所有卡的数据求和再把结果切分散发每卡只拿到一段全班成绩加总后班长只负责记前10名副班长记后10名Broadcast广播一张卡 → 所有卡其他卡被动接收。操作前 GPU0: [A] GPU1: [?] GPU2: [?] GPU3: [?] 操作后GPU0 广播 GPU0: [A] GPU1: [A] GPU2: [A] GPU3: [A]场景把某个参数的最新值同步给所有卡。All-Gather全聚合每张卡都把自己的数据发给所有人最后每张卡都拼接成完整数据。操作前每张卡只有一块 GPU0: [A] GPU1: [B] GPU2: [C] GPU3: [D] 操作后每张卡都有完整数据 GPU0: [A,B,C,D] GPU1: [A,B,C,D] GPU2: [A,B,C,D] GPU3: [A,B,C,D]场景ZeRO-3 中每张卡只存了部分参数需要某层完整参数时用 All-Gather 临时凑齐。Reduce-Scatter散播归约先对所有卡的数据求和再把结果切分散发每张卡只得到求和结果的一部分。操作前每张卡都有完整数据 GPU0: [A0,B0,C0,D0] GPU1: [A1,B1,C1,D1] GPU2: [A2,B2,C2,D2] GPU3: [A3,B3,C3,D3] 操作后求和 切分 GPU0: [A0A1A2A3] ← 只拿第一块的和 GPU1: [B0B1B2B3] ← 只拿第二块的和 GPU2: [C0C1C2C3] GPU3: [D0D1D2D3]场景反向传播时每张卡算出了自己的梯度用 Reduce-Scatter 把梯度加起来每张卡只负责存自己那份ZeRO-2 就是这么做的。三者关系All-Gather Broadcast 的多对多版本主动的每人都发 All-Reduce Reduce-Scatter All-Gather先归约再广播每人得到完整求和结果Transformer 有几十上百层每层都卡一次GPU 利用率直接崩掉。实践建议TP 度数一般设为 2、4、8优先在单机 8 卡内使用配合流水线并行效果更好。策略三流水线并行Pipeline Parallelism, PP核心思路“把模型按层切开每张卡只负责几层数据像工厂流水线一样依次流过”。GPU0负责 layer 1~8 GPU1负责 layer 9~16 GPU2负责 layer 17~24 GPU3负责 layer 25~32 数据流向 输入 → GPU0 算完 → 把激活值传给 GPU1 → GPU1 算完 → 传给 GPU2 → ... 就像汽车装配线第一组工人装发动机第二组装车身第三组装内饰。每组只需要自己那套工具不需要其他组的设备。气泡问题朴素的流水线有个致命缺陷GPU 空闲等待气泡。时间轴 → GPU0[前向传播] [等] [等] [反向传播] GPU1[等] [前向] [等] [反向] GPU2[等] [等] [前向] [反向]GPU0 算完前向就要等 GPU1、GPU2 都算完然后才能开始反向传播大量时间在空转。解决方案微批次Micro-batch把一个大批次切成多个小批次让 GPU 交错执行填补空闲时间时间轴 → GPU0[MB1-前向][MB2-前向][MB3-前向][空闲][MB1-反向][MB2-反向][MB3-反向] GPU1[等 ][MB1-前向][MB2-前向][MB3-前向][MB1-反向][MB2-反向][MB3-反向] GPU2[等 ][等 ][MB1-前向][MB2-前向][MB3-前向][MB1-反向][MB2-反向]微批次数越多气泡占比越小GPU 利用率越高。优缺点✅ 通信开销低只在相邻层之间传激活值✅ 显存占用显著降低每卡只存几层的参数❌ 气泡问题无法完全消除❌ 存在木桶效应最慢的那张卡决定整体速度❌ 需要合理切分层数以保证负载均衡三种策略对比总结DP 数据并行TP 张量并行PP 流水线并行切分对象训练数据矩阵运算层内模型层数层间每卡存什么完整模型部分权重矩阵几层的完整参数解决的问题加速训练、扩展数据量激活内存过大模型整体放不下通信类型All-Reduce梯度同步All-Gather / Reduce-Scatter频繁点对点传激活值少跨节点效果✅ 较好❌ 很差带宽瓶颈✅ 较好主要副作用每卡存完整模型必须节点内使用流水线气泡实践中怎么选一句话原则按问题选策略组合使用效果最好。先上数据并行最简单先跑起来模型单卡放不下→ 加流水线并行PP把层分到多卡激活内存爆显存→ 加张量并行TP在单机内切矩阵三者叠加3D并行是目前训练超大模型的主流方案优化是系统工程没有银弹。理解每种策略的本质结合自己的硬件条件和模型架构多测试才能找到最优配置。参考大模型分布式训练DP、TP、PP、CP、EP、SP六大并行策略深度解析-从原理到实践