当前位置: 首页 > news >正文

大模型分布式训练:DP、TP、PP 三大并行策略通俗讲解

多张 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 优化

为了解决"每卡都存完整模型太浪费"的问题,微软提出了ZeRO(Zero Redundancy Optimizer)

ZeRO 的思路是:把参数、梯度、优化器状态切碎,分散存到各卡上,需要用哪张卡的参数时,临时通过 All-Gather 广播过来,用完立刻丢掉。

普通 DP(8 张卡): 每张卡存完整的 112GB → 显存爆炸 💥 ZeRO-3(8 张卡): 每张卡只存 112GB ÷ 8 = 14GB → 轻松装下 ✅ 代价:需要频繁的卡间通信来临时凑齐参数

📚 ZeRO 像图书馆借书——书分散在各分馆,你需要哪本就借来用完还回去。


策略二:张量并行(Tensor Parallelism, TP)

核心思路

数据并行解决了"数据太多"的问题,但解决不了"激活内存太大"的问题。张量并行的思路是:把模型内部的矩阵运算本身切开,分给多张卡并行计算。一个矩阵乘法A×B可以通过分别计算B的每一列或A的每一行,然后组合结果来完成。

数学依据是矩阵乘法的可切分性:

Y = X · W 可以切成: GPU0:Y₀ = X · W₀ (W 的前半部分列) GPU1:Y₁ = X · W₁ (W 的后半部分列) 最后:Y = [Y₀, Y₁] 拼起来就是完整结果

以 Transformer 的 MLP 层为例:

  • 第一个线性层:按列切分,每张卡负责计算输出的一部分
  • 第二个线性层:按行切分,每张卡拿到上一步的部分结果直接算
  • 算完之后做一次All-Reduce,把各卡的结果加在一起

为什么张量并行不能跨节点用?

每算完一层就必须做一次同步通信,这个通信是阻塞式的——所有卡必须等通信完才能继续算。

节点内(NVLink): 带宽 ≈ 600 GB/s → 每次通信约 3ms,感觉不到 跨节点(网络): 带宽 ≈ 25 GB/s → 每次通信约 80ms,GPU 全在等!

三种关键通信原语

理解张量并行绕不开这三个概念:

通信原语描述类比
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: [A0+A1+A2+A3] ← 只拿第一块的和 GPU1: [B0+B1+B2+B3] ← 只拿第二块的和 GPU2: [C0+C1+C2+C3] GPU3: [D0+D1+D2+D3]

场景:反向传播时每张卡算出了自己的梯度,用 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(频繁)点对点传激活值(少)
跨节点效果✅ 较好❌ 很差(带宽瓶颈)✅ 较好
主要副作用每卡存完整模型必须节点内使用流水线气泡

实践中怎么选?

一句话原则:按问题选策略,组合使用效果最好。

  1. 先上数据并行:最简单,先跑起来
  2. 模型单卡放不下→ 加流水线并行(PP),把层分到多卡
  3. 激活内存爆显存→ 加张量并行(TP),在单机内切矩阵
  4. 三者叠加(3D并行)是目前训练超大模型的主流方案

优化是系统工程,没有银弹。理解每种策略的本质,结合自己的硬件条件和模型架构,多测试才能找到最优配置。


参考:
大模型分布式训练(DP、TP、PP、CP、EP、SP)六大并行策略深度解析-从原理到实践

http://www.cnnetsun.cn/news/1319065.html

相关文章:

  • 【杂谈】-人工智能蓬勃演进背后的隐性支撑体系
  • GLM-4V-9B图文理解SOP:标准操作流程图+异常处理决策树+FAQ手册
  • 从零配置Synplify Premier工程:手把手教你玩转FDC约束文件与安全设计(2025新版)
  • 立创EDA实战:基于FM8118芯片的小黄人新年主题加湿器设计与制作
  • 从TI杯D题手势识别装置出发:OpenMV与Arduino的嵌入式视觉开发指南
  • KVCache长上下文场景下性能与精度平衡的管理策略优化
  • Podman国内镜像加速终极指南:阿里云镜像源配置详解(2023最新版)
  • JWT 算法混淆攻击
  • YOLO26涨点改进| 1区Top 2025 | 全网独家创新、细节涨点改进篇| 3个月喜提一区YOLO真神!引入FSPPF漏斗空间金字塔池化模块,含多种组合创新点,助力小目标检测、图像分割高效涨点
  • 冯诺依曼与哈佛架构对比解析
  • STM32家庭环境监测系统:本地智能+MQTT云联+离线语音三重控制
  • 纯模拟电路实现的音频频谱可视化与机械摇摆系统
  • springboot党员之家服务系统 微信小程序毕业论文
  • Lingyuxiu MXJ LoRA算力优化案例:中小企业GPU资源利用率翻倍实践
  • 基于STM32的多模态智能LED照明系统设计
  • 使用Chainlit调用glm-4-9b-chat-1m注意事项:等待模型加载完成再提问
  • Phi-3 Forest Lab应用场景:开源项目维护者——ISSUE分类、PR描述润色、文档补全
  • Ostrakon-VL-8B零售创新:结合地理围栏,自动触发新开门店首周AI巡检
  • 【ISO14229_UDS诊断】-2.1-$27服务安全访问SecurityAccess实战解析
  • Qwen2.5-VL-7B-Instruct企业实操:与OA系统集成实现会议纪要图文自动归档
  • 解耦利器:深入CommunityToolkit.Mvvm中的Messenger消息机制
  • ESP32串口通信实战:按键控制数据发送
  • Unity PhysicsScene多场景物理仿真:精准预测碰撞与轨迹绘制实战
  • S905L3A/L3AB芯片迎来安卓14新纪元:Sicha移植版固件深度评测与刷机指南
  • ADS1299心电图采集模块实战:从寄存器配置到数据解析全流程
  • 为什么你的Dify集成总卡在审批流?揭秘头部金融客户已验证的5层流程引擎解耦方案
  • 聚类算法实战指南:从K-means到图聚类的场景化应用与优化策略
  • SLAM新手必看:5分钟搞懂世界坐标系到像素坐标系的完整转换链条
  • 解决Windows10中VMware与Hyper-V冲突的3种实用方法
  • 如何用Mac Mouse Fix解决Mac鼠标操作效率低下的问题?