前言

在数据越来越多的时代,随着模型规模参数的增多,以及数据量的不断提升,使用多GPU去训练是不可避免的事情。Pytorch在0.4.0及以后的版本中已经提供了多GPU训练的方式,本文简单讲解下使用Pytorch多GPU训练的方式以及一些注意的地方。

这里我们谈论的是单主机多GPUs训练,与分布式训练不同,我们采用的主要Pytorch功能函数为DataParallel而不是DistributedParallel,后者为多主机多GPUs的训练方式,但是在实际任务中,两种使用方式也存在一部分交集。

 
 

使用方式

使用多卡训练的方式有很多,当然前提是我们的设备中存在两个及以上的GPU:使用命令nvidia-smi查看当前Ubuntu平台的GPU数量(Windows平台类似),其中每个GPU被编上了序号:[0,1]:

 
 

在我们设备中确实存在多卡的条件下,最简单的方法是直接使用torch.nn.DataParallel将你的模型wrap一下即可:

net=torch.nn.DataParallel(model)

这时,默认所有存在的显卡都会被使用。

如果我们机子中有很多显卡(例如我们有八张显卡),但我们只想使用0、1、2号显卡,那么我们可以:

net=torch.nn.DataParallel(model,device_ids=[0,1,2])

或者这样:

 
 

很简单的操作,这样我们就可以比较方便地使用多卡进行训练了。

另一种方法

在前言中提到过,另一种方法DistributedParallel,虽然主要的目标为分布式训练,但也是可以实现单主机多GPU方式训练的,只不过比上一种方法稍微麻烦一点,但是训练速度和效果比上一种更好。

为什么呢?

请看官方相关介绍:

 
 

nccl backend is currently the fastest and highly recommended backend to be used with Multi-Process Single-GPU distributed training and this applies to both single-node and multi-node distributed training

好了,来说说具体的使用方法(下面展示一个node也就是一个主机的情况)为:

 
 

上述的命令和我们平常的命令稍有区别,这里我们用到了torch.distributed.launch这个module,我们选择运行的方式变换为python -m,上面相当于使用torch.distributed.launch.py去运行我们的YOUR_TRAINING_SCRIPT.py,其中torch.distributed.launch会向我们的运行程序传递一些变量。

为此,我们的YOUR_TRAINING_SCRIPT.py也就是我们的训练代码中这样写(省略多余代码,只保留核心代码):

 
 

我们要注意,上述代码在运行的过程中产生了很多个,具体多少个取决你GPU的数量,这也是为什么上面需要torch.cuda.set_device(args.local_rank)设定默认的GPU,因为torch.distributed.launch为我们触发了n个YOUR_TRAINING_SCRIPT.py进程,n就是我们将要使用的GPU数量。

有一点想问的,我们每次必须要使用命令行的方式去运行吗?当然也可以一键解决,如果我们使用Pycharm,只需要配置成下面这样就可以了:

 
 

单显卡与DataParallel多显卡训练对比

最近两天训练一个魔改的mobilenetv2+yolov3,同样的优化方法同样的学习率衰减率,所有的参数都相同的情况下,发现单显卡训练的方式竟然比多显卡训练的方式收敛更快。

配置为两张1080Ti,使用Pytorch的版本为1.0.0。下图红线为使用一张1080Ti训练的情况,蓝线为使用两张1080Ti训练的情况,batchsize每张显卡设置为10,也就是说,使用两张显卡训练时的batchsize为单张显卡的两倍,同一个step时,双卡走的步数为单卡步数的两倍。这里使用的多卡训练方式为DataParallel。

但是下图可以看到,在双卡相同step的情况下,虽然红色曲线的损失相较蓝色下降的稍微慢一些,但是到了一定时候,两者的损失值会相交(此时未达到最低损失点),也就是说使用双卡和单卡训练时候loss损失收敛的速度是一样的。

 
 

更奇怪的是,下图中,在验证集中,单显卡虽然没有双显卡的准确度曲线增长迅速,但是到了某一点,单显卡的曲线会超过双显卡训练的精度,也就是说,单卡训练在前期没有双卡训练效果显著,但是到了训练中期效果就会优于双卡。

 
 

(上述两个图为训练早期和中期的展示,并没有完全训练完毕)关于为什么会这样的情况,有可能是因为训练中期所有的激活值更新幅度不是很明显(一般来说,权重值和激活值更新幅度在训练前期比较大),在不同GPU转化之间会损失一部分精度?。当然这仅仅是猜测,博主还没有仔细研究这个问题,待有结论时会在这里进行更新。

注意点

多GPU固然可以提升我们训练的速度,但弊端还有有一些的,有几个我们需要注意的点:

多个GPU的数量尽量为偶数,奇数的GPU有可能会出现中断的情况

选取与GPU数量相适配的数据集,多显卡对于比较小的数据集来说反而不如单个显卡训练的效果好

多GPU训练的时候注意机器的内存是否足够(一般为使用显卡显存x2),如果不够,建议关闭pin_memory(锁页内存)选项。

