Pytorch学习笔记4——AUTOGRAD
Pytorch Learning Notes
Reference:
Pytorch官方文档——AUTOGRAD
以上是Pytorch官方的文档,本文主要对其进行翻译整理,并加入一些自己的理解,仅作日后复习查阅所用。
AUTOGRAD
对于简单的神经网络,可以通过手动构建表达式来计算梯度,但是对于多层神经网络则很难实现,因此可以通过pytorch的autograd包实现对于神经网络的自动计算梯度。当定义前向传递时,会自动形成一张计算图,节点为Tensors,边为表达式(即实现将输入Tensor转换为输出Tensor的功能的函数)。利用TORCH.AUTOGRAD
进行自动微分。需要在定义张量时将requires_grad设置为True。
1 构建计算图
import torch
x = torch.ones(5) # input tensor
y = torch.zeros(3) # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
#其中requires_grad的值可以在定义变量时设置(如上)也可以利用x.requires_grad_(True)设置
所构建的计算图如下:
- 计算图中,前向传播同时做两个事情:1、运行指定的运算来得到结果tensor;2、保持计算图中函数的梯度。当在计算图的根(Output)上调用.backward() 时反向传递开始,然后开始.autograd,主要做三件事:1、从每个.grad_fn上计算梯度;2、将梯度在各自张量的.grad属性中累计;3、利用链式法则,一路传播到叶节点张量。
2 梯度运算
实际上应用在tensor上去构建计算图的function是一个"Function"类,这类对象可以按照函数前向计算,也可以在反向传播过程中计算对应的导数,grad_fn用于指向对应的Function对象,要计算梯度,可以使用loss.backward()函数后再用.grad提取计算得到的梯度值,代码如下:
#接上面代码块
print('Gradient function for z =', z.grad_fn)
print('Gradient function for loss =', loss.grad_fn)
#Out:
Gradient function for z = <AddBackward0 object at 0x7faf2b6083c8>
Gradient function for loss = <BinaryCrossEntropyWithLogitsBackward0 object at 0x7faf2b6083c8>
#计算梯度
loss.backward()
print(w.grad)
print(b.grad)
#Out:
tensor([[0.2525, 0.0861, 0.0454],
[0.2525, 0.0861, 0.0454],
[0.2525, 0.0861, 0.0454],
[0.2525, 0.0861, 0.0454],
[0.2525, 0.0861, 0.0454]])
tensor([0.2525, 0.0861, 0.0454])
- 只能得到计算图中的叶节点的梯度值,且该叶节点的requires_grad值需要为True。对给定计算图,用backward只能进行一次梯度运算,若要对图像多次运行backward。需要设置backward函数的retain_graph值为True。
- 可以用torch.no_grad()模块停止反向传播计算;也可以利用detach()函数实现,代码如下:
#torch.no_grad()
z = torch.matmul(x, w)+b
print(z.requires_grad)
with torch.no_grad():
z = torch.matmul(x, w)+b
print(z.requires_grad)
#Out
True
False
#detach()
z = torch.matmul(x, w)+b
z_det = z.detach()
print(z_det.requires_grad)
#Out
False
- 需要注意,计算完梯度后需要.grad.zero_()归零,不然再次计算梯度梯度会累计,导致结果计算不准确。