requires_grad

  • 创建一个 Tensor 时,使用 requires_grad 参数指定是否记录对其的操作,以便之后利用 backward() 方法进行梯度求解
  • 一个 Tensorrequires_grad 成员保存该 Tensor 是否记录操作用于计算梯度
  • .requires_grad_(...) 原地改变了现有张量的 requires_grad 标志。如果没有指定的话,默认输入的这个标志是 False

backward

  • 通过运算创建的 Tensor ,会自动被赋值 grad_fn 属性。该属性表示梯度函数
  • 最后得到的 Tensor 执行自身的 backward() 函数,此时之前参与运算并生成当前 Tensor 的叶子(leaf) Tensor 将会保存其梯度在叶子 Tensorgrad 属性中。
  • backward() 函数接受参数,表示在特定位置求梯度值,该参数应和调用 backward() 函数的 Tensor 的维度相同,或者是可 broadcast 的维度。默认为 torch.tensor(1) ,也就是在当前梯度为标量1的位置求叶子Tensor的梯度
  • 默认同一个运算得到的 Tensor 仅能进行一次 backward() 。再次运算得到的 Tesnor ,可以再次进行 backward()
  • 当多个 Tensor 从相同的源 Tensor 运算得到,这些运算得到的 Tensorbackwards() 方法将向源 Tensorgrad 属性中进行数值累加
  • 在PyTorch中对 Tensor 元素直接赋值会产生 CopySlices backward 函数,也就是说,对 Tensor 元素的赋值操作也是可以反向传播的,但是有一定条件。但是这样有时候会使得依赖于其他叶子节点赋值的叶子节点出现RuntimeError: leaf variable has been moved into the graph interior的异常,即叶子节点被移到了图内部,这时需要进行调整,修正方法有两种,第一种如果我们只有确定个数的元素需要组成一个新的 Tensor ,可以使用 torch.cat() 函数,第二种是当我们不知道元素个数,或者元素个数太多手写 cat 太累,可以在创建有依赖的叶子节点时,指定 requires_grad = False

计算梯度

简单案例

现在开始进行反向传播,因为 out 是一个标量,因此 out.backward()out.backward(torch.tensor(1.)) 等价。

  1. out.backward()

输出导数 d(out)/dx

  1. print(x.grad)

输出:

  1. tensor([[4.5000, 4.5000],
  2. [4.5000, 4.5000]])

我们的得到的是一个数取值全部为4.5的矩阵。让我们来调用 out 张量 “backward简单分析 - 图1”。

可以知道backward简单分析 - 图2backward简单分析 - 图3
因此,backward简单分析 - 图4,因而backward简单分析 - 图5

所以对于前面的 backward() 而言,括号里传入的参数就是前面导数式子中,对于求取梯度值针对的特定点。默认是全1的位置。

数学过程

通常来说, torch.autograd 是计算雅可比向量积的一个“引擎”。也就是说,给定任意向量backward简单分析 - 图6,计算乘积backward简单分析 - 图7。如果backward简单分析 - 图8恰好是一个标量函数backward简单分析 - 图9的导数,即backward简单分析 - 图10,那么根据链式法则,雅可比向量积应该是backward简单分析 - 图11backward简单分析 - 图12的导数:
backward简单分析 - 图13
注意:行向量的backward简单分析 - 图14也可以被视作列向量的backward简单分析 - 图15
雅可比向量积的这一特性使得将外部梯度输入到具有非标量输出的模型中变得非常方便。

参考链接