pytorch:自动求导机制

pytorch:自动求导机制


自动求导机制是torch的核心之一。了解这一个概念对我们编写简洁且高效率的代码具有很大的帮助。虽然不求全部理解,但希望能够做到熟悉就好。


requires_grad

每一个张量都含有一个标记(flag)requires_grad, 它允许在一定的“细粒度”上将其在梯度计算图中剔除以提高效率。如果一个操作(或函数)的输入需要梯度计算,那么其输出也必然需要梯度计算。也就是说输入的requires_flag 为真,输出的requires_grad也一定为真,这两者始终保持同样的值。 反向计算并不会在所有张量都不需要梯度的子图中执行。

这一特性可以在冻结部分网络或者部分提前知道不需要梯度的参数,使得其不需要计算梯度。例如,在网络训练时使用finetune操作,就可以让预训练好的网络参数的requires_grad置为false,而新加入的层的参数的requires_grad置为True。

Autograd

Autograd 是一个反向自动微分系统。概念性地说,autograd会自动地记录数据产生过程中所做的操作,并以有向无环图的形式表示。图中的叶子节点代表了输入张量,而输出张量则是根节点。通过追踪根节点到叶子节点,利用链式规则可以很容易地自动计算梯度。

实际上,autograd 得出的是一个函数对象(表达式)所组成的图。当在执行前向传播的时候,autograd会执行预先设置的运算并建立一个可以由梯度函数组成的图(torch.Tensor 的 .grad_fn 是这张图的入口点)。当前向传播结束后,利用所得到的图来计算梯度值。这也就是说,torch是在运行过程中建立图,这张图是动态的,每次运行都重新建图。

原址操作

原址操作(in-place)对于自动求导来说都有点困难的,且 这种方案也并不值得推荐。因为Autograd的良好内存管理并不会使得算法占据过多的内存,且实际情况中原址操作也并不会节省太多的内存。除非在内存限制方面非常严格,否则不太建议使用原址操作。这主要基于以下两个原因:
1)原址操作可能会覆盖需要计算梯度的变量。
2)每一次原址操作都会重写计算图。非原址操作却是简单地重新分配对象并保持对旧有计算图的引用,而原址操作需要改变所有输入的创建者即该操作对应的Function对象。多个张量引用同一个存储空间,这极容易引发错误。

在不得不使用原址操作的情况下,pytorch提供了原址操作校验的方法。每一个张量保存了一个版本计数器,当这个张量发生变化时其计数器都会增加。当函数保存张量用于反向传播时,也会对此事的版本技术器的值进行保存。每次使用self.saved_tensor时它都会进行核验。如果它的值大于保存的值则会抛出错误。这样就保证了你在使用原址操作且为发生错误时,你的梯度计算也是正确的。

reference

[1] Autograd mechanics
[2] pytorch的自动求导机制 - 计算图的建立
[3] PyTorch学习总结(七)——自动求导机制

猜你喜欢

转载自blog.csdn.net/xholes/article/details/81660369