autograd包是PyTorch中所有神经网络的核心。它为Tensors上的所有操作提供自动微分。它是一个由运行定义的框架,这意味着它是以代码运行的方式来定义反向传播。
torch.Tensor是包的核心类。如果将其属性.requires_grad设置为Ture,则会开始跟踪对tensor的所有操作。完成计算后,可以调用.backward()来自动计算所有梯度。该张量的梯度将累积到.grad属性中。
要停止tensor历史记录的跟踪,可以调用.detach(),它将其与计算历史记录分离,并防止将来的计算被跟踪。
要停止跟踪历史记录(和使用内存),还可以将代码块使用with torch.no_grad():包装起来。在评估模型时特别有用。因为模型在训练阶段具有梯度记录,在训练参数时有利于调参。但在评估阶段,则不需要梯度。
还有一个类对于autograd实现非常重要,那就是Function。Tensor和Function互相连接并构建出一个非循环图,它保存整个完整的计算过程的历史信息。每个张量都有一个grad_fn属性保存着创建了张量的Function的引用。(如果张量是用户自己创建的张量,则grad_fn是None)
计算导数可以调用Tensor.backward()。如果Tensor是标量,则backward()不需要指定任何参数。但是如果Tensor有更多的元素,则需要指定一个gradient参数来指定张量的形状。
import torch
x = torch.ones(2,2,requires_grad=True)
print(x)
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
针对张量做一个加法操作
y = x+2
print(y)
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward0>)
y作为操作的结果被创建,所以y有grad_fn
print(y.grad_fn)
<AddBackward0 object at 0x0000014A864D78C8>
针对y做更多操作
z = y*y*3
out = z.mean()
print(z,out)
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)
.requires_grad()会改变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)
False
True
<SumBackward0 object at 0x0000014A864E0708>
现在开始反向传播
out.backward()
打印梯度
print(x.grad)
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
下面再看一个雅可比向量积的例子
x = torch.randn(3,requires_grad=True)
y = x*2
while y.data.norm()<1000:
# .data.norm() 是L2范数
y = y * 2
print(y)
tensor([ -986.1734, -427.3719, -1249.8046], grad_fn=<MulBackward0>)
y不是标量,想要雅可比矩阵则需要传递向量给backward()作为参数
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)
print(x.grad)
tensor([2.0480e+02, 2.0480e+03, 2.0480e-01])
以上分析可以得出,传进去的向量即结果显示的倍数(结果是[1024,1024,1024])将代码段用with torch.no_grad():包裹起来可以停止对张量的自动求导
print(x.requires_grad)
print((x**2).requires_grad)
with torch.no_grad():
print((x**2).requires_grad)
True
True
False