训练过程--学习率与权重衰减

时间:2024-04-10 21:32:18

学习率

  主要是两个方面:学习率的初始化和学习率的更新

  梯度更新的步长就是学习率

学习率初始化

  1)ReLu的线性不饱和**端着相对于Tanh的双饱和端(经验规则0.1),肯定要降量级。

  2)b的学习率一般为w的两倍;
  例如Caffe和Alex给的Model基础都是0.001(W)/0.002(b)。
  至于为什么Bias的学习率是2倍,猜测是更快抑制Wx加权结果,加速学习。

  3)总的来说是用一个一般的学习率开始,然后逐渐的减小它。

  4)一个建议值是0.1,适用于很多NN的问题,一般倾向于小一点。

  5)找出学习率最高且Loss值仍在下降的值来确定最佳初始学习率。

  6)learning rate设置为0.01或者原来loss的1/5或者1/10。

学习率更新/学习率退火

  1)随步数衰减
  每进行几个周期就根据一些因素降低学习率。典型的值是每过5个周期就将学习率减少一半,或者每20个周期减少到之前的0.1。这些数值的设定是严重依赖具体问题和模型的选择的。在实践中经验做法是:使用固定的学习率训练的同时观察验证集错误率,每当验证集错误率停止下降,就乘以一个常数(比如0.5)来降低学习率。

  2)指数衰减
  数学公式是α=α0e−kt,其中α0,k是超参数,t是迭代次数(也可以使用周期作为单位)。

  3)1/t衰减的数学公式是α=α0/(1+kt),其中α0,k是超参数,t是迭代次数。
  实践中,随步数衰减的随机失活(dropout)更受欢迎,因为它使用的超参数(衰减系数和以周期为时间单位的步数)比k更有解释性。

  4)理论上大的参数、深的网络在训练时需要更少的迭代次数,但是并不是参数越大越好,参数越大使得权重更新缓慢,优化速度下降。
  例如:当训练的精确度没有提升时,learn rate更新为原来的1/10,learn rate最多变化三次,且整个训练迭代过程最多不超过74epochs(370K iterations)。

  5)learning rate设置为0.01或者原来loss的1/5或者1/10。将LR除以2或5后继续跑。

  6)一个对于调度学习率的建议:如果在验证集上性能不再增加就让学习率除以2或者5,然后继续,学习率会一直变得很小,到最后就可以停止训练了。

  7)很多人用的一个设计学习率的原则就是监测一个比率(每次更新梯度的norm除以当前weight的norm),如果这个比率在10-3附近,如果小于这个值,学习会很慢,如果大于这个值,那么学习很不稳定,由此会带来失败。

  8)在SGD方法中,需要构建一个合适的学习率退火方案,来得到一个良好的收敛最小值。人们会认为,像Adam这样的自适应学习率方法,对不同的学习率更具有鲁棒性,因为这些方法能自我更新学习率。但是,即使对于这些方法,好的学习率和最佳的学习率也可能有很大的差别(Andrej Karpathy‏Verified account说最佳学习率是3e-4)
  在调整学习率退火方案和动量参数后,该SGD方法的性能与Adam有得一拼,而且收敛速度更快。另一方面,我们可能认为Adam方法中学习率的自适应性可能模仿了学习速率退火,但是一个明确的退火方案仍然是有帮助的。

  9)以前网上有看到过,说是最好按3倍来调整,也就是0.00001、0.00003、0.0001、0.0003、0.001、0.003、0.01、0.03、0.1、0.3……然后确定范围之后再微调。

学习率调节与loss/acc的关系

  1)找出学习率最高且Loss值仍在下降的值来确定最佳当前学习率。

  2)在一开始的时候,我们可以将其设大一点,这样就可以使weights快一点发生改变,从而让你看出cost曲线的走向(上升or下降),进一步地你就可以决定增大还是减小learning rate。

  3)如何自动调节学习率
  一个简单有效的做法就是,当validation accuracy满足 no-improvement-in-n规则时,本来我们是要early stopping的,但是我们可以不stop,而是让learning rate减半,之后让程序继续跑。
  下一次validation accuracy又满足no-improvement-in-n规则时,我们同样再将learning rate减半(此时变为原始learni rate的四分之一)…继续这个过程,直到learning rate变为原来的1/1024再终止程序。(1/1024还是1/512还是其他可以根据实际确定)。【PS:也可以选择每一次将learning rate除以10,而不是除以2.】

  4)经验法则,很多时候跑不到一个好结果,可能是没有充分下降,learning rate收缩得过快的话,可能还没到底就几乎不动了,收缩过慢的话,可能没有耐心等待学习率降到一个比较低的数就停止了。用最常用的指数下降法的话,很容易发生以上两种现象。
  我现在一般使用固定学习率,如果观察到loss已经下降不动,只在一个区间内抖动的话,就停止学习,将学习率除以10继续重复这个过程。从0.01开始,一般搞到1e-6就差不多啦。


