PyTorch多GPU训练时同步梯度是mean还是sum?

PyTorch 通过两种方式可以进行多GPU训练: DataParallel, DistributedDataParallel. 当使用DataParallel的时候, 梯度的计算结果和在单卡上跑是一样的, 对每个数据计算出来的梯度进行累加. 当使用DistributedDataParallel的时候, 每个卡单独计算梯度, 然后多卡的梯度再进行平均.
下面是实验验证:

DataParallel

import torch
import os
import torch.nn as nn

def main():
    model = nn.Linear(2, 3).cuda()
    model = torch.nn.DataParallel(model, device_ids=[0, 1])
    input = torch.rand(2, 2)
    labels = torch.tensor([[1, 0, 0], [0, 1, 0]]).cuda()
    (model(input) * labels).sum().backward()
    print('input', input)
    print([p.grad for p in model.parameters()])


if __name__=="__main__":
    main()

执行CUDA_VISIBLE_DEVICES=0,1 python t.py可以看到输出, 代码中对两个样本分别求梯度, 梯度等于样本的值, DataParallel把两个样本的梯度累加起来在不同GPU中同步.

input tensor([[0.4362, 0.4574],
        [0.2052, 0.2362]])
[tensor([[0.4363, 0.4573],
        [0.2052, 0.2362],
        
<think>嗯,用户问的是PyTorch单卡训练代码改成训练后精度下降的原因。首先,我需要回忆一下分布式训练中常见的问题。可能的原因有几个,比如数据并行中的BatchNorm层处理,学习率调整,参数初始化不一致,数据划分方式,或者梯度同步的问题。 首先,BatchNorm在卡情况下会分别计算每个卡上的均值和方差,这可能导致和单卡的统计量不同,影响模型性能。然后,学习率方面,如果使用数据并行,有效批量大小增加了,可能需要调整学习率。比如,单卡batch是32,4卡的话总batch变成128,学习率可能需要线性缩放,但用户可能没调整,导致收敛不同。 参数初始化也可能有问题,如果模型在初始化没有保证各卡参数一致,比如某些层在初始化有随机性,但主卡和其他卡参数不同步的话,会影响训练结果。另外,数据划分是否均匀,如果数据分布不均匀,或者shuffle方式不同,也会导致训练差异。 还有梯度同步训练梯度是平均还是求和?PyTorch的DataParallel是平均梯度,而DistributedDataParallel是求和,这里如果处理不当,可能会影响参数更新,进而影响精度。此外,随机数种子的设置,如果在卡中没有同步随机种子,比如数据增强的随机性不同,导致每卡看到的数据增强不一致,也会引入差异。 另外,可能还有一些细节,比如混合精度训练,如果开启FP16,但没正确处理梯度缩放,或者某些操作在FP16下不稳定,导致数值误差累积。或者是卡通信中的瓶颈,导致某些梯度同步不及,参数更新有延迟。 用户可能没有正确使用DistributedDataParallel,或者DataParallel在某些情况下效率不高,导致梯度同步的问题。另外,训练,验证过程是否只在主卡上进行,如果验证没有汇总所有卡的数据,可能会影响评估指标,但用户的问题是关于训练精度的,所以可能更是在训练过程中出现的问题。 总结下来,可能的原因包括:BatchNorm统计量、学习率未调整、参数初始化不一致、数据划分或shuffle问题、梯度同步方式、随机种子不同步、混合精度处理不当等。需要逐一检查这些方面,给出解决方案。</think>PyTorch单卡训练代码改为训练精度下降的常见原因及解决方法如下: --- ### 一、BatchNorm层统计量差异 #### 现象 - 单卡BatchNorm计算的是单卡数据的均值和方差 - **卡数据并行,默认每个GPU独立计算BatchNorm统计量**,导致与单卡统计分布不一致 #### 解决方法 ```python # 使用SyncBatchNorm(需DistributedDataParallel) model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model) model = DDP(model, device_ids=[local_rank]) ``` --- ### 二、学习率与批量大小的适配 #### 现象 - 训练总批量大小变为 `batch_size * num_gpus` - **未按线性缩放规则调整学习率**,导致优化轨迹不同 #### 调整公式 $$\text{新学习率} = \text{原学习率} \times \frac{\text{总批量大小}}{\text{单卡批量大小}}$$ #### 代码示例 ```python base_lr = 0.1 effective_batch_size = batch_size * world_size optimizer = torch.optim.SGD(model.parameters(), lr=base_lr * effective_batch_size) ``` --- ### 三、随机数种子同步 #### 现象 - 卡未同步随机种子,**数据增强、参数初始化等随机操作不一致** #### 解决方法 ```python def set_seed(seed): torch.manual_seed(seed) np.random.seed(seed) random.seed(seed) torch.cuda.manual_seed_all(seed) # 分布式训练初始化同步种子 if args.distributed: seed = 42 # 主进程设置 set_seed(seed) torch.distributed.broadcast(torch.tensor([seed]), src=0) # 广播到所有进程 ``` --- ### 四、梯度聚合方式差异 #### 现象 - DataParallel默认对梯度取平均 - **当各卡数据分布差异大梯度方向可能被弱化** #### 验证方法 ```python # 检查梯度是否同步 with torch.no_grad(): for p in model.parameters(): if p.grad is not None: print(f"梯度均值: {p.grad.mean().item()}, 方差: {p.grad.var().item()}") ``` --- ### 五、数据划分不一致 #### 现象 - 单卡加载全部数据,卡使用DistributedSampler - **数据shuffle未正确同步导致epoch间数据分布变化** #### 正确配置 ```python from torch.utils.data.distributed import DistributedSampler train_sampler = DistributedSampler( dataset, num_replicas=world_size, rank=rank, shuffle=True, seed=42 # 必须设置统一随机种子 ) dataloader = DataLoader(dataset, sampler=train_sampler) ``` --- ### 六、验证指标计算方式 #### 现象 - 卡验证直接在各个GPU上计算指标 - **未使用all_reduce同步会导致指标计算错误** #### 正确实现 ```python def reduce_tensor(tensor): rt = tensor.clone() torch.distributed.all_reduce(rt, op=torch.distributed.ReduceOp.SUM) rt /= torch.distributed.get_world_size() return rt acc = calculate_accuracy(...) acc = reduce_tensor(acc) ``` --- ### 总结排查步骤 1. **检查BatchNorm实现**:是否转换为SyncBatchNorm 2. **验证学习率策略**:总批量大小是否适配 3. **确保随机一致性**:种子同步、数据划分 4. **监控梯度分布**:比较单卡与卡的梯度统计量 5. **验证指标同步**:使用all_reduce聚合结果 通过上述方法系统性排查,通常可以解决90%以上的训练精度下降问题。实际调试可逐步开启卡功能(如先禁用BatchNorm同步),通过控制变量定位问题根源。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值