autograd包为tensors上的所有操作提供自动微分。是一个按运行定义的框架,这意味着你的反向求导是由代码的运行方式定义的,并且每个迭代都可以是不同的。

一、torch.Tensor

torch.Tensorautograd包的中心类。

1. 自动求导

将Tensor的属性.requires_grad设置为True,它将开始跟踪其上的所有操作(比如加减乘除等等计算)。

完成计算后,可调用.backward()自动计算所有梯度。此Tensor的梯度将累积到.grad属性中。

2.取消求导

调用.detach()将tensor与梯度跟踪断开连接,防止其未来计算被跟踪

为了防止跟踪历史记录(和使用内存),还可以将代码包装在:with torch.no_grad():里,这在评估模型时尤其有用,因为模型可能有可训练的参数,且.requires_grad = True,但我们不需要求梯度。

二、torch.Function

另一个自动求导里非常重要的类Function

TensorFunction是相互联系的,并建立了一个无环图,编码了完整的计算历史。

每个Tensor包含了一个属性.grad_fn,用来引用创建Tensor的函数(用户创建的Tensor除外-它们的梯度为“None”)

如果要计算梯度,可以对Tensor调用.backward()

若Tensor是标量,则不需要为.backward()指定任何参数,但是如果它有更多元素,则需要指定一个梯度参数,该参数是匹配形状的Tensor

三、示例
  • 创建一个可求导的tensor
import torch
x = torch.ones(2, 2, requires_grad=True)
print(x)

输出:

tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
  • 对tensor x 进行操作
y = x + 2
print(y)

输出:

tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)

因为y是作为加法操作的结果,所以有grad_fn

print(y.grad_fn)

输出:

<AddBackward0 object at 0x7f5ac6502e80>
  • 对tensor 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_( ... )in-place的改变现有Tensor的requires_grad的值. 默认为False
x= torch.randn(2, 2)
x = ((x * 3) / (x - 1))
print(x.requires_grad)
x.requires_grad_(True)
print(x.requires_grad)
y = (x * x).sum()
print(y.grad_fn)

输出:

False
True
<SumBackward0 object at 0x7f5ac649da58>
  • 自动求导
    以上一个示例的b为例
y.backward()

因为b是标量,所以相当于b.backard(torch.tensor(1.))

  • 打印dy/dx
print(x.grad)

输出:

tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

一般而言,autograd是一计算向量-雅可比积的引擎。向量-雅可比积的特性,使得可以非常方便的将外部梯度输入到具有非标量输出的模型里。

  • 向量-雅可比积的示例
x = torch.randn(3, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

print(y)

输出:

tensor([   20.5556,   285.4648, -1303.7313], 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([1.0240e+02, 1.0240e+03, 1.0240e-01])
  • 停止求导跟踪
print(x.requires_grad)
print((x ** 2).requires_grad)

with torch.no_grad():
    print((x ** 2).requires_grad)

输出:

True
True
False
print(x.requires_grad)
y = x.detach()
print(y.requires_grad)
print(x.eq(y).all())

输出

True
False
tensor(True)