一、为什么需要分布式训练?
1.1 现代深度学习的算力困境
- 模型复杂度爆炸式增长:GPT-3(1750亿参数)、Switch Transformer(1.6万亿参数)
- 数据集规模扩大:ImageNet(128万图片)、YouTube-8M(800万视频)
- 单卡训练瓶颈:
- NVIDIA A100 80GB最大batch size仅能处理BERT-Large的batch size=32
- 单卡训练ResNet-50 on ImageNet需要29小时(参考DAWNBench数据)
1.2 分布式训练的核心优势
# 加速比计算公式
加速比 = 1 / [(1 - α) + α / N]
# α: 可并行化计算比例
# N: GPU数量
GPU数量 | 理论加速比(α=0.95) | 实际典型加速比 |
---|---|---|
2 | 1.90 | 1.85 |
4 | 3.63 | 3.40 |
8 | 6.40 | 5.80 |
二、DataParallel原理与实战
2.1 架构设计深度解析
class DataParallel(nn.Module):
def __init__(self, module, device_ids=None, output_device=None):
super().__init__()
self.module = module
self.device_ids = device_ids
self.output_device = output_device
def forward(self, inputs):
# 1. Scatter阶段
inputs = scatter(inputs, self.device_ids)
# 2. Replicate模型
replicas = replicate(self.module, self.device_ids)
# 3. Parallel_apply并行计算
outputs = parallel_apply(replicas, inputs)
# 4. Gather结果
return gather(outputs, self.output_device)
2.1.1 数据流分解
-
输入切分:
- 自动将batch维度切分为N份(N=GPU数量)
- 示例:batch_size=64,4 GPU → 每个GPU处理16个样本
-
模型复制:
- 主GPU(默认device_ids[0])保存原始模型
- 其他GPU获得模型副本(浅拷贝)
-
梯度同步:
- 反向传播时各GPU计算本地梯度
- 梯度自动求和到主GPU
- 主GPU执行参数更新后广播新参数
2.2 训练示例
import torch.optim as optim
from torch.nn.parallel import DataParallel
# 模型定义
model = resnet152(pretrained=True)
model = DataParallel(model, device_ids=[0,1,2,3]).cuda()
# 优化器配置
optimizer = optim.SGD(model.parameters(), lr=0.1 * 4) # 学习率线性缩放
# 数据加载
train_loader = DataLoader(dataset, batch_size=256, shuffle=True)