权重衰减weight decay

  在机器学习或者模式识别中,会出现overfitting,而当网络逐渐overfitting时网络权值逐渐变大,因此,为了避免出现overfitting,会给误差函数添加一个惩罚项,常用的惩罚项是所有权重的平方乘以一个衰减常量之和。其用来惩罚大的权值。

  regularization controlled by weight_decay.
  weight decay(权值衰减)的使用既不是为了提高收敛精确度,也不是为了提高收敛速度,其最终目的是防止过拟合。

  在损失函数中,weight decay是放在正则项(regularization)前面的一个系数,正则项一般指示模型的复杂度,所以weight decay的作用是调节模型复杂度对损失函数的影响,若weight decay很大,则复杂的模型损失函数的值也就大。

  在设置上,Weight Decay是一个L2 penalty,是对参数取值平方和的惩罚。
  权值衰减惩罚项使得权值收敛到较小的绝对值,而惩罚大的权值。因为大的权值会使得系统出现过拟合,降低其泛化性能。

权重衰减的数值设置

  1)一般,Weight Decay=0.001。更多的,base_lr与weight_decay相差大概是两到三个数量级。

  2)我通过对浅层宽模型设置2-3倍默认的Weight Decay往往效果是最好的。太大了实际会严重干扰第一个Learning Rate阶段的精度。太小了(也就是很多论文的默认设置)会距离收敛最优情形有差距。  CIFAR100 Top-1 84.36%是在Weight Decay=0.001上获得的。也就是说,在实践里我比其他人更喜欢加大Weight Decay。

  3)实际工程实践中,大家还是更倾向于使用权重衰减,因为它包含的超参数少一些,计算简单一些,可解释性稍微高一点。

训练过程--学习率与权重衰减

权重衰减的规范化参数L1和L2

  权值衰减归一化系数λ的理解
  为防止过度拟合,为训练准则增加权重衰减项,L2归一化为训练准则增加λ∑iθ2i项,L1增加λ∑i|θi|。
  L2对比较大的值惩罚比较大,对应高斯先验,L1将没有太大用的参数变成0,即变稀疏,对应Laplace密度先验。

权重衰减、L2和高斯假设的理解

  然而我们有大量的论文去考察参数的取值,有三点发现:1. 不是高斯分布。2. 取值可以量子化,即存在大量可压缩空间3. 因为Relu, BN的存在使得其有界。

  那么根据Loss function的设置求导之后,我们得到一个公式:W( t+ 1) = W ( t ) − lr ∗ delta(W)− lr ∗ wd ∗ W ( t )也就是说,实际上我们可以把它化简为W(t)首先以(1- lr ∗ wd )的比例等比例收缩,然后再根据学习率、梯度方向进行一次调整。
  这个一收缩不要紧,我们现在做CNN已经不用Sigmoid+AveragePooling了,我们用的是Relu+MaxPooling,也就是说这一收缩,可能有的干脆就从激发变成了不激发。可有可无的激发也就消失掉了,有点像DropOut,当然如果这个Neuron真有用也可以回头再靠梯度把它学成激发状态。所以说有了这个东西会规避过拟合。现在很少有流行模型使用DropOut了吧?窃以为,道理就在这。最后,假设W只能取0和1两个值,那么L1-Penalty和L2-Penalty其实是等价的。实际上的W取值,是处于我说的这种极端情况和高斯分布之间的,所以按找传统统计里L2-Penalty的思路去思考Weight Decay是不对的。现在CNN里面有很多paper在滥用高斯假设,慎读。


