在PyTorch中所有神经网络的核心是autograd
软件包。我们先来简单介绍一下这个,然后再构建第一个神经网络。
autograd
包为Tensors上的所有操作提供了自动求导。它是一个运行过程中定义的框架(define-by-run),这意味着反向传播是由代码的运行方式来定义的,并且每一次迭代都可能不同。
torch.Tensor
是包的中心类。如果你将属性.requires_grad
设置为True
,它将开始追踪所有的操作。当你完成了计算过程,你可以调用.backward()
,之后所有的梯度计算都是自动的。Tensor
的梯度将累积到.grad
属性中。
要停止跟踪历史记录的Tensor
,可以调用.detach()
将其从计算历史记录中分离出来,并防止跟踪将来的计算。
为了防止跟踪历史记录(和使用内存),你也可以用torch.no_grad()
包装代码块。 这在评估模型时特别有用,因为该模型可能具有require_grad = True
的可训练参数,但我们不需要梯度值。
还有一个类对于autograd
实现非常重要:一个Function
。
Tensor
和Function
是相互关联的,并建立一个非循环图,它编码构建了完整的计算过程。 每个变量都有一个.grad_fn
属性,该属性反应在已创建Tensor
的函数上(用户创建的Tensor
除外 - 它们的grad_fn
为None
)。
如果你想计算导数,可以在Tensor
上调用.backward()
。如果Tensor
是个标量(一个单元素数据),那么你不用为backward()
指定任何参数,然而如果它有多个元素,你需要指定一个gradient
参数,它是一个匹配尺寸的Tensor
。
import torch
x = torch.ones(2, 2, requires_grad=True) # 创建一个张量并设置`requires_grad = True`来跟踪计算
print(x) # 打印x的值
y = x + 2 # 对x张量进行计算操作
print(y) # 打印y值
print(y.grad_fn) # y是一个操作的结果,所以它有一个grad_fn。
print(y.requires_grad) # 打印y的requires_grad标志状态
z = y * y * 3 # 继续实现复杂的操作
out = z.mean() # 输出z的均值
print(z, out) # 打印计算输出结果
print(z.grad_fn)# y是一个操作的结果,所以它有一个grad_fn。
print(z.requires_grad) # 打印z的requires_grad标志状态
tensor([[ 1., 1.],
[ 1., 1.]])
tensor([[ 3., 3.],
[ 3., 3.]])
<AddBackward0 object at 0x7f181420a978>
True
tensor([[ 27., 27.],
[ 27., 27.]]) tensor(27.)
<MulBackward0 object at 0x7f180409e400>
True
.requires_grad_(...)
就地更改现有张量的requires_grad
标志。如果没有给出,函数输入标志默认为True
。需要注意的是:python 的默认参数,调用的时候,test( ) 与 test(True)等价跟内部flag默认值无关。从打印看,内部flag默认值是False,但是输出结果flag为True
a = torch.randn(2, 2) # 创建一个2*2的张量a
a = ((a * 3) / (a - 1))# 计算
print(a.requires_grad) # 打印a的requires_grad标志状态
a.requires_grad_(True) # 就地设置a的requires_grad标志状态
print(a.requires_grad) # 再次打印a的requires_grad标志状态
b = (a * a).sum() # 由a计算引入b
print(b.grad_fn) # b是一个操作的结果,所以它有一个grad_fn。
print(b.requires_grad) # 打印a的requires_grad标志状态
def test(x):
x = x*2
print(x.requires_grad) # False
return y
x = torch.randn(2, 2)
print(x.requires_grad) # False
y = test(x) # False
print(y.requires_grad) # True
False
True
<SumBackward0 object at 0x7f17b4c2d518>
True
False
False
True
让我们使用反向传播out.backward()
,它等同于out.backward(torch.Tensor(1)
)。
x = torch.ones(2, 2, requires_grad=True) # 创建一个张量并设置`requires_grad = True`来跟踪计算
y = x + 2 # 对x张量进行计算操作
z = y * y * 3 # 继续实现复杂的操作
out = z.mean() # 输出z的均值
out.backward() # 实现反向传播
print(x.grad) # 打印梯度 d(out)/dx
tensor([[ 4.5000, 4.5000],
[ 4.5000, 4.5000]])
4.5矩阵的计算过程如下所示:
我们还可以使用autograd做一些疯狂的事情!
x = torch.randn(3, requires_grad=True)
print(x)
y = x * 2
print(type(y))
print(type(y.data))
print(y.data.norm())
while y.data.norm() < 1000:
y = y * 2
print(y)
gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(gradients) # 沿着某方向的梯度
print(x.grad)
tensor([-0.3905, 1.3533, 1.0339])
<class 'torch.Tensor'>
<class 'torch.Tensor'>
tensor(3.4944)
tensor([ -399.9199, 1385.7303, 1058.7094])
tensor([ 102.4000, 1024.0000, 0.1024])
我们还可以通过使用torch.no_grad()
包装代码块来停止autograd
跟踪在张量上的历史记录,其中require_grad = True
:
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
print((x ** 2).requires_grad)
True
True
False
Deep Learning with PyTorch: A 60 Minute Blitz(https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html)