深入浅出梯度下降算法背后的数学原理
0 前言
梯度下降是一种在训练机器学习模型时使用的优化算法,它基于凸函数并迭代调整其参数以将给定函数最小化到其局部最小值。
什么是梯度下降?
梯度下降是一种用于寻找可微函数的局部最小值的优化算法。梯度下降简单地用于机器学习中,以找到尽可能最小化成本函数的函数参数值。
因此,需要定义初始参数的值,然后梯度下降使用微积分迭代调整这些值,使它们最小化给定的成本函数。
1 什么是梯度?
要充分理解梯度下降这个概念,首先需要理解什么是梯度。
梯度只是衡量所有权重相对于误差变化的变化,因此可以将梯度看作是函数的斜率。梯度越高,斜率就越陡,模型可以学习的速度就越快。但是如果斜率为0,模型就会停止学习。从数学上来讲,梯度就是关于输入的偏导数。
什么是梯度?
在机器学习中,梯度是具有多个输入变量的函数的导数。在数学术语中称为函数的斜率,梯度只是衡量所有权重相对于误差变化的变化。
想象一下如果你想用尽可能少的步骤爬到山顶,你可能会从最陡峭的方向迈出真正的大步开始爬山,当越来越接近山顶时,步幅会越来越小,以免会越过山顶。这个过程如果用梯度来解释的话,可以将下图看作是从上到下的视角展示你要爬的山,红色的箭头是台阶,在这种情况下,可以将梯度视为一个向量,其中包含你可以走的最陡一步的方向以及该步应该走多长时间。
从下图可以看出,从 X0 到 X1 的梯度比从 X3 到 X4 的梯度所花的时间要长得多,这是因为决定矢量长度的山坡的陡度/坡度较小,即在同样的步伐下从 X0 到 X1比从 X3 到 X4要陡。
2 梯度下降是如何工作的?
梯度下降可以想象成下山的过程,下面的等式描述了梯度下降的作用:b是你下山的下一个位置,而a代表你当前的位置,减号后面是指梯度下降最快的地方,即下一个你需要走的位置是最陡下降的方向。
b
=
a
−
γ
▽
f
(
a
)
b = a - \gamma \bigtriangledown f\left ( a \right )
b=a−γ▽f(a)
2.1 从生活中的一个小例子讲起
我们举一个生活中的小例子来了解梯度下降是如何工作的。
假设有一组学生身高和体重的数据,我们试图找到身高和体重之间的关系用来预测新生的体重,这本质上就是一个简单的监督机器学习问题。如下左图所示,我们将这些数据画在以横轴为身高、纵轴为体重的二维空间中,现在我们在空间中画一条穿过这些数据点的任意直线,这条直线的方程设为Y=wX+b,其中w是斜率,b是它在Y轴上的截距。
因此,给定一组已知的输入和相应的输出,机器学习模型会尝试对这一组输入进行预测,机器学习的过程就是将预测值不断地逼近实际值,进而减小预测值和实际值之间的误差,如下图所示,而这个误差跟成本函数或者损失函数有关。
2.2 什么是成本函数
成本函数(cost function)和损失函数(loss function)都是用来评估我们的机器学习算法的性能。损失函数是计算单个样本的误差,而成本函数是计算所有样本损失函数的平均值。成本函数和损失函数的关系用数学公式可以表示为:
J
(
w
,
b
)
=
1
m
∑
i
=
1
m
l
(
y
^
,
y
)
J\left ( w,b \right ) =\frac{1}{m}\sum_{i=1}^{m}l\left ( \hat{y},y \right )
J(w,b)=m1i=1∑ml(y^,y)
以上,J(w, b)为成本函数,l为损失函数,假设我们有m组学生的体重身高数据,那么上式可以看作是成本函数等于m组数据中每组数据预测结果的损失值的和的平均值。
成本函数就是告诉我们,我们的模型在给定参数w和b的值下进行预测的结果有多好。
因此,对于预测新生体重这种机器学习问题,我们会用这m组数据进行梯度下降我们的算法,通过调整w和b这两个参数以最小化成本函数J(w, b)达到其局部最小值。下图中,水平轴表示w和b参数,垂直轴表示成本函数J(w, b),可以看出梯度下降是一个凸函数。
红色箭头标记的是成本函数最小值对应的w和b的值,我们的目标就是找到w和b的值。为了寻找这两个目标值,首先需要随机初始化w和b参数,然后梯度下降从初始化的点开始,沿着最陡峭的下行方向一步一步直到它到达成本函数的最低点。
对于预测新生体重这个例子,这里的损失函数用的是平方误差,即:
l
(
y
^
,
y
)
=
(
y
^
−
y
)
2
l\left ( \hat{y},y \right ) =\left (\hat{y} - y \right ) ^{2}
l(y^,y)=(y^−y)2
为什么这个例子我们采用平方差而不采用绝对差?
因为平方差更容易得到回归的直线,实际中,我们要找到这条直线需要计算成本函数的一阶导数,而计算绝对值的导数比计算平方值的导数要困难得多;此外,平方值增加了误差距离,因此,对于误差大的预测要比误差小的预测更明显。
2.3 如何最小化成本函数
在我们的例子中,我们的损失函数在笛卡尔坐标系中是一个抛物线方程,由于这是一个二维空间,我们很容易能够找到最小值,但在高维度下,我们并非很容易找到最小值,对于这种情况,我们需要设计一种算法来找到最小值,该算法称为梯度下降算法。
2.4 什么是梯度下降
梯度下降是最流行的优化算法之一,也是最常用的神经网络优化方法, 它是一种迭代优化算法,用于找到函数的最小值。
从本质上讲,要达到函数的最低点,应该知道两件事,即走哪条路(方向)以及要走多远(大小)。
梯度下降算法帮助我们通过使用梯度有效地做出这些决策。梯度是所有输入值的偏导数,如果可以计算出偏导数,则能够计算出达到最小值的所需方向。
还是以预测新生体重为例,如下图所示,如果我们在绿点处画一条切线,如果我们向上移动,就会远离最小值,反之亦然。蓝点处的斜率要比绿点处的斜率要低很多,可以看出从蓝点到达最小值所需的步长比从绿点处要小很多。
2.5 成本函数的数学解释
现在让我们将所有这些知识放入一个数学公式中。 在方程中,y = wX+b,其中‘w’和‘b’是它的参数。 在训练过程中,参数会有微小的变化,这个微小的变化用δ表示,则参数值将分别更新为 w=w-δw 和 b=b-δb。 我们的目标是找到误差最小的 w 和 b 。下面用数学解释为:
对参数有一个微小的变化:
w
=
w
−
δ
w
b
=
b
−
δ
b
w=w-δw\\ b=b-δb
w=w−δwb=b−δb
基于m个样本的成本函数可以表示为:
c
o
s
t
=
1
m
∑
i
=
1
m
l
(
y
^
,
y
)
cost = \frac{1}{m}\sum_{i=1}^{m}l\left ( \hat{y},y \right )
cost=m1i=1∑ml(y^,y)
成本函数用J表示为:
J
w
,
b
=
1
m
∑
i
=
1
m
l
(
y
^
,
y
)
J_{w,b} = \frac{1}{m}\sum_{i=1}^{m}l\left ( \hat{y},y \right )
Jw,b=m1i=1∑ml(y^,y)
即:
J
w
,
b
=
1
m
∑
i
=
1
m
(
e
r
r
o
r
i
)
2
J_{w,b} = \frac{1}{m}\sum_{i=1}^{m}\left (error_{i} \right ) ^{2}
Jw,b=m1i=1∑m(errori)2
3 学习率
达到最小值或底部所采取的步长大小称为学习率,学习率决定了我们朝着最佳权重移动的速度有多快或多慢。 我们可以用更大的步长/更高的学习率覆盖更多的区域,但有超过最小值的风险,因为它在梯度下降的凸函数之间来回反弹,而小步长/较小的学习率会消耗大量时间才能达到最低点见。
如下图所示:
a) 学习率最优,模型收敛到最小值
b) 学习率太小,耗时较多但收敛到最小值
c) 学习率高于最优值,振荡但减小最终收敛(1/C < η <2/C)
d) 学习率非常大,会出现超调和发散,远离最小值,学习性能下降
因此,为了使梯度下降达到局部最小值,我们必须将学习率设置为适当的值,既不太低也不太高;其次,随着向局部最小值移动时梯度减小,步长也在减小,学习率在优化的过程中可以保持不变,并且不需要反复变化。
4 如何确保梯度下降能够正常工作
确保梯度下降正常运行的一个好方法是在优化过程中绘制成本函数,即将迭代次数放在 x 轴上,将成本函数的值放在 y 轴上,如下左图所示,这可以在每次梯度下降迭代后查看成本函数的值,并提供一种方法来发现此时设置的学习率到底合不合适;也可以尝试不同的值并将它们全部绘制在一起,如下右图所示。下面的左图显示了成本函数与迭代次数的关系,而右图则说明了学习率好坏之间的差异。
如果梯度下降正常,则成本函数应在每次迭代后减小。当梯度下降不能再减小成本函数并且保持在同一水平线上时,它已经收敛。梯度下降需要收敛的迭代次数会有很大差异,可能需要 50 次迭代、60,000 次甚至 300 万次迭代,这使得收敛的迭代次数难以提前估计。有一些算法可以自动告诉你梯度下降是否已经收敛,但是必须事先定义收敛的阈值,这个阈值也很难估计。综合这些原因,简单的方法是设置一些常用的学习率进行简单的测试。
通过绘制成本函数来监控梯度下降的另一个优点是让我们知道梯度下降是否能够正常工作,例如成本函数在增加表示不能正常工作,大多数情况下,使用梯度下降时成本函数增加的原因是学习率太高;如果该成本函数曲线只是上下波动,而没有真正达到较低点,说明需要尝试降低学习率。此外,当从给定问题的梯度下降开始时,只需尝试 0.001、0.003、0.01、0.03、0.1、0.3、1 等作为学习率,并查看哪个表现最好。
5 梯度下降算法的python实现
梯度下降算法是不断重复以下步骤,直到收敛。
计
算
预
测
值
:
(
y
^
i
,
i
=
1
,
2
,
…
,
m
)
d
w
=
α
J
α
w
d
b
=
α
J
α
b
w
=
w
−
α
d
w
b
=
b
−
α
d
b
计算预测值:(\hat{y}^{i},i=1,2,\dots ,m )\\ dw=\frac{\alpha J}{\alpha w}\\ db = \frac{\alpha J}{\alpha b}\\ w = w - \alpha dw\\ b = b - \alpha db\\
计算预测值:(y^i,i=1,2,…,m)dw=αwαJdb=αbαJw=w−αdwb=b−αdb
用python实现如下,定义一个*gradient_descent()*函数,当满足以下任意条件则停止迭代:1.迭代次数超过最大值,2.两次连续迭代之间的函数值差异低于某个阈值。
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import sklearn.datasets as dt
from sklearn.model_selection import train_test_split
def gradient_descent(max_iterations, #最大的迭代次数
threshold, #两次连续迭代之间的函数值差低于该阈值则停止
w_init, #梯度下降w的初始值
b_init, #梯度下b的初始值
obj_func, #目标函数
grad_func, #成本函数
extra_param = [], #其他参数
learning_rate=0.05, #学习率):
w = w_init
w_history = w
b = b_init
b_history = b
f_history = obj_func(w, b, extra_param)
delta_w = np.zeros(w.shape)
delta_b = np.zeros(b.shape)
i = 0
diff = 1.0e10
while i<max_iterations and diff>threshold:
delta_w = -learning_rate*grad_func(w, b, extra_param) + momentum*delta_w
w = w+delta_w
delta_b = -learning_rate*grad_func(w, b, extra_param) + momentum*delta_b
b = b+delta_b
# store the history of w , b and f
w_history = np.vstack((w_history, w))
b_history = np.vstack((b_history, b))
f_history = np.vstack((f_history,obj_func(w, b, extra_param)))
# update iteration number and diff between successive values
# of objective function
i+=1
diff = np.absolute(f_history[-1]-f_history[-2])
return w_history, b_history, f_history
# w_history:空间中被梯度下降访问的所有w的点
# b_history:空间中被梯度下降访问的所有b的点
# f_history:w_history对应的目标函数值
6 梯度下降的类型
这里介绍三种流行的梯度下降类型,主要的区别在于它们使用的数据量上有所不同。
6.1 批量梯度下降
批量梯度下降,也称为普通梯度下降,计算训练数据集中每个样本的误差,但只有在评估了所有训练样本之后,模型才会更新。这整个过程就像一个循环,称为一个训练时期( epoch)。
批量梯度下降:
【优点】其计算效率高,它产生稳定的误差梯度和稳定的收敛;
【缺点】稳定的误差梯度有时会导致收敛状态不是模型所能达到的最佳状态,它还要求整个训练数据集都在内存中并且可供算法使用。
6.2 随机梯度下降
随机梯度下降 (SGD) 对数据集中的每个训练样本执行此操作,这意味着它会一一更新每个训练样本的参数。根据问题,这可以使 SGD 比批量梯度下降更快。
【优点】频繁的更新参数使我们能够获得非常详细的改进率。
【缺点】频繁更新比批量梯度下降方法的计算成本更高。此外,这些更新的频率可能会导致噪声梯度,这可能会导致错误率跳跃而不是缓慢下降。
6.3 小批量梯度下降
小批量梯度下降是首选方法,因为它结合了 SGD 和批量梯度下降的概念。它只是将训练数据集分成小批,并为每个批执行更新。这在随机梯度下降的鲁棒性和批量梯度下降的效率之间建立了平衡。
常见的 mini-batch 大小在 50 到 256 之间,但与任何其他机器学习技术一样,没有明确的规则,因为它因不同的应用程序而异。这是训练神经网络时的首选算法,也是深度学习中最常见的梯度下降类型。