深度学习中优化神经网络是一个重要的问题,我们经常沮丧地发现到了一个节点,不管参数怎么更新,训练的损失都不会下降,神经网络似乎训练不起来了。这可能和损失函数收敛在局部最小值与鞍点有关。
一、 局部最小值(local minama) VS 鞍点(saddle point)
通常我们会认为优化到某个地方,在这个地方参数对损失函数的微分为0,梯度下降就不能再更新参数了,训练就停下来了,损失不再下降了。而提到梯度为零的时候,我们最先想到的可能就是局部极小值(local minimum)。但这个说法是不严谨的。
达到局部最小值的条件:
1.在此处损失函数的微分为0。
2.在该点周围的损失函数值都大于该点的损失函数值。
但其实损失函数不仅在极小值点处的微分为0,在鞍点处的微分也为0,但两个点完全是不一样的概念。 在鞍点处,虽然损失函数的微分为0,但是在该点周围的区域中,有些点的函数值大于**鞍点(saddle point)**处的函数值,有些点的函数值小于鞍点处的函数值。
损失函数在某点处的微分为0,并不能直接判断函数收敛到了局部最小值,只能称该点为临界点(critical point)。
-
局部最小值(local minimum):该点的函数值小于其邻域内的其他点。神经网络的损失函数在局部最小值处趋于稳定,此时参数更新速度减慢。
-
鞍点(saddle point):一个点在某个方向上是局部最小值,而在另一个方向上是局部最大值。这种点在高维优化问题中非常常见,尤其是在神经网络中。
二、避免陷入鞍点或局部最小值的方法
如果一个点的梯度真的很接近零,我们走到临界点的时候,这个临界点到底是局部极小值还是鞍点,是一个值得去探讨的问题。因为如果损失收敛在局极小值,我们所在的位置已经是损失虽低的点了,往四周走提失都会比较高,就没有优化的路可以走了。但遇到鞍点的时候,旁边还是有路可以让损失更低的。只要逃离鞍点,就有可能让损失更低。
为了解决这个问题,诸如mini-batch梯度下降、动量梯度下降、Adam等优化算法可以帮助模型跳出鞍点区域。
2.1 mini-batch梯度下降法
batch与epoch的概念
在训练模型的时候,通常并不是一次性在所有数据上进行参数更新的,而是把所有的数据分成一个一个的批量(batch),每个批量的大小叫做batch size。模型参数(如权重和偏置)是在每个批次的样本上计算的梯度基础上不断更新的。每一次在更新参数的时候,会去取出一个batch的数据用来计算出损失函数并更新参数。遍历所有batch(批量)的过程称为一个回合(epoch)。而且在把数据分为批量的时候,还会对 数据进行随机打乱,一个常见的做法是在每一个回合(epoch)开始之前重新划分batch(批量),也就是说,每个epoch中,批量的数据都不一样。
关系示意
假设我们有一个包含1000个样本的训练集,并将批量大小设为100。
Batch Size = 100
Epoch = 1(完整训练集的一轮遍历)
在这个情况下:
每遍历完1000个样本需要处理 1000 / 100 = 10 个batch(批次)。
如果我们训练5个Epoch,那么模型将经历 5 * 10 = 50 个batch(批次)。
总结
- Batch 是对数据集的小批量处理单元,决定了每次更新模型参数时用到的数据量。
- Epoch 是对整个训练集的完整遍历,一次完整的训练包括多个批次(Batch)。
- 每个Epoch开始之前,都要重新划分batch
使用全批量(fullbatch)的数据来更新参数时,就是**批量梯度下降法(Batch.Gradient Descent,BGD)**此时模型必须把所有训练数据都看完,才能够计算损失和梯度,参数才能够更新一次。
当batch size等于1时,此时使用的方法即随机梯度下降法(Stochastic Gra-dient Descent,SGD)。
实际上,批量梯度下降并没有划分批量,要把所有的数据都看过一遍,才能够更新一次参数,因此其每次迭代的计算量大。但相比随机梯度下降,批量梯度下降每次更新更稳定、更准确。而随机梯度下降的梯度上引入了随机噪声,因此在非凸优化问题中,其相比批量梯度下降更容易逃离局部最小值。
大小批量训练的效率对比
有考虑并行计算的时候,大的批量大小反而是较有效率的,一个回合大的批量花的时间反而是比较少的。
小批量训练的优化结果较好
大的批量更新比较稳定,小的批量的梯度的方向是比较有噪声的(noisy)。但实际上有噪声的的梯度反而可以帮助训练,如果用MNIST和CIFAR这两个数据集做实验,来对比不同batch size对模型accuracy的影响,我们可以从下面2副图的结果看出:批量大小越大,验证集准确率越差。 大的批量大小往往在训练的时候,小的批量大小优化的结果反而是比较好的。
为何小批量训练的优化结果更好?
如果使用Full batch训练,更新参数的时候是沿着一个Loss function,当它遇到一个局部最小值点或者鞍点(总之在这个点的微分值为0)时,它就会停下来不再更新参数。
使用small batch训练时,每次是挑个批量计算损失函数,所以每一次更新参数的时候所使用的损失函数是有差异的。选到第一个批量的时候,用损失函数L1计算梯度; 选到第二个批量的时候,用损失函数L2计算梯度。假设用L1算梯度的时候,梯度是零,训练就会卡住。但L2的函数跟 L1长得不一样,L2不一定会在此处卡住,可以换下个批量的损失函数L2计算梯度,模型还是可以继续训练,继续更新参数,让损失变小。
小批量训练的泛化能力更强
大的批量大小会让我们倾向于走到“峡谷”里面,而小的批量大小倾向于让我们走到“盆地”里面。小的批量有很多的损失,其更新方向比较随机,其每次更新的方向都不太一样。即使“峡谷”非常窄,它也可以跳出去,之后如果有一个非常宽的“盆地”,它才会停下来。
在有并行计算的情况下,小的批量跟大的批量运算的时间并没有太大的差距。除非大的批量非常大,才会显示出差距。但是一个回合需要的时间,小的批量比较长,大的批量反而是比较快的,所以从一个回合需要的时间来看,大的批量是较有优势的。 而小的批量更新的方向比较有噪声的,大的批量更新的方向比较稳
2.2 动量梯度下降法
这种方法借鉴了物理世界里的“动量”概念:一个球如果从高处滚下来,就算滚到鞍点或鞍点,因为惯性的关系它还是会继续往前走。如果球的动量足够大,其甚至翻过小坡继续往前走。
上图中,红色表示负梯度方向,蓝色虚线表示前一步的方向,蓝色实线表示真实的移动量。一开始没有前一次更新的方向,完全按照梯度给指示往右移动参数。负梯度方向跟前一步移动的方向加起来,得到往右走的方向。一般梯度下降走到一个局部最小值或鞍点时,就被困住了。但有动量还是有办法继续走下去,因为动量不是只看梯度,还看前一步的方向。即使梯度方向往左走,但如果前一步的影响力比梯度要大,球还是有可能继续往右走,甚至翻过一个小丘,也许可以走到更好的局部最小值,这就是动量有可能带来的好处。