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

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

  • 多次梯度累计:在一个小批量数据上进行多次前向传播和反向传播,然后将梯度累积起来,而不是在每个批次上立即更新模型参数。这种情况下,我们需要在同一张计算图上进行多次反向传播,并在每次反向传播后累积梯度。最后,根据累积的梯度来更新模型参数。
  • 多任务学习:在多任务学习中,我们可能有多个任务共享同一个模型。每个任务都有自己的损失函数,需要计算对应的梯度。这样,模型可以同时学习多个任务,并共享参数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyTorch是一个基于Python的科学计算库,它是一个用于深度学习的开源框架,具有高度灵活性和可扩展性。PyTorch的一个关键特性是它的自动微分功能,也称为自动求导功能。自动微分PyTorch中非常强大的功能,它可以自动计算函数的导数,因此可以为深度学习中的反向传播算法提供支持。 在PyTorch中,我们可以使用torch.autograd包实现自动微分。该包提供了Variable类,它是一个包装Tensor的类,它不仅保存了Tensor的值,还保存了梯度信息。我们可以在Variable上执行操作,并使用.backward()方法计算梯度。 下面是PyTorch自动微分的基本示例代码: ```python import torch x = torch.tensor([3.0], requires_grad=True) y = x ** 2 + 2 * x + 1 # 计算梯度 y.backward() # 输出梯度 print(x.grad) ``` 在这个例子中,我们定义了一个变量x,并将requires_grad设置为True,以指示PyTorch需要计算x的梯度。然后我们定义了一个函数y,该函数对x进行操作。我们使用backward()方法计算y相对于x的梯度,并使用x.grad输出梯度。 这里需要注意的是,只有requires_grad=True的变量才会被计算梯度。如果我们想要计算多个变量的梯度,可以将它们放在一个元组中,然后调用backward()方法。 ```python import torch x = torch.tensor([3.0], requires_grad=True) y = torch.tensor([4.0], requires_grad=True) z = x ** 2 + y ** 2 # 计算梯度 z.backward() # 输出梯度 print(x.grad) print(y.grad) ``` 在这个例子中,我们定义了两个变量x和y,并将requires_grad设置为True,以指示PyTorch需要计算它们的梯度。然后我们定义了一个函数z,该函数对x和y进行操作。我们使用backward()方法计算z相对于x和y的梯度,并使用x.grad和y.grad输出它们的梯度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值