大部分的机器学习模型里有直接或者间接地使用了梯度下降的算法。虽然不同的梯度下降算法在具体的实现细节上会稍有不同,但是主要的思想是大致一样的。梯度下降并不会涉及到太多太复杂的数学知识,只要稍微了解过微积分里导数的概念,就足够完全理解梯度下降的思想了。
梯度下降的目的
绝大多数的机器学习模型都会有一个损失函数。比如常见的均方误差(Mean Squared Error)损失函数:
(1)
其中, 表示样本数据的实际目标值, 表示预测函数
根据样本数据
计算出的预测值。从几何意义上来说,它可以看成预测值和实际值的平均距离的平方。(关于更多的损失函数的介绍,可以参见这篇文章。)
损失函数用来衡量机器学习模型的精确度。一般来说,损失函数的值越小,模型的精确度就越高。如果要提高机器学习模型的精确度,就需要尽可能降低损失函数的值。而降低损失函数的值,我们一般采用梯度下降这个方法。所以,梯度下降的目的,就是为了最小化损失函数。
梯度下降的原理
寻找损失函数的最低点,就像我们在山谷里行走,希望找到山谷里最低的地方。那么如何寻找损失函数的最低点呢?在这里,我们使用了微积分里导数,通过求出函数导数的值,从而找到函数下降的方向或者是最低点(极值点)。
损失函数里一般有两种参数,一种是控制输入信号量的权重(Weight, 简称 ),另一种是调整函数与真实值距离的偏差(Bias,简称 )。我们所要做的工作,就是通过梯度下降方法,不断地调整权重
和偏差b,使得损失函数的值变得越来越小。
假设某个损失函数里,模型损失值 与权重 有下图这样的关系。实际模型里,可能会有多个权重
,这里为了简单起见,举只有一个权重
的例子。权重
目前的位置是在A点。此时如果求出A点的梯度
,便可以知道如果我们向右移动,可以使损失函数的值变得更小。
通过计算梯度,我们就可以知道 的移动方向,应该让 向右走而不是向左走,也可以知道什么时候会到达最低点(梯度为0的地方)。
上面的例子里只出现了一个权重 , 实际的项目里样本数据会有很多个。对于每一个样本数据,我们都可以求出一个权重的梯度。这个时候,我们需要把各个样本数据的权重梯度加起来,并求出它们的平均值,用这个平均值来作为样本整体的权重梯度。
现在知道了 需要前进的方向,接下来需要知道应该前进多少。这里我们用到学习率(Learning Rate)这个概念。通过学习率,可以计算前进的距离(步长)。
我们用 表示权重的初始值, 表示更新后的权重值,用
表示学习率,则有:
(2)
在梯度下降中,我们会重复式子(2)多次,直至损失函数值收敛不变。
如果学习率 设置得过大,有可能我们会错过损失函数的最小值;如果设置得过小,可能我们要迭代式子(2)非常多次才能找到最小值,会耗费较多的时间。因此,在实际应用中,我们需要为学习率 设置一个合适的值。
上面讲解了对权重 值的优化过程,对于偏差 ,我们也可以用相同的方式进行处理,这里就不再展开了。
梯度下降的过程
我们把上面的内容稍微整理一下,可以得到梯度下降的整体过程:
- for i = 0 to 训练数据的个数:
(1) 计算第 i 个训练数据的权重 和偏差 相对于损失函数的梯度。于是我们最终会得到每一个训练数据的权重和偏差的梯度值。
(2) 计算所有训练数据权重 的梯度的总和。
(3) 计算所有训练数据偏差 的梯度的总和。
2. 做完上面的计算之后,我们开始执行下面的计算:
(1) 使用上面第(2)、(3)步所得到的结果,计算所有样本的权重和偏差的梯度的平均值。
(2) 使用下面的式子,更新每个样本的权重值和偏差值。
(3)
(4)
重复上面的过程,直至损失函数收敛不变。
如果用伪代码把梯度下降的过程表现出来,可以写成下面的样子:
def train(X, y, W, B, alpha, max_iters):
'‘’
选取所有的数据作为训练样本来执行梯度下降
X : 训练数据集
y : 训练数据集所对应的目标值
W : 权重向量
B : 偏差变量
alpha : 学习速率
max_iters : 梯度下降过程最大的迭代次数
'''
dW = 0 # 初始化权重向量的梯度累加器
dB = 0 # 初始化偏差向量的梯度累加器
m = X.shape[0] # 训练数据的数量
# 开始梯度下降的迭代
for i in range(max_iters):
dW = 0 # 重新设置权重向量的梯度累加器
dB = 0 # 重新设置偏差向量的梯度累加器
# 对所有的训练数据进行遍历
for j in range(m):
# 1. 遍历所有的训练数据
# 2. 计算每个训练数据的权重向量梯度w_grad和偏差向量梯度b_grad
# 3. 把w_grad和b_grad的值分别累加到dW和dB两个累加器里
W = W - alpha * (dW / m) # 更新权重的值
B = B - alpha * (dB / m) # 更新偏差的值
return W, B # 返回更新后的权重和偏差。
其他常见的梯度下降算法
上面介绍的梯度下降算法里,在迭代每一次梯度下降的过程中,都对所有样本数据的梯度进行计算。虽然最终得到的梯度下降的方向较为准确,但是运算会耗费过长的时间。于是人们在上面这个算法的基础上对样本梯度的运算过程进行了改进,得到了下面这两种也较为常见的算法:
1. 小批量样本梯度下降(Mini Batch GD)
这个算法在每次梯度下降的过程中,只选取一部分的样本数据进行计算梯度,比如整体样本1/100的数据。在数据量较大的项目中,可以明显地减少梯度计算的时间。
2. 随机梯度下降(Stochastic GD)
随机梯度下降算法只随机抽取一个样本进行梯度计算,由于每次梯度下降迭代只计算一个样本的梯度,因此运算时间比小批量样本梯度下降算法还要少很多,但由于训练的数据量太小(只有一个),因此下降路径很容易受到训练数据自身噪音的影响,看起来就像醉汉走路一样,变得歪歪斜斜的。
总结
这篇文章主要讲解了梯度下降算法的作用和主要原理,给出了梯度下降算法的运算过程和伪代码实现,最后介绍了两种改进后的梯度下降算法。
参考资料
1. Gradient Descent : All You Need to Know by Suryansh S.