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爬虫之打包生成exe文件
Nov 06 Python
Python multiprocessing.Manager介绍和实例(进程间共享数据)
Nov 21 Python
详解Python编程中基本的数学计算使用
Feb 04 Python
Python自然语言处理之词干,词形与最大匹配算法代码详解
Nov 16 Python
对python中for、if、while的区别与比较方法
Jun 25 Python
纯python进行矩阵的相乘运算的方法示例
Jul 17 Python
Win10里python3创建虚拟环境的步骤
Jan 31 Python
wxPython修改文本框颜色过程解析
Feb 14 Python
Python计算指定日期是今年的第几天(三种方法)
Mar 26 Python
Python+Kepler.gl实现时间轮播地图过程解析
Jul 20 Python
基于Python实现简单学生管理系统
Jul 24 Python
如何在windows下安装配置python工具Ulipad
Oct 27 Python
python3实现无权最短路径的方法
Python入门之基础语法详解
May 11 #Python
如何利用Matlab制作一款真正的拼图小游戏
Python机器学习之逻辑回归
Python Pandas知识点之缺失值处理详解
Pytorch实现图像识别之数字识别(附详细注释)
浅谈Python基础之列表那些事儿
You might like
下拉列表多级联动dropDownList示例代码
2013/06/27 PHP
jQuery 1.5最新版本的改进细节分析
2011/01/19 Javascript
JavaScript中的运算符种类及其规则介绍
2013/09/26 Javascript
JavaScript实现的一个日期格式化函数分享
2014/12/06 Javascript
jQuery实现鼠标经过提示信息的地图热点效果
2015/04/26 Javascript
程序员必知35个jQuery 代码片段
2015/11/05 Javascript
浏览器复制插件zeroclipboard使用指南
2016/03/26 Javascript
jQuery基于toggle实现click触发DIV的显示与隐藏问题分析
2016/06/12 Javascript
AngularJS入门教程之REST和定制服务详解
2016/08/19 Javascript
ES6新特性五:Set与Map的数据结构实例分析
2017/04/21 Javascript
详解mpvue小程序中怎么引入iconfont字体图标
2018/10/01 Javascript
JavaScript 复制对象与Object.assign方法无法实现深复制
2018/11/02 Javascript
javascript(基于jQuery)实现鼠标获取选中的文字示例【测试可用】
2019/10/26 jQuery
JavaScript中window和document用法详解
2020/07/28 Javascript
vue 自定指令生成uuid滚动监听达到tab表格吸顶效果的代码
2020/09/16 Javascript
Python的装饰器模式与面向切面编程详解
2015/06/21 Python
Python函数中*args和**kwargs来传递变长参数的用法
2016/01/26 Python
ansible作为python模块库使用的方法实例
2017/01/17 Python
一文带你了解Python中的字符串是什么
2018/11/20 Python
python中退出多层循环的方法
2018/11/27 Python
python实现双色球随机选号
2020/01/01 Python
使用python计算三角形的斜边例子
2020/04/15 Python
如何基于Python Matplotlib实现网格动画
2020/07/20 Python
用python读取xlsx文件
2020/12/17 Python
python中re模块知识点总结
2021/01/17 Python
HTML5自定义data-* data(obj)属性和jquery的data()方法的使用
2012/12/13 HTML / CSS
Spotahome意大利:公寓和房间出租
2020/02/21 全球购物
土地转让协议书
2014/04/15 职场文书
《猴子种果树》教学反思
2014/04/26 职场文书
献爱心标语
2014/06/21 职场文书
工商局领导班子存在的问题整改措施思想汇报
2014/10/05 职场文书
2014年小学数学教师工作总结
2014/12/03 职场文书
开学第一周总结
2015/07/16 职场文书
创业方案:赚钱的烧烤店该怎样做?
2019/07/05 职场文书
8g内存用python读取10文件_面试题-python 如何读取一个大于 10G 的txt文件?
2021/05/28 Python
SQL Server2019安装的详细步骤实战记录(亲测可用)
2022/06/10 SQL Server