【发布时间】:2017-11-27 16:05:15
【问题描述】:
为什么我们需要在 PyTorch 中显式地将梯度归零?为什么调用loss.backward() 时梯度不能归零?将梯度保留在图形上并要求用户显式将梯度归零可以服务于什么场景?
【问题讨论】:
标签: neural-network deep-learning pytorch gradient-descent
为什么我们需要在 PyTorch 中显式地将梯度归零?为什么调用loss.backward() 时梯度不能归零?将梯度保留在图形上并要求用户显式将梯度归零可以服务于什么场景?
【问题讨论】:
标签: neural-network deep-learning pytorch gradient-descent
PyTorch 中有一个循环:
y_hat时转发,loss = loss_fn(y_hat, y)
loss.backward 当我们计算梯度时optimizer.step 当我们更新参数时或者在代码中:
for mb in range(10): # 10 mini batches
y_pred = model(x)
loss = loss_fn(y_pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
如果我们在optimizer.step 之后不清除梯度,这是适当的步骤,或者就在下一个backward() 梯度累积之前。
这是一个显示累积的示例:
import torch
w = torch.rand(5)
w.requires_grad_()
print(w)
s = w.sum()
s.backward()
print(w.grad) # tensor([1., 1., 1., 1., 1.])
s.backward()
print(w.grad) # tensor([2., 2., 2., 2., 2.])
s.backward()
print(w.grad) # tensor([3., 3., 3., 3., 3.])
s.backward()
print(w.grad) # tensor([4., 4., 4., 4., 4.])
loss.backward() 没有任何方式指定这个。
torch.autograd.backward(tensors, grad_tensors=None, retain_graph=None, create_graph=False, grad_variables=None)
从您可以指定的所有选项中,无法手动将渐变归零。就像之前的小例子一样:
w.grad.zero_()
有人讨论过每次用backward() 做zero_grad()(显然是以前的渐变),并用preserve_grads=True 留住毕业生,但这从未实现。
【讨论】:
我有一个 PyTorch 中当前设置的用例。
如果使用在每一步都进行预测的循环神经网络 (RNN),则可能需要一个超参数,以便及时累积梯度。在每个时间步不将梯度归零允许人们以有趣和新颖的方式使用反向传播时间(BPTT)。
如果您想了解有关 BPTT 或 RNN 的更多信息,请参阅文章 Recurrent Neural Networks Tutorial, Part 3 – Backpropagation Through Time and Vanishing Gradients 或 The Unreasonable Effectiveness of Recurrent Neural Networks。
【讨论】:
我们明确需要调用zero_grad(),因为在loss.backward()(计算梯度时)之后,我们需要使用optimizer.step() 来进行梯度下降。更具体地说,梯度不会自动归零,因为loss.backward() 和optimizer.step() 这两个操作是分开的,而optimizer.step() 需要刚刚计算的梯度。
另外,有时我们需要在一些批次之间累积梯度;为此,我们可以简单地调用backward 多次并优化一次。
【讨论】:
optimizer.step()。
在调用.step() 之前保留渐变非常有用,以防您想在多个批次中累积渐变(正如其他人提到的那样)。
如果您想为 SGD 实现动量,在调用 .step() 之后也很有用,并且各种其他方法可能取决于先前更新的梯度值。
【讨论】: