来自于论文Snapshot Ensembles: Train 1, get M for free, 代码见SnapshotEnsemble, keras版本见Snapshot Ensemble in Keras.
提出问题
在做比赛的时候, 经常把训练集训练集使用KFold方法分成若干train set
和dev set
, 训练得到K个不同的模型, 所有的模型再对测试集进行预测, 将多个预测结果进行综合, 例如投票或平均这种简单的方式, 就能在LB上取得较大的提升.
导致这种的现象的原因, 在这篇文章中提出了一种观点.
但我们更关心的是, 本来复杂模型的训练速度就已经很慢了, 通过这种方式直接成倍的放大了训练模型所需的时间, 是没有足够的资源进一步提升的. 在这篇文章中, 提出了一种方式, 能够使用正常的训练一次的时间, 达到多个模型集成的效果.
论文内容
Stochastic Gradient Descent(SGD)算法在最优化神经网络的方法中已经是一种很优秀的方法了, 主要是因为:
- 这种方法能够避免陷入假鞍点(spurious saddle-points), 即局部极小点(local minima)
- 这是因为small mini-batches的随机性, 使得梯度的计算具有随机性.
但是, 这些局部极小中, 就可能包含能够提升模型表现的一些信息. 而且因为理论上讲, 我们找不到全局最小, 那么对这些局部极小就有好坏区分, 我们认为:
- 具有平坦区域的局部极小通常表现的更好
而SGD的随机性, 配合合适大小的learning rate, 就能够避免下降过程中, 陷入到比较陡峭的局部极小范围中. 但当learning rate比较小时, 模型就会趋向于收敛到最近的局部极小. SGD的这种特征, 在训练的不同阶段被巧妙的使用:
- 初始时, learning rate较大, 模型尽快步入一个邻近的平坦的局部极小
- 当模型的表现不再提升时, 逐步减小learning rate, 直到到达最终的局部极小
为什么多次训练结果的综合就能提升预测效果
可能的局部极小的数量, 随着模型中参数的数量, 呈指数增长. 因此对于神经网络模型, 可能的局部极小的数量是数不胜数的. 因此:
- 不同的初始化参数
- 不同的训练的minibatch的样本顺序
都会导致模型在最优化过程中收敛到不同的局部极小. 尽管这些不同的局部极小拥有非常相近的loss, 但每个模型会犯不同的错误. 这种模型表现的多样性就可以通过集成(ensembling)的形式, 通过投票或者取平均值等简单的方法, 大大降低模型的最终loss, 大幅提升模型的表现.
但是这种集成的方式造成算例线性增加, 是我们难以承受的. 解决方法如下.
显著提升效果的方法
我们不需要训练若干个模型然后集成, 而是只需要训练一个模型, 配合SGD收敛和逃脱局部极小的功能, 在模型训练的过程中多次收敛:
- 每次收敛之后保存下模型的参数, 这样就相当于得到了一个完整的训练好的模型
- 提高learning rate, 继续训练逃脱出当前的局部极小
- 重复上面两步, 直到满足需要的模型的个数.
文中提到了这样操作的具体方法: 根据一个cosine function, 迅速提高和降低learning rate以达到目的**.
这个过程如下图所示
具体训练方法
总的来说, 本模型就是在最优化过程中, 访问多个局部最优, 直到最后一次收敛, 每次收敛对应一个模型(snapshot model), 在预测时, 平均所有模型的预测结果.
每个单独的模型要求:
- dev loss必须低, 这是保证模型预测能力的要求
- 每个模型误分类的样本不能重叠, 这是保证模型之间差异性的要求
Ilya Loshchilov & Frank Hutter的Stochastic Gradient Descent with Warm Restarts中提到, 较早的降低学习率对最终的模型预测损失影响很小. 因此为了快速收敛, 我们尽快降低学习率.
为了达到收敛到多个局部最优的目的, 使用一种Cyclic Cosine Annealing(循环余弦退火)的方法:
- 以大步幅降低学习率, 使模型在很少(50)个epochs之内收敛到第一个局部最优
- 然后使用一个大的学习率继续优化, 使模型跳出局部最优
- 重复这两个过程, 直到收集到指定数目的模型
我们定义学习率为:
\(\alpha(t) = f(mod(t-1, ceil(T/M)))\)
\(t\)是迭代轮数, \(T\)是总的迭代轮数, \(f\)是一个单调递减的函数. 我们将训练过程分成\(M\)个循环, 对应\(M\)个模型.
每次从一个大的学习率开始训练, 逐渐收缩到一个小的学习率. \(\alpha=f(0)\)代表着每次退火开始的较大的那个学习率, 使用这个学习率从局部最优中跳出. 最小的学习率为\(\alpha=f(ceil(T/M))\), 在这个学习率下达到预测效果较好的局部最优. 论文中使用如下的方式:
\[\alpha(t)=\frac{\alpha_0}{2}(\cos(\frac{\pi \mod(t - 1, ceil(T / M))}{ceil(T / M)}) + 1)\]
\(\alpha_0\)是初始的学习率, 因此学习率在\(\alpha_0\)到$f(ceil(T/M))\approx0 $之间变换.
在论文中, 学习率在每次迭代, 即每个batch迭代更新后, 进行更新, 而不是在每次epoch之后更新.