将Pytorch模型从CPU转换成GPU的实现方法


Posted in Python onAugust 19, 2019

最近将Pytorch程序迁移到GPU上去的一些工作和思考

环境:Ubuntu 16.04.3

Python版本:3.5.2

Pytorch版本:0.4.0

0. 序言

大家知道,在深度学习中使用GPU来对模型进行训练是可以通过并行化其计算来提高运行效率,这里就不多谈了。

最近申请到了实验室的服务器来跑程序,成功将我简陋的程序改成了“高大上”GPU版本。

看到网上总体来说少了很多介绍,这里决定将我的一些思考和工作记录下来。

1. 如何进行迁移

由于我使用的是Pytorch写的模型,网上给出了一个非常简单的转换方式: 对模型和相应的数据进行.cuda()处理。通过这种方式,我们就可以将内存中的数据复制到GPU的显存中去。从而可以通过GPU来进行运算了。

网上说的非常简单,但是实际使用过程中还是遇到了一些疑惑。下面分数据和模型两方面的迁移来进行说明介绍。

1.1 判定使用GPU

下载了对应的GPU版本的Pytorch之后,要确保GPU是可以进行使用的,通过torch.cuda.is_available()的返回值来进行判断。返回True则具有能够使用的GPU。

通过torch.cuda.device_count()可以获得能够使用的GPU数量。其他就不多赘述了。

常常通过如下判定来写可以跑在GPU和CPU上的通用模型:

if torch.cuda.is_available():
  ten1 = ten1.cuda()
  MyModel = MyModel.cuda()

2. 对应数据的迁移

数据方面常用的主要是两种 —— Tensor和Variable。实际上这两种类型是同一个东西,因为Variable实际上只是一个容器,这里先视其不同。

2.1 将Tensor迁移到显存中去

不论是什么类型的Tensor(FloatTensor或者是LongTensor等等),一律直接使用方法.cuda()即可。

例如:

ten1 = torch.FloatTensor(2)
>>>> 6.1101e+24
   4.5659e-41
   [torch.FloatTensor of size 2]

ten1_cuda = ten1.cuda()
>>>>  6.1101e+24
    4.5659e-41
    [torch.cuda.FloatTensor of size 2 (GPU 0)]

其数据类型会由torch.FloatTensor变为torch.cuda.FloatTensor (GPU 0)这样代表这个数据现在存储在

GPU 0的显存中了。

如果要将显存中的数据复制到内存中,则对cuda数据类型使用.cpu()方法即可。

2.2 将Variable迁移到显存中去

在模型中,我们最常使用的是Variable这个容器来装载使用数据。主要是由于Variable可以进行反向传播来进行自动求导。

同样地,要将Variable迁移到显存中,同样只需要使用.cuda()即可实现。

这里有一个小疑问,对Variable直接使用.cuda和对Tensor进行.cuda然后再放置到Variable中结果是否一致呢。答案是肯定的。

ten1 = torch.FloatTensor(2)
>>> 6.1101e+24
   4.5659e-41
  [torch.FloatTensor of size 2]

ten1_cuda = ten1.cuda()
>>>> 6.1101e+24
   4.5659e-41
  [torch.cuda.FloatTensor of size 2 (GPU 0)]

V1_cpu = autograd.Variable(ten1)
>>>> Variable containing:
   6.1101e+24
   4.5659e-41
  [torch.FloatTensor of size 2]

V2 = autograd.Variable(ten1_cuda)
>>>> Variable containing:
   6.1101e+24
   4.5659e-41
  [torch.cuda.FloatTensor of size 2 (GPU 0)]

V1 = V1_cpu.cuda()
>>>> Variable containing:
   6.1101e+24
   4.5659e-41
  [torch.cuda.FloatTensor of size 2 (GPU 0)]

最终我们能发现他们都能够达到相同的目的,但是他们完全一样了吗?我们使用V1 is V2发现,结果是否定的。

