在神经网络中,一个重要内容就是进行参数的学习,而参数的学习离不开求导,那么PyTorch是如何进行求导的呢?
Autograd包为张量上所有的操作提供了自动求导功能,torch.Tensor和torch.Function是Autograd的两个核心类,它们相互连接并生成一个有向非循环图。接下来我们先简单介绍Tensor如何实现自动求导,然后介绍计算图,最后用代码来实现这些功能。
为实现对Tensor自动求导,需考虑如下事项:
1) 创建叶节点(Leaf Node)的Tensor,使用requires_grad(可微分性)参数指定是否记录对其的操作,以便之后利用backward()方法进行梯度求解。requires_grad参数的缺省值为False,如果要对其求导需设置为True,然后与之有依赖关系的节点的requires_grad参数会自动变为True。
2) 可利用requires_grad_()方法修改Tensor的requires_grad属性。可以调用.detach()或with torch.no_grad():,将不再计算张量的梯度,跟踪张量的历史记录。这点在评估模型、测试模型阶段中常常用到。
3) 通过计算创建的Tensor(非叶子节点),会自动被赋予grad_fn(保存了函数关系)属性。该属性表示梯度函数。叶节点的grad_fn为None,因为是手动创建的初始的张量。
4) 最后得到的Tensor执行backward()函数,此时自动计算各变量的梯度,并将累加结果保存到grad属性中。计算完成后,非叶节点的梯度自动释放。
5) backward()函数接收参数,该参数应和调用backward()函数的Tensor的维度相同,或者是可broadcast的维度。如果求导的Tensor为标量(即一个数字),则backward中的参数可省略。
6) 反向传播的中间缓存会被清空,如果需要进行多次反向传播,需要指定backward中的参数retain_graph=True。多次反向传播时,梯度是累加的。
7) 非叶节点的梯度backward调用后即被清空。
8) 可以通过用torch.no_grad()包裹代码块的形式来阻止autograd去跟踪那些标记为.requesgrad=True的张量的历史记录。这步在测试阶段经常使用。
在整个过程中,PyTorch采用计算图的形式进行组织,该计算图为动态图,且在每次前向传播时,将重新构建。其他深度学习架构,如TensorFlow、Keras一般为静态图。接下来我们介绍计算图,用图的形式来描述就更直观了,该计算图为有向无环图(DAG)