最近被评为 ICLR 2018 最佳论文, 其中提出了一个 Adam 的变体 AMSGrad. 那么, 在实践中, AMSGrad 是不是能够取代 Adam(目前深度学习中最流行的优化方法之一)呢? 让我们一起来看奥地利林茨大学 (JKU) 博士 Filip Korzeniowski 所做的试验.
在 ICLR 2018 最佳论文 On the Convergence of Adam and Beyond(关于 Adam 的收敛性及其他)中, Google 的 Reddi 等指出了 Adam 收敛性证明的缺陷, 并提出了一个 Adam 算法的变体 AMSGrad. 论文通过一个合成任务和少量试验展示了 AMSGrad 的优势. 然而, 它仅仅使用了小型网络(MNIST 上的单层 MLP,CIFAR-10 上的小型卷积网络), 并且没有表明测试精确度(显然, 比起交叉熵损失, 我们更加关心精确度). 从训练和测试损失上看, 他们在 CIFAR-10 上训练的卷积网络, 比当前最先进的结果要差很多(我们并不知道精确度).
由于我一般习惯使用 Adam, 所以我决定在更实际的网络上评估一下 AMSGrad. 请注意, 我这里训练的模型也不大, 也不是当前最先进的, 但绝对比论文展示的更实际.
我在 Lasagne 的 Adam 实现的基础上做了修改, 实现了 AMSGrad. 我还添加了一个关闭 Adam 的偏置纠正 (bias correction) 的选项.
def amsgrad(loss_or_grads, params, learning_rate=0.001, beta1=0.9,
- beta2=0.999, epsilon=1e-8, bias_correction=True):
- all_grads = get_or_compute_grads(loss_or_grads, params)
- t_prev = theano.shared(utils.floatX(0.))
- updates = OrderedDict()
- # 使用 theano 常量以避免向上转型 (upcast) 到 float32
- one = T.constant(1)
- t = t_prev + 1
- if bias_correction:
- a_t = learning_rate*T.sqrt(one-beta2**t)/(one-beta1**t)
- else:
- a_t = learning_rate
- for param, g_t in zip(params, all_grads):
- value = param.get_value(borrow=True)
- m_prev = theano.shared(np.zeros(value.shape, dtype=value.dtype),
- broadcastable=param.broadcastable)
- v_prev = theano.shared(np.zeros(value.shape, dtype=value.dtype),
- broadcastable=param.broadcastable)
- v_hat_prev = theano.shared(np.zeros(value.shape, dtype=value.dtype),
- broadcastable=param.broadcastable)
- m_t = beta1*m_prev + (one-beta1)*g_t
- v_t = beta2*v_prev + (one-beta2)*g_t**2
- v_hat_t = T.maximum(v_hat_prev, v_t)
- step = a_t*m_t/(T.sqrt(v_hat_t) + epsilon)
- updates[m_prev] = m_t
- updates[v_prev] = v_t
- updates[v_hat_prev] = v_hat_t
- updates[param] = param - step
- updates[t_prev] = t
- return updates
首先, 让我们检查下实现是否正确. 我运行了论文中概述的合成试验(使用随机配置). 下图为所得学习曲线.
这和论文中的图形相当接近了, 也和 ycmario 的重新实现的结果差不多. Adam 错误地收敛于 1, 而 x 的最佳值为 - 1.
我接着试验了四种配置:
MNIST 上的逻辑回归.
CIFAR-10 上的 CifarNet(论文中描述的 CNN).
CIFAR-10 上的 SmallVgg(一个小型的 VGG 风格网络)
CIFAR-10 上的 Vgg(一个较大的 VGG 风格网络)
在每种配置中, 我为所有下列组合各运行了 5 遍训练:
beta2 {0.99, 0.999} (据论文建议)
学习率 {0.01, 0.001, 0.0001}
偏置纠正 {on, off}
batch 大小为 128(和原论文一样). 训练了 150 个 epoch, 初始学习率线性下降, 直到在第 150 个 epoch 后降至 0. 在 CIFAR-10 试验中, 我同样使用了标准的左右翻转数据增强. 相应的代码见 GitHub 仓库 fdlm/amsgrad_experiments.
让我们首先关注 Vgg 配置. 虽然这些配置各有其古怪之处, 我们可以从结果得出的结论却是类似的.
CIFAR-10 上的 Vgg
我这里使用的卷积网络结构如下:
每层卷积之后是 batch normalisation 和 rectifier 激活函数. 虚线标志着 dropout, 相应的概率标明在线的上方. 细节详见代码.
在下面的图形中, Adam 的结果用蓝色表示, AMSGrad 的结果用红色表示. 较淡的颜色表明偏置纠正关闭了. 每条线表示一次训练.
训练损失
在我的试验中, 训练损失非常接近 0, 而论文中的数值则是 0.3. 这当然是因为我用的是大得多的模型. 我们同时看到, 如果学习率不是太低的话, AMSGrad 看起来在最后的训练阶段收敛得快一点, 并且大多数情况下, 使用偏置纠正有助于收敛. 不过, 最后所有变体在大多数超参数配置下 (学习率过低除外) 收敛至相似的最终损失. 如果我们仔细查看, 我们会发现在最后的若干 epoch 上 Adam 超越了 AMSGrad. 这没什么大不了的 -- 毕竟这是训练损失. 然而, 这类模型 (以及训练方案) 和论文中报告的 CifarNet 模型的结果很不一样, 论文中的情况是, AMSGrad 的训练损失比 Adam 低很多.
验证损失
验证损失的表现不同. 我们看到, AMSGrad 持续超越 Adam, 特别是在后期的 epoch 中. 两个算法达到了相似的最小验证误差 (在第 20-25 个 epoch 周围), 但自此之后, Adam 看起来过拟合地更厉害, 至少是就交叉熵损失而言. 所以 AMSGrad 可以弥补 Adam 经常比标准 SGD(随机梯度下降) 概括性差这一点吗? 需要做一些标准 SGD 的试验来回答这一问题.
训练精确度
让我们看下精确度. 在分类问题中, 精确度是一个比交叉熵损失重要得多的量度. 毕竟, 我们在乎的是我们的模型成功分类了多少样本. 首先, 让我们看下训练精确度. 就 CIFAR-10 而言, 大部分强大的模型能够达到接近 100% 的精确度, 如果训练是恰当的话(事实上, 即使使用随机标签, 它们仍能达到 100% 精确度.)
正如我们看到的, 训练精确度和训练损失的表现差不多: AMSGrad 比 Adam 收敛得快, 但最终的结果差不多. 如果超参数不是太离谱的话, 不管使用哪种算法, 我们都能达到差不多 100% 的精确度(同样, 学习率不能太低).
最后, 到了最有意思的部分 -- 验证精确度.
验证精确度
现在是失望时刻. 尽管在所有超参数配置上, AMSGrad 的验证损失更低, 从验证精确性来看, 基本是平局. 在某些设定下, Adam 表现更好 (lr = 0.01,b2 = 0.999), 在其他一些设定下, AMSGrad(lr = 0.001,b2 = 0.999) 表现更好. 在所有配置中取得最好结果的是 Adam(lr = 0.001,b2 = 0.99), 但我认为这一差别并不显著. 看起来, 给定合适的超参数设定, 两个算法的表现差不多好.
讨论
论文指出了 Adam 收敛性证明的一个致命缺陷, 并展示了一个证明成立的 Adam 变体, AMSGrad. 然而, 我发现论文对 AMSGrad 的实际影响的试验评估比较有限. 在论文中, 作者声称(着重由我所加)"AMSGrad 在训练损失和精确度上表现得比 Adam 好多了. 此外, 这一表现提升同样转换到了测试损失上." 不幸的是, 就我使用的模型和训练方案而言, 我的试验不能证实这些:
无论是基于损失, 还是基于精确度, 两者在训练集上的表现类似.
AMSGrad 的测试 (这里是验证) 损失确实比较低. 然而,
测试损失上的提升并没有转换为更好的测试精确度(公平起见, 作者从来没有声称这一点).
测试损失和测试精确度间的表现差异提出了一个关键的问题: 类别交叉熵训练用于分类的神经网络有多合适? 我们能做得更好吗?
特此声明: 我确实非常欣赏论文作者指出 Adam 弱点的工作. 尽管我并没有验证证明(显然, 直到这篇论文, 都没人验证 Adam 的证明), 我倾向于相信他们的结论. 同时, 人造样本确实表明 Adam 在特定条件下无法工作. 我认为这是一篇好论文.
然而, 实际影响需要更多的以经验为基础的探索. 我在本文中描述的试验并没有表明 Adam 和 AMSGrad 之间在实践上有很大的差异.
附录
这里我展示其他设定的结果.
MNIST 上的逻辑回归
这一设定和论文中的一个试验类似. 唯一的差别是学习率: 论文使用的是α/t, 其中 t 为迭代, 而我使用的是之前提到的每个 epoch 后的线性衰减. 让我们看下结果.
训练损失
我们首先看到的是, 线性学习率衰减可以得到低得多的训练损失. 在论文中, 训练曲线看起来在 5000 多次迭代 (batch 大小 128, 约 13 个 epoch) 后, 在约 0.25 处保持平坦. 而在我的试验中, 取决于超参数, 它达到了 0.2. 另外一个有趣的发现是, 在所有配置中, Adam 取得了最低的最终训练损失. 这和论文中的结果相反, 特别是论文声称的, 相比 Adam,AMSGrad 对参数变动更加强韧(robust).
验证损失
这里情况有所不同. AMSGrad 通常给出最低的验证损失(除非我们用了过低的学习率). 然而, 在 lr = 0.002,b2 = 0.99 时, Adam 取得了最低的验证损失(差别微乎其微), 不过之后发散了.
训练精确度
训练精确度的表现和训练损失非常类似, 验证精确度同样如此.
验证精确度
从这些结果来看, 在实践层面, 相比 Adam,AMSGrad 并没有明确的优势. 结果取决于学习率和 beta2 的选择. 同样, 结果并未确认 AMSGrad 对超参数变动更强韧这一主张.
CIFAR-10 上的 CifarNet
我尝试重现实现论文描述的卷积神经网络. 然而, 我没能重现训练取现. 取决于学习率和 beta2, 我要么得到了更好的训练损失(但是验证损失更差), 要么两者都比论文中的差. 由于论文并未提供模型的所有细节(例如, 我们不知道初始化方案, 是否使用了 L2 正则化), 很难查找原因. 不管怎么说, 下面是我得到的结果.
训练损失
我们看到, 两个算法在较高的学习率下都不能收敛. 就训练损失而言, 学习率 0.001 看起来效果最好. 尽管 Adam 取得了最低的训练损失, 但 AMSGrad 的训练看起来更稳定(差异较小), 不过我认为需要更多试验来确认这一点.
验证损失
在取得最佳训练损失的配置上, 验证损失很糟糕地发散了. 两种算法都受到了类似的影响. 看起来基于较低的学习率训练的模型概括性要好很多. 我在这里说点扫兴的话, 精确度的图片会大不一样.
训练精确度
训练精确度的表现和训练损失类似.
验证精确度
这里是最有意思的部分了. 我们之前看到验证损失糟糕地发散的模型, 验证精确度实际上是最优的. 就验证损失而言看起来概括性更好的模型, 从验证精确性的角度而言, 概括性并不好. 记住这一点很重要.
取决于设定, Adam 或 AMSGrad 以微小的优势超越彼此. 更重要的是, 和当前最先进模型相比, 模型的表现差太多了(只有 78% 的精确度), 不管使用的是什么优化算法.
CIFAR-10 上的 SmallVgg
这是我在本文主要部分所用模型的一个较小的版本. 在每层中, 使用一半的过滤器, 每块 (block) 只使用两个卷积层. 我将省略这些试验的结果的解释, 因为它们并没有增加了什么新的内容.
训练损失
验证损失
训练精确度
验证精确度
来源: https://juejin.im/entry/5ae2bf476fb9a07ab110e5e5