PyTorch 1.0 基础教程(2):autograd: 自动微分器
- 张量
- 梯度
- 更多
- 参考
所有在PyTorch神经网络的核心是autograd
包. 让我们来简要地观察一下这个,我们将先去训练我们的神经网络.
autograd
包为所有在张量上的操作提供自动微分.auto
是一个通过运行来定义(define-by-run
)的框架,意味着你的反向传播有你运行的代码定义,同时,每个迭代都可以不一样.
接下来我们通过一些例子来看看它时怎么做的吧.
张量
torch.Tensor
时autograd
包的核心类. 如果我们设置.requires_grad
为True
,autograd
将跟踪发生在这个张量的所有操作.当完成我们需要的计算后,调用.backwoad()
,它将为我们自动计算好所有的梯度. 这些张量的梯度值将被保存到该张量的.grad
属性中.
如果该张量接下来的操作中,我们不再需要跟踪张量的历史,可以调用.detach()
将其从计算历史中分离开来,这样以后该张量的计算就不会被跟踪了.
为了防止跟踪张量的历史以及占用内存空间,可以用with torch.no_grad():
包裹代码块. 在评估模型时,这样做特别有帮助,因为模型可能具有带requires_grad=True
的可训练参数,但是在评估过程,我们并不需要计算梯度.
还有一个类对autograd的实现是非常重要的–函数.Tensors
和Function
是相互关联的,他们构建了一个无环图,编织成一个完整的计算历史. 每个张量有一个属性.grad_fn
,其引用一个已经创建了Tensors
的Function
(除了被用户创建的Tensors
–他们的grad_fn
为None
).
如果要进行计算过程的推导,需要调用一个Tensor
的.backward()
. 如果Tensor
是一个标量(例如:它包含一个元素数据),就不需要特别指定任何backward()
的命令参数,然而如果它有多个元素,则需要指定一个拥有对应匹配张量形状的gradient
命令参数.
import torch
创建一个张量并且设置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 0x7f1b248453c8>
在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_(...)
可以用in-place方式改变一个存在的张量的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 0x7f1b24845f98>
梯度
现在可以开始反向传播了,因为out
包含仅一个标量,out.backward()
等价于out.backward(torch.tensor(1.))
.
out.backward()
输出梯度d(out)/dx
print(x.grad)
Out:
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
上面的结果究竟时怎样得出的呢,接下来让我们手工推导一下公式.
因为
所以
所以
故
在数学上来看,设
那么,y⃗
对x⃗
的所有梯度可以表示为一个雅可比矩阵(Jacobian matrix):
通常,torch.autograd
是一个计算雅可比向量乘积的引擎. 即给定向量
计算J⋅v
如果v
恰好是标量函数l=g(y⃗ )
的梯度,即
那么根据链式法则,雅可比向量乘积就是l
对x⃗
的梯度:
雅可比向量积的这一特性使得将外部梯度输入到具有非标量输出的模型中变得非常方便.
现在,我们看看雅可比向量积的一个示例:
x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)
Out:
tensor([-278.6740, 935.4016, 439.6572], grad_fn=<MulBackward0>)
在这个例子中,y
不再是一个标量. torch.autograd
不能直接计算全部雅可比,但我们只想要雅可比向量积,仅需要简单的将向量传到backward
中作为命令参数:
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)
print(x.grad)
Out:
tensor([4.0960e+02, 4.0960e+03, 4.0960e-01])
当然,我们也可以可以用with 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
的更多文档在这里.
参考