深度学习基础
优化神经网络过程中,首先,要理解为什么优化会失败,收敛在局部极限值与鞍点会导致优化失败。其次,可以对学习率进行调整,使用自适应学习率和学习率调度。最后,批量归一化可以改变误差表面。
目录
1. 局部极小值与鞍点
我们在做优化的时候经常会发现,随着参数不断更新,训练的损失不会再下降, 但是我们对这个损失仍然不满意。
1.1 临界点及其种类
图 1 中的两条曲线对应两个神经网络训练的过程。当参数对损失微分为零的时候,梯度下降就不能再更新参数了,训练就停下来了,损失不再下降了。
图1、梯度下降失效的情况
损失不是只在局部极小值的梯度是零,还有其他可能会让梯度是零的点,比如鞍点(saddle point)。鞍点其实就是梯度是零且区别于局部极小值和局部极大值(localmaximum)的点。图 1.2b 红色的点在 y 轴方向是比较高的,在 x 轴方向是比较低的,这就是一个鞍点。鞍点的叫法是因为其形状像马鞍。鞍点的梯度为零,但它不是局部极小值。我们把梯度为零的点统称为临界点(critical point)。损失没有办法再下降,也许是因为收敛在了临界点,但不一定收敛在局部极小值,因为鞍点也是梯度为零的点。但是如果一个点的梯度真的很接近零,我们走到临界点的时候,这个临界点到底是局部极小值还是鞍点,是一个值得去探讨的问题。
图 1.2 局部极小值与鞍点
1.2 判断临界值种类的方法
给定某一组参数,比如 θ′,在 θ′ 附近的损失函数是有办法写出来的——虽然 L(θ) 完整的样子写不出来。θ′ 附近的 L(θ) 可近似为:上式是泰勒级数近似(Tayler series appoximation)。其中,第二项中,g 代表梯度,它是一个向量,可以弥补 L(θ′) 跟 L(θ) 之间的差距。有时候梯度 g 会写成 ∇L(θ′)。是向量 g 的第 i 个元素,就是 L 关于 θ 的第 i 个元素的微分,即
第三项跟海森矩阵(Hessian matrix)H 有关。H 里面放的是 L 的二次微分,它第 i 行,第 j 列的值 就是把 θ 的第 i 个元素对 作微分,再把 θ 的第 j 个元素对 作微分后的结果,即
在临界点,梯度 g 为零,因此 为零。所以在临界点的附近,损失函数可被近似为
我们可以根据上式子第二项来判断在 θ′ 附近的误差表面(error surface)的‘地貌’。判断 L(θ′) 是局部极小值、局部极大值,还是鞍点。为了符号简洁,我们用向量 v 来表示 θ − θ′,可改写为 ,有如下三种情况。
(1)如果对所有 v, > 0. 这意味着对任意 θ,L(θ) > L(θ′). 只要 θ 在 θ′ 附近,L(θ) 都大于 L(θ′). 这代表 L(θ′) 是附近的一个最低点,所以它是局部极小值。
(2)如果对所有 v, < 0. 这意味着对任意 θ,L(θ) < L(θ′),θ′ 是附近最高的一个点,L(θ′) 是局部极大值。
(3)如果对于 v,有时候大于零,有时候小于零。这意味着在 θ′ 附近,有时候L(θ) > L(θ′),有时候 L(θ) < L(θ′). 因此在 θ′ 附近,L(θ′) 既不是局部极大值,也不是局部极小值,而是鞍点。
对最终结果进行简化:算出一个海森矩阵后,看 H的特征值。若 H 的所有特征值都是正的,H 为正定矩阵,则> 0,临界点是局部极小值。若 H的所有特征值都是负的,H为负定矩阵,则 < 0,临界点是局部极大值。若 H的特征值有正有负,临界点是鞍点。
举个例子,我们有一个简单的神经网络,它只有两个神经元,而且这个神经元还没有激活函数和偏置。输入 x,x 乘上 以后输出,然后再乘上 ,接着再输出,最终得到的数据就是 y。
我们还有一个简单的训练数据集,这个数据集只有一组数据 (1,1),也就是 x = 1 的标签是 1. 所以输入 1 进去,我们希望最终的输出跟 1 越接近越好,
图 1.3 简单的神经网络
可以直接画出这个神经网络的误差表面,如图 1.4 所示,可以取 [−2,2] 之间的 跟 的数值,算出这个范围内 , 数值所带来的损失,四个角落的损失是高的。我们用黑色的点来表示临界点,原点 (0,0) 是临界点,另外两排点是临界点。
把损失的函数写出来。对于图 1.3所示的神经网络,损失函数 L 是正确答案 y 减掉模型的输出 后取平方误差(squareerror),这里只有一组数据,因此不会对所有的训练数据进行加和。令 x = 1, y = 1,损失函数为
可以求出损失函数的梯度:
什么时候梯度会为零(也就是到一个临界点)呢?比如,在原点时,w1= 0, w2 = 0,此时的梯度为零,原点就是一个临界点,但通过海森矩阵才能判断它是哪种临界点。
海森矩阵 H 收集了 L 的二次微分:
对于原点,只要把 = 0, = 0 代进去,有海森矩阵
通过海森矩阵来判断原点是局部极小值还是鞍点,要看它的特征值,这个矩阵有两个特征值:2 和 −2,特征值有正有负,因此原点是鞍点。如果我们当前处于鞍点,就不用那么害怕了。H 不只可以帮助我们判断是不是在一个鞍点,还指出了参数可以更新的方向。之前我们参数更新的时候,都是看梯度 g,但是我们走到某个地方以后发现 g 变成 0 了,就不能再看 g 了,g 不见了。但如果临界点是一个鞍点,还可以再看 H,怎么再看 H 呢,H 怎么告诉我们怎么更新参数呢?设 λ 为 H 的一个特征值,为其对应的特征向量。对于我们的优化问题,可令 ,则
若 < 0,则< 0。所以 < 0。此时,L(θ) < L(θ′),且
沿着 u 的方向更新 θ,损失就会变小。因为根据上面2个公式,只要 ,沿着特征向量 的方向去更新参数,损失就会变小,所以虽然临界点的梯度为零,如果我们是在一个鞍点,只要找出负的特征值,再找出这个特征值对应的特征向量。将其与 θ′ 相加,就可以找到一个损失更低的点。
图1.5训练不同神经网络的结果
图1.5是训练某不同神经网络的结果,每个点对应一个神经网络。纵轴代表训练网络时,损失收敛到临界点,损失没法下降时的损失。我们常常会遇到两种情况:损失仍然很高,却遇到了临界点而不再下降;或者损失降得很低,才遇到临界点。图 1.5 中,横轴代表最小值比例(minimum ratio),
实际上,我们几乎找不到所有特征值都为正的临界点。在图 1.5 所示的例子中,最小值比例最大也不过处于 0.5 ~ 0.6 的范围,代表只有约一半的特征值为正,另一半的特征值为负,代表在所有的维度里面有约一半的路可以让损失上升,还有约一半的路可以让损失下降。虽然在这个图上,越靠近右侧代表临界点“看起来越像”局部极小值,但是这些点都不是真正的局部极小值。所以从经验上看起来,局部极小值并没有那么常见。多数的时候,我们训练到一个梯度很小的地方,参数不再更新,往往只是遇到了鞍点。
2 批量和动量
如图1.6 所示。每个批量的大小是 B ,即带有 B 笔数据。每次在更新参数的时候,会去取出 B 笔数据用来计算出损失和梯度更新参数。遍历所有批量的过程称为一个回合(epoch)。事实上,在把数据分为批量的时候,我们还会进行随机打乱(shuffle)。随机打乱有很多不同的做法,一个常见的做法是在每一个回合开始之前重新划分批量,也就是说,每个回合的批量的数据都不一样。
图 1.6 使用批量优化
2.1 批量大小对梯度下降法的影响
假设现在我们有 20 笔训练数据,先看下两个最极端的情况,如图 1.7所示。
图 1.7 批量梯度下降法与随机梯度下降法
图 1.7 (a)的情况是没有用批量,批量大小为训练数据的大小,这种使用全批量(fullbatch)的数据来更新参数的方法即批量梯度下降法BGD。此时模型必须把 20 笔训练数据都看完,才能够计算损失和梯度,参数才能够更新一次。图 1.7 (b)中,批量大小等于 1,此时使用的方法即随机梯度下降法SGD,也称为增量梯度下降法。批量大小等于 1 意味着只要取出一笔数据即可计算损失、更新一次参数。如果总共有 20 笔数据,那么在每一个回合里面,参数会更新 20 次。用一笔数据算出来的损失相对带有更多噪声。实际上,批量梯度下降并没有“划分批量”:要把所有的数据都看过一遍,才能够更新一次参数,因此其每次迭代的计算量大。但相比随机梯度下降,批量梯度下降每次更新更稳定、更准确。
批量梯度下降花费的时间不一定更长;对于比较大的批量,计算损失和梯度花费的时间不一定比使用小批量的计算时间长 图1.8中横坐标表示批量大小,纵坐标表示给定批量大小的批量,计算梯度并更新参数所耗费的时间。批量大小从 1 到 1000,需要耗费几乎是一样的,因为在实际上 GPU 可以做并行运算,这 1000 笔数据是并行处理的,所以 1000笔数据所花的时间并不是一笔数据的 1000 倍。当然 GPU 并行计算的能力还是存在极限的, 当批量大小非常大的时候,GPU 在“跑”完一个批量,计算出梯度所花费的时间还是会随着批量大小的增加而逐渐增长 。当批量大小增加到10000,甚至增加到 60000 的时候,GPU 计算梯度并更新参数所耗费的时间确实随着批量大小的增加而逐渐增长。
图 1.9 不同的批量来训练模型来做图像识别问题的实验结果
大的批量更新比较稳定,小的批量的梯度的方向是比较有噪声的(noisy)。但实际上有噪声的的梯度反而可以帮助训练,如果拿不同的批量来训练模型来做图像识别问题,实验结果如图 1.9 所示,横轴是批量大小,纵轴是正确率。图 1.9(a) 是 MNIST 数据集上的结果,图 1.9(b) 是 CIFAR-10 数据集上的结果。批量大小越大,验证集准确率越差。但这不是过拟合,因为批量大小越大,训练准确率也是越低。因为用的是同一个模型,所以这不是模型偏见的问题。 但大的批量大小往往在训练的时候,结果比较差。这个是优化的问题,大的批量大小优化可能会有问题,小的批量大小优化的结果反而是比较好的。
图 1.10小批量梯度下降更好的原因
一个可能的解释如图 1.10 所示,批量梯度下降在更新参数的时候,沿着一个损失函数来更新参数,走到一个局部最小值或鞍点显然就停下来了。梯度是零,如果不看海森矩阵,梯度无法更新参数了,但小批量梯度下降法每次是挑一个批量计算损失,所以每一次更新参数的时候所使用的损失函数是有差异的。选到第一个批量的时候,用 L1 计算梯度;选到第二个批量的时候,用 L2 计算梯度。假设用 L1 算梯度的时候,梯度是零,就会卡住。但 L2 的函数跟 L1 又不一样,L2 不一定会卡住,可以换下个批量的损失 L2 计算梯度,模型还是可以训练,还是有办法让损失变小,所以这种有噪声的更新方式反而对训练其实是有帮助的。
图 1.11 小批量优化容易跳出局部最小值的原因
其实小的批量也对测试有帮助。假设有一些方法(比如调大的批量的学习率)可以把大的批量跟小的批量训练得一样好。实验结果发现小的批量在测试的时候会是比较好的。在论文“On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima”中给出一个解释,如图 1.11 所示,训练损失上面有多个局部最小值,这些局部最小值的损失都很低,其损失可能都趋近于 0。但是局部最小值有好最小值跟坏最小值之分,如果局部最小值在一个“峡谷”里面,它是坏的最小值。训练的损失跟测试的损失函数是不一样的,这有两种可能。一种可能是本来训练跟测试的分布就不一样;另一种可能是因为训练跟测试都是从采样的数据算出来的,训练跟测试采样到的数据可能不一样,所以它们计算出的损失是有一点差距。 对在一个“盆地”里面的最小值,其在训练跟测试上面的结果不会差太多,但对在右边在“峡谷”里面的最小值,一差就可以天差地远 。虽然它在训练集上的损失很低,但训练跟测试之间的损失函数不一样,因此测试时,损失函数一变,计算出的损失就变得很大。.
大的批量跟小的批量的对比结果如表1.1 所示。在有并行计算的情况下,小的批量跟大的批量运算的时间并没有太大的差距。除非大的批量非常大,才会显示出差距。但是一个回合需要的时间,小的批量比较长,大的批量反而是比较快的,所以从一个回合需要的时间来看,大的批量是较有优势的。 而小的批量更新的方向比较有噪声的,大的批量更新的方向比较稳定。但是有噪声的更新方向反而在优化的时候有优势,而且在测试的时候也会有优势。所以大的批量跟小的批量各有优缺点,批量大小是需要去调整的超参数。
2.2 动量法
动量法(momentum method)是另外一个可以对抗鞍点或局部最小值的方法。如图 1.12所示,假设误差表面就是真正的斜坡,参数是一个球,把球从斜坡上滚下来,如果使用梯度下降,球走到局部最小值或鞍点就停住了。 但是在物理的世界里,一个球如果从高处滚下来,就算滚到鞍点或鞍点,因为惯性的关系它还是会继续往前走。如果球的动量足够大,其甚至翻过小坡继续往前走。 因此在物理的世界里面,一个球从高处滚下来的时候,它并不一定会被鞍点或局部最小值卡住,如果将其应用到梯度下降中,这就是动量。
图 1.12 物理世界中的惯性
一般的梯度下降(vanilla gradient descent)如图 1.13 所示。初始参数为 ,计算一下梯度,计算完梯度后,往梯度的反方向去更新参数 。有了新的参数 后,再计算一次梯度,再往梯度的反方向,再更新一次参数,到了新的位置以后再计算一次梯度,再往梯度的反方向去更新参数。
图 1.13 一般梯度下降
引入动量后,每次在移动参数的时候,不是只往梯度的反方向来移动参数,而是根据梯度的反方向加上前一步移动的方向决定移动方向。 图 1.14 中红色虚线方向是梯度的反方向,蓝色虚线方向是前一次更新的方向,蓝色实线的方向是下一步要移动的方向。把前一步指示的方向跟梯度指示的方向相加就是下一步的移动方向。
图 1.14 动量法
动量的简单例子如图 1.15 所示。红色表示负梯度方向,蓝色虚线表示前一步的方向,蓝色实线表示真实的移动量。一开始没有前一次更新的方向,完全按照梯度给指示往右移动参数。负梯度方向跟前一步移动的方向加起来,得到往右走的方向。一般梯度下降走到一个局部最小值或鞍点时,就被困住了。但有动量还是有办法继续走下去,因为动量不是只看梯度,还看前一步的方向。
图 1.15 动量带来的好处