关于PyTorch 自动求导机制详解


Posted in Python onAugust 18, 2019

自动求导机制

从后向中排除子图

每个变量都有两个标志:requires_grad和volatile。它们都允许从梯度计算中精细地排除子图,并可以提高效率。

requires_grad

如果有一个单一的输入操作需要梯度,它的输出也需要梯度。相反,只有所有输入都不需要梯度,输出才不需要。如果其中所有的变量都不需要梯度进行,后向计算不会在子图中执行。

>>> x = Variable(torch.randn(5, 5))
>>> y = Variable(torch.randn(5, 5))
>>> z = Variable(torch.randn(5, 5), requires_grad=True)
>>> a = x + y
>>> a.requires_grad
False
>>> b = a + z
>>> b.requires_grad
True

这个标志特别有用,当您想要冻结部分模型时,或者您事先知道不会使用某些参数的梯度。

autograd是专门为了BP算法设计的,所以这autograd只对输出值为标量的有用,因为损失函数的输出是一个标量。如果y是一个向量,那么backward()函数就会失效。

model = torchvision.models.resnet18(pretrained=True)
for param in model.parameters():
  param.requires_grad = False
# Replace the last fully-connected layer
# Parameters of newly constructed modules have requires_grad=True by default
model.fc = nn.Linear(512, 100)

# Optimize only the classifier
optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)

上面的optim.SGD()只需要传入需要优化的参数即可。

volatile

纯粹的inference模式(可以理解为只需要进行前向)下推荐使用volatile,当你确定你甚至不会调用.backward()时。它比任何其他自动求导的设置更有效——它将使用绝对最小的内存来评估模型。volatile也决定了require_grad is False。

volatile不同于require_grad的传递。如果一个操作甚至只有有一个volatile的输入,它的输出也将是volatile。Volatility比“不需要梯度”更容易传递——只需要一个volatile的输入即可得到一个volatile的输出,相对的,需要所有的输入“不需要梯度”才能得到不需要梯度的输出。使用volatile标志,您不需要更改模型参数的任何设置来用于inference。创建一个volatile的输入就够了,这将保证不会保存中间状态。

>>> regular_input = Variable(torch.randn(5, 5))
>>> volatile_input = Variable(torch.randn(5, 5), volatile=True)
>>> model = torchvision.models.resnet18(pretrained=True)
>>> model(regular_input).requires_grad
True
>>> model(volatile_input).requires_grad
False
>>> model(volatile_input).volatile
True
>>> model(volatile_input).creator is None
True

自动求导如何编码历史信息

每个变量都有一个.creator属性,它指向把它作为输出的函数。这是一个由Function对象作为节点组成的有向无环图(DAG)的入口点,它们之间的引用就是图的边。每次执行一个操作时,一个表示它的新Function就被实例化,它的forward()方法被调用,并且它输出的Variable的创建者被设置为这个Function。然后,通过跟踪从任何变量到叶节点的路径,可以重建创建数据的操作序列,并自动计算梯度。

variable和function它们是彼此不分开的,先上图:

关于PyTorch 自动求导机制详解

如图,假设我们有一个输入变量input(数据类型为Variable)input是用户输入的,所以其创造者creator为null值,input经过第一个数据操作operation1(比如加减乘除运算)得到output1变量(数据类型仍为Variable),这个过程中会自动生成一个function1的变量(数据类型为Function的一个实例),而output1的创造者就是这个function1。随后,output1再经过一个数据操作生成output2,这个过程也会生成另外一个实例function2,output2的创造者creator为function2。

在这个向前传播的过程中,function1和function2记录了数据input的所有操作历史,当output2运行其backward函数时,会使得function2和function1自动反向计算input的导数值并存储在grad属性中。

creator为null的变量才能被返回导数,比如input,若把整个操作流看成是一张图(Graph),那么像input这种creator为null的被称之为图的叶子(graph leaf)。而creator非null的变量比如output1和output2,是不能被返回导数的,它们的grad均为0。所以只有叶子节点才能被autograd。

>>> from torch.autograd import Variable
>>> import torch
>>> x = Variable(torch.ones(2), requires_grad = >>> True)
>>> z=4*x*x
>>> y=z.norm()
>>> y
Variable containing:
 5.6569
[torch.FloatTensor of size 1]
>>> y.backward()
>>> x.grad
Variable containing:
 5.6569
 5.6569
[torch.FloatTensor of size 2]
>>> z.grad

>>> y.grad

Variable上的In-place操作

in-place计算,类似'+='运算,表示内部直接替换,in-place操作都使用_作为后缀。例如,x.copy_(y)

>>> a = torch.Tensor(3,4)
>>> a
 0 0 0 0
 0 0 0 0
 0 0 0 0
[torch.FloatTensor of size 3x4]
>>> a.fill_(2.5)  
 2.5000 2.5000 2.5000 2.5000
 2.5000 2.5000 2.5000 2.5000
 2.5000 2.5000 2.5000 2.5000
[torch.FloatTensor of size 3x4]
>>> b = a.add(4.0) 
>>> b
 6.5000 6.5000 6.5000 6.5000
 6.5000 6.5000 6.5000 6.5000
 6.5000 6.5000 6.5000 6.5000
[torch.FloatTensor of size 3x4]
>>> a
 2.5000 2.5000 2.5000 2.5000
 2.5000 2.5000 2.5000 2.5000
 2.5000 2.5000 2.5000 2.5000
[torch.FloatTensor of size 3x4]
>>> c = a.add_(4.0) 
>>> c
 6.5000 6.5000 6.5000 6.5000
 6.5000 6.5000 6.5000 6.5000
 6.5000 6.5000 6.5000 6.5000
