当前位置: 首页 > news >正文

Pytorch分布式训练/多卡训练(二) —— Data Parallel并行(DDP)(2.3)(torch.multiprocessing(spawn) Apex)

使用 torch.multiprocessing 取代torch.distributed.launch启动器

      我们可以手动使用 torch.multiprocessing 进行多进程控制。绕开 torch.distributed.launch 自动控制开启和退出进程的一些小毛病

      使用时,只需要调用 torch.multiprocessing.spawn,torch.multiprocessing 就会帮助我们自动创建进程。

import torch.multiprocessing as mp

mp.spawn(main_worker, nprocs=4, args=(4, myargs))

      这里spawn 开启了 nprocs=4 个进程,每个进程执行 main_worker 并向其中传入 local_rank(当前进程 index)和 args(即 4 和 myargs)作为参数

      这样我们就将原本需要 torch.distributed.launch 管理的执行内容,封装进 main_worker 函数中

      值得注意的是,由于没有 torch.distributed.launch 读取的默认环境变量作为配置,我们需要手动为 init_process_group 指定参数

      添加 multiprocessing 后并行训练部分主要与如下代码段有关

# main.py
import torch
import torch.distributed as dist
import torch.multiprocessing as mp

mp.spawn(main_worker, nprocs=4, args=(4, myargs))

def main_worker(proc, nprocs, args):

   dist.init_process_group(backend='nccl', init_method='tcp://127.0.0.1:23456', world_size=4, rank=gpu)
   torch.cuda.set_device(args.local_rank)

   train_dataset = ...
   train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset)

   train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler)

   model = ...
   model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank])

   optimizer = optim.SGD(model.parameters())

   for epoch in range(100):
      for batch_idx, (data, target) in enumerate(train_loader):
          images = images.cuda(non_blocking=True)
          target = target.cuda(non_blocking=True)
          ...
          output = model(images)
          loss = criterion(output, target)
          ...
          optimizer.zero_grad()
          loss.backward()
          optimizer.step()

在使用时,直接使用 python 运行就可以了:

python main.py

使用 Apex 再加速

      Apex 是 NVIDIA 开源的用于混合精度训练和分布式训练库。

      注意apex不只是混合精度库,也是一个分布式训练库!!!

      Apex 对混合精度训练的过程进行了封装,改两三行配置就可以进行混合精度的训练,从而大幅度降低显存占用,节约运算时间。此外,Apex 也提供了对分布式训练的封装,针对 NVIDIA 的 NCCL 通信库进行了优化。

      在混合精度训练上,Apex 的封装十分优雅。直接使用 amp.initialize 包装模型和优化器,apex 就会自动帮助我们管理模型参数和优化器的精度了,根据精度需求不同可以传入其他配置参数。

from apex import amp

model, optimizer = amp.initialize(model, optimizer)

       在分布式训练的封装上,Apex 在胶水层的改动并不大,主要是优化了 NCCL 的通信。因此,大部分代码仍与 torch.distributed 保持一致。使用的时候只需要将

       torch.nn.parallel.DistributedDataParallel 替换为 apex.parallel.DistributedDataParallel 用于包装模型。在 API 层面,相对于 torch.distributed ,它可以自动管理一些参数(可以少传一点):

from apex.parallel import DistributedDataParallel

model = DistributedDataParallel(model)
# # torch.distributed
# model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank])
# model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank], output_device=args.local_rank)

      在正向传播计算 loss 时,Apex 需要使用 amp.scale_loss 包装,用于根据 loss 值自动对精度进行缩放:

with amp.scale_loss(loss, optimizer) as scaled_loss:
   scaled_loss.backward()

汇总一下,Apex 的并行训练部分主要与如下代码段有关

# main.py
import torch
import argparse
import torch.distributed as dist

from apex.parallel import DistributedDataParallel

parser = argparse.ArgumentParser()
parser.add_argument('--local_rank', default=-1, type=int,
                    help='node rank for distributed training')
args = parser.parse_args()

dist.init_process_group(backend='nccl')
torch.cuda.set_device(args.local_rank)

train_dataset = ...
train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset)

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler)

model = ...
model, optimizer = amp.initialize(model, optimizer)
model = DistributedDataParallel(model, device_ids=[args.local_rank])

optimizer = optim.SGD(model.parameters())

for epoch in range(100):
   for batch_idx, (data, target) in enumerate(train_loader):
      images = images.cuda(non_blocking=True)
      target = target.cuda(non_blocking=True)
      ...
      output = model(images)
      loss = criterion(output, target)
      optimizer.zero_grad()
      with amp.scale_loss(loss, optimizer) as scaled_loss:
         scaled_loss.backward()
      optimizer.step()

在使用时,调用 torch.distributed.launch 启动器启动:

CUDA_VISIBLE_DEVICES=0,1,2,3 python -m torch.distributed.launch --nproc_per_node=4 main.py

相关文章:

  • OpenStack
  • Python logging日志模块
  • CUDA编程(三) —— 编程实践
  • Python函数传参(*星号)
  • Python调用函数带括号和不带括号的区别
  • Microsoft CMT 系统
  • Python导入上层目录中的包(..) / 导入同级目录的包 (相对导入)
  • mxnet导出模型json和params文件
  • Linux(ubuntu)(0.5) —— 装系统相关
  • Python OrderedDict(collections) 有序字典 orderdict
  • .gitattributes 文件
  • 简单PageRank —— 希拉里邮件门
  • Python NetworkX
  • Python复杂网络结构可视化——matplotlib+networkx
  • FairScale
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • Java 网络编程(2):UDP 的使用
  • java正则表式的使用
  • Linux CTF 逆向入门
  • nfs客户端进程变D,延伸linux的lock
  • spring cloud gateway 源码解析(4)跨域问题处理
  • swift基础之_对象 实例方法 对象方法。
  • TCP拥塞控制
  • TypeScript实现数据结构(一)栈,队列,链表
  • Vue--数据传输
  • 从setTimeout-setInterval看JS线程
  • 分享一份非常强势的Android面试题
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 计算机常识 - 收藏集 - 掘金
  • 马上搞懂 GeoJSON
  • 微信小程序:实现悬浮返回和分享按钮
  • 微信小程序设置上一页数据
  • 【干货分享】dos命令大全
  • 翻译 | The Principles of OOD 面向对象设计原则
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​ArcGIS Pro 如何批量删除字段
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • #pragma once
  • (2)Java 简介
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (十五)使用Nexus创建Maven私服
  • (五)MySQL的备份及恢复
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)甲方乙方——赵民谈找工作
  • ***通过什么方式***网吧
  • . Flume面试题
  • .java 9 找不到符号_java找不到符号
  • .NET MVC第三章、三种传值方式
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?