本章主要介绍深度学习常见的一些概念,方便我们从不同的角度来更好地优化神经网络。
1.局部极小值与鞍点
1.1临界点及其种类
在神经网络的训练过程中,我们可能会遇到不管我们怎么update我们的参数,损失都降不下来的情况。
这时,我们就会猜想,我们走到了一个地方,这个地方对参数的微分为0,因此梯度下降法就没有办法update参数了,损失就不会下降了。提到梯度为0,我们最先想到的可能是局部极小值:
局部极小值是指损失函数在参数空间中的一个局部区域内最小的点,即梯度为零且二阶导数正定的位置。
反之,局部极大值是指损失函数在参数空间中的一个局部区域内最大的点,即梯度为零且二阶导数负定的位置。
但是损失不只是在局部极小值的梯度是0,还有其他的点,比如鞍点。鞍点是梯度是零且区别于局部极小值和局部极大值的点。
鞍点是指损失函数在参数空间中的一个点,该点在某些方向上是局部极小值而在其他方向上是局部极大值,如上图,因其形状似马鞍而得名。它既不是局部极小值也不是局部极大值。
临界点是梯度为零的点的统称。
局部极小值与鞍点的区别:局部极小值的位置已经是损失最低的点了,往四周走损失都会比较高,就没有路可以走了。但鞍点没有这个问题,旁边还是有路可以让损失更低的。只要逃离鞍点,就有可能让损失更低。
1.2判断临界值种类的方法
判断一个临界点到底是局部极小值还是鞍点需要知道损失函数的形状。但是损失函数是很复杂的,虽然无法完整的知道损失函数的样子,但是如果给定一组参数θ′,在θ′附近的损失函数可以通过泰勒级数近似得出。
(1.1)
上式是泰勒级数近似。第一项 L(θ)′ 告诉我们,当 θ 跟 θ′ 很近的时候,L(θ) 应该跟 L(θ′) 还蛮靠近的;第二项 中,g 代表梯度,它是一个向量,可以弥补 L(θ′) 跟 L(θ) 之间的差距。有时候梯度 g 会写成 ∇L(θ′)。gi 是向量 g 的第 i 个元素,就是 L 关于 θ 的第 i 个元素的微分,即
(1.2)
光看 g 还是没有办法完整地描述 L(θ),还要看公式的第三项,第三项跟海森矩阵H 有关。H 里面放的是 L 的二次微分,它第 i 行,第 j 列的值
就是把 θ 的第 i 个元素对 L(θ′)作微分,再把 θ 的第 j 个元素对
作微分后的结果,即
(1.3)
总结一下,损失函数 L(θ) 在 θ′ 附近可近似为式 (1.1),式 (1.1) 跟梯度和海森矩阵有关,梯度就是一次微分,海森矩阵里面有二次微分的项。
在临界点,梯度 g 为零,因此为零,所以在临界点附近损失函数可以被近似为
(1.4)
我们可以根据来判断在 θ′ 附近的误差表面(error surface)到底长什么样子。知道误差表面的“地貌”,我们就可以判断 L(θ′) 是局部极小值、局部极大值,还是鞍点。
令,因此
,会出现三种情况:
Ⅰ.如果对所有 v,,这意味着对任意 θ,L(θ) > L(θ′). 只要 θ 在 θ′ 附近,L(θ) 都大于 L(θ′). 这代表 L(θ′) 是附近的一个最低点,所以它是局部极小值。
Ⅱ.如果对所有 v,,这意味着对任意 θ,L(θ) < L(θ′),θ′ 是附近最高的一个点,L(θ′) 是局部极大值。
Ⅲ.如果对所有 v,有时候大于零,有时候小于零。这意味着在 θ′ 附近,有时候L(θ) > L(θ′),有时候 L(θ) < L(θ′). 因此在 θ′ 附近,L(θ′) 既不是局部极大值,也不是局部极小值,而是鞍点。
还有一个更简单的方法来判断的正负性。算出一个海森矩阵后,不需要把它跟所有的 v 都乘乘看,只要看 H的特征值。若 H 的所有特征值都是正的,H 为正定矩阵,
;临界点是局部极小值。若 H 的所有特征值都是负的,H 为负定矩阵,则
,临界点是局部极大值。若 H 的特征值有正有负,临界点是鞍点。
如果 n 阶对称矩阵 A 对于任意非零的 n 维向量 x 都有 > 0,则称矩阵 A 为正定矩阵。如果 n 阶对称矩阵 A 对于任意非零的 n 维向量 x 都有
<0,则称矩阵 A 为负定矩阵。
1.3逃离鞍点的方法
如下图所示,在一维空间中有一个局部极小值
但是在二维空间中,这个点就可能是一个鞍点,如图
这告诉我们深度学习的训练是非常复杂的。如果我们移动某两个参数,误差表面的变化非常的复杂,有非常多局部极小值。低维度空间中的局部极小值点,在更高维的空间中,实际是鞍点。同样地,如果在二维的空间中没有路可以走,会不会在更高维的空间中,其实有路可以走?更高的维度难以视化它,但我们在训练一个网络的时候,参数数量动辄达百万千万级,所以误差表面其实有非常高的维度—— 参数的数量代表了误差表面的维度。
上图是训练某不同神经网络的结果,每个点对应一个神经网络。纵轴代表训练网络时,损失收敛到临界点,损失没法下降时的损失。我们常常会遇到两种情况:损失仍然很高,却遇到了临界点而不再下降;或者损失降得很低,才遇到临界点。图中,横轴代表最小值比例,最小值比例定义为
实际上,我们几乎找不到所有特征值都为正的临界点。在图中所示的例子中,最小值比例最大也不过处于 0.5 ~ 0.6 的范围,代表只有约一半的特征值为正,另一半的特征值为负,代表在所有的维度里面有约一半的路可以让损失上升,还有约一半的路可以让损失下降。虽然在这个图上,越靠近右侧代表临界点“看起来越像”局部极小值,但是这些点都不是真正的局部极小值。所以从经验上看起来,局部极小值并没有那么常见。多数的时候,我们训练到一个梯度很小的地方,参数不再更新,往往只是遇到了鞍点。
2.批量和动量
实际上在计算梯度的时候,并不是对所有数据的损失 L 计算梯度,而是把所有的数据分成一个一个的批量,每个批量的大小是 B ,即带有 B 笔数据。每次在更新参数的时候,会去取出 B 笔数据用来计算出损失和梯度更新参数。遍历所有批量的过程称为一个回合。事实上,在把数据分为批量的时候,我们还会进行随机打乱。随机打乱有很多不同的做法,一个常见的做法是在每一个回合开始之前重新划分批量,也就是说,每个回合的批量的数据都不一样。
2.1批量大小对梯度下降算法的影响
假设现在我们有 20 笔训练数据,先看下两个最极端的情况,如下图
图a的情况是没有用批量,批量大小为训练数据的大小,这种使用全批量的数据来更新参数的方法即批量梯度下降法。此时模型必须把 20 笔训练数据都看完,才能够计算损失和梯度,参数才能够更新一次。
图b中,批量大小等于 1,此时使用的方法即随机梯度下降法,也称为增量梯度下降法。批量大小等于 1 意味着只要取出一笔数据即可计算损失、更新一次参数。如果总共有 20 笔数据,那么在每一个回合里面,参数会更新 20 次。用一笔数据算出来的损失相对带有更多噪声,因此其更新的方向如图 所示,是曲曲折折的 。
实际上,批量梯度下降并没有“划分批量”:要把所有的数据都看过一遍,才能够更新一次参数,因此其每次迭代的计算量大。但相比随机梯度下降,批量梯度下降每次更新更稳定、更准确。
随机梯度下降的梯度上引入了随机噪声,因此在非凸优化问题中,其相比批量梯度下降更容易逃离局部最小值。
实际上,考虑并行运算,批量梯度下降花费的时间不一定更长;对于比较大的批量,计算损失和梯度花费的时间不一定比使用小批量的计算时间长 。。使用 Tesla V100 GPU 在 MNIST数据集得到的实验结果如下图,图中横坐标表示批量大小,纵坐标表示给定批量大小的批量,计算梯度并更新参数所耗费的时间。批量大小从 1 到 1000,需要耗费的时间几乎是一样的,因为在实际上 GPU 可以做并行运算,这 1000 笔数据是并行处理的,所以 1000笔数据所花的时间并不是一笔数据的 1000 倍。当然 GPU 并行计算的能力还是存在极限的,当批量大小很大的时候,时间还是会增加的。 当批量大小非常大的时候,GPU 在“跑”完一个批量,计算出梯度所花费的时间还是会随着批量大小的增加而逐渐增长 。当批量大小增加到10000,甚至增加到 60000 的时候,GPU 计算梯度并更新参数所耗费的时间确实随着批量大小的增加而逐渐增长。
但是因为有并行计算的能力,因此实际上当批量大小小的时候,要“跑”完一个回合,花的时间是比大的。假设训练数据只有 60000 笔,批量大小设 1,要 60000 个更新才能“跑”完一个回合;如果批量大小等于 1000,60 个更新才能“跑”完一个回合,计算梯度的时间差不多。但60000 次更新跟 60 次更新比起来,其时间的差距量就非常大了。下图a是用一个批量计算梯度并更新一次参数所需的时间。假设批量大小为 1,“跑”完一个回合,要更新 60000 次参数,其时间是非常大的。但假设批量大小是 1000,更新 60 次参数就会“跑”完一个回合。图b是“跑”完一个完整的回合需要花的时间。如果批量大小为 1000 或 60000,其时间比批量大小设 1 还要短 。
大的批量更新比较稳定,小的批量的梯度的方向是比较有噪声的(noisy)。但实际上有噪声的的梯度反而可以帮助训练,如果拿不同的批量来训练模型来做图像识别问题,实验结果如下图所示,横轴是批量大小,纵轴是正确率。下图a是 MNIST 数据集上的结果,图b是 CIFAR-10 数据集上的结果。批量大小越大,验证集准确率越差。但这不是过拟合,因为批量大小越大,训练准确率也是越低。因为用的是同一个模型,所以这不是模型偏见的问题。 但大的批量大小往往在训练的时候,结果比较差。这个是优化的问题,大的批量大小优化可能会有问题,小的批量大小优化的结果反而是比较好的。
一个可能的解释如下图,批量梯度下降在更新参数的时候,沿着一个损失函数来更新参数,走到一个局部最小值或鞍点显然就停下来了。梯度是零,如果不看海森矩阵,梯度下降就无法再更新参数了 。但小批量梯度下降法每次是挑一个批量计算损失,所以每一次更新参数的时候所使用的损失函数是有差异的。选到第一个批量的时候,用 L1 计算梯度;选到第二个批量的时候,用 L2 计算梯度。假设用 L1 算梯度的时候,梯度是零,就会卡住。但 L2 的函数跟 L1 又不一样,L2 不一定会卡住,可以换下个批量的损失 L2 计算梯度,模型还是可以训练,还是有办法让损失变小,所以这种有噪声的更新方式反而对训练其实是有帮助的。
其实小的批量也对测试有帮助。假设有一些方法(比如调大的批量的学习率)可以把大的批量跟小的批量训练得一样好。实验结果发现小的批量在测试的时候会是比较好的[1]。在论文“On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima”中,作者在不同数据集上训练了六个网络(包括全连接网络、不同的卷积神经网络),在很多不同的情况都观察到一样的结果。在小的批量,一个批量里面有 256 笔样本。在大的批量中,批量大小等于数据集样本数乘 0.1。比如数据集有 60000 笔数据,则一个批量里面有 6000 笔数据。大的批量跟小的批量的训练准确率差不多,但就算是在训练的时候结果差不多,测试的时候,大的批量比小的批量差,代表过拟合。
2.2动量法
动量法是另外一个可以对抗鞍点或局部最小值的方法。如下图所示,假设误差表面就像一个真实的斜坡,参数就像是一个球从斜坡上滚下来。如果使用梯度下降法,球可能会在局部最小值或鞍点停下来。然而,在物理世界中,即使球滚到了鞍点或局部最小值,由于惯性的原因,它仍会继续滚动。如果球的动量足够大,它甚至可以越过小坡继续前进。因此,在物理世界里,一个球从高处滚下来时,并不一定会被鞍点或局部最小值所困住。将这一原理应用于梯度下降法中,动量的概念便应运而生。
一般的梯度下降,如下图所示。初始参数为 ,计算一下梯度,计算完梯度后,往梯度的反方向去更新参数
。有了新的参数
后,再计算一次梯度,再往梯度的反方向,再更新一次参数,到了新的位置以后再计算一次梯度,再往梯度的反方向去更新参数。
引入动量后,每次在移动参数的时候,不是只往梯度的反方向来移动参数,而是根据梯度的反方向加上前一步移动的方向决定移动方向。下图中红色虚线方向是梯度的反方向,蓝色虚线方向是前一次更新的方向,蓝色实线的方向是下一步要移动的方向。把前一步指示的方向跟梯度指示的方向相加就是下一步的移动方向。
3.自适应学习率
临界点其实不一定是在训练一个网络的时候会遇到的最大的障碍。下图1中的横坐标代表参数更新的次数,竖坐标表示损失。一般在训练一个网络的时候,损失原来很大,随着参数不断的更新,损失会越来越小,最后就卡住了,损失不再下降。当我们走到临界点的时候,意味着梯度非常小,但损失不再下降的时候,梯度并没有真的变得很小,下图2给出了示例。图2中横轴是迭代次数,竖轴是梯度的范数,即梯度这个向量的长度。随着迭代次数增多,虽然损失不再下降,但是梯度的范数并没有真的变得很小。
上图2是误差表面,梯度在山谷的两个谷壁间,不断地来回“震荡”,这个时候损失不会再下降,它不是真的卡到了临界点,卡到了鞍点或局部最小值。但它的梯度仍然很大,只是损失不一定再减小了。所以训练一个网络,训练到后来发现损失不再下降的时候,有时候不是卡在局部最小值或鞍点,只是单纯的损失无法再下降。
我们现在训练一个网络,训练到现在参数在临界点附近,再根据特征值的正负号判断该临界点是鞍点还是局部最小值。实际上在训练的时候,要走到鞍点或局部最小值,是一件困难的事情。一般的梯度下降,其实是做不到的。用一般的梯度下降训练,往往会在梯度还很大的时候,损失就已经降了下去,这个是需要特别方法训练的。要走到一个临界点其实是比较困难的,多数时候训练在还没有走到临界点的时候就已经停止了。
最原始的梯度下降连简单的误差表面都做不好,因此需要更好的梯度下降的版本。在梯度下降里面,所有的参数都是设同样的学习率,这显然是不够的,应该要为每一个参数定制化学习率,即引入自适应学习率的方法,给每一个参数不同的学习率。如下图所示,如果在某一个方向上,梯度的值很小,非常平坦,我们会希望学习率调大一点;如果在某一个方向上非常陡峭,坡度很大,我们会希望学习率可以设得小一点。