3、多 GPU 的分工方式
单卡调整仍不够,或希望缩短训练时间时,才需要进一步考虑多卡。先理解三种分工:数据并行分文章,张量并行分同一层的计算,流水线并行分模型层。
这一节读完,能用文章例子解释三者,并判断增加卡数是否解决当前问题即可。阅读图时始终问:两张卡收到的是不是同一批文章?卡之间传递的是什么?
图:三种并行的分工示意。张量并行与流水线并行面板只画前向数据流。
3.1 数据并行:同一个模型处理不同文章
假设单卡已经能训练,只是速度不够快。现在有两张 GPU,可以让它们同时处理不同文章。
先让两张卡各自拥有同样的模型,再这样分工:
GPU 0:处理文章 1~4 → 算出这批文章的梯度
GPU 1:处理文章 5~8 → 算出另一批文章的梯度
↓
汇总梯度,再更新两边的参数第 30 章把梯度解释为参数更新所需的方向信息。这里要汇总,是因为两张卡练习的文章不同;如果各自更新、从不交流,模型参数就会逐渐不同。
在常见的分布式数据并行训练中,两边同步梯度,并按一致的规则更新,共同训练同一个模型。
这种分工叫数据并行(Data Parallelism,DP);常见的实现之一叫 DDP,即分布式数据并行。
普通 DDP 中,每张 GPU 仍要放下一份模型。 因此,两张 24 GB 的卡不会自动变成一张可任意使用的 48 GB 显卡。若单卡连基础权重都放不下,单纯增加数据并行副本不能解决它。
3.2 张量并行:一起计算同一层
第 30 章用矩阵解释过模型层的计算。张量并行(Tensor Parallelism,TP)不是让两张卡各读四篇不同文章,而是把同一层的一次计算分给它们。
例如,一层需要算出若干组输出特征,可以让 GPU 0 算其中一部分,GPU 1 算另一部分,再按切分方式拼接或汇总结果,继续下一层。
可以把差别说成两句话:
- 数据并行:你处理这几篇,我处理另外几篇,更新前交流。
- 张量并行:我们一起处理这份输入,你算这一部分,我算另一部分。
一层的计算分开以后,相关权重也能分散存放。但每层之间往往需要交换结果,通信会影响速度。
所以 TP 不只是“多选几张卡”。模型结构、训练框架和配置都要支持这种切分,不能把 LLaMA-Factory 中显示的 GPU 数量直接当作 TP 数量。
3.3 流水线并行:按模型层接力
流水线并行(Pipeline Parallelism,PP)采用另一种拆法:把前面若干层放在 GPU 0,后面若干层放在 GPU 1。
一份输入先经过 GPU 0,再把中间结果传给 GPU 1。这就像两道连续的加工步骤,后一道必须等前一道给出结果。
按层接力能分担模型,但后面的卡需要等待前面的结果。实际训练会交错安排多份输入来减少等待,具体时间轴见下图;不能只按 GPU 数量估算加速比例。
<details> <summary>进阶阅读:微批次怎样减少等待,什么是流水线气泡</summary>为了减少等待,可以把一个批次再拆成几个小份,让不同 GPU 交错处理。这些小份常称为微批次(micro-batch)。下面把三份输入记作 A、B、C,对照两种安排:
先横着跟踪蓝色的 A:它始终先经过 GPU 0,再经过 GPU 1。再看交错接力的第 2 个时段:GPU 1 处理 A 的同时,GPU 0 已经开始处理 B,不必等 A 全部完成才接下一份。
开头和末尾仍有卡等待,这种空闲间隙常称为流水线气泡。图中假设每个阶段耗时相同,只画前向计算;实际训练还有反向传播和数据传输,不能直接把图中的 6 个时段变成 4 个时段当作训练加速比例。
</details>3.4 多卡有效批次的计算
先计算最容易遇到的情况:两张卡做数据并行,每张卡一次处理 4 篇文章,累积 4 次后更新。
有效批次 = 单卡 batch × 数据并行卡数 × 梯度累积次数
= 4 × 2 × 4
= 32 篇它和第 31 章单卡 4 × 1 × 8 = 32 一样,每次更新合计使用 32 篇文章。
差别在于,两卡方案每次同时处理 8 篇,累积 4 次;单卡方案每次处理 4 篇,累积 8 次。两卡需要通信,所以耗时不一定减半。
如果两张卡使用 TP 合作计算同一份模型,它们处理的是同一批输入,不能再把样本数乘以 2。
图中三种安排都得到 32 篇,但只有数据并行那一行把组数乘以了 2。判断时数的是独立处理不同文章的数据并行组,不是机箱里装了几张显卡。
假设有四张卡:GPU 0、1 用 TP 合作计算一份模型;GPU 2、3 合作计算另一份。两组处理不同文章。
这时数据并行组数是 2,而不是 4。若每组一次处理 4 篇,累积 4 次:
有效批次 = 每组一次处理的样本数 × 数据并行组数 × 累积次数
= 4 × 2 × 4
= 32TP、PP 分担同一批输入的模型计算,不能重复计入新样本数。后面的 ZeRO 则是在数据并行中分片训练状态,不要因此把数据并行组数误算成 TP 组数。
3.5 多卡不一定更快
多张卡协作,除了计算,还要交换数据。卡间连接速度、传输量、各卡工作是否均衡,都会影响训练耗时。
GPU 之间需要交换梯度、参数或中间结果。实例说明中的 NVLink 等互联信息,与这种交换能力有关。
先检查各张 GPU 是否按预期参与计算,再比较相同工作量下的训练耗时;具体检查方法见第 5 节。
也不要看到多张卡,就直接从 LoRA 改成全参数训练。全参数训练要为更多参数保存梯度和优化器状态,资源要求会明显改变。
若只是检查多卡是否能正常启动,先保持已有 LoRA 任务,调整必要的分布式配置。只有任务确实需要、显存和时间也能接受,才继续比较全参数方案。
<details> <summary>选读:MoE 模型的总参数量与激活参数量</summary>有些模型说明会同时给出“总参数量”和“每个 token 激活的参数量”。这是因为模型内部有多组“专家”,每次只选择其中一部分参与计算;这种结构叫 混合专家模型(MoE)。
可以先把它理解为:模型有许多可用的处理分支,但不是每次都经过所有分支。选择分支的过程通常称为路由。
“本次只用了部分专家”主要影响参与的计算量,并不等于训练时只需要保存这些专家的全部相关文件和状态。不能只按激活参数量估算整个模型的加载显存。
把不同专家分到不同设备,又会涉及专家并行。本课程的单卡关键词主线不使用这种配置。
</details>