pytorch中ad()函数的⽤法说明
我们在⽤神经⽹络求解PDE时,经常要⽤到输出值对输⼊变量(不是Weights和Biases)求导;在训练WGAN-GP 时,也会⽤到⽹络对输⼊变量的求导。
以上两种需求,均可以⽤pytorch 中的ad() 函数实现。
outputs: 求导的因变量(需要求导的函数)
inputs: 求导的⾃变量
grad_outputs: 如果 outputs为标量,则grad_outputs=None,也就是说,可以不⽤写; 如果outputs 是向量,则此参数必须写,不写将会报如下错误:
那么此参数究竟代表着什么呢?
先假设为⼀维向量, 即可设⾃变量因变量分别为,其对应的 Jacobi 矩阵为
grad_outputs 是⼀个shape 与 outputs ⼀致的向量, 即
在给定grad_outputs 之后,真正返回的梯度为
为⽅便下⽂叙述我们引⼊记号
其次假设 ,第i个列向量对应的Jacobi矩阵为
此时的grad_outputs 为(维度与outputs⼀致)
由第⼀种情况,我们有
也就是说对输出变量的列向量求导,再经过权重累加。
若沿⽤第⼀种情况记号
, 其中每⼀个均由第⼀种⽅法得出,
即对输⼊变量列向量求导,之后按照原先顺序排列即可。
retain_graph: True 则保留计算图, False则释放计算图
create_graph: 若要计算⾼阶导数,则必须选为True
allow_unused: 允许输⼊变量不进⼊计算
下⾯我们看⼀下具体的例⼦:
import torch
from torch import autograd
x = torch.rand(3, 4)
观察 x 为
不妨设 y 是 x 所有元素的和,因为 y是标量,故计算导数不需要设置grad_outputs y = torch.sum(x)
grads = ad(outputs=y, inputs=x)[0]
print(grads)
结果为
若y是向量
y = x[:,0] +x[:,1]
# 设置输出权重为1
grad = ad(outputs=y, inputs=x, grad_s_like(y))[0]
print(grad)
# 设置输出权重为0
grad = ad(outputs=y, inputs=x, grad_s_like(y))[0]
print(grad)
结果为
最后,我们通过设置 create_graph=True 来计算⼆阶导数
y = x ** 2
grad = ad(outputs=y, inputs=x, grad_s_like(y), create_graph=True)[0]
grad2 = ad(outputs=grad, inputs=x, grad_s_like(grad))[0]
print(grad2)
结果为
综上,我们便搞清楚了它的求导机制。
补充:pytorch学习笔记:⾃动微分机制(backward、ad)
⼀、前⾔
神经⽹络通常依赖反向传播求梯度来更新⽹络参数,求梯度过程通常是⼀件⾮常复杂⽽容易出错的事情。
⽽深度学习框架可以帮助我们⾃动地完成这种求梯度运算。
Pytorch⼀般通过反向传播 backward⽅法实现这种求梯度计算。该⽅法求得的梯度将存在对应⾃变量张量的grad属性下。除此之外,也能够调⽤ad函数来实现求梯度计算。
这就是Pytorch的⾃动微分机制。
⼆、利⽤backward⽅法求导数
backward⽅法通常在⼀个标量张量上调⽤,该⽅法求得的梯度将存在对应⾃变量张量的grad属性下。如果调⽤的张量⾮标量,则要传⼊⼀个和它同形状的gradient参数张量。相当于⽤该gradient参数张量与调⽤张量作向量点乘,得到的标量结果再反向传播。
1, 标量的反向传播
import numpy as np
import torch
# f(x) = a*x**2 + b*x + c的导数
x = sor(0.0,requires_grad = True) # x需要被求导
a = sor(1.0)
b = sor(-2.0)
c = sor(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 = sor([[0.0,0.0],[1.0,2.0]],requires_grad = True) # x需要被求导
c = sor(1.0)
y = a*torch.pow(x,2) + b*x + c
gradient = sor([[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 = sor([[0.0,0.0],[1.0,2.0]],requires_grad = True) # x需要被求导
a = sor(1.0)
b = sor(-2.0)
c = sor(1.0)numpy官方教程
y = a*torch.pow(x,2) + b*x + c
gradient = sor([[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.]])
三、利⽤ad⽅法求导数import numpy as np
import torch
# f(x) = a*x**2 + b*x + c的导数
x = sor(0.0,requires_grad = True) # x需要被求导
a = sor(1.0)
y = a*torch.pow(x,2) + b*x + c
# create_graph 设置为 True 将允许创建更⾼阶的导数
dy_dx = ad(y,x,create_graph=True)[0]
print(dy_dx.data)
# 求⼆阶导数
dy2_dx2 = ad(dy_dx,x)[0]
print(dy2_dx2.data)
输出:
tensor(-2.)
tensor(2.)
import numpy as np
import torch
x1 = sor(1.0,requires_grad = True) # x需要被求导
x2 = sor(2.0,requires_grad = True)
y1 = x1*x2
y2 = x1+x2
# 允许同时对多个⾃变量求导数
(dy1_dx1,dy1_dx2) = ad(outputs=y1,
inputs = [x1,x2],retain_graph = True)
print(dy1_dx1,dy1_dx2)
# 如果有多个因变量,相当于把多个因变量的梯度结果求和
(dy12_dx1,dy12_dx2) = ad(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 = sor(0.0,requires_grad = True) # x需要被求导
a = sor(1.0)
b = sor(-2.0)
c = sor(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):
<_grad()
y = f(x)
y.backward()
optimizer.step()
print("y=",f(x).data,";","x=",x.data)
输出:
y= tensor(0.) ; x= tensor(1.0000)
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。如有错误或未考虑完全的地⽅,望不吝赐教。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。