为什么我们需要在PyTorch中调用zero_grad()?

时间:2017-12-28 04:31:41

标签: python neural-network deep-learning pytorch gradient-descent

需要在培训期间调用方法zero_grad()。但是documentation并不是很有帮助

|  zero_grad(self)
|      Sets gradients of all model parameters to zero.

为什么我们需要调用此方法?

3 个答案:

答案 0 :(得分:25)

PyTorch中,我们需要在开始进行反向传播之前将渐变设置为零,因为PyTorch 会在后续的反向传递中累积渐变。在训练RNN时这很方便。因此,默认操作是在每次loss.backward()调用时累积渐变。

因此,当您开始训练循环时,理想情况下您应该zero out the gradients以便正确执行参数更新。否则,梯度将指向除预期方向之外的其他方向(即最大化目标)。

这是一个简单的例子:

import torch
from torch.autograd import Variable
import torch.optim as optim

def linear_model(x, W, b):
    return torch.matmul(x, W) + b

data, targets = ...

W = Variable(torch.randn(4, 3), requires_grad=True)
b = Variable(torch.randn(3), requires_grad=True)

optimizer = optim.Adam([W, b])

for sample, target in zip(data, targets):
    # clear out the gradients of all Variables 
    # in this optimizer (i.e. W, b)
    optimizer.zero_grad()
    output = linear_model(sample, W, b)
    loss = (output - target) ** 2
    loss.backward()
    optimizer.step()

或者,如果您正在进行香草梯度下降,那么

W = Variable(torch.randn(4, 3), requires_grad=True)
b = Variable(torch.randn(3), requires_grad=True)

for sample, target in zip(data, targets):
    # clear out the gradients of Variables 
    # (i.e. W, b)
    W.grad.data.zero_()
    b.grad.data.zero_()

    output = linear_model(sample, W, b)
    loss = (output - target) ** 2
    loss.backward()

    W -= learning_rate * W.grad.data
    b -= learning_rate * b.grad.data

答案 1 :(得分:2)

zero_grad()正在重新启动循环,如果您使用梯度方法来减少错误(或损失),则不会从上一步中丢失

如果您不使用zero_grad(),那么损失将减少而不会根据需要增加

例如 如果使用zero_grad(),则会找到以下输出:

model training loss is 1.5
model training loss is 1.4
model training loss is 1.3
model training loss is 1.2

如果不使用zero_grad(),则会发现以下输出:

model training loss is 1.4
model training loss is 1.9
model training loss is 2
model training loss is 2.8
model training loss is 3.5

答案 2 :(得分:0)

虽然这个想法可以从选择的答案中得出,但我觉得我想明确地写出来。

能够决定何时调用 optimizer.zero_grad()optimizer.step() 为优化器在训练循环中如何累积和应用梯度提供了更多的自由。当模型或输入数据很大并且一个实际训练批次不适合 GPU 卡时,这一点至关重要。

在这个来自 google-research 的示例中,有两个参数,分别命名为 train_batch_sizegradient_accumulation_steps

  • train_batch_size 是前向传递的批量大小,跟在 loss.backward() 之后。这是受gpu内存限制的。

  • gradient_accumulation_steps 是实际的训练批量大小,其中累积了多次前向传递的损失。这不受 gpu 内存的限制。

从此示例中,您可以看到 optimizer.zero_grad() 后面是如何optimizer.step()NOT loss.backward() 后面。 loss.backward() 会在每次迭代中调用(第 216 行),但 optimizer.zero_grad()optimizer.step() 仅在累积训练批次数等于 gradient_accumulation_steps 时才会调用(if 中的第 227 行)第 219 行中的 {1}} 块)

https://github.com/google-research/xtreme/blob/master/third_party/run_classify.py

也有人在询问 TensorFlow 中的等效方法。我猜 tf.GradientTape 的用途相同。

(我对 AI 库还是个新手,如果我说的有误请指正)