Pytorch的autograd模块中实现了计算图的相关功能,autograd中的核心数据结构是Variable。
Variable封装了tensor,并记录对tensor的操作记录用来构建计算图
Variable主要包含三个属性
-
data: 保存variable包含的tensor
-
grad: 保存data对应的梯度,grad也是variable,而非tensor,grad与data形状一致
-
grad_fn: 指向一个记录Variable操作历史的Function,即它是什么操作的输出,用来构建计算图。如果某个变量由用户创建,则其为叶子节点,对应的grad_fn等于None。每一个变量在图中的位置可通过grad_fn属性在图中的位置推测得到。
Variable的构造函数需要传入tensor,同时有两个可选参数:
-
requires_grad (bool): 是否需要对该variable进行求导
-
volatile (bool): 设置为True,则构建在该variable之上的图都不会求导,专为推理阶段设计
Variable支持大部分tensor支持的函数,但不支持部分会修改tensor自身的inplace函数,在反向传播中,variable需要缓存原来的tensor来计算梯度。每一个前向传播操作的函数都有与之对应的反向传播函数用来计算输入的各个variable的梯度。
变量的requires_grad属性默认为False,如果某一个节点requires_grad被设置为True,那么所有依赖它的节点requires_grad都是True
volatile=True能够将所有依赖于它的节点全部设为volatile=True,优先级比requires_grad高。volatile=True的节点不会求导,即使设置了requires_grad=True,也无法进行反向传播。在不需要反向传播时(例如inference,即测试推理时),设置该参数可实现一定程度的速度提升,并节省约一半的显存,因为其不需要分配空间保存梯度
在反向传播过程中非叶子结点的导数计算完之后即被清空,可以使用autograd.grad函数和hook查看这些变量的梯度
hook是一个函数,输入是梯度,不应该有返回值
只有对variable的操作才能使用autograd,如果对variable的data直接进行操作,将无法使用反向传播。除参数初始化外,一般不会直接修改variable.data的值
PyTorch中计算图的特点:
-
autograd根据用户对variable的操作构建计算图
-
由用户创建的节点称为叶子节点,叶子节点的grad_fn为None。因梯度是累加的,叶子节点中需要求导的variable具有AccumulateGrad标识
-
variable默认不需要求导,即requires_grad属性默认为False。若某一节点requries_grad设为True,则所有依赖它的节点requires_grad都是True
-
variable的volatile属性默认为False,若某一个variable的属性被设为True,则所有依赖它的节点volatile属性都是True。volatile属性为True的节点不会求导,其优先级比requires_grad高
-
多次反向传播时,梯度是累加的。反向传播的中间缓存会被清空,为了进行多次反向传播需要指定retain_graph=True来保存缓存
-
非叶子节点的梯度计算完之后即被清空,可以使用autograd.grad或hook技术获取非叶子节点梯度的值
-
variable的grad与data形状一致,应避免直接修改variable.data,因为对data的直接操作无法利用autograd进行反向传播
-
反向传播backward的参数grad_variables可看成链式求导的中间结果,如果是标量,可以省略,默认为1
-
PyTorch采用动态图设计,可方便查看中间层的输出,动态地设计计算图结构
实现了自己的Function之后,可以使用gradcheck函数检测实现是否正确。gradcheck通过数值逼近计算梯度,可能具有一定的误差,通过控制eps的大小可以控制容忍的误差。
Pytorch可以通过设置随机数种子来保证结果可复现
用autograd实现的线性回归最大的不同点就在于利用autograd不需要手动计算梯度,可以自动微分。需要注意的是在每次反向传播之前要先把梯度清零
Tensor是一个类似numpy数组的数据结构,能高效执行数据运算,有和numpy类似的结构,并提供简单易用的GPU加速。Variable封装了Tensor并提供自动求导技术,具有和Tensor几乎一样的接口。autograd是PyTorch的自动微分引擎,采用动态计算图,能快速高效计算导数