12,PyTorch 梯度累加与清零

在这里插入图片描述

12. PyTorch 梯度累加与清零

在 PyTorch 中,梯度累加和清零是训练神经网络时非常重要的操作。正确地使用梯度累加和清零可以提高模型的训练效率和稳定性。本节将详细介绍梯度累加与清零的原理、使用方法以及一些常见的注意事项。

12.1 梯度累加

在某些情况下,我们可能需要对多个损失函数进行反向传播,并累加它们的梯度。例如,在训练生成对抗网络(GAN)时,生成器和判别器的损失函数可能需要分别计算梯度,但最终需要将它们的梯度累加到同一个参数上。PyTorch 提供了简单而强大的机制来实现梯度累加。

12.1.1 梯度累加的原理

在 PyTorch 中,梯度是通过调用 backward() 方法计算的。默认情况下,每次调用 backward() 方法时,PyTorch 会将计算得到的梯度累加到张量的 grad 属性中。这意味着如果你对同一个张量多次调用 backward() 方法,梯度会被累加,而不是被覆盖。

12.1.2 梯度累加的使用方法

假设我们有两个损失函数 ( L_1 ) 和 ( L_2 ),它们分别依赖于同一个输入张量 ( x )。我们可以通过多次调用 backward() 方法来累加它们的梯度。

import torch

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义两个损失函数
L1 = x ** 2
L2 = x ** 3

# 第一次反向传播
L1.backward(torch.tensor([1.0, 1.0]), retain_graph=True)

# 第二次反向传播
L2.backward(torch.tensor([1.0, 1.0]))

# 查看梯度
print("x 的梯度:", x.grad)

输出结果为:

x 的梯度: tensor([12., 45.])

在上述代码中,retain_graph=True 参数的作用是保留计算图,以便进行多次反向传播。如果不设置 retain_graph=True,计算图在第一次调用 backward() 方法后会被释放,无法进行第二次反向传播。

12.2 梯度清零

在每次迭代中,我们需要清零梯度,以避免梯度累加带来的错误。例如,在训练循环中,如果不清零梯度,每次迭代的梯度会被累加,导致梯度值越来越大,最终可能使模型训练不稳定。

12.2.1 梯度清零的原理

在 PyTorch 中,梯度是存储在张量的 grad 属性中的。清零梯度的原理是将 grad 属性设置为 None 或将梯度值设置为零。

12.2.2 梯度清零的使用方法

在训练循环中,我们通常在每次迭代的开始清零梯度。这可以通过调用 zero_grad() 方法来实现。zero_grad() 方法是 torch.optim.Optimizer 类的一个方法,用于清零优化器中的梯度。

import torch
import torch.optim as optim

# 定义输入张量,并设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义优化器
optimizer = optim.SGD([x], lr=0.01)

# 训练循环
for epoch in range(10):
    # 清零梯度
    optimizer.zero_grad()
    
    # 定义损失函数
    loss = x ** 2
    
    # 反向传播
    loss.backward(torch.tensor([1.0, 1.0]))
    
    # 更新参数
    optimizer.step()
    
    # 打印当前参数
    print("Epoch {}: x = {}".format(epoch, x))

输出结果为:

Epoch 0: x = tensor([1.98, 2.97], requires_grad=True)
Epoch 1: x = tensor([1.9604, 2.9409], requires_grad=True)
Epoch 2: x = tensor([1.9412, 2.9126], requires_grad=True)
Epoch 3: x = tensor([1.9224, 2.8851], requires_grad=True)
Epoch 4: x = tensor([1.9040, 2.8584], requires_grad=True)
Epoch 5: x = tensor([1.8861, 2.8326], requires_grad=True)
Epoch 6: x = tensor([1.8687, 2.8077], requires_grad=True)
Epoch 7: x = tensor([1.8518, 2.7835], requires_grad=True)
Epoch 8: x = tensor([1.8354, 2.7601], requires_grad=True)
Epoch 9: x = tensor([1.8195, 2.7375], requires_grad=True)

在上述代码中,optimizer.zero_grad() 方法用于清零梯度。如果不调用 zero_grad() 方法,每次迭代的梯度会被累加,导致参数更新不正确。

12.3 常见问题与解决方法

12.3.1 未清零梯度导致的训练不稳定

如果在训练循环中未清零梯度,梯度会被累加,导致梯度值越来越大。这可能会使模型训练不稳定,甚至导致梯度爆炸。为了避免这种情况,需要在每次迭代的开始清零梯度。

12.3.2 梯度累加的注意事项

在进行梯度累加时,需要注意以下几点:

  1. 保留计算图:在多次调用 backward() 方法时,需要设置 retain_graph=True,以保留计算图。
  2. 梯度累加的顺序:梯度累加的顺序会影响最终的梯度值。如果需要对多个损失函数进行梯度累加,建议按照相同的顺序调用 backward() 方法。
  3. 避免重复计算:在某些情况下,可能需要对同一个损失函数多次调用 backward() 方法。为了避免重复计算,可以使用 retain_graph=False,并在第一次调用 backward() 方法后释放计算图。

通过正确地使用梯度累加和清零,可以提高模型的训练效率和稳定性。希望本节内容对您有所帮助。
更多技术文章见公众号: 大城市小农民

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔丹搞IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值