一、多卡同步概述:为什么需要多卡同步、同步与异步的区别、常见的多卡训练范式
大家好,我是你们的老朋友。今天咱们聊聊多卡同步这个话题。
说实话,我刚入行那会儿,觉得单卡训练挺香的。一张V100丢上去,跑个ResNet-50,三天出结果,美滋滋。直到有一天,老板丢给我一个GPT级别的模型——单卡训练要跑三个月。嗯,那一刻我明白了,多卡同步不是选择题,是生存题。
1.1 为什么需要多卡同步?
先问个问题:你让10个人一起搬砖,结果有人搬得快,有人搬得慢,最后这堵墙能砌整齐吗?
多卡训练也是这个道理。每张GPU都在独立计算梯度,但最终模型参数只有一份。如果各卡各算各的,不互相通气,那模型就乱套了。
我总结三个核心原因:
- 梯度一致性:每张卡算出的梯度必须汇总,否则参数更新方向不一致
- 模型收敛:不同步会导致loss震荡,甚至发散。我在项目中遇到过,8卡训练loss死活降不下去,最后发现是同步逻辑写错了
- 硬件利用率:同步机制决定了卡与卡之间的等待关系,直接影响训练吞吐
核心观点:多卡同步的本质,是用通信开销换取计算加速。没有同步,多卡就是一群散兵游勇。
1.2 同步与异步的区别
这个坑我踩过。当年做分布式训练,图省事用了异步模式,结果模型精度掉了两个点。后来排查了三天,才发现是梯度延迟导致的。
咱们直接看对比:
| 特性 | 同步训练 | 异步训练 |
|---|---|---|
| 梯度更新 | 所有卡算完才更新 | 谁先算完谁先更新 |
| 收敛稳定性 | 高,数学上等价于单卡 | 低,存在梯度陈旧问题 |
| 训练速度 | 受最慢卡限制 | 快,无等待 |
| 实现复杂度 | 简单,AllReduce一把梭 | 复杂,需要处理梯度延迟 |
说白了,同步模式是「共同富裕」——大家一起算完再更新,虽然慢但稳。异步模式是「先富带动后富」——谁先算完谁先更新,快是快了,但容易跑偏。
避坑指南:我曾经在百卡集群上试过异步训练,梯度延迟超过10个step,模型直接不收敛。如果你不是做强化学习这类对延迟不敏感的场景,建议老老实实用同步模式。
1.3 常见的多卡训练范式
聊完为什么同步,咱们看看怎么同步。目前主流的有三种范式,我按使用频率排序:
数据并行(Data Parallelism)
这是最常用的方式。每张卡都有一份完整的模型副本,但只处理一部分数据。每张卡算完梯度后,通过AllReduce操作把梯度汇总,然后同步更新参数。
你想想看,这就像10个学生做同一套卷子,每人只做10道题,最后对答案。谁做错了,大家一起改。
代码示例(PyTorch DDP):
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel
model = MyModel().to(device)
model = DistributedDataParallel(model)
for data in dataloader:
outputs = model(data)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step() # 内部自动完成梯度同步
个人经验:DDP是我用得最多的方案。它内部用了桶(bucket)机制,把梯度打包后一次性通信,效率比老版的DataParallel高不少。我建议新手直接上DDP,别碰DataParallel。
模型并行(Model Parallelism)
当模型大到一张卡放不下时,就得把模型拆开。比如Transformer有12层,每张卡放3层,数据流依次经过各卡。
这种方式的难点在于:卡与卡之间有依赖关系。前一层算完才能算后一层,没法并行。所以模型并行通常用于单机多卡场景,跨机器延迟太高。
我做过一个千亿参数模型,就是模型并行+数据并行混合使用。嗯,那段时间我基本住在机房了。
流水线并行(Pipeline Parallelism)
这是模型并行的升级版。把模型分成多个阶段(stage),每个阶段放在一张卡上。数据被切分成微批次(micro-batch),像流水线一样依次流过各个阶段。
举个例子:模型分4个阶段,数据分4个微批次。第一个微批次进入阶段1时,阶段2是空闲的。等它进入阶段2,阶段1就可以处理第二个微批次了。这样就能让所有卡同时工作。
GPipe和PipeDream是两种经典实现。我个人更倾向GPipe,因为它用同步梯度更新,收敛更稳定。
一句话总结:数据并行解决「数据太多」,模型并行解决「模型太大」,流水线并行解决「模型并行效率低」。
知识体系总览
下面这张图是我手绘的,把三种范式的关系和适用场景说清楚了:
这张图里,从左到右,模型规模越来越大,通信模式也越来越复杂。数据并行最简单,流水线并行最灵活。实际工程中,这三种范式经常混合使用。
好了,这一章就聊到这儿。多卡同步的核心就三件事:为什么要同步、怎么同步、用什么范式同步。下一章咱们深入AllReduce的底层实现,看看梯度到底是怎么在卡之间传递的。
课后思考:如果你有4张卡,模型刚好能放进1张卡,但数据量很大。你会选数据并行还是模型并行?为什么?