autograd
软件包是PyTorch中所有神经网络的核心,它可自动区分张量上的所有操作。这是一个按运行定义(define-by-run)的框架,这意味着反向传播由代码的运行方式决定,并且每次迭代都是可以不同的。
张量
torch.Tensor
是程序包的核心类。如果将其属性 .requires_grad
设置为True
,它将开始跟踪对其的所有操作。完成计算后,可以调用.backward()
并自动计算所有梯度。该张量的梯度将累加到.grad
属性中。
要停止张量跟踪历史记录,可以调用.detach()
将其从计算历史记录中分离出来,并防止跟踪将来的计算。
为了防止跟踪历史记录(和使用内存),我们还可以将代码块包装在中。这在评估模型时特别有用,因为模型可能具有的可训练参数 ,但我们不需要梯度。
还有一个对autograd实现非常重要的类-a Function
。
Tensor
与 Function
相互连接并建立一个无环图,该图会对完整的计算历史进行编码。每个张量都有一个.grad_fn
属性,该属性引用Function
已创建的Tensor
(除非用户设置了 grad_fn is None
)。
如果需要计算导数,我们可以在Tensor
上调用.backward()
。如果Tensor
是标量(即只包含一个元素数据),则无需为指定参数backward()
,但如果它有更多的元素,则需要指定gradient
参数为匹配形状的张量。
import torch
创建一个张量并设置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 0x7f7a8636d9e8>
进行更多操作 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_(...)
会立刻修改现有Tensor的 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 0x7f7a86384320>
梯度
我们现在来看下反向传播。由于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的矩阵。这部分后面再来做补充~
############
向量雅可比积的这一特性使得将外部梯度输入具有非标量输出的模型变得非常方便。
我们来看一个向量雅各布积的例子:
x = torch.randn(3, requires_grad=True) y = x * 2 while y.data.norm() < 1000: y = y * 2 print(y)
将得到:
tensor([1305.6464, 159.6618, -691.0499], 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)
就可以得到:
tensor([2.0480e+02, 2.0480e+03, 2.0480e-01])
我们还可以可以通过将代码块包装在 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
或者可以使用.detach()
来获取具有相同内容但不需要求梯度的新Tensor:
print(x.requires_grad)
y = x.detach()
print(y.requires_grad)
print(x.eq(y).all())
可以得到如下:
True
False
tensor(True)
注意:本文归作者所有,未经作者允许,不得转载