论文解析(CLRpolicy):Cyclical Learning Rates for Training Neural Networks

1,278 阅读6分钟

1.背景介绍

这是一篇发布于2015年的老论文Cyclical Learning Rates for Training Neural Networks,因为在fastai库中经常使用fit_one_cycle这个方法,就去看了一些底层代码,同时找到了这篇论文大致浏览了一下,在此做一下总结。

论文的作者主要讨论的问题是如何科学的在训练过程中调整学习率,而不是单纯的使用余弦退火(Cosine annealing)方法让学习率在训练过程中持续下降。

所谓余弦退火,即采用梯度下降算法时,神经网络应该越来越接近Loss值的全局最小值。当它逐渐接近这个最小值时,学习率应该变得更小来使得模型不会出现梯度爆炸且尽可能接近这一点。下图一为余弦函数变化范围,图二为一个Cycle(即训练从开始到结束)的学习率变化。

而作者观察到,学习率持续下降并不是最优的方法,而在训练过程的前期适当提高学习率可能会产生短期的负面影响,但也会产生长期的有益影响。这就是所谓的CLR(Cyclical Learning Rates) policy。

下图展示了应用CLR时从训练开始到结束的学习率变化:

2.原理浅析

在论文中,作者引入了三个比较重要的参数:base_lr(lr的下限), max_lr(lr的上限), stepsize(lr处于上升状态时的iters范围)。

且在比较后认为三角型函数的线性变化趋势与正余弦函数等曲线变化趋势对CLR政策的实际效果影响并不大,所以选用了三角形函数做退火,如图。

2.1 为什么训练前期的学习率上升有助于梯度下降

首先,我们需要知道什么是鞍点,即在曲面或超曲面上不是极大值也不是极小值的临界点,如图所示。

根据作者的叙述,最大限度地减少损失的困难来自于鞍点,而不是糟糕的局部最小值。鞍点附近的梯度值很小,会减慢学习过程。但是,适当的提高学习率可以更快地使得梯度下降函数通过鞍点,从而加快模型的拟合。

2.2 如何选择合适的stepsize

根据作者的实验,最优的stepsize范围在(2~8)*num of iters in an epoch。

举例来说,如果一个图片数据集有4000个样本,bs=100,则完成一个epoch需要将4000/100=40个batch输入模型,即num of iters in an epoch=40。如果这个模型要训练3次,即进行3个epoch,那么总共需要进行3*40=120次iter。此时我们可以选择stepsize=2*40=80,即在前80次迭代中让学习率从base_lr逐步上升到max_lr,后40次迭代中从max_lr逐步下降到base_lr。

2.3 如何选择合理的最小(base_lr)和最大(max_lr)边界值

有一个简单的方法来估计合理的最小和最大的边界值。即一个“LR范围测试”,运行模型几个周期,同时让学习率在低LR值和高LR值之间线性增长。当面对一个新的架构或数据集时,这个测试是非常有价值的。如图所示。

即设置一个cycle,其中包含若干个epoch,让学习率从一个较低的值线性上升到一个较高的值,观察准确率开始上升(或损失下降)时的学习率,将其设置为base_lr,观察准确率或损失开始波动前的学习率,将其设置为max_lr。显然对于图中的模型,base_lr可以选择0.001,max_lr可以选择0.06。当应用一个新的数据集或模型架构时,进行这样的“LR测试”是有必要的。

另外,根据经验法则,最优学习率大概是模型开始收敛时的学习率的两倍左右,那么base_lr大概是max_lr的三分之一或四分之一。

3.CLR policy在fastai库中的实现

在fastai中,将论文实现为一个封装好的函数learn.fit_one_cycle(),但是存在几点变化。

# n是iters of a epoch * tot_epochs = num of all iters
n = len(self.learn.data.train_dl) * self.tot_epochs  
# stepsize通过百分比设定
a1 = int(n * self.pct_start)
a2 = n-a1
self.phases = ((a1, annealing_cos), (a2, annealing_cos))
# base_lr是max_lr的加权
low_lr = self.lr_max/self.div_factor
self.lr_scheds = self.steps((low_lr, self.lr_max), (self.lr_max, self.lr_max/self.final_div))
def steps(self, *steps_cfg:StartOptEnd):
"Build anneal schedule for all of the parameters."
    return [Scheduler(step, n_iter, func=func)
            for (step,(n_iter,func)) in zip(steps_cfg, self.phases)]

在fastai中,论文的实现主要有几点变化:

1.实现lr变化并没有使用论文中的三角形函数,而是使用了余弦函数进行退火

2.stepsize的设定通过百分比参数self.pct_start进行,参数的大小表示在整个cycle中学习率上升的范围。

3.max_lr通过用户人工设置,而base_lr则是max_lr与参数self.div_factor的加权。

因此在使用该函数时,2、3两条所提到的两个参数可以根据论文所述实验结果进行调整。

另外,fit_one_cycle()方法不仅实现了学习率的调整,同时也实现了指数移动加权平均法(Exponential moving weighted average method) 中超参数moms的变化,关于EMWA方法请见我的另一篇文章深度学习中指数加权移动平均(EWMA)优化方法及其发展

3.1 CLR pilicy与EMWA方法的结合

我们都知道,EMWA方法之所以能加速模型的收敛,是因为进行本次优化时,之前几次优化的梯度大小和方向对本次优化的向量大小和方向有较大影响,它们能很好的反映近期变化的趋势。这里设超参数moms是前几次梯度对本次优化向量的加权值,即moms越大,前几次梯度对本次优化向量的影响越大;反之影响越小。

那么在CLR policy中,学习率是由小变大再变小的,应当如何调整moms使得两种优化方法更好的结合呢?

如上图,fastai已经给了答案,当lr小时,梯度的大小较小,方向大概率是相同的,这时我们可以增大moms(即增大前几次梯度所造成的影响),达到快速收敛的目的(如下图所示)。
而当lr大时,梯度大小较大,且容易出现左右跳跃的情况,即迭代的方向不一致(如下图所示),这时需要减小动量,即减弱前几次梯度所造成的影响(因为可能是反方向的),使得模型能正确的拟合。