对于V1,我们是直接对Variable进行操作的,这样子V1的.grad_fn中会记录下创建的方式。因此这二者并不是完全相同的。

2.3 数据迁移小结

.cuda()操作默认使用GPU 0也就是第一张显卡来进行操作。当我们想要存储在其他显卡中时可以使用.cuda(<显卡号数>)来将数据存储在指定的显卡中。还有很多种方式,具体参考官方文档。

对于不同存储位置的变量,我们是不可以对他们直接进行计算的。存储在不同位置中的数据是不可以直接进行交互计算的。

换句话说也就是上面例子中的torch.FloatTensor是不可以直接与torch.cuda.FloatTensor进行基本运算的。位于不同GPU显存上的数据也是不能直接进行计算的。

对于Variable,其实就仅仅是一种能够记录操作信息并且能够自动求导的容器,实际上的关键信息并不在Variable本身,而更应该侧重于Variable中存储的data。

3. 模型迁移

模型的迁移这里指的是torch.nn下面的一些网络模型以及自己创建的模型迁移到GPU上去。

上面讲了使用.cuda()即可将数据从内存中移植到显存中去。

对于模型来说,也是同样的方式,我们使用.cuda来将网络放到显存上去。

3.1 torch.nn下的基本模型迁移

这里使用基本的单层感知机来进行举例(线性模型)。

data1 = torch.FloatTensor(2)
data2 = data1.cuda

# 创建一个输入维度为2,输出维度为2的单层神经网络
linear = torch.nn.Linear(2, 2)
>>>> Linear(in_features=2, out_features=2)

linear_cuda = linear.cuda()
>>>> Linear(in_features=2, out_features=2)

我们很惊奇地发现对于模型来说,不像数据那样使用了.cuda()之后会改变其的数据类型。模型看起来没有任何的变化。

但是他真的没有改变吗。

我们将data1投入linear_cuda中去可以发现,系统会报错,而将.cuda之后的data2投入linear_cuda才能正常工作。并且输出的也是具有cuda的数据类型。

那是怎么一回事呢?

这是因为这些所谓的模型,其实也就是对输入参数做了一些基本的矩阵运算。所以我们对模型.cuda()实际上也相当于将模型使用到的参数存储到了显存上去。

对于上面的例子,我们可以通过观察参数来发现区别所在。

linear.weight
>>>> Parameter containing:
  -0.6847 0.2149
  -0.5473 0.6863
  [torch.FloatTensor of size 2x2]

linear_cuda.weight
>>>> Parameter containing:
  -0.6847 0.2149
  -0.5473 0.6863
  [torch.cuda.FloatTensor of size 2x2 (GPU 0)]

3.2 自己模型的迁移

对于自己创建的模型类,由于继承了torch.nn.Module,则可同样使用.cuda()来将模型中用到的所有参数都存储到显存中去。

这里笔者曾经有一个疑问:当我们对模型存储到显存中去之后,那么这个模型中的方法后面所创建出来的Tensor是不是都会默认变成cuda的数据类型。答案是否定的。具体操作留给读者自己去实现。

3.3 模型小结

对于模型而言,我们可以将其看做是一种类似于Variable的容器。我们对它进行.cuda()处理,是将其中的参数放到显存上去(因为实际使用的时候也是通过这些参数做运算)。

4. 总结

Pytorch使用起来直接简单,GPU的使用也是简单明了。然而对于多GPU和CPU的协同使用则还是有待提高。

