backward只能被应用在一个标量上,也就是一个一维tensor,或者传入跟变量相关的梯度。特别注意Variable里面默认的参数requires_grad=False,所以这里我们要重新传入requires_grad=True让它成为一个叶子节点。
对其求偏导:
import torch
from torch.autograd import Variable
a = Variable(torch.Tensor([2,3]),requires_grad = True)
b = a + 3
c = b * b * 3
out = c.mean()
out.backward()
print(‘*’ * 10)
print(‘====simple gradient=====’)
print(‘input’)
print(a.data)
print('compute result is:')
print(out.data[0])
print('input gradients are:')
print(a.grad.data)
注:torch.autograd.Variable是Autograd的核心类,它封装了Tensor,并整合了反向传播的相关实现
Varibale包含三个属性:
• data:存储了Tensor,是本体的数据
• grad:保存了data的梯度,grad本身也是个Variable而非Tensor,与data形状一致
•grad_fn:指向Function对象,用于反向传播的梯度计算之用
下面研究一下如何能够对非标量的情况下使用backward。backward里传入的参数是每次求导的一个系数。
首先定义好输入
m=(x1,x2)=(2,3)
m
=
(
x
1
,
x
2
)
=
(
2
,
3
)
,然后我们做的操作就是n=
(x21,x32)
(
x
1
2
,
x
2
3
)
,这样我们就定义好了一个向量输出,结果第一项只和x1有关,结果第二项只和
x2
x
2
有关,那么求解这个梯度
m = Variable(torch.Tensor([[2,3]]),requires_grad = True)
n = Variable(torch.zeros(1,2))
n[0,0] = m[0,0] ** 2
n[0,1] = m[0,1] ** 3
n.backward(torch.Tensor([[1,1]]))
print('*' * 10)
print('==== non scalar output ======')
print('input')
print(m.data)
print('input gradient are')
print(m.grad.data)
jacobian矩阵
对其求导:
k.backward(parameters)接受的参数parameters必须要和k的大小一模一样,然后作为k的系数传回去,backward里传入的参数是每次求导的一个系数。
j = t.zeros(2 ,2)
k = v(t.zeros(1, 2))
k[0, 0] = m[0, 0] ** 2 + 3 * m[0 ,1]
k[0, 1] = m[0, 1] ** 2 + 2 * m[0, 0]
# [1, 0] dk0/dm0, dk1/dm0
k.backward(t.FloatTensor([[1, 0]]), retain_variables=True) # 需要两次反向求导
j[:, 0] = m.grad.data
m.grad.data.zero_()
# [0, 1] dk0/dm1, dk1/dm1
k.backward(t.FloatTensor([[0, 1]]))
j[:, 1] = m.grad.data
print('jacobian matrix is') print(j)
我们要注意backward()里面另外的一个参数retain_variables=True,这个参数默认是False,也就是反向传播之后这个计算图的内存会被释放,这样就没办法进行第二次反向传播了,所以我们需要设置为True,因为这里我们需要进行两次反向传播求得jacobian矩阵。