-
[PyTorch入门之60分钟入门闪击战]之自动推倒
AUTOGRAD: AUTOMATIC DIFFERENTIATION(自动分化)
autograd
包是PyTorch中所有神经网络的核心。首先我们先简单地了解下它,然后我们将训练我们的第一个神经网络。
autograd
包为Tensors上的所有操作提供自动分化。它是一个逐步执行的框架,这意味着你的反向传播(backprop)函数是由你的代码运行方式定义的,而且每个迭代器可以是不同的。接下来通过一些例子用更简单的术语来了解autograd
。
Tensor
torch.tensor
是autograd
包的核心。如果你将它的属性.requires_grad
设置为True
,那么它将开始追踪其上的所有操作。当完成你的计算之后,你可以调用.backward()
是所有的梯度自动计算完成。这个张量的梯度会被累积到.grad
属性中。
要停止张量追踪记录,你可以使用.detach()
将它熊计算记录中分离出来,并防止将来的计算被追踪。
为了阻止追踪记录(和使用内存),你可以使用with torch.no_grad()
打包代码块。这在评估模型的时候非常有用,因为当模型的requires_grad=True
时,可能具有可训练的参数,但我们并不需要这些梯度。
另外还有一个对自动推倒非常重要的类 --- Function
。
Tensor
和Function
相互关联、构建出一个无环图,它编码了一个完整的计算历史记录。每个tensor都有一个.grad_fn
属性,该属性引用自一个创建张量(用户创建的张量除外,它们的.grad_fn是空
)的函数。
如果你想计算导数,你可以调用张量上的backward()
。如果张量是一个标量(比如它只有一个数据元素),那么你不需要给backward()
传递任何特殊的参数;但是如果它拥有多个元素,你需要指定一个特殊的梯度参数,它是一个与形状匹配的张量。
创建一个张量,并设置requires_grad=True
来追踪计算。
|
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
是作为一个操作的结果被创建的,所以它有grad_fn
属性:
|
print(y.grad_fn) |
输出:
|
<AddBackward0 object at 0x121669470> |
对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 0x121726588> |
Gradients(梯度)
现在进行反向传播。因为out
只包含一个标量,out.backward()
等价于out.backward(torch.tensor(1.))
。
|
out.backward() |
打印梯度 d(out)/dx:
|
print(x.grad) |
输出:
|
tensor([[4.5000, 4.5000], |
|
[4.5000, 4.5000]]) |
如上,得到了一个4.5填充的2x2的矩阵。我们将out
张量命名为。我们知道,而且,那么,,因此。
在数学上,如果你有一个向量值函数,那么遵循的的梯度是一个Jacobian矩阵:
通常来讲,torch.autograd
是一个计算vector-Jacobian结果的引擎。也就是说,给定任意的,计算的结果。如果恰好是标量函数的梯度,那么,然后根据链接规则,vector-Jacobain的结果就是遵循的的梯度:
注意 给出了一个可以看做是从获取的列向量的行向量。
vector-Jacobain结果的特性使得在一个非标量输出的模型中反馈外部梯度非常方便。
现在我们来看一个vector-Jacobain结果的例子:
|
x = torch.rands(3,requires_grad=True) |
|
y = x * 2 |
|
|
|
while y.data.norm() < 1000: |
|
y = y * 2 |
|
|
|
print(y) |
输出:
|
tensor([805.7939, -90.6879, 624.5883], grad_fn=<MulBackward0>) |
现在这种情况下,y
不再是一个标量。torch.autograd
不能直接计算完整的Jacobain矩阵,但如果我们只想要vector-Jacobain结果,那么只需将向量作为参数传递给backward
即可。
|
v = torch.tensor([0.1,1.0,0.0001],dtype=torch.float) |
|
y.backward(v) |
|
|
|
print(x.grad) |
输出:
|
tensor([2.5600e+01, 2.5600e+02, 2.5600e-02]) |
你也可以通过使用with torch.no_grad()
打包代码块的方式在.requires_grad=True
的张量上停止追踪历史记录的自动推倒。
|
print(x.requires_grad) |
|
print((x ** 2).requires_grad) |
|
|
|
with torch.no_grad(): |
|
print((x ** 2).requires_grad) |
输出:
|
True |
|
True |
|
False |
进阶阅读
更详细的autograd
和Function
文档在这里。
出处:https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html