3.1 局部极小值与鞍点
1、临界点及其种类
在我们的训练中是会存在梯度下降失效的问题的
提到梯度为零的时候,大家最先想到的可能就是局部极小值(local minimum) ,但其实损失不是只在局部极小值的梯度是零,还有其他可能会让梯度是零的点,比如鞍点(saddle point)。鞍点其实就是梯度是零且区别于局部极小值和局部极大值(localmaximum)的点,我们将梯度为零的点统称为临界点(critical point)
2、判断临界点种类的方法
判断一个临界点到底是局部极小值还是鞍点需要知道损失函数的形状。虽然无法完整知道整个损失函数的样子,但是如果给定某一组参数,比如,在
附近的损失函数是有办法写出来的:
,我们利用泰勒级数近似(Tayler series appoximation)得到这个近似公式。
- 第一项
告诉我们,当
跟
很近的时候,
应该跟
比较接近
- 第二项
中,
代表梯度,它是一个向量,可以弥补
跟
之间的差距。有时候梯度
会写成
。
是向量
的第 i 个元素,就是
关于
的第 i 个元素的微分,即
- 第三项
跟海森矩阵(Hessian matrix)
有关。
里面放的是
的二次微分,它第 i 行,第 j 列的值
就是把
的第 i 个元素对
作微分,再把
的第 j 个元素对
作微分后的结果,即
在临界点,梯度为零,因此
为零。所以在临界点的附近,损失函数可被近似为
,我们可以根据这个式子的第二项来判断在
附近的误差表面(error surface)到底是什么样子的。为了符号简洁,我们用向量
来表示
,
可改写为
,有如下三种情况:
- 对所有
,
。这意味着对任意
,
。这代表 L(θ′) 是附近的一个最低点,所以它是局部极小值
- 对所有
,
。这意味着对任意
,
。这代表 L(θ′) 是附近的一个最高点,所以它是局部极大值
- 对于
,
有时候大于零,有时候小于零。这意味着在
附近,有时候
,有时候
,所以它既不是局部极大值,也不是局部极小值,而是鞍点
3、逃离鞍点的方法
最小值比例(minimum ratio)定义为: 最小值比例=正特征值数量/总特征值数量。从经验上来看,遇到局部极小值的可能性极小,多数的时候,我们训练到一个梯度很小的地方,参数不再更新,往往只是遇到了鞍点。
3.2 批量和动量
事实上,在把数据分为批量的时候,我们还会进行随机打乱(shuffle)。随机打乱有很多不同的做法,一个常见的做法是在每一个回合开始之前重新划分批量,也就是说,每个回合的批量的数据都不一样。
1、批量大小对梯度下降法的影响
假设我们现在有20笔数据,下面出现两种情况:
- 批量大小为训练数据的大小。这种使用全批量(fullbatch)的数据来更新参数的方法即批量梯度下降法(Batch Gradient Descent,BGD),此时模型必须把 20 笔训练数据都看完,才能够计算损失和梯度,参数才能够更新一次。
- 批量大小等于 1。此时使用的方法即随机梯度下降法(Stochastic Gradient Descent,SGD),也称为增量梯度下降法。批量大小等于 1 意味着只要取出一笔数据即可计算损失、更新一次参数。如果总共有 20 笔数据,那么在每一个回合里面,参数会更新 20 次。用一笔数据算出来的损失相对带有更多噪声,因此其更新的方向是曲折的
实际上,考虑并行运算,批量梯度下降花费的时间不一定更长;对于比较大的批量,计算损失和梯度花费的时间不一定比使用小批量的计算时间长。
大的批量更新比较稳定,小的批量的梯度的方向是比较有噪声的(noisy)。但实际上有噪声的的梯度反而可以帮助训练,如果拿不同的批量来训练模型来做图像识别问题,得到的结果是:批量大小越大,验证集准确率越差。这个是优化的问题,大的批量大小优化可能会有问题,小的批量大小优化的结果反而是比较好的。
2、动量法
动量法(momentum method)是另外一个可以对抗鞍点或局部最小值的方法。
一般的梯度下降(vanilla gradient descent)初始参数为,计算一下梯度,计算完梯度后,往梯度的反方向去更新参数
。有了新的参数
后,再计算一次梯度,再往梯度的反方向更新一次参数,以此类推。
引入动量后,每次在移动参数的时候,不是只往梯度的反方向来移动参数,而是根据梯度的反方向加上前一步移动的方向决定移动方向。过程如下:
3.3 自适应学习率
训练一个网络,训练到后来发现损失不再下降的时候,有时候不是卡在局部最小值或鞍点,只是单纯的损失无法再下降。最原始的梯度下降连简单的误差表面都做不好,因此需要更好的梯度下降的版本。在梯度下降里面,所有的参数都是设同样的学习率,这显然是不够的,应该要为每一个参数定制化学习率,即引入自适应学习率(adaptive learning rate)的方法,给每一个参数不同的学习率。如果在某一个方向上,梯度的值很小,非常平坦,我们会希望学习率调大一点;如果在某一个方向上非常陡峭,坡度很大,我们会希望学习率可以设得小一点。
1、AdaGrad
AdaGrad(Adaptive Gradient)是典型的自适应学习率方法,其能够根据梯度大小自动调整学习率。AdaGrad 可以做到梯度比较大的时候,学习率就减小,梯度比较小的时候,学习率就放大。
梯度下降更新某个参数的过程为:
在第 t 个迭代的值减掉在第 t 个迭代参数 i 算出来的梯度:
,
代表在第 t 个迭代,即
时, 参数
对损失
的微分,学习率是固定的。
现在要有一个随着参数定制化的学习率,即把原来学习率变成
:
,其中
的上标为 i,这代表参数
与 i 相关,不同的参数的
不同。
的下标为 t,这代表参数
与迭代相关,不同的迭代也会有不同的
。学习率从
改成
的时候,学习率就变得参数相关(parameter dependent)
参数相关的一个常见的类型是算梯度的均方根(root mean square)
- 第一次更新参数过程为:
,其中
是初始化参数。而
的计算过程为:
,其中
是梯度。将
的值代入更新的公式可知
的值是 +1 或 −1
- 第二次更新参数过程为:
,其中
是过去所有计算出来的梯度的平方的平均再开根号,即均方根
- 以此类推,第 t + 1 次更新参数的时候,有:
,
因此有了这一项以后,就可以随着梯度的不同,每一个参数的梯度的不同,来自动调整学习率的大小。
2、RMSProp
同一个参数需要的学习率,也会随着时间而改变,于是就有了一个新的方法———RMSprop(Root Mean Squared propagation)
- 第一次更新过程为:
,
- 第二次更新过程为:
,
- 以此类推,第 t + 1 次更新参数的时候,有:
,
RMSProp 通过可以决定,
相较于之前存在
里面的
,
, · · · · · · ,
的重要性有多大。如果使用 RMSprop,就可以动态调整
这一项
3、Adam
最常用的优化的策略或者优化器(optimizer)是Adam(Adaptive moment estimation)。Adam 可以看作 RMSprop 加上动量,其使用动量作为参数更新方向,并且能够自适应调整学习率。PyTorch 里面已经帮我们写好了 Adam 优化器,这个优化器里面有一些超参数需要人为决定,但是往往用 PyTorch 预设的参数就好了,并不需要我们进行改动。
3.4 学习率调度
之前的学习率调整方法中是一个固定的值,而在学习率调度(learning rate scheduling)中
跟时间有关。学习率调度中最常见的策略是学习率衰减(learning rate decay),也称为学习率退火(learning rateannealing),随着参数的不断更新,让
越来越小
除了学习率下降以外,还有另外一个经典的学习率调度的方式———预热。预热的方法是让学习率先变大后变小,至于变到多大、变大的速度、变小的速度是超参数。残差网络,BERT 和 Transformer 的训练都使用了预热。
3.5 优化总结
所以我们从最原始的梯度下降,进化到这一个版本:,其中
是动量
3.6 分类
1、分类与回归的关系
回归是输入一个向量,输出
,我们希望
跟某一个标签
越接近越好,
是要学习的目标。而分类可当作回归来看,输入
后,输出仍然是一个标量
,它跟正确答案的那个类越接近越好。实际上,在做分类的问题的时候,比较常见的做法是用独热向量表示类,这样类两两之间的距离都是一样的。
如果是有多个元素的向量,网络也要产生多个输出,每个输出都是跟目标越接近越好:
2、带有 softmax 的分类
按照上述的设定,分类实际过程是:输入,乘上
,加上
,通过激活函数
,乘上
,再加上
得到向量
。但实际做分类的时候,往往会把
通过 softmax 函数得到
,才去计算
跟
之间的距离。
softmax 的计算:
,其中
,
3、分类损失
当我们把输入到一个网络里面产生
后,通过softmax得到
,再去计算
跟
之间的距离
,有两种计算方法,一种是均方误差:
,一种是交叉熵:
,当
跟
相同时,可以最小化交叉熵的值,其实就是最大化似然(maximize likelihood),此时均方误差也是最小的。
从优化的角度来说,相较于均方误差,交叉熵是被更常用在分类上 。
3.7 批量归一化
如果我们可以给不同的维度,同样的数值范围的话,那我们可能就可以制造比较好的误差表面,让训练变得比较容易一点其实有很多不同的方法,这些不同的方法往往就合起来统称为特征归一化(feature normalization)
Z 值归一化(Z-score normalization),也称为标准化(standardization)。假设到
是我们所有的训练数据的特征向量,把所有训练数据的特征向量,统统都集合起来。向量
里面
代表
的第一个元素,
代表
的第一个元素,以此类推。我们把不同笔数据即不同特征向量,同一个维度里面的数值取出来,对于每个维度 i,计算其平均值(mean)
和标准差(standard deviation)
。接下来就可以进行归一化:
归一化有个好处,做完归一化以后,这个维度上面的数值就会平均是 0,其方差是 1,所以这一排数值的分布就都会在 0 上下。对每一个维度都做一样的归一化,所有特征不同维度的数值都在 0 上下,可能就可以制造一个比较好的误差表面。所以特征归一化方式往往对训练有帮助,它可以使得在做梯度下降时,损失收敛更快一点,训练更顺利一点。
1、考虑深度学习
代表归一化的特征,把它丢到深度网络里面,去做接下来的计算和训练。
如何对
做特征归一化?
可以看成另外一种特征。
首先计算下,
,
的平均值:
,接下来计算标准差:
,在这个式子里,平方就是指对每一个元素都去做平方,开根号指的是对向量里面的每一个元素开根号。最后,根据计算出的
和
进行归一化:
,其中,除号代表逐元素的除,即分子分母两个向量对应元素相除。
接下来可以通过激活函数得到其他向量,但是训练数据非常多,现在一个数据集可能有上百万笔数据,GPU 的显存无法把它整个数据集的数据都加载进去。因此,在实现的时候,我们不会让这一个网络考虑整个训练数据里面的所有样本,而是只会考虑一个批量里面的样本。批量归一化适用于批量大小比较大的时候,批量大小如果比较大,也许这个批量大小里面的数据就足以表示整个数据集的分布。这个时候就不需要对整个数据集做特征归一化,而改成只在一个批量上做特征归一化作为近似。
在做批量归一化的时候往往还会做如下操作:,其中,
代表逐元素的相乘,
和
可以想成是网络的参数,需要另外再被学习出来。
2、测试时的批量归一化
批量归一化在测试也就是推断(inference)的时候,并不需要做什么特别的处理,PyTorch 已经处理好了。在训练的时候,如果有在做批量归一化,每一个批量计算出来的,
,都会拿出来算移动平均(moving average)。假设现在有各个批量计算出来的
,
,
, · · · · · · ,
,则可以计算移动平均:
,其中,
是
的个平均值,
是因子,这也是一个常数,这也是一个超参数,在 PyTorch 里面,
设 0.1
3、内部协变量偏移
原始的批量归一化论文里面提出内部协变量偏移(internal covariate shift)概念
其实批量归一化不是唯一的归一化方法,还有很多归一化方法,比如批量重归一化(batchrenormalization)、层归一化(layer normalization)、实例归一化(instance normalization)、组归一化(group normalization)、权重归一化(weight normalization)和谱归一化(spectrum normalization)
hahaha都看到这里了,要是觉得有用的话就辛苦动动小手点个赞吧!