博客
关于我
PyTorch 多机多卡训练:DDP 实战与技巧
阅读量:799 次
发布时间:2023-04-15

本文共 2432 字,大约阅读时间需要 8 分钟。

PyTorch多机多卡DDP加速实践指南

PyTorch的多机多卡分布式训练(DDP)技术,能够显著提升训练效率。以下是基于实践总结的一系列优化技巧和实现方案。

1. SyncBN引入与性能优化

SyncBN的核心作用

Batch Normalization(BN)在深度学习中扮演着重要角色。然而,在多卡训练环境下,传统BN存在性能瓶颈。PyTorch提出的SyncBN(Sync Batch Normalization)有效解决了这一问题。

SyncBN通过分布式接口all_gather,实现了真正的多卡BN训练。其核心优化包括只传输小批量的mean和variance,减少了通信开销。

SyncBN的实现要点

  • 原理:各卡计算小批量mean和variance,通过all_gather同步得到全局统计量。
  • 依赖:SyncBN仅在DDP单进程单卡模式下支持,需在DDP环境初始化后使用。

实践技巧

  • 使用torch.nn.SyncBatchNorm.convert_sync_batchnorm将普通BN替换为SyncBN。
  • 注意:自定义BN类需继承_BatchNorm,否则无法直接替换。

2. DDP下的梯度累加优化

梯度累加的意义

梯度累加(Gradient Accumulation)允许多个小步骤合并为一个大步骤,提升训练效率。然而,在DDP环境下,传统梯度累加方式存在效率低下问题。

优化方法

  • 使用model.no_sync()临时禁用梯度同步。
  • 优雅写法:结合nullcontextcontextlib.nullcontext,实现梯度累加与同步控制。

实践示例

from contextlib import nullcontext
if local_rank != -1:
model = DDP(model)
optimizer.zero_grad()
for i, (data, label) in enumerate(dataloader):
my_context = model.no_sync if local_rank != -1 and i % K != 0 else nullcontext
with my_context():
prediction = model(data)
loss_fn(prediction, label).backward()
if i % K == 0:
optimizer.step()
optimizer.zero_grad()

3. 多机多卡推理加速

推理性能瓶颈

在多卡训练环境下,推理测试难以充分利用多卡资源。

解决方案

  • 数据分割:使用自定义SequentialDistributedSampler,实现连续数据分割。
  • 结果聚合:通过all_gather接口,聚合各卡推理结果。

实践流程

  • 数据分割
  • class SequentialDistributedSampler(torch.utils.data.sampler.Sampler):
    def __init__(self, dataset, batch_size, rank, num_replicas):
    # ...(完整实现见参考代码)
    1. 结果聚合
    2. def distributed_concat(tensor, num_total_examples):
      output_tensors = [tensor.clone() for _ in range(torch.distributed.get_world_size())]
      torch.distributed.all_gather(output_tensors, tensor)
      concat = torch.cat(output_tensors, dim=0)
      return concat[:num_total_examples]

      4. 数据一致性保证

      随机种子管理

      为保证一致性,需在不同进程间分配不同的随机种子。

      实践方法

      def init_seeds(seed=0, cuda_deterministic=True):
      random.seed(seed)
      np.random.seed(seed)
      torch.manual_seed(seed)
      if cuda_deterministic:
      cudnn.deterministic = True
      cudnn.benchmark = False
      else:
      cudnn.deterministic = False
      cudnn.benchmark = True
      rank = torch.distributed.get_rank()
      init_seeds(1 + rank)

      5. 实用小技巧

      控制进程执行顺序

      • 单进程操作:直接判断当前进程是否为主进程。
      if rank == 0:
      # 进行独特操作
      torch.distributed.barrier()
      • 同步操作:使用torch.distributed.barrier()实现多进程同步。

      防止冗余输出

      • 日志控制:根据进程设置不同输出等级。
      logging.basicConfig(level=logging.INFO if rank in [-1, 0] else logging.WARN)
      logging.error("This is a fatal log!")

      总结

      通过以上优化,充分发挥多卡环境性能。建议结合实际场景灵活调整配置,逐步提升训练效率。更多内容请参考前两篇DDP系列文章。

    转载地址:http://pgrfk.baihongyu.com/

    你可能感兴趣的文章
    mysql 编译安装 window篇
    查看>>
    mysql 网络目录_联机目录数据库
    查看>>
    MySQL 聚簇索引&&二级索引&&辅助索引
    查看>>
    Mysql 脏页 脏读 脏数据
    查看>>
    mysql 自增id和UUID做主键性能分析,及最优方案
    查看>>
    Mysql 自定义函数
    查看>>
    mysql 行转列 列转行
    查看>>
    Mysql 表分区
    查看>>
    mysql 表的操作
    查看>>
    mysql 视图,视图更新删除
    查看>>
    MySQL 触发器
    查看>>
    mysql 让所有IP访问数据库
    查看>>
    mysql 记录的增删改查
    查看>>
    MySQL 设置数据库的隔离级别
    查看>>
    MySQL 证明为什么用limit时,offset很大会影响性能
    查看>>
    Mysql 语句操作索引SQL语句
    查看>>
    MySQL 误操作后数据恢复(update,delete忘加where条件)
    查看>>
    MySQL 调优/优化的 101 个建议!
    查看>>
    mysql 转义字符用法_MySql 转义字符的使用说明
    查看>>
    mysql 输入密码秒退
    查看>>