为什么需要在训练期间调用 zero_grad()
?
| zero_grad(self)
| Sets gradients of all model parameters to zero.
在 PyTorch
中,对于 训练 阶段的每个小批量,我们通常希望在开始执行反向传播之前将梯度显式设置为零(即更新 W< /strong>eights 和 biases),因为 PyTorch 在随后的反向传递中累积梯度。这种累积行为在训练 RNN 或当我们想要计算多个 mini-batches 的总损失梯度时很方便。因此,每个 loss.backward()
调用的默认操作都设置为 accumulate (i.e. sum) the gradients。
因此,当您开始训练循环时,理想情况下您应该 zero out the gradients
以便正确更新参数。否则,梯度将是您已用于更新模型参数的旧梯度和新计算的梯度的组合。因此,它会指向一些其他方向,而不是指向 minimum(或 maximum,在最大化目标的情况下)的预期方向。
这是一个简单的例子:
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
笔记:
当在损失张量上调用 .backward() 时,会发生梯度的累积(即总和)。
从 v1.7.0 开始,Pytorch 提供了将梯度重置为 None optimizer.zero_grad(set_to_none=True) 的选项,而不是用零张量填充它们。文档声称此设置减少了内存需求并略微提高了性能,但如果不小心处理可能会出错。
虽然这个想法可以从选择的答案中得出,但我觉得我想明确地写出来。
能够决定何时调用 optimizer.zero_grad()
和 optimizer.step()
为优化器在训练循环中如何累积和应用梯度提供了更多自由。当模型或输入数据很大并且一个实际的训练批次不适合 gpu 卡时,这一点至关重要。
在这个来自 google-research 的示例中,有两个参数,名为 train_batch_size
和 gradient_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
时调用(第 227 行在第 219 行的 if
块内)
https://github.com/google-research/xtreme/blob/master/third_party/run_classify.py
也有人在询问 TensorFlow 中的等效方法。我猜 tf.GradientTape 有同样的目的。
(我还是AI库的新手,如果我说的有问题,请纠正我)
如果您使用梯度方法减少误差(或损失),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
.zero_grad()
时它会增加,当你不做时它会减少。您显示的输出来自哪里?
您不必调用 grad_zero() 或者可以衰减梯度,例如:
optimizer = some_pytorch_optimizer
# decay the grads :
for group in optimizer.param_groups:
for p in group['params']:
if p.grad is not None:
''' original code from git:
if set_to_none:
p.grad = None
else:
if p.grad.grad_fn is not None:
p.grad.detach_()
else:
p.grad.requires_grad_(False)
p.grad.zero_()
'''
p.grad = p.grad / 2
这样学习就更继续了
在前馈传播期间,权重被分配给输入,并且在第一次迭代之后,权重被初始化模型从样本(输入)中学到的东西。当我们开始反向传播时,我们想要更新权重,以使我们的成本函数损失最小。所以我们清除之前的权重,以获得更好的权重。我们在训练中一直这样做,我们在测试中不这样做,因为我们在训练时间得到了最适合我们数据的权重。希望这会更清楚!
不定期副业成功案例分享