backward用法
pytorch中backward自动求导原理解释
标量对矢量求导
- 默认的时候是不采用梯度跟踪的,需要在创建的时候加入
requires_grad=True
- 若创建的时候无梯度跟踪,需要加入
a.requires_grad_(True)
- 标量对矢量求导的时候backward不需要加入参数
in
a = torch.randn(2,2)
a = ((a * 3) / (a - 1))
a
out
tensor([[ 8.4251, -1.6011],
[-22.3855, -0.5603]])
in
print(a.requires_grad)
out
False
in
a.requires_grad_(True)
out
tensor([[ 8.4251, -1.6011],
[-22.3855, -0.5603]], requires_grad=True)
in
b = (a * a).sum()
print(b.grad_fn)
out
<SumBackward0 object at 0x00000200A4D84BE0>
in
b.backward()
print(a.grad)
求完导数后,2a为其导数,所以结果为:
tensor([[ 16.8502, -3.2023],
[-44.7710, -1.1205]])
矢量对矢量求导
- 矢量对矢量求导需要在backward后面加入一个和result维度相同的矩阵
- 我们传入的参数,被看作是行向量,进行矩阵的乘法
in
import torch
from torch.autograd import Variable
a = Variable(torch.FloatTensor([[2., 4.]]), requires_grad=True)
b = torch.zeros(1,2)
b[0,0] = a[0,0] ** 2 + a[0,1]
b[0,1] = a[0,1] ** 3 + a[0,0]
out = 2 * b
# 参数需要传入和out相同维度的
out.backward(torch.FloatTensor([[1., 2.]]))
print('input:')
print(a.data)
print('output:')
print(out.data)
print('input gradients:')
print(a.grad)
out
input:
tensor([[2., 4.]])
output:
tensor([[ 16., 132.]])
input gradients:
tensor([[ 12., 194.]])
求完导后
行列式为
4 a 1 = 8 4a_1=8 4a1=8 | 2 |
---|---|
2 | 6 a 2 2 = 96 6a^2_2=96 6a22=96 |
传入的参数是行向量 [ 1 , 2 ] [1,2] [1,2]
动手验证一下是正确的
因此结果为 ( a r g × J a c o b i ) T (arg \times Jacobi)^T (arg×Jacobi)T
可以自己输出雅可比行列式
import torch
from torch.autograd import Variable
import copy
a = Variable(torch.FloatTensor([[2., 4.]]), requires_grad=True)
b = torch.zeros(1,2)
b[0,0] = a[0,0] ** 2 + a[0,1]
b[0,1] = a[0,1] ** 3 + a[0,0]
out = 2 * b
out.backward(torch.FloatTensor([[1,0]]), retain_graph = True)
A_temp = copy.deepcopy(a.grad)
a.grad.zero_()
out.backward(torch.FloatTensor([[0,1]]))
B_temp = a.grad
print('Jacobi Matrix:')
print(torch.cat((A_temp, B_temp), 0))
out
Jacobi Matrix:
tensor([[ 8., 2.],
[ 2., 96.]])
因为经过了复杂的神经网络之后,out中每个数值都是由很多输入样本的属性(也就是输入数据)线性或者非线性组合而成的,那么out中的每个数值和输入数据的每个数值都有关联,也就是说【out】中的每个数都可以对【a】中每个数求导,那么我们backward()的参数[k1,k2,k3…kn]的含义就是:每个out分量对an求导时的权重。