pytorch 中autograd.grad()函数的用法说明


Posted in Python onMay 12, 2021

我们在用神经网络求解PDE时, 经常要用到输出值对输入变量不是Weights和Biases)求导; 在训练WGAN-GP 时, 也会用到网络对输入变量的求导。

以上两种需求, 均可以用pytorch 中的autograd.grad() 函数实现。

autograd.grad(outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=False, only_inputs=True, allow_unused=False)

outputs: 求导的因变量(需要求导的函数)

inputs: 求导的自变量

grad_outputs: 如果 outputs为标量,则grad_outputs=None,也就是说,可以不用写; 如果outputs 是向量,则此参数必须写,不写将会报如下错误:

pytorch 中autograd.grad()函数的用法说明

那么此参数究竟代表着什么呢?

先假设pytorch 中autograd.grad()函数的用法说明为一维向量, 即可设自变量因变量分别为 pytorch 中autograd.grad()函数的用法说明 , 其对应的 Jacobi 矩阵为

pytorch 中autograd.grad()函数的用法说明

grad_outputs 是一个shape 与 outputs 一致的向量, 即

pytorch 中autograd.grad()函数的用法说明

在给定grad_outputs 之后,真正返回的梯度为

pytorch 中autograd.grad()函数的用法说明

为方便下文叙述我们引入记号 pytorch 中autograd.grad()函数的用法说明

其次假设 pytorch 中autograd.grad()函数的用法说明,第i个列向量对应的Jacobi矩阵为

pytorch 中autograd.grad()函数的用法说明

此时的grad_outputs 为(维度与outputs一致)

pytorch 中autograd.grad()函数的用法说明

由第一种情况, 我们有

pytorch 中autograd.grad()函数的用法说明

也就是说对输出变量的列向量求导,再经过权重累加。

pytorch 中autograd.grad()函数的用法说明 沿用第一种情况记号

pytorch 中autograd.grad()函数的用法说明 , 其中每一个pytorch 中autograd.grad()函数的用法说明 均由第一种方法得出,

即对输入变量列向量求导,之后按照原先顺序排列即可。

retain_graph: True 则保留计算图, False则释放计算图

create_graph: 若要计算高阶导数,则必须选为True

allow_unused: 允许输入变量不进入计算

下面我们看一下具体的例子:

import torch
from torch import autograd
 
x = torch.rand(3, 4)
x.requires_grad_()

观察 x 为

pytorch 中autograd.grad()函数的用法说明

不妨设 y 是 x 所有元素的和, 因为 y是标量,故计算导数不需要设置grad_outputs

y = torch.sum(x)
grads = autograd.grad(outputs=y, inputs=x)[0]
print(grads)

结果为

pytorch 中autograd.grad()函数的用法说明

若y是向量

y = x[:,0] +x[:,1]
# 设置输出权重为1
grad = autograd.grad(outputs=y, inputs=x, grad_outputs=torch.ones_like(y))[0]
print(grad)
# 设置输出权重为0
grad = autograd.grad(outputs=y, inputs=x, grad_outputs=torch.zeros_like(y))[0]
print(grad)

结果为

pytorch 中autograd.grad()函数的用法说明

最后, 我们通过设置 create_graph=True 来计算二阶导数

y = x ** 2
grad = autograd.grad(outputs=y, inputs=x, grad_outputs=torch.ones_like(y), create_graph=True)[0]
grad2 = autograd.grad(outputs=grad, inputs=x, grad_outputs=torch.ones_like(grad))[0]
print(grad2)

结果为

pytorch 中autograd.grad()函数的用法说明

综上,我们便搞清楚了它的求导机制。

补充:pytorch学习笔记:自动微分机制(backward、torch.autograd.grad)

一、前言

神经网络通常依赖反向传播求梯度来更新网络参数,求梯度过程通常是一件非常复杂而容易出错的事情。

而深度学习框架可以帮助我们自动地完成这种求梯度运算。

Pytorch一般通过反向传播 backward方法 实现这种求梯度计算。该方法求得的梯度将存在对应自变量张量的grad属性下。

