[机器学习] 梯度下降优化算法
前言
为什么需要更好的优化算法?
机器学习的应用是一个高度依赖经验的过程和伴随着大量迭代的过程,需要训练很多模型才能找到合适的那一个。因此优化算法能够帮助我们快速的训练模型。
在训练神经网络模型中,通常需要定义一个损失函数来衡量我们模型的预测结果和标签之间的差异。
θ
i
←
θ
i
−
η
▽
θ
i
L
(
θ
)
\theta _{i}\gets \theta _{i} - \eta \bigtriangledown _{\theta _{i} }L\left ( \theta \right )
θi←θi−η▽θiL(θ)
上式是带有损失函数 L 的参数 θ 的梯度下降公式。
在模型训练的过程中,我们调整和更新模型的参数θ以最小化该损失函数,使得我们的预测尽可能正确。这里的优化算法就是要告诉我们如何调整和更新模型的参数,更新多少以及合适更新。
首先计算损失函数 L 相对于我们想要改进的权重(或参数 θ)的梯度,然后在梯度的负方向上更新权重/参数。通过周期性地对想要改进的权重应用梯度下降算法,最终使得损失函数最小化并获得神经网络模型做出更好预测的最佳权重。
然而在实际的训练模型过程中,梯度下降这种技术会遇到一些问题,这些问题会减慢学习过程,甚至会阻止算法找到最佳权重/参数。这些问题一方面是损失函数的鞍点(如下右图)和局部最小值(如下左图),此时损失函数变得平坦且梯度变为0,接近0的梯度不会改善权重参数并阻止整个学习过程。
另一方面,即使我们有不接近0的梯度,但来自训练集的不同数据样本计算的梯度值也有可能在值和方向上有所不同,这个不同会导致向最佳权重的曲折运动,并且使得学习变得更慢。
常见的梯度下降优化算法
Exhaustive search
穷举搜索或蛮力搜索(Exhaustive search)是通过检查每个候选者是否匹配来寻找最佳参数的过程。现实生活中当忘记行李箱密码,你会穷举搜索所有的可能性,但在机器学习中,如果采取穷举搜索所有的可能性,因为可能性的数量通常很大,导致效率不高。
穷举搜索方法很简单。例如,如果使用 k-means 算法,你将手动搜索正确数量的集群,但是如果必须考虑成百上千种可能性时,这使得穷举搜索在大多数现实生活中效率低下。
summary:
【优点】方法简单
【缺点】效率低
Gradient Descent
梯度下降(gradient descent)是一种在训练机器学习模型时最常使用的优化算法,它基于凸函数并迭代调整其参数以将损失函数最小化到其局部最小值。
如下图所示,首先定义一些随机的θ值,然后梯度下降迭代更新参数θ
,直到收敛到出一个最小值。
【梯度下降算法易陷入局部最优】当损失函数有几个局部最小值时,梯度下降算法找到第一个最小值时将停止搜索,此时的最小值有可能是局部最小而不是全局最小。
如下图所示,当随机初始化参数在starting model 1时,朝着梯度下降的方向进行更新参数,最终在local minimum处停止更新,但损失函数的最小值在true model处,此时算法只找到局部最小而非全局最小;当随机初始化参数在starting model 2时,最终会在global minimum处停止更新,此时算法找到了全局最小。
【梯度下降算法中学习率的重要性】梯度下降到局部最小值方向的步长有多大取决于学习率,它计算出我们朝着最佳参数移动的速度。
为了使梯度下降达到局部最小值,我们必须将学习率设置为适当的值,既不太低也不太高。如果它采取的步数太大,它可能无法达到局部最小值,因为它在梯度下降的凸函数之间来回反弹(见下图左图)。如果我们将学习率设置为非常小的值,梯度下降最终将达到局部最小值,但这可能需要一段时间(见右图)。因此,适当的学习率是很重要的,它会使得梯度下降成为优化模型的一种计算效率高且快速的方法。
梯度下降算法实现:
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params) #params_grad为损失函数梯度向量
params = params - learning_rate * params_grad
summary:
【优点】计算方便;原理易理解
【缺点】
易陷入局部最小值;
需要大内存来计算整个数据集的梯度;
数据集太大,收敛到最小值需要的时间久
Stochastic Gradient Descent (SGD)
随机梯度下降(SGD)是梯度下降算法的扩展,它克服了梯度下降算法的一些缺点。从上一小节中可以看出,梯度下降算法有一个缺点,它需要大量内存来一次加载整个数据集来计算损失函数的导数,而在SGD算法中,batch size为1,即导数只需要通过一个样本来计算。
随机梯度下降 VS 梯度下降:
下图展示的是随机梯度下降(如下左图)和梯度下降(如下右图)的示意图。
对于随机梯度下降算法,每次迭代只对一个样本进行梯度下降,大部分时候会朝着全局最小值靠近,如果这个样本恰好给你指的方向不对就会远离最小值,因此随机梯度下降是有很多噪声的。总体来看,随机梯度下降最终会靠近最小值,不过有时候方向也会错误,因此随机梯度下降永远不会收敛,而是会一直在最小值附近波动,并不会达到并停留在最小值处。
对于梯度下降算法,每次迭代是对整个训练集进行梯度下降,因此相对噪声低一些,幅度要大一些。
随机梯度下降算法实现:
for i in range(nb_epochs):
np.random.shuffle(data)
for example in data:
params_grad = evaluate_gradient(loss_function, example, params)
params = params - learning_rate * params_grad
summary:
【优点】与梯度下降算法相比,内存要求更少,因为一次只对一个样本进行迭代
【缺点】
与梯度下降算法相比,完成一个epoch所需的时间更长;
需要很长的时间才能收敛;
可能停留在局部最小值。
SGD with momentum
理想状态下,损失函数如下图所示,这种情况下能找到全局最小值。
但是在实际中,损失函数表面更复杂(如下图所示),可能包含几个局部最小值,在这种情况下,很容易陷入局部最小值,此时算法可能会认为达到了全局最小值,从而得到次优结果。
带有动量的随机梯度下降算法(SGD with momentum)为了避免这种问题,在目标函数中使用了动量项,它是介于0和1之间的值,通过尝试从局部最小值跳跃来增加向局部最小值迈出的步长。比如一个滚下山坡并随着时间的增加,速度一直增加的小球,如果小球在途中遇到没有向下坡度的平坦地面或者一个洞,那么速度v会使小球具有足够的动力滚过这些障碍。在这种情况下,平坦的地面和洞分别代表损失函数的鞍点和局部最小值。
因此,在某一点上,对于随机梯度下降算法,它是朝着梯度方向移动,而对于带有动量的随机梯度下降算法,它是朝着速度方向移动。
带有动量的随机梯度下降算法是利用指数加权平均值来更新模型中的参数,指数加权平均值是在n个连续样本上计算的平均值,在数学上表示为:
A
i
=
β
A
i
−
1
+
(
1
−
β
)
X
i
A_{i}=\beta A_{i-1}+\left ( 1-\beta \right ) X_{i}
Ai=βAi−1+(1−β)Xi
以上,A[i] 表示样本 X[i] 在第 i 个样本处的加权平均值,β 控制加权平均值的样本值 n。例如,如果 β=0.9,则考虑 10 个连续样本值来计算加权平均值;如果 β=0.99,则考虑 100 个连续样本值来计算加权平均值。一般来说,n的值可以用下面的公式来近似:
n
=
1
1
−
β
n=\frac{1}{1-\beta }
n=1−β1
下图展示的是加权平均值的工作原理。随着 β 值的增加,n 增加,曲线更加平坦,但是曲线进一步向右移动。然而,当 β 减小时n 减小,所得到的曲线噪声越大,更有可能出现异常值,但是逼近真实场景。因此,必须找出合适的 β 值以获得合理的加权平均值。可以观察到,β=0.9 在大多数情况下效果很好。
在训练神经网络中,如下图所示,传统的梯度下降算法遵循着蓝色的路径,而带有动量的梯度下降算法遵循着绿色的路径到达最小(红色)点。
与 Momentum 相比,梯度下降所遵循的路径需要的步骤太多(这是因为梯度下降在 y 轴上振荡太多,而在 x 轴上移动得非常少),而且这种上下振荡减慢了梯度下降的速度,因此无法使用更大的学习率(因为结果可能会偏离函数的范围),为了避免振荡太大,要用一个较小的学习率。一个正确的解决方案是通过抑制 y 轴上的运动来减少振荡,而在x轴上希望快速移动到最小值,这就是加权平均值发挥作用的地方。
如果我们观察蓝色路径,我们会看到 y 轴上的运动是一系列正负变化。我们将加权平均值应用于几乎为零的运动,不仅适用于减少y轴上的运动,同样也适用于x轴,因此减少了y轴路径中的振荡且加快了x轴上的运动,最终神经网络在更短的时间内达到最小值,同时训练迭代次数更少。
summary:
【优点】
具有随机梯度下降算法所有的优点;
收敛速度比梯度下降算法快。
【缺点】需要为每次更新再计算一次变量。
RMSProp
RMS Prop( Root-Mean-Square Propagation)是均方根传播,与动量类似,它是一种抑制 y 轴运动的技术。为了更好地理解,我们将 Y 轴表示为偏差 b,将 X 轴表示为权重 W。
一般来说,当我们将一个大数除以另一个数时,结果会变小。在我们的例子中,第一个大数是 db,我们使用的第二个大数是 db² 的加权平均值。我们引入了两个新变量 Sdb 和 SdW,以跟踪 db² 和 dW² 的加权平均值。
db 和 Sdb 的除法会产生一个较小的值(如下第四个公式),这会抑制 y 轴上的移动。引入 Ⲉ 是为了避免除以 0 错误。
类似的,也适用于 W 的更新,即 X 轴上的值(如下第三个公式)。
S
d
W
=
β
S
d
W
+
(
1
−
β
)
d
W
2
S
d
b
=
β
S
d
b
+
(
1
−
β
)
d
b
2
W
=
W
−
α
d
W
S
d
W
+
ε
b
=
b
−
α
d
b
S
d
b
+
ε
S_{dW}= \beta S_{dW}+\left ( 1-\beta \right ) dW^{2}\\ S_{db}= \beta S_{db}+\left ( 1-\beta \right ) db^{2}\\ W =W - \alpha \frac{dW}{\sqrt{S_{dW}}+\varepsilon } \\ b =b - \alpha \frac{db}{\sqrt{S_{db}}+\varepsilon }
SdW=βSdW+(1−β)dW2Sdb=βSdb+(1−β)db2W=W−αSdW+εdWb=b−αSdb+εdb
因此,我们可以抑制由任何偏差 b(b1, b2, …, bn) 或权重 W(W1, W2, …, Wn) 或两者以类似方式引起的任何此类振荡。
虽然 RMSProp 和 momentum 都能抑制y轴上的移动,但是在 RMSProp 中,由以上第一个和第二个公式可以看出,最近的梯度对结果有更大的影响,过去的梯度对结果影响比较小;而在 momentum 中, 它直接在n个连续样本上计算的平均值。因此,具有动量的 SGD 虽然能够更快地找到全局最小值,但该算法需要更长的路径,更长的路径意味着会遇到鞍点和局部最小值对可能性更大;另一方面,RMSProp 直接朝着损失函数的全局最小值前进,而不会绕道而行。
summary:
【优点】
具有随机梯度下降算法所有的优点;
收敛速度比momentum算法快。
【缺点】需要为每次更新再计算一次变量。
Adam
Adam(Adaptive Momentum)代表自适应动量,可以看作是 RMSprop 和带有动量的随机梯度下降的组合。
Adam 计算每个参数的自适应学习率。 除了像 RMSprop 一样存储过去平方梯度 vt 的指数衰减平均值之外,Adam 还保留过去梯度 mt 的指数衰减平均值,类似于动量。 动量可以看作是一个沿着斜坡向下运动的球,而 Adam 的行为就像一个带有摩擦的球,因此更喜欢损失函数中的平坦最小值。