Pytorch官方指南(一) 翻译版本

  • 自动求导机制(Autograd mechanics)
  • 倒序逐层移除子图(Excluding subgraphs from backward)
  • 自动求导技术如何编码历史(How autograd encodes the history)
  • 广播机制(BROADCASTING SEMANTICS)
  • Numpy原本的广播含义
  • 更新后兼容性


自动求导机制(Autograd mechanics)

本说明将概述自动求导的工作原理并记录操作。完全没有必要理解所有这些,但我们建议您熟悉它,因为它将帮助您编写更高效、更干净的程序,并可以帮助您进行调试。

倒序逐层移除子图(Excluding subgraphs from backward)

每个张量都有一个标志:requires_grad允许细粒度地从梯度计算中排除子图,并且可以提高效率。

requires_grad
就算只有一个在操作图中的输入需要梯度下降,那么它的输出也需要梯度下降。相反,只有当所有输入都不需要梯度下降时,输出才不需要。当所有在子图中的张量都不需要梯度下降时,这个子图不参与反向传播。

x = torch.randn(5, 5) # requires_grad=False by default
y = torch.randn(5, 5)  # requires_grad=False by default
z = torch.randn((5, 5), requires_grad=True)
a = x + y
>>> a.requires_grad
False
b = a + z
>>> b.requires_grad
True

当你想冻结你的模型的一部分,或者你事先知道你不打算使用梯度w.r.t.一些参数的时候,这是特别有用的。例如,如果你想微调一个预训练好的CNN,在冻结的基础上改变require s_grad就足够了,并且不会保存中间缓冲区,直到计算到达最后一层,仿射变换将使用需要梯度下降权重,网络的输出也将需要它们。

model = torchvision.models.resnet18(pretrained=True)
for param in model.parameters():
    param.requires_grad = False
# Replace the last fully-connected layer
# Parameters of newly constructed modules have requires_grad=True by default
model.fc = nn.Linear(512, 100)
# 模型首先将所有参数的requires_grad设置为False,接着将fc层改为线性层实现降维,新创建的线性层的参数默认参与梯度下降。
# Optimize only the classifier
optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)

自动求导技术如何编码历史(How autograd encodes the history)

Autograd是一种逆向自动识别系统。从概念上讲,autograd记录了一个图,它记录了在执行操作时创建数据的所有操作,为您提供了一个有向无环图,它的叶子是输入张量,根是输出张量。通过从根到叶跟踪此图,可以使用链规则自动计算梯度。

在内部,autograd将此图表示为函数对象(真正的表达式)的图,可以将其应用于计算图对应的求值的结果。当计算正向传播时,autograd执行用户请求的计算的同时,构建一个表示计算梯度的函数的图(每个torch的.grad_fn属性。张量是该图的入口点)。当前向过程完成时,我们在后向过程中计算该图以计算梯度。

需要注意的一点是,图在每次迭代时都是从头开始重新创建的,这正是允许使用任意Python控制流语句的原因,这些语句可以在每次迭代时更改图的总体形状和大小。在开始训练之前,你不必对所有可能的路径进行编码——你所跑的就是你所区分的。(就是说每次迭代的图,都是可以变化的)

广播机制(BROADCASTING SEMANTICS)

许多Pytorch操作支持Numpy的广播机制。简而言之,如果一个Pytorch操作支持广播,那么它本身的Tensor参数就可以自动地扩展成相同的大小(不直接复制数据)。

Numpy原本的广播含义

如果两个Tensor满足以下规则,它们是可传播的:

  1. 每个Tensor有至少一个维度。
  2. 在迭代维度大小时,从尾部维度开始,两个Tensor的维度大小必须相等,其中一个是1,或者其中一个不存在。
    例如:
x = torch.empty(5,7,3)
y = torch.empty(5,7,3)
# same shapes are always broadcastable (i.e. the above rules always hold)

x = torch.empty((0,))
y = torch.empty(2, 2)
# x and y are not broadcastable, because x does not have at least 1 dimension

x = torch.empty(5, 3, 4, 1)
y = torch.empty(  3, 1, 1)
>>> (x + y).size()
(5, 3, 4, 1) 
# but:
x = torch.empty(5, 2, 4, 1)
y = torch.empty(  3, 1, 1)
# RuntimeError: The size of tensor a (2) must match the size of tensor b (3) at non-singleton dimension 1

更新后兼容性

以前版本的PyTorch允许在不同形状的张量上执行某些逐点函数,只要每个张量中的元素数相等。然后,通过将每个张量视为一维来执行逐点操作。PyTorch现在支持广播,“一维”的点式行为被认为是不推荐的,并且在张量不可广播但具有相同数量的元素的情况下,将生成Python警告。例如:

torch.add(torch.ones(4,1), torch.randn(4))

以前生成的张量大小为torch.size([4,1]),但现在生成的张量大小为torch.size([4,4])。为了帮助识别代码中可能存在由广播引入的向后不兼容的情况,可以将Tro.Upj.BuffCast.BulkStudioWaveNo.Trime:Trtrue设置为Trtrue,这将在这种情况下生成Python警告,正常使用不会造成警告。