autograd

  • 自动求梯度
  • 概念
  • tensor
  • 梯度

自动求梯度

概念

在深度学习中,我们经常需要对函数求梯度(gradient)。PyTorch提供的autograd包能够根据输入和前向传播过程自动构建计算图,并执行反向传播。

其中Tensor是这个包的核心类,如果将其属性.requires_grad设置为True,它将开始追踪(track)在其上的所有操作(这样就可以利用链式法则进行梯度传播了)。完成计算后,可以调用.backward()来完成所有梯度计算。此Tensor的梯度将累积到.grad属性中。

注意在y.backward()时,如果y是标量,则不需要为backward()传入任何参数;否则,需要传入一个与y同形的Tensor
如果不想要被继续追踪,可以调用.detach()将其从追踪记录中分离出来,这样就可以防止将来的计算被追踪,这样梯度就传不过去了。此外,还可以用with torch.no_grad()将不想被追踪的操作代码块包裹起来,这种方法在评估模型的时候很常用,因为在评估模型时,我们并不需要计算可训练参数(requires_grad=True)的梯度。
Function是另外一个很重要的类。TensorFunction互相结合就可以构建一个记录有整个计算过程的有向无环图(DAG)。每个Tensor都有一个.grad_fn属性,该属性即创建该TensorFunction,
就是说该Tensor是不是通过某些运算得到的,若是,则grad_fn返回一个与这些运算相关的对象,否则是None。

tensor

// 创建一个Tensor并设置requires_grad=True:
x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn)
//输出
//tensor([[1., 1.],
//       [1., 1.]], requires_grad=True)
//None
y = x + 2
print(y)
print(y.grad_fn)
//输出
//tensor([[3., 3.],
//        [3., 3.]], grad_fn=<AddBackward>)
//<AddBackward object at 0x1100477b8>

注意x是直接创建的,所以它没有grad_fn, 而y是通过一个加法操作创建的,所以它有一个为 (AddBackward)的grad_fn。 像x这种直接创建的称为叶子节点,叶子节点对应的grad_fn是None。

梯度

设 y = x + 2, z = y * y * 3 , out = z.mean()

//因为out是一个标量,所以调用backward()时不需要指定求导变量:
out.backward() # 等价于 out.backward(torch.tensor(1.))

我们来看看out关于x的梯度 pytorch 梯度计算效率 flops pytorch梯度上升_标量:

print(x.grad)
//输出
//tensor([[4.5000, 4.5000],
//       [4.5000, 4.5000]])

我们令outpytorch 梯度计算效率 flops pytorch梯度上升_自动构建_02 , 因为
pytorch 梯度计算效率 flops pytorch梯度上升_标量_03
所以
pytorch 梯度计算效率 flops pytorch梯度上升_自动构建_04
所以上面的输出是正确的。

数学上,如果有一个函数值和自变量都为向量的函数 pytorch 梯度计算效率 flops pytorch梯度上升_自动构建_05, 那么 pytorch 梯度计算效率 flops pytorch梯度上升_子节点_06 关于
pytorch 梯度计算效率 flops pytorch梯度上升_子节点_07 的梯度就是一个雅可比矩阵(Jacobian matrix):
pytorch 梯度计算效率 flops pytorch梯度上升_自动构建_08
torch.autograd这个包就是用来计算一些雅克比矩阵的乘积的。例如,如果 pytorch 梯度计算效率 flops pytorch梯度上升_标量_09 是一个标量函数的
pytorch 梯度计算效率 flops pytorch梯度上升_深度学习_10 的梯度:
pytorch 梯度计算效率 flops pytorch梯度上升_深度学习_11
那么根据链式法则我们有 pytorch 梯度计算效率 flops pytorch梯度上升_深度学习_12 关于 pytorch 梯度计算效率 flops pytorch梯度上升_子节点_07 的雅克比矩阵就为:
pytorch 梯度计算效率 flops pytorch梯度上升_子节点_14
注意:grad在反向传播过程中是累加的(accumulated),这意味着每一次运行反向传播,梯度都会累加之前的梯度,所以一般在反向传播之前需把梯度清零。

注:
本节主要参考PyTorch官方文档