[torch.FloatTensor of size 3x4]
>>> a
 6.5000 6.5000 6.5000 6.5000
 6.5000 6.5000 6.5000 6.5000
 6.5000 6.5000 6.5000 6.5000
[torch.FloatTensor of size 3x4]

在自动求导中支持in-place操作是一件很困难的事情,我们在大多数情况下都不鼓励使用它们。Autograd的缓冲区释放和重用非常高效,并且很少场合下in-place操作能实际上明显降低内存的使用量。除非您在内存压力很大的情况下,否则您可能永远不需要使用它们。

限制in-place操作适用性主要有两个原因:

1.覆盖梯度计算所需的值。这就是为什么变量不支持log_。它的梯度公式需要原始输入,而虽然通过计算反向操作可以重新创建它,但在数值上是不稳定的,并且需要额外的工作,这往往会与使用这些功能的目的相悖。

2.每个in-place操作实际上需要实现重写计算图。不合适的版本只需分配新对象并保留对旧图的引用,而in-place操作则需要将所有输入的creator更改为表示此操作的Function。这就比较棘手,特别是如果有许多变量引用相同的存储(例如通过索引或转置创建的),并且如果被修改输入的存储被任何其他Variable引用,则in-place函数实际上会抛出错误。

In-place正确性检查

每个变量保留有version counter,它每次都会递增,当在任何操作中被使用时。当Function保存任何用于后向的tensor时,还会保存其包含变量的version counter。一旦访问self.saved_tensors,它将被检查,如果它大于保存的值,则会引起错误。

以上这篇关于PyTorch 自动求导机制详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python爬虫常用的模块分析
Aug 29 Python
Python多线程实例教程
Sep 06 Python
Python过滤txt文件内重复内容的方法
Oct 21 Python
Python编程在flask中模拟进行Restful的CRUD操作
Dec 28 Python
Python数据结构与算法(几种排序)小结
Jun 22 Python
Python的垃圾回收机制详解
Aug 28 Python
python 实现按对象传值
Dec 26 Python
Keras - GPU ID 和显存占用设定步骤
Jun 22 Python
一些关于python 装饰器的个人理解
Aug 31 Python
Python获取指定网段正在使用的IP
Dec 14 Python
python 视频下载神器(you-get)的具体使用
Jan 06 Python
利用Python第三方库实现预测NBA比赛结果
Jun 21 Python
pytorch神经网络之卷积层与全连接层参数的设置方法
Aug 18 #Python
pytorch numpy list类型之间的相互转换实例
Aug 18 #Python
对Pytorch中nn.ModuleList 和 nn.Sequential详解
Aug 18 #Python
pytorch 自定义数据集加载方法
Aug 18 #Python
PyTorch的Optimizer训练工具的实现
Aug 18 #Python
Pytorch反向求导更新网络参数的方法
Aug 17 #Python
pytorch 模型可视化的例子
Aug 17 #Python
You might like
PHP下打开phpMyAdmin出现403错误的问题解决方法
2013/05/23 PHP
laravel 实现登陆后返回登陆前的页面方法
2019/10/03 PHP
使用js简单实现了tree树菜单
2013/11/20 Javascript
js或jquery实现页面打印可局部打印
2014/03/27 Javascript
JavaScript Length 属性的总结
2015/11/02 Javascript
基于Jquery实现仿百度百科右侧导航代码附源码下载
2015/11/27 Javascript
使用jquery的jsonp如何发起跨域请求及其原理详解
2017/08/17 jQuery
关于js对textarea换行符的处理方法浅析
2018/08/03 Javascript
微信小程序里引入SVG矢量图标的方法
2019/09/20 Javascript
在Layui中操作数据表格,给指定单元格添加事件示例
2019/10/26 Javascript
vue实现禁止浏览器记住密码功能的示例代码
2021/02/03 Vue.js
vue3.0封装轮播图组件的步骤
2021/03/04 Vue.js
[45:52]2018DOTA2亚洲邀请赛 4.1小组赛 A组加赛 LGD vs Liquid
2018/04/02 DOTA
[01:14]英雄,所敬略同——2018完美盛典宣传视频4K
2018/12/05 DOTA
举例讲解Python中的算数运算符的用法
2015/05/13 Python
Python中用post、get方式提交数据的方法示例
2017/09/22 Python
python制作mysql数据迁移脚本
2019/01/01 Python
Flask框架踩坑之ajax跨域请求实现
2019/02/22 Python
Python获取数据库数据并保存在excel表格中的方法
2019/06/12 Python
python3+PyQt5 实现Rich文本的行编辑方法
2019/06/17 Python
解决python中用matplotlib画多幅图时出现图形部分重叠的问题
2019/07/07 Python
Django 开发环境与生产环境的区分详解
2019/07/26 Python
解决python中的幂函数、指数函数问题
2019/11/25 Python
Django实现将views.py中的数据传递到前端html页面,并展示
2020/03/16 Python
解决keras GAN训练是loss不发生变化,accuracy一直为0.5的问题
2020/07/02 Python
Pycharm Git 设置方法
2020/09/15 Python
html5拖曳操作 HTML5实现网页元素的拖放操作
2013/01/02 HTML / CSS
查询优化的一般准则有哪些
2015/03/08 面试题
食品安全工作方案
2014/05/07 职场文书
公路绿化方案
2014/05/12 职场文书
私营公司诉讼代理委托书范本
2014/09/13 职场文书
2015年财务部年度工作总结
2015/05/19 职场文书
2015年中秋放假通知范文
2015/08/18 职场文书
大学学习委员竞选稿
2015/11/20 职场文书
2016关于预防职务犯罪的心得体会
2016/01/21 职场文书
create-react-app开发常用配置教程
2022/06/25 Javascript