• 关于反向传播.backward()


    目录

    标量

    张量

    gradient取11111


    标量

    在PyTorch中,.backward() 方法用于自动计算神经网络中所有可微分张量的梯度。这是执行反向传播过程的关键步骤。以下是 .backward() 方法的具体用法:

     

    tensor.backward(gradient=None, retain_graph=None, create_graph=False)
    

    以下是参数的详细解释:

    • gradient (Tensor or None):

      • 这个参数是可选的。如果提供了 gradient,它必须与 tensor 具有相同的形状,表示 tensor 的梯度。通常在计算非标量张量的梯度时使用。如果 tensor 是一个标量(即它只有一个元素),则可以省略这个参数,因为默认的梯度是一个与 tensor 相同形状的张量,其中所有元素都是 1。
    • retain_graph (bool, optional):

      • 默认情况下,每次调用 .backward() 之后,PyTorch 会释放计算图中的一些内存,以节省空间。如果设置为 True,则可以保留计算图,这样就可以在后续的操作中再次调用 .backward()。这在需要多次调用 .backward() 的情况下非常有用,例如在复杂的训练循环或二阶导数计算中。
    • create_graph (bool, optional):

      • 当设置为 True 时,.backward() 会在计算梯度时创建计算图,这样就可以在之后的操作中计算更高阶的导数。默认为 False

    以下是一个简单的使用示例:

    python

    复制

    1. import torch
    2. # 假设我们有一个简单的模型,输入x,权重w和偏置b
    3. x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
    4. w = torch.tensor([0.5, 0.1, 0.2], requires_grad=True)
    5. b = torch.tensor([0.1], requires_grad=True)
    6. # 前向传播
    7. y = w.dot(x) + b
    8. # 假设我们的损失函数是 y 的平方
    9. loss = y ** 2
    10. # 反向传播
    11. loss.backward()
    12. # 现在,我们可以查看每个参数的梯度
    13. print("Gradient of x:", x.grad)
    14. print("Gradient of w:", w.grad)
    15. print("Gradient of b:", b.grad)

    在这个例子中,我们计算了一个关于 xw, 和 b 的损失函数,然后调用 loss.backward() 来计算每个参数的梯度。由于 loss 是一个标量,我们不需要为 .backward() 提供任何额外的参数。如果 loss 不是一个标量,我们需要提供一个与 loss 形状相同的 gradient 参数。

    张量

    以下是一个非标量张量的 .backward() 调用示例。在这个例子中,我们将使用一个简单的神经网络,其中输出不是一个标量。然后,我们将展示如何计算非标量输出的梯度。

    python

    复制

    1. import torch
    2. # 创建一个简单的神经网络,只有一个线性层
    3. class SimpleNN(torch.nn.Module):
    4. def __init__(self):
    5. super(SimpleNN, self).__init__()
    6. self.linear = torch.nn.Linear(3, 2) # 输入特征是3,输出特征是2
    7. def forward(self, x):
    8. return self.linear(x)
    9. # 实例化网络
    10. net = SimpleNN()
    11. # 创建一个输入张量,并指定需要计算梯度
    12. x = torch.tensor([[1.0, 2.0, 3.0]], requires_grad=True)
    13. # 前向传播
    14. output = net(x)
    15. # 假设我们的损失函数是对输出张量的每个元素求和,但输出不是标量
    16. # 因此,我们需要创建一个与输出形状相同的梯度张量
    17. # 在这个例子中,我们使用全为1的张量,表示每个输出元素的梯度都是1
    18. gradient = torch.ones_like(output)
    19. # 反向传播
    20. output.backward(gradient)
    21. # 查看输入张量的梯度
    22. print("Gradient of input x:", x.grad)

    在这个例子中,我们首先定义了一个非常简单的神经网络,它只有一个线性层。然后,我们创建了一个输入张量 x 并指定了 requires_grad=True,这样我们就可以在反向传播时计算它的梯度。

    在计算损失时,我们并没有直接计算一个标量损失,而是创建了一个与输出张量 output 形状相同的 gradient 张量,这个张量中的所有元素都是1。这样做的原因是因为 .backward() 方法需要知道每个输出元素对最终损失的贡献,从而能够计算输入的梯度。

    当我们调用 output.backward(gradient) 时,我们实际上是在告诉 PyTorch,我们想要计算每个输出元素对输入的梯度,假设每个输出元素对损失的贡献都是1。最后,我们打印了输入张量 x 的梯度,这些梯度表示了损失对输入的每个分量的影响。

    gradient取11111

    如果在使用 PyTorch 的 .backward() 方法时,创建的 gradient 张量不全是1,而是取了其他值,这将影响以下方面:

    1. 梯度的规模:如果 gradient 张量中的元素不是1,那么在调用 .backward() 时,计算得到的梯度将会被这个 gradient 张量中的元素所缩放。具体来说,如果 gradient 张量中的元素是 a,那么得到的梯度将是实际梯度的 a 倍。

    2. 训练稳定性:如果 gradient 张量中的值过大,可能会导致梯度爆炸,这会使得权重更新过大,从而使得训练过程不稳定。相反,如果值过小,可能会导致梯度消失,使得权重更新过小,训练过程变得非常缓慢。

    3. 损失的解释:通常情况下,我们希望损失函数是一个标量,表示整个批次的平均损失或总损失。如果 gradient 张量不是全1,那么 .backward() 计算的损失就不再是对应于原始损失函数的标量损失,而是某种“加权”损失,这可能会使得损失的解释变得复杂。

    具体影响如下:

    • 非均匀权重:如果 gradient 张量的元素不同,那么不同的输出元素对损失的贡献将不同。例如,如果你正在处理一个分类问题,并且希望类别 i 的错误比类别 j 的错误更重要,你可以在 gradient 张量中为类别 i 的对应位置设置更高的值。

    • 特定任务的需求:在某些任务中,可能需要根据特定需求来调整梯度的权重,比如在强化学习中,某些动作的奖励可能需要比其他动作的奖励有更大的影响力。

    • 调试和可视化:在调试过程中,可能需要创建特殊的 gradient 张量来检查或可视化网络中的特定部分如何响应不同的输入。

    总之,改变 gradient 张量的值会直接影响通过 .backward() 方法计算得到的梯度,进而影响模型的训练过程。在实际应用中,通常我们希望 gradient 张量是全1的,以便正确地反映损失函数对每个输出元素的梯度。如果需要非均匀的 gradient 张量,这通常是为了满足特定的优化或模型设计需求。

  • 相关阅读:
    C++新经典 | C++ 查漏补缺(并发与多线程)
    04【Spring声明式事、传播行为、AOP事务控制】
    1312. 让字符串成为回文串的最少插入次数
    自媒体赚钱方式有哪些?如何高效运营自媒体
    第三套.py
    【无标题】
    Python中[-1]、[:-1]、[::-1]、[n::-1]、[:,:,0]、[…,0]、[…,::-1] 的理解
    淘宝Tmall,1688,拼多多API商品详情接口
    vue请求代理查看真实地址
    【Python百日进阶-Web开发-Feffery】Day406 - fac实例:利用dash-leaflet实现可点击多选的区域地图
  • 原文地址:https://blog.csdn.net/m0_68339197/article/details/143438434