net.zero_grad()
将其所有参数(包括子模块的参数)的梯度设置为零。 如果调用optim.zero_grad()
将会执行相同的操作,但是是对于已指定要优化的所有参数。 如果您在优化器中仅使用net.parameters()
,例如 optim = Adam(net.parameters(), lr=1e-3)
,则两者相等,因为它们包含的参数完全相同。
你可能有其他参数正在由同一优化器进行优化,但不是网络的一部分,在这种情况下,您将不得不手动将其梯度设置为零并因此跟踪所有参数,或者可以简单地调用optim.zero_grad()
以确保所有正在优化的参数的梯度都设置为零。
问题一:如果同时做这两个会怎样?
回答:没什么,梯度只会再次设置为零,但是由于它们已经为零,因此绝对没有区别。
问题二:如果这两个什么也不做,则梯度会累积,但这到底是什么意思? 他们被相加吗?
回答:是的,它们正在被加到现有梯度中。 在反向传播中,计算每个参数的梯度,然后将梯度加到参数的梯度(param.grad
)。 这允许你可以有多个影响相同参数的反向传播,如果梯度是覆盖而不是相加,则不可能。
例如,如果你需要更大的batchsize
来提高训练的稳定性,但没有足够的内存来增加batchsize
,则你可以累积多个batch
的梯度。 这在PyTorch中实现是微不足道的,它实际上省去了optim.zero_grad()
并延迟了optim.step()
,直到您收集了足够的step
为止。
这种灵活性是以必须将梯度手动设置为零为代价的。 坦白说,一行是花费非常小的代价,即使很多用户不会使用它,尤其是对于初学者来说可能混淆。