龙空技术网

梯度下降法的来龙去脉

小白学视觉 1091

前言:

今天各位老铁们对“小批量梯度下降算法的流程”大体比较关怀,朋友们都需要剖析一些“小批量梯度下降算法的流程”的相关知识。那么小编在网络上收集了一些关于“小批量梯度下降算法的流程””的相关资讯,希望看官们能喜欢,朋友们一起来了解一下吧!

梯度下降是一个优化算法,用于通过迭代向最“陡”的方向移动,使某些代价函数最小化。也就是说,向负梯度最大的方向移动。在机器学习中,我们使用梯度下降法来不断调整模型中的参数,以使代价函数最小化。我们从一组模型参数的值(神经网络中的权重和偏差)开始,然后慢慢地改进它们。在这篇文章中,我们将首先探索一些经典机器学习中常用的基本优化器,然后继续探索神经网络和深度学习中使用的一些更流行的算法。

想象一下,你正在山上跑步(或者散步) ,突然间浓雾破坏了你的视力。下山的一个好策略就是在每个方向都感觉到地面,并朝着地面下降速度最快的方向迈出一步。重复这个步骤,你应该会到达山脚(尽管你也可能会到达看起来像山脚的地方,但后面会更详细)。这正是梯度下降法所做的:它测量代价函数 J(ω)的局部梯度(参数由模型参数 ω 组成) ,并沿着下降梯度的方向移动。一旦我们达到零的梯度,我们就达到了我们的最小值。

假设现在山坡的陡峭程度对你来说并不明显(也许你太冷了以至于感觉不到你的脚,运用你的想象力吧!),所以你必须使用你的手机的加速度计测量你的梯度值。外面也很冷,所以要检查你的手机,你必须停止跑步,脱掉手套。因此,如果你希望尽快下来,你需要尽量减少使用你的手机!因此,你需要选择正确的频率来测量山坡的陡度,以免偏离轨道,同时在日落之前回家。两次检查手机之间的这段时间被称为学习率,也就是我们走下坡路的步数。如果我们的学习率太小,那么算法将需要很长的时间收敛。但是,如果我们的学习率太高,算法可能会分化,刚刚超过最小值。

描绘不同学习速度的梯度下降法

需要注意的一点是,并非所有的代价函数都是凸的(然而,线性回归的 MSE 代价函数是凸的)。如果函数图中任意两点之间的线段位于两点之间的图之上,则函数是凸的。凸性是好的,因为它意味着有一个单一的全局最小值。当成本函数不是凸的时候,问题就开始出现了: 可能有山脊、高原、洞等等。这使得收敛到最小值变得困难。幸运的是,我们可以利用一些技术来帮助解决其中的一些问题。

描述梯度下降法可能出现的问题

批量梯度下降法

在批处理梯度下降法中,我们在每个迭代步骤中使用完整的训练集 X。正因为如此,当使用大型训练集时,它可能会缓慢地令人痛苦。

我们从找到代价函数的梯度向量开始,我们用:

这里 J(ω)是由模型参数 ω 所参数化的代价函数,∇ 表示向量微分算子。现在我们有了梯度向量,我们只需要它向相反的方向(下坡)运动。然后,乘以学习率 η,我们得到了一个一步梯度下降法更新方程:

在 Python 中实现批处理梯度下降法是再简单不过的了!

import numpy as np eta = 0.01 # our chosen learning rate iterations = 10^3n = 100theta = np.random.randn(d,1) # random initialization, with d being # the dimension of thetafor i in range(iterations):    gradients = 2/n * X.T.dot(X.dot(theta) - y)    theta = theta - eta * gradients

如果我们愿意,我们可以使用网格搜索来找到一个好的学习率。为了找到正确的迭代次数,通常只需将迭代次数设置为一个非常大的数字,但当梯度向量(梯度)小于某个预先设置的公差(通常表示 ε)时,就会中断算法。这是因为当梯度向量变得很小时,我们已经非常接近最小值了。

另一个重要的注意事项是,当你使用梯度下降法时,你应该确保你所有的功能都有一个相似的尺度,否则,它将花费更长的时间使算法收敛ー Sckikit-Learn 的 StandardScaler 通常可以做到这一点。我们能做些什么来加速我们的优化器呢?进入随机梯度下降。

随机梯度下降

随机梯度下降不是在每个步骤中使用整个训练集,它在每个步骤中采用训练集的一个随机实例,并使用这个实例来计算梯度。这显然比批处理梯度下降快得多,尤其是在使用大型训练集时。然而,缺点是由于它的随机行为,算法不那么规则:它只是平均地减少,而不是在每一步逐渐减少。因此,我们的最终参数值将是良好的,但不是最优的(不像批处理梯度下降法) ,因为一旦我们接近最小值,算法仍将持续震荡。

虽然这听起来不怎么样,但是它确实有帮助!例如,如果代价函数非常不规则(甚至不是凸的) ,随机性可以帮助跳出局部最小值。所以实际上,随机梯度下降实际上比普通的旧批梯度下降更有可能找到全局最小值。

当我们接近最小值时,我们实际上也可以做一些事情来帮助解决缺乏收敛性的问题:逐渐降低学习率。我们可以从(相对)大的步骤开始,这有助于更快地收敛到最小值,也有助于跳出局部最小值。然后逐渐降低学习速率,使算法稳定在全局最小值。这个过程被称为学习策略。

下面的代码实现了随机梯度下降学习过程和一个简单的学习策略:

epochs = 50t0, t1 = 1, 10 # Learning schedule hyperparamsn = 100def learning_schedule(t):    return t0/(t + t1)    theta = np.random.randn(d,1) # random initialization, with d being # the dimension of thetafor epoch in range(epochs):    for i in range(n):        rand_idx = np.random.randint(n)        xi = X[rand_idx:rand_idx+d]        yi = y[rand_idx:rand_idx+d]        gradients = 2 * xi.T.dot(xi.dot(theta) - yi)        eta = learning_schedule(epoch * n + i)        theta = theta - eta * gradients

