一、分布式训练基础概念
什么是分布式训练
分布式训练,说白了就是把一个超大模型的训练任务,拆成多份,交给多台机器一起干。
我刚开始接触这个概念时,也觉得有点玄乎。后来在项目中真正跑了一次千亿参数模型,才明白它的重要性。你想想看,单卡显存就那么大,模型一放大,根本塞不进去。
分布式训练的核心思路其实很简单:
- 把模型拆开——每台机器负责一部分
- 把数据拆开——每台机器处理不同的数据
- 把梯度汇总——算完后再同步更新参数
嗯,这里要注意,分布式不是简单的「多机多卡」就完事了。通信开销、同步策略、负载均衡,哪一环出问题,训练效率可能还不如单卡。
核心定义:分布式训练 = 多计算节点 + 协同训练 + 参数同步
为什么需要分布式训练
这个问题,我在面试时经常被问到。其实答案很直白:
- 模型太大了——GPT-3 1750亿参数,单卡显存根本装不下
- 数据太多了——TB级训练数据,单机跑完要几个月
- 时间等不起——业务迭代周期短,训练速度就是竞争力
我记得有一次,团队要训练一个百亿参数的推荐模型。单卡跑一次需要45天。后来上了分布式,8台机器并行,时间压缩到6天。这就是分布式训练的价值。
个人经验:我建议不要一上来就上分布式。先评估模型大小和数据量。如果单卡能跑,优先单卡。分布式带来的通信开销,有时候反而得不偿失。
数据并行与模型并行
这是分布式训练的两大基本范式。我习惯把它们比作「分工方式」:
| 对比维度 | 数据并行 | 模型并行 |
|---|---|---|
| 核心思路 | 每卡一份完整模型,分数据 | 每卡一部分模型,处理全部数据 |
| 适用场景 | 模型能塞进单卡,数据量大 | 模型太大,单卡放不下 |
| 通信模式 | 梯度同步(AllReduce) | 激活值传递(P2P) |
| 典型框架 | PyTorch DDP, Horovod | Megatron-LM, DeepSpeed |
数据并行详解
数据并行是最常用的方式。每张卡上都有一份完整的模型副本,但只处理不同的数据批次。
举个例子:你有4张卡,batch size=64。每张卡分到16条数据,各自前向传播、计算梯度。然后通过 AllReduce 操作,把梯度汇总平均,再统一更新参数。
我曾经踩过一个坑:数据并行时,如果 batch size 太大,模型收敛会变慢。后来我习惯用「线性缩放法则」——卡数翻倍,学习率也适当调大。
# PyTorch DDP 典型用法
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
# 初始化进程组
dist.init_process_group(backend='nccl')
# 模型包装
model = MyModel().to(device)
model = DDP(model, device_ids=[local_rank])
# 训练循环
for data, target in dataloader:
output = model(data)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
注意:数据并行要求模型能完整放入单卡显存。如果模型太大,强行用数据并行会导致 OOM。这时候就该考虑模型并行了。
模型并行详解
模型并行是把模型「切」成多块,每张卡只负责其中一部分。
我参与过一个千亿参数模型的训练,用的就是模型并行。模型被按层切分:第1-10层在卡0,第11-20层在卡1,依此类推。前向传播时,数据像流水线一样,从卡0传到卡1,再传到卡2...
这里有个关键点:模型并行的通信量比数据并行大得多。因为每层之间都要传递激活值和梯度。所以网络带宽很重要,我建议用 NVLink 或 InfiniBand。
# 模型并行示意(伪代码)
class ModelParallelModule(nn.Module):
def __init__(self):
self.layer1 = nn.Linear(1024, 1024).to('cuda:0')
self.layer2 = nn.Linear(1024, 1024).to('cuda:1')
def forward(self, x):
x = self.layer1(x)
x = x.to('cuda:1') # 跨卡传输
x = self.layer2(x)
return x
混合并行:实际项目中的选择
说实话,实际项目中很少只用一种并行策略。大模型训练通常是「混合并行」——数据并行 + 模型并行 + 流水线并行一起上。
我习惯这样设计:
- 层间模型并行:把模型按层切分,解决显存问题
- 层内数据并行:每层内部用多卡并行计算
- 流水线并行:让不同微批次在模型不同阶段同时计算
避坑指南:我曾经在混合并行时,忽略了通信拓扑的优化。结果8台机器,通信占了一半时间。后来改用环形 AllReduce,效率提升了3倍。记住:通信优化和计算优化同样重要。
总结一下:分布式训练不是银弹。选对策略,才能事半功倍。我个人习惯先跑小规模实验,验证并行策略的有效性,再上全量训练。这样能避免很多坑。
一句话记住:数据并行解决「数据太多」,模型并行解决「模型太大」,混合并行解决「既要又要」。