本文主要介绍PyTorch中backward函数和grad的各种用法
梯度的定义
- \(y\)对\(x\)的梯度可以理解为: 当 \(x\) 增加1的时候, \(y\) 值的增加量
- 如果\(x\)是矢量(矩阵或者向量等),那么计算时也需要看成是多个标量的组合来计算,算出来的值表示的也是 \(x\) 当前维度的值增加1的时候, \(y\) 值的增加量
backward基础用法
- tensorflow是先建立好图,在前向过程中可以选择执行图的某个部分(每次前向可以执行图的不同部分,前提是,图里必须包含了所有可能情况)
- pytorch是每次前向过程都会重新建立一个图,反向(backward)的时候会释放,每次的图可以不一样, 所以在Pytorch中可以随时使用
if
,while
等语句- tensorflow中使用
if
,while
就得在传入数据前(构建图时)告诉图需要构建哪些逻辑,然后才能传入数据运行 - PyTorch中由于不用在传入数据前先定义图(图和数据一起到达,图构建的同时开始计算数据?)
- tensorflow中使用
计算标量对标量的梯度
结构图如下所示
上面图的代码构建如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import torch
from torch.autograd import Variable
w1 = Variable(torch.Tensor([2]),requires_grad=True)
w2 = Variable(torch.Tensor([3]),requires_grad=True)
w3 = Variable(torch.Tensor([5]),requires_grad=True)
x = w1 + w2
y = w2*w3
z = x+y
z.backward()
print(w1.grad)
print(w2.grad)
print(w3.grad)
print(x.grad)
print(y.grad)
# output:
tensor([1.])
tensor([6.])
tensor([3.])
None
None- 从图中的推导可知,梯度符合预期
- \(x, y\)不是叶节点,没有梯度存储下来,注意可以理解为梯度计算了,只是没有存储下来,PyTorch中梯度是一层层计算的
计算标量对矢量的梯度
修改上面的构建为
- 增加变量 \(s = z.mean\),然后直接求取\(s\)的梯度
结构图如下:
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26import torch
from torch.autograd import Variable
w1 = Variable(torch.ones(2,2)*2,requires_grad=True)
w2 = Variable(torch.ones(2,2)*3,requires_grad=True)
w3 = Variable(torch.ones(2,2)*5,requires_grad=True)
x = w1 + w2
y = w2*w3
z = x+y
# z.backward()
s = z.mean()
s.backward()
print(w1.grad)
print(w2.grad)
print(w3.grad)
print(x.grad)
print(y.grad)
# output:
tensor([[0.2500, 0.2500],
[0.2500, 0.2500]])
tensor([[1.5000, 1.5000],
[1.5000, 1.5000]])
tensor([[0.7500, 0.7500],
[0.7500, 0.7500]])
None
None- 显然推导结果符合代码输出预期
- 梯度的维度与原始自变量的维度相同,每个元素都有自己对应的梯度,表示当当前元素增加1的时候, 因变量值的增加量
计算矢量对矢量的梯度
还以上面的结构图为例
直接求中间节点 \(z\) 关于自变量的梯度
代码如下
1
2
3
4
5
6
7
8
9
10
11import torch
from torch.autograd import Variable
w1 = Variable(torch.ones(2,2)*2, requires_grad=True)
w2 = Variable(torch.ones(2,2)*3, requires_grad=True)
w3 = Variable(torch.ones(2,2)*5, requires_grad=True)
x = w1 + w2
y = w2*w3
z = x+y
z_w1_grad = torch.autograd.grad(outputs=z, inputs=w1, grad_outputs=torch.ones_like(z))
print(z_w1_grad)- 在因变量是矢量时,
grad_outputs
参数不能为空,标量时可以为空(grad_outputs
为空时和grad_outputs
维度为1时等价) grad_outputs
的维度必须和outputs
参数的维度兼容
- 在因变量是矢量时,
关于autograd.grad函数
grad_outputs
参数详解
- 在因变量是矢量时,
grad_outputs
参数不能为空,标量时可以为空(grad_outputs
为空时和grad_outputs
维度为1时等价) grad_outputs
的维度必须和outputs
参数的维度兼容
[待更新]