当前位置:网站首页>torch单机多卡和多机多卡训练
torch单机多卡和多机多卡训练
2022-08-04 21:49:00 【爱CV】
前言 本文主要介绍单机多卡训练和多机多卡训练的实现方法和一些注意事项。其中单机多卡训练介绍两种实现方式,一种是DP方式,一种是DDP方式。多机多卡训练主要介绍两种实现方式,一种是通过horovod库,一种是DDP方式。
单机单卡训练
前面我们已经介绍了一个完整的训练流程,但这里由于要介绍单机多卡和多机多卡训练的代码,为了能更好地理解它们之间的区别,这里先放一个单机单卡也就是一般情况下的代码流程。
import torch
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
train_dataset = ...
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=...)
model = ...
optimizer = optim.SGD(model.parameters())
for epoch in range(opt.num_epoch):
for i, (input, target) in enumerate(train_loader):
input= input.to(device)
target = target.to(device)
...
output = model(input)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()
单机多卡训练
单机多卡训练的部分有两种实现方式,一种是DP方式,一种是DDP方式。
nn.DataParallel(DP)
DP方式比较简单,仅仅通过nn.DataParallel对网络进行处理即可。
其它部分基本与单机单卡训练流程相同。
import torch
train_dataset = ...
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=...)
model = ...
model = nn.DataParallel(model.to(device), device_ids=None, output_device=None)
optimizer = optim.SGD(model.parameters())
for epoch in range(opt.num_epoch):
for i, (input, target) in enumerate(train_loader):
input= input.cuda()
target = target.cuda()
...
output = model(input)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()
上面唯一关键的一句是在定义model后,使用nn.DataParallel把模型放到各个GPU上。
其中,device_dis有几种设置方式,如果设置为None, 如下几行源码所示,默认使用所有gpu
#nn.DataParallel中的源码
if device_ids is None:
device_ids = list(range(torch.cuda.device_count()))
if output_device is None:
output_device = device_ids[0
也可以手动指定用哪几个gpu。如下所示
gpus = [0, 1, 2, 3]
torch.cuda.set_device('cuda:{}'.format(gpus[0]))
model = nn.DataParallel(model.to(device), device_ids=None, output_device=gpus[0]
DDP方式
上面DP是比较简单的单机多卡的实现方式,但DDP是更高效的方式,不过实现要多几行代码。
该部分代码由读者投稿,非本人原创。
import torch
import argparse
import torch.distributed as dist
parser = argparse.ArgumentParser()
parser.add_argument('--local_rank', default=-1, type=int,
help='node rank for distributed training')
opt = parser.parse_args()
# 初始化GPU通信方式(NCCL)和参数的获取方式(env代表通过环境变量)。
dist.init_process_group(backend='nccl', init_method='env://')
torch.cuda.set_device(opt.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)
#使用 DistributedDataParallel 包装模型,
#它能帮助我们为不同 GPU 上求得的梯度进行 all reduce
#(即汇总不同 GPU 计算所得的梯度,并同步计算结果)。
#all reduce 后不同 GPU 中模型的梯度均为 all reduce 之前各 GPU 梯度的均值。
model = ...
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank])
optimizer = optim.SGD(model.parameters())
for epoch in range(opt.num_epoch):
for i, (input, target) in enumerate(train_loader):
input= input.cuda()
target = target.cuda()
...
output = model(input)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()
#运行命令
CUDA_VISIBLE_DEVICES=0,1,2,3 python -m torch.distributed.launch --nproc_per_node=4 train.py
下面对这段代码进行解析。
设置local_rank参数,可以把这个参数理解为进程编号。该参数在运行上面这条指令时就会确定,每块GPU上的该参数都会不一样。
配置初始化方式,一般有tcp方式和env方式。上面是用的env,下面是用tcp方式用法。
dist.init_process_group(backend='nccl', init_method='tcp://localhost:23456'
通过local_rank来确定该进程的设备:torch.cuda.set_device(opt.local_rank)
数据加载部分我们在该教程的第一篇里介绍过,主要时通过torch.utils.data.distributed.DistributedSampler来获取每个gpu上的数据索引,每个gpu根据索引加载对应的数据,组合成一个batch,与此同时Dataloader里的shuffle必须设置为None。
多机多卡训练
多机多卡训练的一般有两种实现方式,一种是上面这个DDP方式,这里我们就不再介绍了,另一种是使用一个额外的库horovod。
Horovod
Horovod是基于Ring-AllReduce方法的深度分布式学习插件,以支持多种流行架构包括TensorFlow、Keras、PyTorch等。这样平台开发者只需要为Horovod进行配置,而不是对每个架构有不同的配置方法。
来自博客:
https://blog.csdn.net/weixin_44388679/article/details/106564349
该部分代码由读者投稿,非本人原创。
import torch
import horovod.torch as hvd
hvd.init()
torch.cuda.set_device(hvd.local_rank())
train_dataset = ...
train_sampler = torch.utils.data.distributed.DistributedSampler(
train_dataset, num_replicas=hvd.size(), rank=hvd.rank)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler)
model = ...
model.cuda()
optimizer = optim.SGD(model.parameters())
optimizer = hvd.DistributedOptimizer(optimizer, named_parameters=model.named_parameters())
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
for epoch in range(opt.num_epoch):
for i, (input, target) in enumerate(train_loader):
input= input.cuda()
target = target.cuda()
...
output = model(input)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()
if hvd.rank()==0:
print("loss: ")
下面对以上代码进行简单的介绍。
与DDP相同的是,先初始化,再根据进程设置当前设备,然后使用torch.utils.data.distributed.DistributedSampler来产生每个GPU读取数据的索引。
不同的是接下来几个操作,horovod不需要使用torch.nn.parallel.DistributedDataParallel,而是通过使用horovod的两个库,通过hvd.DistributedOptimizer和hvd.broadcast_parameters分别对优化器和模型参数进行处理。
除了训练以外,其它操作基本都在主进程上完成,例如打印信息,保存模型等。通过最后if hvd.rank()==0来判定。
除了DDP和horovod这两种方式实现多机多卡以外,实际上在混合精度训练里的库apex也有对应的多机多卡训练实现方式,但这个我们就留到下一篇混合精度训练和半精度训练中来介绍。
边栏推荐
- 硬件开发定制全流程解析
- 8 年产品经验,我总结了这些持续高效研发实践经验 · 协同篇
- UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xd6 in position 120: invalid continuation byte
- ES6高级-Promise的用法
- JdbcTemplate概述和测试
- Codeforces Round #811 (Div. 3)
- 立即升级!WPS Office 出现 0day 高危安全漏洞:可完全接管系统,官方推出紧急更新
- boostrap多选PID查找端口 window
- 传奇服务器需要什么配置?传奇服务器租用价格表
- 《剑指offer》刷题分类
猜你喜欢
PowerCLi import license to vCenter 7
【SQL之降龙十八掌】01——亢龙有悔:入门10题
国际项目管理师PMP证书,值得考嘛?
ue unreal 虚幻 高分辨率无缩放 编辑器字太小 调整编辑器整体缩放
Win11如何开启Telnet客户端?
y87.第五章 分布式链路追踪系统 -- 分布式链路追踪系统起源(一)
SPSS-System Clustering Hand Calculation Practice
Hands-on Deep Learning_NiN
如何将二叉搜索树转化为一个有序的双向链表(原树上修改)
STM32MP157A驱动开发 | 01- 板载LED作为系统心跳指示灯
随机推荐
rk3399-9.0一级二级休眠
LeetCode143:重排链表
PMP证书在哪些行业有用?
Analysis and treatment of Ramnit infectious virus
数字重塑客观世界,全空间GIS发展正当其时
JWT actively checks whether the Token has expired
如何根据“前序遍历,中序遍历”,“中序遍历,后序遍历”构建按二叉树
CountDownLatch使用及原理
OC-协议
docker 部署redis集群
国内的PMP证书含金量到底如何
laravel whereDoesntHave
webmine网页挖矿木马分析与处置
如何一键重装Win11系统 一键重装系统方法
Chapter7 : Network-Driven Drug Discovery
LayaBox---TypeScript---Problems encountered at first contact
Develop your own text recognition application with Tesseract
Some problems with passing parameters of meta and params in routing (can be passed but not passed, empty, collocation, click to pass multiple parameters to report an error)
VSCode—常用快捷键(持续记录
OC-拷贝