转载于:https://blog.csdn.net/zhangbaoanhadoop/article/details/83050111
真的结束于最优点吗?
我们知道,在局部最优点附近,各个维度的导数都接近0,而我们训练模型最常用的梯度下降法又是基于导数与步长的乘积去更新模型参数的,因此一旦陷入了局部最优点,就像掉进了一口井,你是无法直着跳出去的,你只有连续不间断的依托四周的井壁努力向上爬才有可能爬出去。更何况梯度下降法的每一步对梯度正确的估计都在试图让你坠入井底,因此势必要对梯度“估计错很多次”才可能侥幸逃出去。那么从数学上看,什么才是局部最优点呢?
这个问题看似很白痴,很多人会说“局部最优点不就是在loss曲面上某个一阶导数为0的点嘛”。这就不准确啦,比如下面这个马鞍形状的中间的那个点:
(图片来自《deep learning》)
显然这个点也是(一阶)导数为0,但是肯定不是最优点。事实上,这个点就是我们常说的鞍点。
显然,只用一阶导数是难以区分最优点和鞍点的。
我们想一下,最优点和鞍点的区别不就在于其在各个维度是否都是最低点嘛~只要某个一阶导数为0的点在某个维度上是最高点而不是最低点,那它就是鞍点。而区分最高点和最低点当然就是用二阶导数(斜率从负变正的过程当然就是“下凸”,即斜率的导数大于0,即二阶导数大于0。反之则为“上凹”,二阶导数小于0)。
也就是说,若某个一阶导数为0的点在至少一个方向上的二阶导数小于0,那它就是鞍点。在鞍点处,横着看的话,鞍点就是个极小值点,但是竖着看的话,鞍点就是极大值点(线性代数和最优化算法过关的同学应该能反应过来,鞍点处的Hessian矩阵的特征值有正有负。
二阶泰勒展开式
当Hessian矩阵正定时(即对任意的u≠0,有u⊤∇2f(x)u > 0恒成立),对于任何方向向量u,通过二阶泰勒展开式,可知x必定是一个局部最小值点。同样,当Hessian矩阵负定时,此点是一个局部最大值点;当Hessian矩阵同时具有正负特征值时,此点便是鞍点。
那么二阶导数大于0和小于0的概率各是多少呢?由于我们并没有先验知识,因此按照最大熵原理,我们认为二阶导数大于和小于0的概率均为0.5!
那么对于一个有n个参数的机器学习/深度学习模型,“loss曲面”即位于n+1维空间(loss值为纵轴,n个参数为n个横轴)。在这个空间里,如果我们通过梯度下降法一路下滑终于滑到了一个各方向导数均为0的点,那么它为局部最优点的概率即0.5^n,为鞍点的概率为1-0.5^n,显然,当模型参数稍微一多,即n稍微一大,就会发现这个点为鞍点的概率会远大于局部最优点!
所以实际中,当我们的深度学习模型收敛时,几乎没有必要认为它收敛到了一个局部最优点,这完全等同于杞人忧天。也就是说,如果最后模型确实在梯度下降法的指引下收敛到了一个导数为0的点,那这个点几乎可以肯定就是一个鞍点。
显然,站在马鞍中央的时候,虽然很难翻过两边的山坡,但是往前或者往后随便走一步就能摔下马鞍!我们默认使用的mini-batch梯度下降法本身就是带有噪声的梯度估计,哪怕我们位于梯度为0的点,也经常在某个mini-batch下的估计把它估计偏了,导致往前或者往后挪了一步摔下马鞍,也就是mini-batch的梯度下降法使得模型很容易逃离特征空间中的鞍点。
原因如下:
样本均值的方差
首先,我们假设每个样本相对于大自然真实分布的标准差为σ,那么根据概率统计的知识,很容易推出n个样本的标准差为σ/sqrt(n)(如上推导),从这里可以看出,我们使用样本来估计梯度的时候,1个样本带来σ的标准差,但是使用n个样本区估计梯度并不能让标准差线性降低(也就是并不能让误差降低为原来的1/n,即无法达到σ/n),而n个样本的计算量却是线性的(每个样本都要平等的跑一遍前向算法)。
因此想一想,当样本量少的时候会带来很大的方差,而这个大方差恰好会导致我们在梯度下降到很差的局部最优点(只是微微凸下去的最优点)和鞍点的时候不稳定,一不小心就因为一个大噪声的到来导致炸出了局部最优点,或者炸下了马(此处请保持纯洁的心态!),从而有机会去寻找更优的最优点。但是与之相反的,当样本量很多时,方差很小(咦?最开始的时候好像在说标准差来着,反正方差与标准差就差个根号,没影响的哈~),对梯度的估计要准确和稳定的多,因此反而在差劲的局部最优点和鞍点时反而容易自信的呆着不走了,从而导致神经网络收敛到很差的点上,跟出了bug一样的差劲。
那么问题来了,既然局部最优点很难踩到,鞍点也很容易逃离出去,那么为什么我们的模型看起来是收敛了呢?
初学者可能会说 “诶诶,会不会是学习率太大了,导致在“鞍点”附近震荡?” 首先,鞍点不像最优点那样容易震荡,而且哪怕你不断的减小学习率继续让模型收敛,你这时计算output层或者后几层的梯度向量的长度时会发现它依然离0很遥远!
所以更令人信服的是,在高维空间里(深度学习问题上)真正可怕的不是局部最优也不是鞍点问题,而是一些特殊地形。比如大面积的平坦区域:
在平坦区域,虽然导数不为0但是却不大。虽然是在不断下降但是路程却非常长。对于优化算法来说,它需要走很多很多步才有可能走过这一片平坦区域。甚至在这段地形的二阶导数过于特殊的情况下,一阶优化算法走无穷多步也走不出去(设想一下,如果终点在一米外,但是你第一次走0.5米,后续每一步都是前一步的一半长度,那么你永远也走不到面前的一米终点处)。
所以相比于栽到最优点和鞍点上,优化算法更有可能载到这种类似平坦区的地形中(如果这个平坦区又是“高原地带”,即loss值很高的地带,那么恭喜你悲剧了)。更糟糕的是,由于高维地形难以可视化,还有很多更复杂的未知地形会导致假收敛,一旦陷入到这些危险地形中,几乎是无解的。
所以说,在深度学习中,与其担忧模型陷入局部最优点怎么跳出来,更不如去好好考虑:
1、如何去设计一个尽量没有“平坦区”等危险地形的loss空间,即着手于loss函数的设计以及深度学习模型的设计;
2、尽量让模型的初始化点远离空间中的危险地带,让最优化游戏开始于简单模式,即着手于模型参数的初始化策略;
3、让最优化过程更智能一点,该加速冲时加速冲,该大胆跳跃时就大胆跳,该慢慢踱步时慢慢走,对危险地形有一定的判断力,如梯度截断策略;
4、开外挂,本来下一步要走向死亡的,结果被外挂给拽回了安全区,如batch normalization策略等。
针对 batch size,不能设置的太大也不能太小,实际工程中最常用 mini-batch,一般size设置为几十或者几百;另外,听说GPU对2的幂次的batch可以发挥更佳的性能,但是:
这之前我们的讨论是基于梯度下降的,而且默认是一阶的(即没有利用二阶导数信息,仅仅使用一阶导数去优化)。因此对于SGD(随机梯度下降)及其改良的一阶优化算法如Adagrad、Adam等是没问题的,但是对于强大的二阶优化算法如共轭梯度法、L-BFGS来说,如果估计不好一阶导数,那么对二阶导数的估计会有更大的误差,这对于这些靠二阶导数吃饭的算法来说是致命的。
因此,对于二阶优化算法,减小 batch size 带来的收敛速度提升远 < 引入大量误差导致的性能下降,因此在使用二阶优化算法时,往往要采用大batch哦。此时往往batch设置成几千甚至一两万才能发挥出最佳性能(比如 batch size 设置的 2048 配合 L-BFGS 取得了比 SGD 好得多的效果,无论是收敛速度还是最终的准确率)。