采用DistributedDataParallel多GPUs训练的方式比DataParallel更快一些,如果你的Pytorch编译时有nccl的支持,那么最好使用DistributedDataParallel方式。

关于什么是锁页内存:

pin_memory就是锁页内存,创建DataLoader时,设置pin_memory=True,则意味着生成的Tensor数据最开始是属于内存中的锁页内存,这样将内存的Tensor转义到GPU的显存就会更快一些。

主机中的内存,有两种存在方式,一是锁页,二是不锁页,锁页内存存放的内容在任何情况下都不会与主机的虚拟内存进行交换(注:虚拟内存就是硬盘),而不锁页内存在主机内存不足时,数据会存放在虚拟内存中。显卡中的显存全部是锁页内存,当计算机的内存充足的时候,可以设置pin_memory=True。当系统卡住,或者交换内存使用过多的时候,设置pin_memory=False。因为pin_memory与电脑硬件性能有关,pytorch开发者不能确保每一个炼丹玩家都有高端设备,因此pin_memory默认为False。

 

作者:我爱学python
链接:https://www.jianshu.com/p/bb28669018b3
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Pytorch中多GPU训练指北的更多相关文章

  1. Pytorch:使用GPU训练

    1.模型转为cuda gpus = [0] #使用哪几个GPU进行训练,这里选择0号GPU cuda_gpu = torch.cuda.is_available() #判断GPU是否存在可用 net ...

  2. pytorch中查看gpu信息

    其他:windows使用nvidia-smi查看gpu信息 为什么将数据转移至GPU的方法叫做.cuda而不是.gpu,就像将数据转移至CPU调用的方法是.cpu?这是因为GPU的编程接口采用CUDA ...

  3. 转pytorch中训练深度神经网络模型的关键知识点

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_42279044/articl ...

  4. pytorch 多GPU训练总结(DataParallel的使用)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/weixin_40087578/artic ...

  5. Pytorch多GPU训练

    Pytorch多GPU训练 临近放假, 服务器上的GPU好多空闲, 博主顺便研究了一下如何用多卡同时训练 原理 多卡训练的基本过程 首先把模型加载到一个主设备 把模型只读复制到多个设备 把大的batc ...

  6. pytorch中如何使用预训练词向量

    不涉及具体代码,只是记录一下自己的疑惑. 我们知道对于在pytorch中,我们通过构建一个词向量矩阵对象.这个时候对象矩阵是随机初始化的,然后我们的输入是单词的数值表达,也就是一些索引.那么我们会根据 ...

  7. PyTorch在NLP任务中使用预训练词向量

    在使用pytorch或tensorflow等神经网络框架进行nlp任务的处理时,可以通过对应的Embedding层做词向量的处理,更多的时候,使用预训练好的词向量会带来更优的性能.下面分别介绍使用ge ...

  8. [源码解析] PyTorch 如何使用GPU

    [源码解析] PyTorch 如何使用GPU 目录 [源码解析] PyTorch 如何使用GPU 0x00 摘要 0x01 问题 0x02 移动模型到GPU 2.1 cuda 操作 2.2 Modul ...

  9. pytorch中tensorboardX的用法

    在代码中改好存储Log的路径 命令行中输入 tensorboard --logdir /home/huihua/NewDisk1/PycharmProjects/pytorch-deeplab-xce ...

随机推荐

  1. Django项目:CRM(客户关系管理系统)--09--04PerfectCRM实现King_admin注册功能01

  2. OpenLayers在地图外放置控件

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...

  3. Haskell 学习

    truncate pi -- 表示截断, 此处结果为 3 haskell中的touple是可变的,而python中是不可变的 lines函数: lines :: String -> [Strin ...

  4. 大数据技术之Hive

    第1章 Hive入门 1.1 什么是Hive Hive:由Facebook开源用于解决海量结构化日志的数据统计. Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提 ...

  5. oracle如何检查用户是否用了默认密码

    如果使用默认密码,很可能就对你的数据库造成一定的安全隐患,那么可以使用如下的查询获得那些用户使用默认密码 select username "User(s) with Default Pass ...

  6. php 正则学习取反符号~

    php 正则学习取反符号~ ~(<a .*?>.*?</a>|<.*?>)~i 先看正则图形,有点偏差,但可以初步看出结果. 关于 ~ 是取反符号,看下面说明.

  7. SqlSugar 笔记

    分组: 日期分组一: var result = await temp .GroupBy("date_format(Day,'%Y-%m')") .Select(s => ne ...

  8. js、php判断手机PC

    用于phpcms <script type="text/javascript"> var url = window.location.href; if(/Android ...

  9. NDK(1)简介

    AndroidNDK Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”. Android程序运行在Dalv ...

  10. 【NS2】用eclipse调试NS2(转载)

    相信很多喜欢Java的人对eclipse都情有独钟.NS2程序的调试,可以用打印命令调试,这样太繁琐.也可以用gdb调试,个人觉得上手比较困难.相信各位学习NS2的新手,在看代码的时候,很多的函数或者 ...