在 PyTorch 分布式训练中,混合精度训练
在 PyTorch 分布式训练中,混合精度训练(AMP,Automatic Mixed Precision)和梯度累积(Gradient Accumulation)是两种常用的优化技术,可以显著提升训练效率和模型性能。• 昇腾 NPU:将torch.cuda.amp替换为torch.npu.amp,并确保后端为hccl。• 解决:调整init_scale(默认2**16)或使用scaler.upd
在 PyTorch 分布式训练中,混合精度训练(AMP,Automatic Mixed Precision)和梯度累积(Gradient Accumulation)是两种常用的优化技术,可以显著提升训练效率和模型性能。以下是它们的实现方法和关键注意事项,结合之前的 DDP 流程进行扩展。
------
1. 混合精度训练(AMP)
混合精度训练通过使用 FP16(半精度浮点)和 FP32(单精度浮点)的组合,减少显存占用并加速计算。PyTorch 提供了torch.cuda.amp或torch.npu.amp(昇腾 NPU)模块来简化实现。
关键步骤
1. 初始化 AMP:使用GradScaler管理梯度缩放。
2. 包装前向和反向传播:在autocast上下文中执行计算。
3. 更新权重:使用scaler.step()和scaler.update()。
代码示例
【python】
from torch.cuda.amp import GradScaler, autocast # GPU用cuda.amp,NPU用npu.amp
def train(rank, world_size):
model = ... # 初始化模型和DDP(见前文)
train_loader = prepare_dataloader(rank, world_size)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
scaler = GradScaler() # 初始化梯度缩放器
for epoch in range(10):
model.train()
train_loader.sampler.set_epoch(epoch)
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
data = data.view(data.size(0), -1)
optimizer.zero_grad()
# 使用autocast混合精度计算
with autocast():
output = model(data)
loss = criterion(output, target)
# 反向传播(梯度缩放)
scaler.scale(loss).backward()
scaler.step(optimizer) # 更新权重
scaler.update() # 更新缩放因子
if batch_idx % 100 == 0 and rank == 0:
print(f"Epoch: {epoch} | Batch: {batch_idx} | Loss: {loss.item()}")
关键点
• autocast():自动选择 FP16/FP32 计算,减少显存占用。
• GradScaler:防止 FP16 梯度下溢(underflow)。
• 昇腾 NPU:将torch.cuda.amp替换为torch.npu.amp,并确保后端为hccl。
------
2. 梯度累积
梯度累积通过在多个批次上累积梯度,模拟更大批次(batch size)的训练效果,适用于显存不足的场景。
关键步骤
1. 设置累积步数:例如accum_steps=4表示每 4 个批次更新一次权重。
2. 跳过优化器更新:仅在累积足够步数后执行optimizer.step()。
3. 同步梯度:DDP 会自动处理跨进程的梯度同步。
代码示例
【python】
def train(rank, world_size):
model = ... # 初始化模型和DDP
train_loader = prepare_dataloader(rank, world_size)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
accum_steps = 4 # 累积4个批次的梯度
for epoch in range(10):
model.train()
train_loader.sampler.set_epoch(epoch)
optimizer.zero_grad() # 初始化梯度
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
data = data.view(data.size(0), -1)
output = model(data)
loss = criterion(output, target) / accum_steps # 损失归一化
loss.backward() # 反向传播(梯度累积)
# 每accum_steps更新一次权重
if (batch_idx + 1) % accum_steps == 0:
optimizer.step()
optimizer.zero_grad()
if batch_idx % 100 == 0 and rank == 0:
print(f"Epoch: {epoch} | Batch: {batch_idx} | Loss: {loss.item() * accum_steps}")
关键点
• 损失归一化:loss = loss / accum_steps避免梯度放大。
• 梯度清零:在optimizer.step()后调用zero_grad()。
• 与 AMP 结合:在autocast上下文中使用梯度累积:
【python】
with autocast():
output = model(data)
loss = criterion(output, target) / accum_steps
scaler.scale(loss).backward()
if (batch_idx + 1) % accum_steps == 0:
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
------
3. 完整流程整合
将 DDP、AMP 和梯度累积结合的完整训练流程:
【python】
def train(rank, world_size):
model = ... # 初始化模型和DDP
train_loader = prepare_dataloader(rank, world_size)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
scaler = GradScaler()
accum_steps = 4
for epoch in range(10):
model.train()
train_loader.sampler.set_epoch(epoch)
optimizer.zero_grad()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
data = data.view(data.size(0), -1)
with autocast():
output = model(data)
loss = criterion(output, target) / accum_steps
scaler.scale(loss).backward()
if (batch_idx + 1) % accum_steps == 0:
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
if batch_idx % 100 == 0 and rank == 0:
print(f"Epoch: {epoch} | Batch: {batch_idx} | Loss: {loss.item() * accum_steps}")
------
常见问题与解决
Q1: 混合精度训练损失爆炸
• 原因:梯度缩放因子(GradScaler)设置不当。
• 解决:调整init_scale(默认2**16)或使用scaler.update()动态调整。
Q2: 梯度累积效果不明显
• 原因:累积步数(accum_steps)设置过小,或学习率未调整。
• 解决:增大accum_steps或按比例调整学习率(如lr *= accum_steps)。
Q3: 多进程打印冲突
• 原因:所有进程同时打印日志。
• 解决:仅rank == 0的进程打印日志。
------
总结
1. 混合精度训练:通过autocast和GradScaler减少显存占用并加速计算。
2. 梯度累积:通过多批次累积梯度,模拟更大批次训练。
3. 结合使用:在autocast上下文中实现梯度累积,并注意损失归一化和梯度清零。
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐


所有评论(0)