小毛驴

Adventure may hurt you, but monotony will kill you.

0%

梯度下降算法分类及调参优化技巧

梯度下降算法是机器学习中使用非常广泛的优化算法,尤其常用来解非凸优化问题。因此,特别适合在深度学习中应用,几乎每一个先进的(state-of-the-art)机器学习库或者深度学习库都会包括梯度下降算法不同变种的实现。

梯度下降是一种用来最小化目标函数$J(\theta)$($\theta \in \mathbb{R}^d$是模型的参数)的方法,其沿着与目标函数相对于参数的梯度$\nabla_\theta J(\theta)$相反的方向更新参数的值。形象地说,就是沿着目标函数所在的超平面上的斜坡下降,直到到达山谷(目标函数极小值)。

根据计算目标函数的梯度时所用的数据量的多少,梯度下降算法共有三个不同的变种,它们之间的主要区别在于每次参数更新的精度和所花的时间。

批量梯度下降(Batch gradient descent)

最普通的梯度下降,也叫做批量梯度下降,有时候会把“批量”省略,直接叫做梯度下降。它在计算目标函数的梯度时需要使用所有的训练数据。

也就是说,批量梯度下降在执行每一次参数更新时都需要在整个数据集上计算梯度。当数据集大到不能一次性装入内存时,这种方法就不可行。同时,批量梯度下降也不支持在线学习。

批量梯度下降的代码如下:

1
2
3
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params)
params = params - learning_rate * params_grad

其中,epochs 是用户输入的最大迭代次数。

批量梯度下降每次学习都使用整个训练集,因此其优点在于每次更新都会朝着正确的方向进行,最后能够保证收敛于极值点(凸函数收敛于全局极值点,非凸函数可能会收敛于局部极值点),但是其缺点在于每次学习时间过长,并且如果训练集很大则需要消耗大量的内存,并且全量梯度下降不能进行在线模型参数更新。

随机梯度下降(Stochastic gradient descent)

随机梯度下降算法每次从训练集中随机选择一个样本来进行学习,计算目标函数的梯度并更新参数。

1
2
3
4
5
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

随机梯度下降算法每次只随机选择一个样本来更新模型参数,因此每次的学习是非常快速的,并且可以进行在线更新。其最大的缺点在于每次更新可能并不会按照正确的方向进行,导致目标函数剧烈的波动(扰动),如下图:
from  Wikipedia

不过从另一个方面来看,随机梯度下降所带来的波动有个好处就是,对于类似盆地区域(即很多局部极小值点)那么波动可能会导致从当前的局部极小值点跳到另一个更好的局部极小值点,最终收敛于一个较好的局部极值点,甚至全局极值点。

由于波动,学习的迭代次数会增多,即收敛速度变慢。不过如果我们缓慢地降低学习率,随机梯度下降最终会和批量梯度下降算法一样,具有相同的收敛性,即凸函数收敛于全局极值点,非凸损失函数收敛于局部极值点。

小批量梯度下降(Mini-batch gradient descent)

小批量梯度下降综合了批量梯度下降与随机梯度下降,在每次更新速度与更新次数中间取得一个平衡,其每次更新从训练集中随机选择$n$个样本进行学习,即:

其代码如下:

1
2
3
4
5
for i in range(nb_epochs):
np.random.shuffle(data)
for batch in get_batches(data, batch_size=50):
params_grad = evaluate_gradient(loss_function, batch, params)
params = params - learning_rate * params_grad

相对于随机梯度下降,Mini-batch梯度下降降低了收敛波动性,即降低了参数更新的方差,使得更新更加稳定。相对于批量梯度下降,其提高了每次学习的速度。并且其不用担心内存瓶颈从而可以利用矩阵运算进行高效计算。一般而言每次更新随机选择[50,256]个样本进行学习,但是也要根据具体问题选择,实践中可以进行多次试验,选择一个更新速度与更次次数都较适合的样本数。

mini-batch梯度下降算法常用于神经网络的训练中,这个时候其也被称为随机梯度下降(SGD)。也就是说深度学习文献资料中说的SGD,通常都是指mini-batch梯度下降。

mini-batch梯度下降和随机梯度下降的一个重要的性质是每一步更新的计算时间不依赖训练样本数目的多寡。即使训练样本数目非常大时,它们也能收敛。 对于足够大的数据集,它们可能会在处理完整个训练集之前就收敛到最终测试集误差的某个固定容差范围内。

设置合适的学习率

学习率可通过试错来选取,通常最好的选择方法是监测目标函数值随时间变化的学习曲线。下面对最常用的Mini-batch梯度下降算法,介绍如何选择合适的学习率。

由于Mini-batch梯度下降算法中梯度估计引入的噪声源($n$个训练样本的随机采样),并且不会在极小点处消失。相比之下,当我们使用批量梯度下降算法到达极小点时,整个代价函数的真实梯度会变得很小,最后为0,因此批量梯度下降可以使用固定的学习率。

保证Mini-batch梯度下降算法(以及随机梯度下降算法)收敛需要在算法迭代过程中不断降低学习率。保证收敛的一个充分条件是 并且

实践中,一般会线性衰减学习率直到第$\tau$次迭代: 其中$\alpha = \frac{k}{\tau}$。 在$\tau$步迭代之后,一般使$\eta$保持常数。

使用线性策略时,需要选择的参数为$\eta_0$,$\eta_\tau$,$\tau$。通常$\tau$被设为需要反复遍历训练集几百次的迭代次数。 通常$\eta_\tau$应设为大约$\eta_0$的1%。 主要问题是如何设置$\eta_0$。 若$\eta_0$太大,学习曲线将会剧烈振荡,代价函数值通常会明显增加。 温和的振荡是良好的,容易在训练随机代价函数(例如使用Dropout)时出现。 如果学习率太小,那么学习过程会很缓慢。如果初始学习率太低,那么学习可能会卡在一个相当高的代价值。通常,就总训练时间和最终代价值而言,最优初始学习率要高于前100次左右迭代产生最佳效果的学习率。因此,通常会检测最早的几轮迭代中效果最佳的学习率,然后把初始学习率设为比检测到的最佳学习率稍大的值,但又不能太大导致严重的震荡。

关于梯度下降算法的优化请参考我的另一篇博文:《深度学习中的常用优化技巧》