Autograd: 自动求导
pyTorch里神经网络能够训练就是靠autograd
包。我们来看下这个包,然后我们使用它来训练我们的第一个神经网络。
autograd
包提供了对张量的所有运算自动求导。它是一种在运行时才被定义的,意味着反向传播只有再代码运行的时候才会计算,每次循环的时候都可以不同,就是说可以有不同的计算图。
用以下几个例子来看autograd:
张量
torch.Tensor
是torch库的核心类。如果你把Tensor类的 .requires_grad
设置为
True
,它就会计算其上的梯度。 当你计算完所有的值后使用 .backward()
就可以自动的计算所有的导数。 该张量的梯度会累加到 .grad
属性。
To stop a tensor from tracking history, you can call .detach()
to detach it from the computation history, and to prevent future computation from being tracked.
To prevent tracking history (and using memory), you can also wrap the code block in with torch.no_grad():
. This can be particularly helpful when evaluating a model because the model may have trainable parameters with requires_grad=True, but for which we don’t need the gradients.
有一个对自动求导实现非常关键的类:Function。
Tensor
和
Function
互相连接起来,构建了一个无圈图,对所有的历史进行了编码。每个张量都有一个叫 .grad_fn
的属性,是生成该tensor的Function的
索引(而那些由我们创建的Tensor的.grad_fn是None)
如果你想计算导数,那么你就可以对一个Tensor调用它的.backward()方法。如果Tensor是一个标量(只有一个元素的数据),你不需要指明backward()的任何参数,如果它有多个元素的话,就需要指定一个gradient的参数,该参数与调用该Tensor的形状相同。
import torch
创建一个tensor并且设置 requires_grad=True 来跟踪计算。
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 0x7f0ea616bac8>
给 y再来一些运算:
z = y * y * 3
out = z.mean()
print(z, out)
输出:
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward1>)
.requires_grad_( ... )
改变现有张量的 requires_grad
标志。如果没有提供.requires_grad参数的话,输入的标志默认是False。参看例子:
#这在fine tune神经网络时候很有用,特别是迁移的时候
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 0x7f0e86396e48>
梯度
Let’s backprop now Because out
contains a single scalar, out.backward()
is equivalent to out.backward(torch.tensor(1))
.
让我们反向传播,由于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*4的元素是 4.5的举证。让我们称为
out
张量。
至于这个函数的偏导数怎么计算,参见微积分吧!
有了autograd,我们可以做一些疯狂的事情!
x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)
输出:
tensor([-1178.9551, 1202.9015, 293.6342], grad_fn=<MulBackward0>) #每次的输出可能不同
gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(gradients)
print(x.grad)
输出:
tensor([ 102.4000, 1024.0000, 0.1024])
You can also stop autograd from tracking history on Tensors with .requires_grad=True
by wrapping the code block in with torch.no_grad()
:
你可以使用with torch.no_grad()停止自动的梯度计算,即使tensor的属性.requires_grad=True
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
print((x ** 2).requires_grad)
Out:
True
True
False