base_lr与weight_decay

  1)base_lr与weight_decay相差大概是两到三个数量级
  例如:base_lr=0.01;weight_decay=0.0002

  2)
  最重要的是要关注学习率。一些研究人员(比如Alex Krizhevsky)使用的方法是,监视更新范数和权值范数之间的比率。比率取值大约为10¯³。如果取值过小,那么学习会变得非常慢;如果取值过大,那么学习将会非常不稳定甚至失败。

  梯度更新的步长就是学习率
  以前网上有看到过,说是最好按3倍来调整,也就是0.00001、0.00003、0.0001、0.0003、0.001、0.003、0.01、0.03、0.1、0.3……然后确定范围之后再微调。
  如果α取值过大,可能会导致迭代不收敛,从而发散。所以,一开始α的取值也要比较小心才行。
  随着迭代次数的增加,一般需要慢慢减小α,因为这样能得到一个更好的结果。至于怎么减小α,也是有很多种策略,可以每次迭代都更新α的值,如α = 0.96, 也可以 α=α, 也可以每迭代几次更新一次α的值,方法很多,什么方式更好呢?实验吧……这跟数据有很大关系。

  关于正则化参数λ的取值,因为才疏学浅,了解得不多,所以不便多说。不过一般来说λ不会取太小,我的感觉是0.001和1之间吧,也可以每次迭代都更新λ的值。比如一开始取比较小的值,然后随着迭代次数的增加,慢慢增加λ。

  总结下,学习速率α越大,收敛越快,正则化参数λ越大,收敛越慢。收敛速度太快,可能一下子就越过极值点,导致发散;太慢则可能需要迭代非常多次,导致时间成本非常高。所以,α和λ取到一个合适的值,还是非常重要的。

  3)其实梯度下降算法,在使用的时候无非是要考虑到2个方面,一个是方向,一个是步长,方向决定你是否走在了优化的道路上还是优化道路的负方向,步长是决定你要走多久才能到最优的地方。对于第一个问题很好解决,就是求梯度,梯度的负方向就是了。难的是求步长,如果步子太小,则需要很长的时间才能走到目的地,如果步子过大可能在目的地的周围来走震荡。所以重点在于如何选择步长。

  4)early-stop,其实也是很成熟的方法了,大概思路是在训练的过程中,使用验证集周期性的来测试当前计算出来的参数,在验证集上测试当前参数对验证集的效果,如果效果可以,就保存起来,当很长一段时间都是此效果的话那么就迭代停止,该组参数就认为是不错的参数。这个方法叫做交叉验证,但是我看到有的地方写的是交叉验证用于超参的选择,而这个地方我不是选取的超参,所以不知道到底用对了没有。

带随机数的超参数调整

  深度神经网络涉及很多的超参数,如学习率大小、L2正则化系数、动量大小、批量大小、隐层神经元数目、层数、学习率衰减率等。
  1)随机搜索
  由于你事先并不知道哪些超参数对你的问题更重要,因此随机搜索通常是比网格搜索(grid search)更有效的调参策略。

  2)对数空间搜索
  对于隐层神经元数目和层数,可以直接从均匀分布采样进行搜索。而对于学习率、L2正则化系数、和动量,在对数空间搜索更加有效。例如:

import random
learning_rate = 10 ** random.uniform(-5, -1)   # From 1e-5 to 1e-1
weight_decay = 10 ** random.uniform(-7, -1)   # From 1e-7 to 1e-1
momentum = 1 - 10 ** random.uniform(-3, -1)   # From 0.9 to 0.999

fineturn时的学习率设置

  1) 使用多个而不是单一学习率
  差分学习率(Differential Learning rates),改变前面网络层。
  大部分已有网络(如Resnet、VGG和Inception等)都是在ImageNet数据集训练的,因此我们要根据所用数据集与ImageNet图像的相似性,来适当改变网络权重。在修改这些权重时,我们通常要对模型的最后几层进行修改,因为这些层被用于检测基本特征(如边缘和轮廓),不同数据集有着不同基本特征。
  在实际中,一般将学习率的缩小倍数设置为10倍。例如:在网络中从前往后的不同层分别设置为0.001,0.01,0.1。


超大批量训练的trick

  包含以下两种技术手段:
  1)线性缩放(Krizhevsky 于 2014 年提出):如果我们将 batch size 由 B 增加至 kB,我们亦需要将学习率由η增加至 kη(其中 k 为倍数)。
  2)预热模式(Goyal 等人于 2017 年提出):如果我们使用高学习率(η),则应以较小的η作为起点,而后在前几次 epochs 中逐步将其递增至较大η。