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 字典(Dictionary)操作详解
Mar 11 Python
在Python中使用SQLite的简单教程
Apr 29 Python
python实现xlsx文件分析详解
Jan 02 Python
Python实现批量修改图片格式和大小的方法【opencv库与PIL库】
Dec 03 Python
python向图片里添加文字
Nov 26 Python
Python统计时间内的并发数代码实例
Dec 28 Python
Tensorflow 自定义loss的情况下初始化部分变量方式
Jan 06 Python
Python气泡提示与标签的实现
Apr 01 Python
解决Python在导入文件时的FileNotFoundError问题
Apr 10 Python
python 深度学习中的4种激活函数
Sep 18 Python
python 基于DDT实现数据驱动测试
Feb 18 Python
Python OpenCV快速入门教程
Apr 17 Python
python3实现无权最短路径的方法
Python入门之基础语法详解
May 11 #Python
如何利用Matlab制作一款真正的拼图小游戏
Python机器学习之逻辑回归
Python Pandas知识点之缺失值处理详解
Pytorch实现图像识别之数字识别(附详细注释)
浅谈Python基础之列表那些事儿
You might like
用php实现批量查询清除一句话后门的代码
2008/01/20 PHP
PHP中使用asort进行中文排序失效的问题处理
2014/08/18 PHP
百度工程师讲PHP函数的实现原理及性能分析(三)
2015/05/13 PHP
php计算title标题相似比的方法
2015/07/29 PHP
php+ajax 实现输入读取数据库显示匹配信息
2015/10/08 PHP
[原创]php求圆周率的简单实现方法
2016/05/30 PHP
suggestion开发小结以及对键盘事件的总结(针对中文输入法状态)
2011/12/20 Javascript
JavaScript实现自己的DOM选择器原理及代码
2013/03/04 Javascript
JS简单实现文件上传实例代码(无需插件)
2013/11/15 Javascript
asp.net刷新本页面的六种方法总结
2014/01/07 Javascript
3种Jquery限制文本框只能输入数字字母的方法
2014/12/03 Javascript
jQuery中:eq()选择器用法实例
2014/12/29 Javascript
javascript实现状态栏文字首尾相接循环滚动的方法
2015/07/22 Javascript
js实现当复选框选择匿名登录时隐藏登录框效果
2015/08/14 Javascript
JavaScript实现的背景自动变色代码
2015/10/17 Javascript
js实现简单计算器
2015/11/22 Javascript
Bootstrap组件(一)之菜单
2016/05/11 Javascript
第六篇Bootstrap表格样式介绍
2016/06/21 Javascript
用js实现博客打赏功能
2016/10/24 Javascript
vue实现可增删查改的成绩单
2016/10/27 Javascript
通过原生JS实现为元素添加事件的方法
2016/11/23 Javascript
原生JS实现跑马灯效果
2017/02/20 Javascript
详解基于Koa2开发微信二维码扫码支付相关流程
2018/05/16 Javascript
vue实现登录页面的验证码以及验证过程解析(面向新手)
2019/08/02 Javascript
JS严格模式原理与用法实例分析
2020/04/27 Javascript
es5 类与es6中class的区别小结
2020/11/09 Javascript
python中pandas.DataFrame的简单操作方法(创建、索引、增添与删除)
2017/03/12 Python
python爬虫 爬取58同城上所有城市的租房信息详解
2019/07/30 Python
Python 为什么推荐蛇形命名法原因浅析
2020/06/18 Python
Python jieba结巴分词原理及用法解析
2020/11/05 Python
生产厂长岗位职责
2014/02/21 职场文书
竞聘演讲稿怎么写
2014/08/28 职场文书
2015年助理工程师工作总结
2015/04/03 职场文书
少先队中队工作总结2015
2015/07/23 职场文书
百年校庆宣传标语口号
2015/12/26 职场文书
Java 多态分析
2022/04/26 Java/Android