以上这篇将Pytorch模型从CPU转换成GPU的实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python模拟登录百度贴吧(百度贴吧登录)实例
Dec 18 Python
Python 执行字符串表达式函数(eval exec execfile)
Aug 11 Python
Python中处理时间的几种方法小结
Apr 09 Python
Python中title()方法的使用简介
May 20 Python
Python遍历目录中的所有文件的方法
Jul 08 Python
python读取几个G的csv文件方法
Jan 07 Python
Python递归函数实例讲解
Feb 27 Python
Python二叉树的镜像转换实现方法示例
Mar 06 Python
利用python-docx模块写批量生日邀请函
Aug 26 Python
基于python实现蓝牙通信代码实例
Nov 19 Python
python GUI库图形界面开发之PyQt5线程类QThread详细使用方法
Feb 26 Python
python实现同一局域网下传输图片
Mar 20 Python
pytorch 使用单个GPU与多个GPU进行训练与测试的方法
Aug 19 #Python
在pytorch中为Module和Tensor指定GPU的例子
Aug 19 #Python
pytorch使用指定GPU训练的实例
Aug 19 #Python
关于pytorch多GPU训练实例与性能对比分析
Aug 19 #Python
pytorch 更改预训练模型网络结构的方法
Aug 19 #Python
pytorch打印网络结构的实例
Aug 19 #Python
pytorch索引查找 index_select的例子
Aug 18 #Python
You might like
php侧拉菜单 漂亮,可以向右或者向左展开,支持FF,IE
2009/10/15 PHP
php验证码实现代码(3种)
2015/09/07 PHP
windows下的WAMP环境搭建图文教程(推荐)
2017/07/27 PHP
js 操作符实例代码
2009/10/24 Javascript
jquery实现的带缩略图的焦点图片切换(自动播放/响应鼠标动作)
2013/01/23 Javascript
JQuery中使用ajax传输超大数据的解决方法
2014/07/14 Javascript
js表单中选择框值的获取及表单的序列化
2015/12/17 Javascript
论Bootstrap3和Foundation5网格系统的异同
2016/05/16 Javascript
jquery.Jcrop结合JAVA后台实现图片裁剪上传实例
2016/11/05 Javascript
JS动态遍历json中所有键值对的方法(不知道属性名的情况)
2016/12/28 Javascript
JavaScript 实现 Tab 点击切换实例代码
2017/03/25 Javascript
微信小程序踩坑记录之解决tabBar.list[3].selectedIconPath大小超过40kb
2018/07/04 Javascript
JavaScript实现浅拷贝与深拷贝的方法分析
2018/07/05 Javascript
vue里input根据value改变背景色的实例
2018/09/29 Javascript
node微信开发之获取access_token+自定义菜单
2019/03/17 Javascript
微信小程序实现授权登录
2019/05/15 Javascript
nodejs实现的http、https 请求封装操作示例
2020/02/06 NodeJs
js+canvas实现图片格式webp/png/jpeg在线转换
2020/08/22 Javascript
[01:23:35]Ti4主赛事胜者组 DK vs EG 1
2014/07/19 DOTA
Python内置函数dir详解
2015/04/14 Python
Python Django框架实现应用添加logging日志操作示例
2019/05/17 Python
Python全局锁中如何合理运用多线程(多进程)
2019/11/06 Python
使用html5 canvas绘制圆环动效
2019/06/03 HTML / CSS
美国现代家具购物网站:LexMod
2019/01/09 全球购物
这段代码难道不该打印出56吗
2013/02/27 面试题
Shell编程面试题
2016/05/29 面试题
中学实习教师自我鉴定
2013/12/12 职场文书
党的群众路线教育实践活动批评与自我批评
2014/02/16 职场文书
珠宝店促销方案
2014/03/21 职场文书
国旗下的讲话演讲稿
2014/05/08 职场文书
信用卡逾期证明示例
2014/09/13 职场文书
《为人民服务》教学反思
2016/02/20 职场文书
go mod 安装依赖 unkown revision问题的解决方案
2021/05/06 Golang
Java实现给Word文件添加文字水印
2022/02/15 Java/Android
python opencv将多个图放在一个窗口的实例详解
2022/02/28 Python
九大龙王魂骨,山龙王留下躯干骨,榜首死的最憋屈(被捏碎)
2022/03/18 国漫