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中循环语句while用法实例
May 16 Python
python开发之文件操作用法实例
Nov 13 Python
Python爬虫包 BeautifulSoup  递归抓取实例详解
Jan 28 Python
python 按不同维度求和,最值,均值的实例
Jun 28 Python
Python图像处理之颜色的定义与使用分析
Jan 03 Python
基于python实现KNN分类算法
Apr 23 Python
python实现Dijkstra算法的最短路径问题
Jun 21 Python
python中update的基本使用方法详解
Jul 17 Python
解决tensorflow读取本地MNITS_data失败的原因
Jun 22 Python
Python爬虫之爬取淘女郎照片示例详解
Jul 28 Python
python中通过pip安装库文件时出现“EnvironmentError: [WinError 5] 拒绝访问”的问题及解决方案
Aug 11 Python
Python读写Excel表格的方法
Mar 02 Python
python3实现无权最短路径的方法
Python入门之基础语法详解
May 11 #Python
如何利用Matlab制作一款真正的拼图小游戏
Python机器学习之逻辑回归
Python Pandas知识点之缺失值处理详解
Pytorch实现图像识别之数字识别(附详细注释)
浅谈Python基础之列表那些事儿
You might like
php自动获取字符串编码函数mb_detect_encoding
2011/05/31 PHP
PHP curl CURLOPT_RETURNTRANSFER参数的作用使用实例
2015/02/07 PHP
php强大的时间转换函数strtotime
2016/02/18 PHP
ThinkPHP框架实现FTP图片上传功能示例
2019/04/08 PHP
js实时监听文本框状态的方法
2011/04/26 Javascript
javascript验证上传文件的类型限制必须为某些格式
2013/11/14 Javascript
Node.js 的异步 IO 性能探讨
2014/10/08 Javascript
javascript Promise简单学习使用方法小结
2016/05/17 Javascript
浅谈jquery采用attr修改form表单enctype不起作用的问题
2016/11/25 Javascript
jQuery Validate表单验证插件的基本使用方法及功能拓展
2017/01/04 Javascript
vue实现全选、反选功能
2020/11/17 Javascript
JavaScript+HTML5实现的日期比较功能示例
2017/07/12 Javascript
你有必要知道的10个JavaScript难点
2017/07/25 Javascript
原生js 封装get ,post, delete 请求的实例
2017/08/11 Javascript
vue编译打包本地查看index文件的方法
2018/02/23 Javascript
在react-router4中进行代码拆分的方法(基于webpack)
2018/03/08 Javascript
nodejs实现一个word文档解析器思路详解
2018/08/14 NodeJs
Vue-CLI3.x 设置反向代理的方法
2018/12/06 Javascript
简单了解JavaScript异步
2019/05/23 Javascript
vue开发中遇到的问题总结
2020/04/07 Javascript
Python缩进和冒号详解
2016/06/01 Python
Python遍历numpy数组的实例
2018/04/04 Python
python判断单向链表是否包括环,若包含则计算环入口的节点实例分析
2019/10/23 Python
关于pandas的离散化,面元划分详解
2019/11/22 Python
python @propert装饰器使用方法原理解析
2019/12/25 Python
解决jupyter notebook 前面书写后面内容消失的问题
2020/04/13 Python
毕业生的自我鉴定
2013/10/29 职场文书
怎么写好自荐书
2014/03/02 职场文书
运动会方阵口号
2014/06/07 职场文书
党代会心得体会
2014/09/04 职场文书
女生抽烟检讨书
2014/10/05 职场文书
幼儿学前班评语
2014/12/29 职场文书
租车协议书
2015/01/27 职场文书
中国世界遗产导游词
2015/02/13 职场文书
刑事附带民事上诉状
2015/05/23 职场文书
婚礼父母致辞
2015/07/28 职场文书