这里我们进行 n 轮迭代,每轮被称为一个 epoch。

另外值得一提的方法是:小批量梯度下降法。简单地说,它只是 Batch 和随机梯度下降方法的组合:在每个步骤中,小批量梯度下降法 计算训练实例的一个小的随机子集(一个小批处理)上的梯度。这样做的优点是不像随机梯度下降那样不稳定;然而,它更有可能陷入局部最小值。

到目前为止,我们已经讨论了几个经典的梯度下降算法,这些算法在训练更经典的机器学习模型时能够达到令人满意的水平,例如 SVMs、随机森林等。但是,使用这些方法来训练大型深度自然网络可能会非常缓慢。更快的优化器可以在训练中提供额外的速度提升。下面将讨论一些最流行的算法。

Momentum 优化

动量优化使用动量的概念,并积累以前的梯度来帮助确定前进的方向,而不是仅仅使用当前步骤中损失函数的梯度来指导下降的方向。回想一下我们之前的类比:想象你现在骑着自行车,正在下山,你会慢慢开始,但是你会逐渐开始获得越来越多的动力,直到你到达一个终端速度。这正是动量算法所做的。另一种思考方式是,梯度向量现在用来表示加速度,而不是速度。因此,我们的模型参数的更新方程是:

在每次迭代中,我们从动量向量 m 中减去局部梯度(乘以 η) ,然后通过增加动量向量 m 来更新权值 ω。在一般情况下收敛得更快的同时,动量帮助算法更快地逃离稳定的区域,也越过了局部极小点。超参数 β 是设置的超参数,可以理解为衰减因子,β 值越高,代表越依赖原来的梯度值。

加速梯度

稍微调整一下动量算法,我们几乎总能得到更快的收敛速度。NAG 方法测量的梯度代价函数略高于局部位置 ω。一步更新是由

原因很简单:一般来说,动量矢量指向最小值,所以在这个方向上稍微测量一下梯度会有所帮助。这些小的速度改进累加起来,最终 NAG 算法的速度明显提高。在 Keras 实现这一点非常容易,我们可以这样写:

optimizer = keras.optimizers.SGD(lr=0.001, momentum=0.9, nesterov=True)
RMSProp

RMSProp 算法是 AdaGrad 算法的一个改进版本,由 Geoffrey Hinton 和 Tijmen Tieleman 在2012年引入。想象一下这样的场景:代价函数看起来像一个拉长的碗,梯度下降算法将开始沿着最陡的斜坡下行,但这个斜坡并不直接指向全局最小值。AdaGrad 算法为我们提供了一个校正,使算法确实朝着全局最小值移动。这是通过沿着最陡的维度向下缩放梯度向量来实现的。另一种思考这个问题的方式是,我们在陡峭的维度中衰减学习速度更快,而在更平缓的维度中衰减速度更慢。要理解这个过程,最简单的方法是亲身体验一下这个一步更新的方程式:

其中 s 的计算过程为:

因此,如果代价函数 J(ω)在 i-th 维上是“陡峭”的,那么 s 就会在我们迭代过程中不断累积,变得越来越大。这里的第二步实际上与通常的梯度下降法值的更新相同,除了我们按比例缩小梯度向量。⊘ 表示元素除法,因此梯度向量的每个元素越大,我们在这个方向上的下降步伐就越小。ε 是一个非常小的平滑术语(例如 ε = 1e-10) ,它的存在就是为了避免被0除。

然而,AdaGrad 的问题在于,当训练神经网络时,它通常停止得太早。这是因为学习率下降太多了。RMSProp 做了一个简单的调整。相反,我们以指数衰减最近迭代中积累的梯度。

虽然我们引入了一个新的超参数来调整(ρ) ,但是 ρ = 0.9通常就可以了。正如你现在可能已经猜到的,在 Keras 实施 RMSProp 是非常容易的:

optimizer = keras.optimizers.RMSprop(lr=0.001, rho=0.9)

我想现在是时候谈谈优化器的老大了。

Adam and Nadam 优化

自适应矩估计(Adam)结合了我们已经研究过的两种方法:动量优化和 RMSProp 优化。它从动量优化中窃取了跟踪先前梯度的指数衰减平均值的想法,从 RMSProp 中窃取了跟踪过去平方梯度的指数衰减平均值的想法。

这里,t 是迭代次数(从1开始)。第一个、第二个和第五个方程几乎与动量优化算法和 RMSProp 优化算法相同,差异来自超参数。第三个和第四个方程在算法开始时只是简单地增加 m 和 s,因为它们偏向于0。和 Keras 的所有东西一样,Adam 非常容易实现(下面还给出了超参数的默认值)。

optimizer = keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999)

Nadam 算法与 Adam 算法相同,但它也包含 Nesterov 技巧,这意味着它通常比标准的 Adam 收敛得稍快一些。

Adam (以及 Nadam 和 RMSProp)的另一个不那么明显的优势是,它需要更少的 η 调整ーー因此,在某些方面,它甚至比标准的普通随机下降方法更容易实现!

总结

我们从经典的梯度下降法开始,逐渐使用我们的方法变得越来越复杂。当使用计算能力较弱的模型时,我发现通常简单的 SGD/小批量模型工作得非常好。当训练大型神经网络时,像 Adam/Nadam 和 RMSProp 这样的神经网络往往工作得很好。正如机器学习世界中的所有事情一样,尝试不同的方法通常会得到最好的结果。

标签: #小批量梯度下降算法的流程