将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实现从url中提取域名的几种方法
Sep 26 Python
Python类的专用方法实例分析
Jan 09 Python
python登录pop3邮件服务器接收邮件的方法
Apr 30 Python
Django自定义插件实现网站登录验证码功能
Apr 19 Python
详解numpy的argmax的具体使用
May 27 Python
10分钟教你用python动画演示深度优先算法搜寻逃出迷宫的路径
Aug 12 Python
Python上下文管理器类和上下文管理器装饰器contextmanager用法实例分析
Nov 07 Python
python suds访问webservice服务实现
Jun 26 Python
Python3爬虫里关于识别微博宫格验证码的知识点详解
Jul 30 Python
python 下载m3u8视频的示例代码
Nov 11 Python
python中函数返回多个结果的实例方法
Dec 16 Python
Python基础之变量的相关知识总结
Jun 23 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 编程请选择正确的文本编辑软件
2006/12/21 PHP
ajax实现无刷新分页(php)
2010/07/18 PHP
Zend Framework框架之Zend_Mail实现发送Email邮件验证功能及解决标题乱码的方法
2016/03/21 PHP
PHP 将数组打乱 shuffle函数的用法及简单实例
2016/06/17 PHP
PHP项目多语言配置平台实现过程解析
2020/05/18 PHP
用jscript实现列出安装的软件列表
2007/06/18 Javascript
js 颜色选择器(兼容firefox)
2009/03/05 Javascript
asp(javascript)全角半角转换代码 dbc2sbc
2009/08/06 Javascript
当鼠标移动到图片上时跟随鼠标显示放大的图片效果
2013/06/06 Javascript
iScroll中事件点击触发两次解决方案
2015/03/11 Javascript
JavaScript使用DeviceOne开发实战(二) 生成调试安装包
2015/12/01 Javascript
浅析JavaScript中的array数组类型系统
2016/07/18 Javascript
jQuery实现的placeholder效果完整实例
2016/08/02 Javascript
Express之get,pos请求参数的获取
2017/05/02 Javascript
vue修改vue项目运行端口号的方法
2017/08/04 Javascript
javascript、php关键字搜索函数的使用方法
2018/05/29 Javascript
详解babel升级到7.X采坑总结
2019/05/12 Javascript
node 标准输入流和输出流代码实例
2019/09/19 Javascript
Jquery滑动门/tab切换实现方法完整示例
2020/06/05 jQuery
基于jquery实现彩色投票进度条代码解析
2020/08/26 jQuery
python通过ftplib登录到ftp服务器的方法
2015/05/08 Python
Django 忘记管理员或忘记管理员密码 重设登录密码的方法
2018/05/30 Python
python实现自主查询实时天气
2018/06/22 Python
Python 通过requests实现腾讯新闻抓取爬虫的方法
2019/02/22 Python
Python实现定期检查源目录与备份目录的差异并进行备份功能示例
2019/02/27 Python
浅谈python 中类属性共享的问题
2019/07/02 Python
Python logging自定义字段输出及打印颜色
2020/11/30 Python
GEOX鞋美国官方网站:意大利会呼吸的鞋
2017/07/12 全球购物
搬家公司的创业计划书
2014/01/01 职场文书
捐资助学倡议书
2014/04/15 职场文书
中学生爱国演讲稿
2014/09/05 职场文书
2015年见习期工作总结
2014/12/12 职场文书
2019年入党思想汇报
2019/03/25 职场文书
position:sticky 粘性定位的几种巧妙应用详解
2021/04/24 HTML / CSS
mysql中int(3)和int(10)的数值范围是否相同
2021/10/16 MySQL
pytorch中的torch.nn.Conv2d()函数图文详解
2022/02/28 Python