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模拟登陆类
Mar 29 Python
用Python中的__slots__缓存资源以节省内存开销的方法
Apr 02 Python
Python中利用sorted()函数排序的简单教程
Apr 27 Python
在Python中使用成员运算符的示例
May 13 Python
在Python的Flask中使用WTForms表单框架的基础教程
Jun 07 Python
python中set常用操作汇总
Jun 30 Python
Python基于csv模块实现读取与写入csv数据的方法
Jan 18 Python
Python获取指定字符前面的所有字符方法
May 02 Python
对Python字符串中的换行符和制表符介绍
May 03 Python
Python PyAutoGUI模块控制鼠标和键盘实现自动化任务详解
Sep 04 Python
PyCharm代码提示忽略大小写设置方法
Oct 28 Python
使用tensorboard可视化loss和acc的实例
Jan 21 Python
python3实现无权最短路径的方法
Python入门之基础语法详解
May 11 #Python
如何利用Matlab制作一款真正的拼图小游戏
Python机器学习之逻辑回归
Python Pandas知识点之缺失值处理详解
Pytorch实现图像识别之数字识别(附详细注释)
浅谈Python基础之列表那些事儿
You might like
2020年4月新番动漫目录 官方宣布4月播出的作品一览
2020/03/08 日漫
Yii框架防止sql注入,xss攻击与csrf攻击的方法
2016/10/18 PHP
自写的利用PDO对mysql数据库增删改查操作类
2018/02/19 PHP
Laravel 将数据表的数据导出,并生成seeds种子文件的方法
2019/10/09 PHP
javascript 图片上传预览-兼容标准
2009/06/01 Javascript
jQuery中filter(),not(),split()使用方法
2010/07/06 Javascript
javascript实现全角与半角字符的转换
2015/01/07 Javascript
jQuery实现右侧显示可向左滑动展示的深色QQ客服效果代码
2015/10/23 Javascript
JS Ajax请求如何防止重复提交
2016/06/13 Javascript
教你JS中的运算符乘方、开方及变量格式转换
2016/08/09 Javascript
knockoutjs动态加载外部的file作为component中的template数据源的实现方法
2016/09/01 Javascript
JS调用打印机功能简单示例
2016/11/28 Javascript
jQGrid动态填充select下拉框的选项值(动态填充)
2016/11/28 Javascript
js浏览器滚动条卷去的高度scrolltop(实例讲解)
2017/07/07 Javascript
JavaScript的查询机制LHS和RHS解析
2019/08/16 Javascript
vue缓存之keep-alive的理解和应用详解
2020/11/02 Javascript
使用python将mdb数据库文件导入postgresql数据库示例
2014/02/17 Python
Python实现获取操作系统版本信息方法
2015/04/08 Python
Python读写ini文件的方法
2015/05/28 Python
python django 增删改查操作 数据库Mysql
2017/07/27 Python
使用python将时间转换为指定的格式方法
2018/11/12 Python
Python设计模式之解释器模式原理与用法实例分析
2019/01/10 Python
python操作docx写入内容,并控制文本的字体颜色
2020/02/13 Python
Python3标准库之functools管理函数的工具详解
2020/02/27 Python
Python中如何添加自定义模块
2020/06/09 Python
Opencv python 图片生成视频的方法示例
2020/11/18 Python
用python-webdriver实现自动填表的示例代码
2021/01/13 Python
详解如何用canvas画一个微笑的表情
2019/03/14 HTML / CSS
浅谈html5与APP混合开发遇到的问题总结
2018/03/20 HTML / CSS
canvas 基础之图像处理的使用
2020/04/10 HTML / CSS
德国街头和运动文化高品质商店:BSTN Store
2017/08/26 全球购物
纽约复古灵感的现代珠宝品牌:Lulu Frost
2018/03/03 全球购物
介绍一下write命令
2014/08/10 面试题
公安个人四风问题对照检查及整改措施
2014/10/28 职场文书
第一军规观后感
2015/06/12 职场文书
CSS的class与id常用的命名规则
2021/05/18 HTML / CSS