4. 分布式训练基础:数据并行、模型并行、流水线并行、张量并行概念解析
分布式训练,说白了就是让多个GPU一起干活。你想想看,单卡训练大模型,显存不够、速度太慢,怎么办?那就把活分出去,大家一起干。
我刚开始接触分布式训练时,也搞不清这些并行策略到底有啥区别。后来在项目中踩了不少坑,才慢慢摸清楚门道。今天咱们就把这四种并行方式掰开揉碎了讲清楚。
4.1 数据并行——最常用的并行方式
数据并行,顾名思义,就是把数据切分到多个GPU上。每个GPU都有一份完整的模型副本,但只处理一部分数据。
举个例子:假设你有4张卡,每张卡上都放着一个一模一样的模型。训练数据有1024条,那就每张卡分256条。每张卡各自算梯度,然后汇总求平均,再更新所有卡的模型参数。
核心流程:
- 将batch数据切分到各GPU
- 每个GPU独立前向传播、计算损失
- 每个GPU独立反向传播,得到梯度
- AllReduce操作汇总梯度
- 每个GPU用平均后的梯度更新参数
我在项目中遇到过一个问题:当模型大到一张卡放不下时,数据并行就失效了。因为每张卡都需要完整的模型副本,显存不够就是不够。这时候就得考虑其他并行方式了。
我的经验:数据并行适合模型能塞进单卡的情况。如果模型太大,别硬撑,换别的方案。
4.2 模型并行——把模型拆开
模型并行,就是把模型本身切分成多个部分,分别放到不同的GPU上。每个GPU只负责模型的一部分计算。
比如一个12层的Transformer,你可以把前6层放在GPU0上,后6层放在GPU1上。数据先经过GPU0,算完再把中间结果传给GPU1继续算。
嗯,这里要注意:模型并行有个天然的问题——计算串行化。GPU0算完之前,GPU1只能干等着。这会导致GPU利用率不高。
避坑指南:我曾经在一个项目中把模型切成4块放在4张卡上,结果发现大部分时间都在等待数据传输,实际加速比远低于预期。后来才意识到,模型并行要尽量让各部分的计算量均衡,否则会出现「木桶效应」。
4.3 流水线并行——让GPU忙起来
流水线并行,说白了就是模型并行的升级版。它解决了模型并行中GPU空闲等待的问题。
怎么解决的?把数据也切成小份,像流水线一样送进去。GPU0算完第一个小份,就把结果传给GPU1,同时GPU0开始算第二个小份。这样所有GPU都能同时工作。
举个例子:
# 传统模型并行(串行)
GPU0: [batch1] → GPU1: [batch1] → GPU2: [batch1] → GPU3: [batch1]
GPU0: [batch2] → GPU1: [batch2] → GPU2: [batch2] → GPU3: [batch2]
# 流水线并行
GPU0: [batch1] → GPU1: [batch1] → GPU2: [batch1] → GPU3: [batch1]
[batch2] → [batch2] → [batch2] → [batch2]
[batch3] → [batch3] → [batch3] → [batch3]
你看,流水线并行让所有GPU几乎同时在工作,利用率高多了。
我个人习惯把流水线并行想象成工厂的流水线。每个GPU就是一个工位,数据就是待加工的产品。产品依次经过每个工位,所有工位同时开工,效率自然高。
小技巧:流水线并行中,micro-batch的大小很关键。太小了通信开销大,太大了又会导致GPU空闲。我一般会调成让每个micro-batch的计算时间刚好覆盖通信延迟。
4.4 张量并行——最细粒度的并行
张量并行,是在单个算子层面做切分。比如一个矩阵乘法,可以拆成多个小矩阵乘法,分别在不同GPU上算,最后再拼起来。
这跟模型并行不一样。模型并行是按层切分,张量并行是按张量(矩阵)切分。说白了,张量并行更「微观」。
举个例子,一个全连接层 y = xW,其中W是一个大矩阵。我们可以把W按列切成两块:
W = [W1, W2] # 按列切分
y = x * [W1, W2] = [x*W1, x*W2] # 两个GPU分别计算
y = concat([y1, y2]) # 最后拼起来
张量并行在Megatron-LM、DeepSpeed等框架中广泛使用。它能把超大模型塞进多卡,但通信量也很大,因为每次计算都要同步中间结果。
四种并行方式对比:
| 并行方式 | 切分对象 | 通信频率 | 适用场景 |
|---|---|---|---|
| 数据并行 | 数据 | 每个batch一次 | 模型能塞进单卡 |
| 模型并行 | 模型层 | 每层一次 | 模型太大,单卡放不下 |
| 流水线并行 | 模型层+数据 | 每个micro-batch一次 | 需要提高GPU利用率 |
| 张量并行 | 张量/矩阵 | 每个算子一次 | 超大模型,单层都放不下 |
4.5 知识体系总览
下面这张图,是我自己总结的分布式训练并行策略全景图。你看一眼就能明白它们之间的关系:
4.6 实际项目中的选择建议
说了这么多,到底该用哪种?我个人的经验是:
- 模型能塞进单卡:直接用数据并行,简单高效
- 模型稍大,单卡放不下:试试流水线并行,利用率高
- 模型超大,单层都放不下:必须上张量并行
- 追求极致性能:组合使用,比如3D并行
我曾经踩过的坑:一开始做分布式训练时,我总想着把所有并行方式都用上,结果通信开销巨大,反而比单卡还慢。后来才明白,并行不是越多越好,要根据模型大小和硬件条件来选。记住一个原则:能不并行就不并行,能少并行就少并行。
好了,这四种并行方式就讲到这里。你想想看,其实核心就一句话:数据并行分数据,模型并行分层,流水线并行分流水,张量并行分矩阵。搞清楚了切分对象,剩下的就是调参和踩坑了。