关于 AMSGrad 是一个糟糕的「解决方案」的建议是正确的。我们一直发现,AMSGrad 在准确率(或其他相关指标)上没有获得比普通 Adam / AdamW 更高的增益。 当你听到人们说 Adam 的泛化性能不如 SGD+Momentum时,你基本上总会发现他们为自己的模型所选择的超参数不咋地。通常 Adam 需要的正则化比 SGD 多,因此在从 SGD 转向 Adam 时,确保调整正则化超参数。 L2正则化是减少过拟合的经典方法,它会向损失函数添加由模型所有权重的平方和组成的惩罚项,并乘上特定的超参数以控制惩罚力度。以下本文所有的方程式都是用 Python、NumPy 和 PyTorch 风格的表达方式: 其中 wd 为我们设置的超参数,用以控制惩罚力度。这也可以称为权重衰减,因为每一次运用原版 SGD 时,它都等价于使用如下方程式更新权重: 其中 lr 表示学习率、w.grad 表示损失函数对 w 的导数,而后面的 wd * w 则表示惩罚项对 w 的求导结果。在这个等式中,我们会看到每一次更新都会减去一小部分权重,这也就是「衰减」的来源。 fast.ai 查看过的所有库都使用第一种形式。在实践中,几乎都是通过向梯度 wd*w 而实现算法,而不是真正地改变损失函数。因为我们并不希望增加额外的计算量来修正损失,尤其是还有其它简单方法的时候。 既然它们是同一种表达,那么我们为什么需要区分这两种概念呢?原因在于它们只对于原版 SGD 是等价的,而当我们添加动量或使用如 Adam 那样复杂的最优化方法,L2正则化(第一个方程)和权重衰减(第二个方程)就会存在很大的不同。在本文其余的部分中,我们讨论权重衰减指的都是第二个方程式,而讨论 L2正则化都是讨论第一个经典方式。 如下在带动量的 SGD 中,L2正则化与权重衰减是不等价的。L2正则化会将 wd*w 添加到梯度中,但现在权重并不是直接减去梯度。首先我们需要计算移动均值: 然后权重才能通过减去乘上了学习率的移动均值而得到更新。所以 w 更新中涉及到的正则化为 lr* (1-alpha)*wd * w 加上已经在 moving_avg 中前面权重的组合。 我们可以观察到,从 w 中减去有关正则化的部分在两种方法中是不同的。当我们使用 Adam优化器时,权重衰减的部分可能相差更大。因为 Adam 中的 L2正则化需要添加 wd*w 到梯度中,并分别计算梯度及其平方的移动均值,然后再能更新权重。然而权重衰减方法只是简单地更新权重,并每次从权重中减去一点。 显然这是两种不同的方法,在进行了实验后,Ilya Loshchilov 和Frank Hutter建议我们应该在 Adam 算法中使用权重衰减方法,而不是像经典深度学习库中实现的 L2正则化。 那么我们要如何才能实现 AdamW 算法呢?如果你们在使用 fastai 的库,那么在使用 fit 函数时添加参数use_wd_sched=True 就能简单地实现: 如果你更喜欢新的训练 API,你就能在每一个训练阶段中使用参数wd_loss=False: 以下简要地概述了 fastai 是如何实现 AdamW 的。在优化器中的阶梯函数,我们只需要使用梯度修正参数,根本不使用参数本身的值(除了权重衰减,我们将在外部处理它)。然后我们可以在最优化器之前通简单的实现权重衰减,但这仍需要在计算梯度后才能完成,否则它就会影响梯度的值。所以在训练循环中,我们必须确定计算权重衰减的位置。 当然,最优化器应该设定 wd=0,否则它还会做一些 L2正则化,这也是我们不希望看到的。现在在权重衰减的位置中,我们可以在所有参数上写一个循环语句,并依次采用权重衰减的更新。而我们的参数应该存储在优化器的字典 param_groups 中,所以这个循环应该表示为如下语句: 我们首先在计算机视觉问题上进行测试,效果非常好。具体来说,Adam 和 L2正则化在 30 个 epoch 中获得的平均准确率为 93.96%,在两次中有一次超过 94%。我们选择 30 个 epoch 是因为通过 1cycle 策略和 SGD 可以获得 94%准确率。当我们使用 Adam 与权重衰减方法,我们持续获得 94% 到 94.25% 的准确率。为此,我们发现使用 1cycle 策略时的最优 beta2 值为 0.99。我们将 beta1参数视为 SGD 中的动量,这也就意味着它学习率的增长由 0.95 降低到 0.85,然后随学习率的降低而又增加到 0.95。 |