除此之外,也能够调用torch.autograd.grad函数来实现求梯度计算。

这就是Pytorch的自动微分机制。

二、利用backward方法求导数

backward方法通常在一个标量张量上调用,该方法求得的梯度将存在对应自变量张量的grad属性下。如果调用的张量非标量,则要传入一个和它同形状的gradient参数张量。相当于用该gradient参数张量与调用张量作向量点乘,得到的标量结果再反向传播。

1, 标量的反向传播

import numpy as np 
import torch 

# f(x) = a*x**2 + b*x + c的导数

x = torch.tensor(0.0,requires_grad = True) # x需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a*torch.pow(x,2) + b*x + c 

y.backward()
dy_dx = x.grad
print(dy_dx)

输出:

tensor(-2.)

2, 非标量的反向传播

import numpy as np 
import torch 

# f(x) = a*x**2 + b*x + c

x = torch.tensor([[0.0,0.0],[1.0,2.0]],requires_grad = True) # x需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a*torch.pow(x,2) + b*x + c 

gradient = torch.tensor([[1.0,1.0],[1.0,1.0]])

print("x:\n",x)
print("y:\n",y)
y.backward(gradient = gradient)
x_grad = x.grad
print("x_grad:\n",x_grad)

输出:

x:

tensor([[0., 0.],

[1., 2.]], requires_grad=True)

y:

tensor([[1., 1.],

[0., 1.]], grad_fn=<AddBackward0>)

x_grad:

tensor([[-2., -2.],

[ 0., 2.]])

3, 非标量的反向传播可以用标量的反向传播实现

import numpy as np 
import torch 

# f(x) = a*x**2 + b*x + c

x = torch.tensor([[0.0,0.0],[1.0,2.0]],requires_grad = True) # x需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a*torch.pow(x,2) + b*x + c 

gradient = torch.tensor([[1.0,1.0],[1.0,1.0]])
z = torch.sum(y*gradient)

print("x:",x)
print("y:",y)
z.backward()
x_grad = x.grad
print("x_grad:\n",x_grad)

输出:

x: tensor([[0., 0.],

[1., 2.]], requires_grad=True)

y: tensor([[1., 1.],

[0., 1.]], grad_fn=<AddBackward0>)

x_grad:

tensor([[-2., -2.],

[ 0., 2.]])

三、利用autograd.grad方法求导数

import numpy as np 
import torch 

# f(x) = a*x**2 + b*x + c的导数

x = torch.tensor(0.0,requires_grad = True) # x需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a*torch.pow(x,2) + b*x + c


# create_graph 设置为 True 将允许创建更高阶的导数 
dy_dx = torch.autograd.grad(y,x,create_graph=True)[0]
print(dy_dx.data)

# 求二阶导数
dy2_dx2 = torch.autograd.grad(dy_dx,x)[0] 

print(dy2_dx2.data)

输出:

tensor(-2.)

tensor(2.)

import numpy as np 
import torch 

x1 = torch.tensor(1.0,requires_grad = True) # x需要被求导
x2 = torch.tensor(2.0,requires_grad = True)

y1 = x1*x2
y2 = x1+x2


# 允许同时对多个自变量求导数
(dy1_dx1,dy1_dx2) = torch.autograd.grad(outputs=y1,
                inputs = [x1,x2],retain_graph = True)
print(dy1_dx1,dy1_dx2)

# 如果有多个因变量,相当于把多个因变量的梯度结果求和
(dy12_dx1,dy12_dx2) = torch.autograd.grad(outputs=[y1,y2],
            inputs = [x1,x2])
print(dy12_dx1,dy12_dx2)

输出:

tensor(2.) tensor(1.)

tensor(3.) tensor(2.)

四、利用自动微分和优化器求最小值

import numpy as np 
import torch 

# f(x) = a*x**2 + b*x + c的最小值

x = torch.tensor(0.0,requires_grad = True) # x需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)

optimizer = torch.optim.SGD(params=[x],lr = 0.01)


def f(x):
    result = a*torch.pow(x,2) + b*x + c 
    return(result)

