Pytorch自动微分计算笔记

学习Pytorch官方文档的自动微分一章,有许多细节没有看懂。查了一些资料,汇总在这里。
PS:建议大家上手Pytorch深度学习还是直接看官方文档吧。我之前东看西看了许多教程,但是脑子还是一团浆糊,耐下心来五六个小时就能读完官方文档,脑子清楚多了。
Pytorch官方文档Automatic Differentiation的链接

Automatic Differentiation

反向传播(back propagation)根据损失函数对某个参数的梯度(gradient)来调整参数。

pytorch使用torch.autograd()来计算梯度。

为了进行参数优化,我们需要计算损失函数相对于这些参数的梯度(gradients)。梯度告诉我们在当前参数值下,沿着哪个方向以及多大程度上调整参数可以减小损失函数的值。通过梯度下降等优化算法,我们可以根据梯度的方向调整参数的值,逐渐接近最优解。

在PyTorch等深度学习框架中,张量(tensors)是计算图中的关键组件,用于表示数据和参数。默认情况下,张量的requires_grad属性被设置为False,表示它们不需要计算梯度。然而,对于需要优化的参数,我们需要将其requires_grad属性设置为True,以便在后续的反向传播过程中计算梯度。

通过将参数的requires_grad属性设置为True,框架会跟踪这些参数的计算历史,并在需要时自动计算它们的梯度。这使得我们可以使用自动微分(automatic differentiation)技术来计算损失函数相对于参数的梯度,从而进行优化。

# 创建一个张量
x = torch.tensor([1.0, 2.0, 3.0])

# 将requires_grad属性设置为True
x.requires_grad_(True)

# 或者可以使用下面的方式
x.requires_grad = True

# 创建一个张量并设置requires_grad为True
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)

Tensor.backward(gradient=None, retain_graph=None, create_graph=False, inputs=None)

用于计算当前张量相对于计算图的叶节点的梯度,使用链式求导法则。

梯度累积

  • 叶节点(Graph Leaves):计算图中没有进一步后续计算的节点,通常是输入数据或模型的参数。

  • 梯度累积:每次调用反向传播算法,梯度值会累加到叶节点的.grad属性中。

    • 批量梯度下降等优化算法有意义:可以在多个样本上累积梯度,从而更好地更新参数

    • 不恰当的梯度累积

      • 梯度爆炸:梯度绝对值非常大,数值不稳定、参数更新难以预测
      • 梯度消失:梯度绝对值非常小,参数更新缓慢
    • 清除梯度累积的方法

      • optimizer.zero_grad()  # 清零所有参数的梯度
        
      • leaf_tensor.grad = None  # 将特定叶节点的梯度设置为None
        

叶节点和非叶节点

  • 叶节点是requires_grad = True的节点
  • 只有叶节点的.grad属性可以直接访问
  • 非叶节点的梯度值没办法直接获取,但是在梯度传播、参数更新和梯度裁剪中有重要作用
Disabling Gradient Tracking
# torch.no_grad()的上下文中执行的操作不会跟踪梯度
with torch.no_grad():
    z = torch.matmul(x, w)+b
    
z = torch.matmul(x, w)+b
# z_det不会跟踪梯度, 但是z还会跟踪
z_det = z.detach()

禁用梯度跟踪与非叶节点

  • 禁用梯度跟踪,节点将不会出现在计算图中
  • requires_grad=False,节点在计算图中作为非叶节点出现。不会计算和存储梯度,梯度值为0.
  • 某个节点设置为禁止梯度跟踪,可能导致与该节点相关的叶子节点无法连接到计算图中

禁用梯度跟踪的情况

  • 冻结参数(frozen parameters):训练中这些参数不动。
    • 参数固定性:参数在预训练中已经得到比较好的初始值。为保留先前的知识或防止过拟合,不再修改。
    • 计算效率:冻结参数的梯度不会计算与更新,以节省反向传播的计算资源
    • 防止权重漂移:某些参数对训练数据比较敏感,为了防止过度适应训练数据,冻结他们以提高泛化性
  • 加速推理:只进行前向传递,不进行反向传播的情况。
Computational Graphs

这是一张有向无环图(DAG),叶子节点是输入张量,根是输出张量。在这张图上做前向传递后向传播两件事。

Forward Pass

  • 运行要求的操作以生成结果张量
  • 在DAG图上维护梯度函数(Gradient Function
    • 计算图上的每个操作节点都有一个梯度函数,它定义了操作节点对于输出值的梯度计算方式
    • 保存每个节点的输出。有了梯度函数和输出可以保证在反向传播时可以计算梯度。

Backward Pass

  • DAG的根(通常是损失函数)调用.backward()
  • 将梯度累计在.grad属性中
  • 使用链式法则,一直传播到叶节点

Note

计算图是动态变化的,每次都在前向传递时生成。

每张计算图只能调用一次后向传播(.backward()),计算完毕后该计算图会被自动清除。

如果想要在一张计算图上计算多次后向传播,需要在调用.backward()时,使用参数retain_graph=True

需要在一张计算图上进行多次后向传播的情况:

  • 多次梯度累计:在一个小批量数据上进行多次前向传播和反向传播,然后将梯度累积起来,而不是在每个批次上立即更新模型参数。这种情况下,我们需要在同一张计算图上进行多次反向传播,并在每次反向传播后累积梯度。最后,根据累积的梯度来更新模型参数。
  • 多任务学习:在多任务学习中,我们可能有多个任务共享同一个模型。每个任务都有自己的损失函数,需要计算对应的梯度。这样,模型可以同时学习多个任务,并共享参数。

你可能感兴趣的:(杂项,pytorch,笔记,人工智能)