AUTOGRAD: AUTOMATIC DIFFERENTIATION

PyTorch中所有神经网络的核心是autograd包。让我们先简单地看一下这个,然后我们来训练我们的第一个神经网络。

autograd包为张量上的所有操作提供自动微分。它是一个按运行定义的框架,这意味着您的反向传播是由代码的运行方式定义的,并且每个迭代都可以是不同的。

让我们用更简单的术语和一些例子来看看。

Tensor

torch.Tensor是包的中心类。如果将其属性.requires_grad设置为True,它将开始跟踪其上的所有操作当您完成计算时,您可以调用. backward()并自动计算所有的梯度。这个tensor的梯度将累积为.grad属性。

要阻止tensor跟踪历史,可以调用.detach()将其从计算历史中分离出来,并防止跟踪未来的计算。

为了防止跟踪历史(和使用内存),还可以使用torch.no_grad():将代码块封装起来。这在评估模型时特别有用,因为模型可能有requires_grad=True的可训练参数,但我们不需要梯度。

还有一个类对autograd实现非常重要——Function。

Tensor和Function是相互联系的,并建立一个无环图,它编码了一个完整的计算历史。每个tensor都有一个.grad_fn属性,该属性引用一个创建了Tensor的Function(用户创建的Tensors除外——它们的grad_fn是None)。

如果你想计算导数,你可以在一个Tensor上调用. backward()。如果Tensor是一个标量(即它包含一个元素数据),你不需要指定任何backward()的参数,但是如果它有更多的元素,你需要指定一个梯度参数,这是一个匹配形状的tensor。

import torch

创建一个tensor,并设置requires_grad=True来跟踪计算

x = torch.ones(2, 2, requires_grad=True)
print(x)

Out:

tensor([[1., 1.],
        [1., 1.]], requires_grad=True)

做一个张量运算:

y = x + 2
print(y)

Out:

tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)

y是一个操作的结果,所以它有一个grad_fn。

print(y.grad_fn)

Out:

<AddBackward0 object at 0x7f341a4efef0>

对y做更多的运算

z = y * y * 3
out = z.mean()

print(z, out)

Out:

tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)

.requires_grad_ (…)更改现有Tensor的requires_grad标志。如果没有给出输入标志,则默认为False。

a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)

Out:

False
True
<SumBackward0 object at 0x7f341a51a898>

Gradients

现在让我们反向传播一下。因为out包含一个标量,所以out. backwards()等价于out. backwards (torch.tensor(1))。

out.backward()

打印梯度d (out) / dx

print(x.grad)

Out:

tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

你应该得到一个4.5的矩阵。我们称这个out张量为o。我们有o=\frac{1}{4}\sum_{i}z_{i},z_{i}=3(x_{i}+2)^{2}z_{i}|_{x_{i}=1}=27。因此,\frac{\partial o}{\partial x_{i}}=\frac{3}{2}(x_{i}+2),因此\frac{\partial o}{\partial x_{i}}|_{x_{i}=1}=\frac{9}{2}=4.5

数学上,如果你有一个向量值函数\vec{y}=f(\vec{x}),那么\vec{y}关于\vec{x}的梯度就是雅可比矩阵:

\LARGE J=\bigl(\begin{smallmatrix} &\frac{\partial y_{1}}{\partial x_{1}} &. &. &. &\frac{\partial y_{1}}{\partial x_{n}}\\ &. &. & & &. \\ &. & &. & &.\\ &. & & &. &. \\ &\frac{\partial y_{m}}{\partial x_{1}} &. &. &. &\frac{\partial y_{m}}{\partial x_{n}} \end{smallmatrix}\bigr)

一般来说,torch.autograd是一个计算向量雅可比矩阵乘积的引擎。也就是说,给定任意向量v=(v_{1},v_{2}...v_{m})^{T},计算乘积v^{T}.J。如果v恰好是标量函数l=g(\vec{y})的梯度,即v=(\frac{\partial l}{\partial y_{1}} ... \frac{\partial l}{\partial y_{m}})^{T},那么根据链式法则,向量雅可比矩阵积就是l关于\vec{x}的梯度:

\LARGE J^{T}.v=\bigl(\begin{smallmatrix} \frac{\partial y_{1}}{\partial x_{1}}& .& .& .& \frac{\partial y_{1}}{\partial x_{n}}\\ .& .& & & .&\\ .& & .& & .&\\ .& & & .& .&\\ \frac{\partial y_{m}}{\partial x_{1}}& .& .& .& \frac{\partial y_{m}}{\partial x_{n}} \end{smallmatrix}\bigr)\bigl(\begin{smallmatrix} \frac{\partial l}{\partial y_{1}}\\ .\\ .\\ .\\ \frac{\partial l}{\partial y_{m}}\\ \end{smallmatrix}\bigr)=\bigl(\begin{smallmatrix} \frac{\partial l}{\partial x_{1}}\\ .\\ .\\ .\\ \frac{\partial l}{\partial x_{n}} \end{smallmatrix}\bigr)

(注意,v^{T}\cdot J给出了一个行向量,它可以通过J^{T}\cdot v作为列向量来处理)

向量-雅可比矩阵乘积的这种特性使得将外部梯度输入到具有非标量输出的模型非常方便。

现在让我们看一个向量雅可比矩阵乘积的例子:

x = torch.randn(3, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

print(y)

Out:

tensor([-1109.3398,    -1.4602,   835.0535], grad_fn=<MulBackward0>)

y.data.norm()是向量y所有的元素平方和,再开根号。

在这种情况下,y不再是标量。torch.autograd不能直接计算出整个雅可比矩阵,但是如果我们只想要向量-雅可比矩阵的乘积,只需将向量作为backward参数传递

v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)

print(x.grad)

Out:

tensor([1.0240e+02, 1.0240e+03, 1.0240e-01])

您还可以使用.requires_grad=True来停止autograd跟踪Tensor上的历史记录,方法是使用torch.no_grad()来封装代码块

print(x.requires_grad)
print((x ** 2).requires_grad)

with torch.no_grad():
    print((x ** 2).requires_grad)

Out:

True
True
False

稍后阅读:

autograd和Function的文档位于https://pytorch.org/docs/autograd

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值