for i in range(500):
    optimizer.zero_grad()
    y = f(x)
    y.backward()
    optimizer.step()
   
    
print("y=",f(x).data,";","x=",x.data)

输出:

y= tensor(0.) ; x= tensor(1.0000)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Python 相关文章推荐
python抓取百度首页的方法
May 19 Python
Python脚本暴力破解栅栏密码
Oct 19 Python
简单谈谈Python流程控制语句
Dec 04 Python
python抓取网页中链接的静态图片
Jan 29 Python
Python 实现删除某路径下文件及文件夹的实例讲解
Apr 24 Python
Python面向对象之静态属性、类方法与静态方法分析
Aug 24 Python
python+unittest+requests实现接口自动化的方法
Nov 29 Python
在Python中调用Ping命令,批量IP的方法
Jan 26 Python
手把手教你使用Python创建微信机器人
Apr 29 Python
Python通过递归获取目录下指定文件代码实例
Nov 07 Python
关于初始种子自动选取的区域生长实例(python+opencv)
Jan 16 Python
Python预测2020高考分数和录取情况
Jul 08 Python
python3实现无权最短路径的方法
Python入门之基础语法详解
May 11 #Python
如何利用Matlab制作一款真正的拼图小游戏
Python机器学习之逻辑回归
Python Pandas知识点之缺失值处理详解
Pytorch实现图像识别之数字识别(附详细注释)
浅谈Python基础之列表那些事儿
You might like
PHP中对数据库操作的封装
2006/10/09 PHP
yii框架源码分析之创建controller代码
2011/06/28 PHP
php与java通过socket通信的实现代码
2013/10/21 PHP
phpQuery占用内存过多的处理方法
2013/11/13 PHP
zf框架db类的分页示例分享
2014/03/14 PHP
php实现smarty模板无限极分类的方法
2015/12/07 PHP
Javscript调用iframe框架页面中函数的方法
2014/11/01 Javascript
Angular发布1.5正式版,专注于向Angular 2的过渡
2016/02/18 Javascript
Javascript 调用 ActionScript 的简单方法
2016/09/22 Javascript
200行代码实现blockchain 区块链实例详解
2018/03/14 Javascript
快速解决vue-cli不能初始化webpack模板的问题
2018/03/20 Javascript
bootstrap treeview 树形菜单带复选框及级联选择功能
2018/06/08 Javascript
详解create-react-app 2.0版本如何启用装饰器语法
2018/10/23 Javascript
小程序Request的另类用法详解
2019/08/09 Javascript
JavaScript实现沿五角星形线摆动的小圆实例详解
2020/07/28 Javascript
JavaScript 获取滚动条位置并将页面滑动到锚点
2021/02/08 Javascript
Python实现FTP上传文件或文件夹实例(递归)
2017/01/16 Python
Python实现向服务器请求压缩数据及解压缩数据的方法示例
2017/06/09 Python
TensorFlow实现卷积神经网络CNN
2018/03/09 Python
Python在for循环中更改list值的方法【推荐】
2018/08/17 Python
python3通过selenium爬虫获取到dj商品的实例代码
2019/04/25 Python
Python3 执行Linux Bash命令的方法
2019/07/12 Python
在django-xadmin中APScheduler的启动初始化实例
2019/11/15 Python
Python csv文件的读写操作实例详解
2019/11/19 Python
Python创建文件夹与文件的快捷方法
2020/12/08 Python
使用CSS Grid布局实现网格的流动
2014/12/30 HTML / CSS
html5使用canvas画一条线
2014/12/15 HTML / CSS
大学生职业生涯规划范文
2013/12/31 职场文书
大学新生欢迎词
2014/01/10 职场文书
食品安全检查制度
2014/02/03 职场文书
2014道德模范事迹材料
2014/02/16 职场文书
开业庆典主持词
2014/03/21 职场文书
农业开发项目建议书
2014/05/16 职场文书
优秀毕业生找工作自荐信
2014/06/23 职场文书
父亲节活动总结
2015/02/12 职场文书
会计稽核岗位职责
2015/04/13 职场文书