因为是CV出身的,转了推荐算法,前面也写了很多关于推荐算法的东西,但是最近写的有点疲了,思前想后决定先放一下推荐算法的基础模型。这几天先写一下机器学习和深度学习的东西,各个领域融会贯通一下。梯度下降算法是求解无约束多元函数极值最常用的数值方法, 很多机器学习常用算法和神经网络都是以它作为算法框架进行优化参数。 所以这个算法非常重要。梯度下降也是一种优化算法, 通过迭代的方式寻找使模型目标函数达到最小值时的最优参数, 当目标函数为凸函数的时候,梯度下降的解是全局最优解,但在一般情况下,梯度下降无法保证全局最优。
介绍梯度下降之前按先讲一下为什么大家公认的负梯度方向是f ( x ) 减小最快的方向, 这背后又又又又涉及到了泰勒的知识, 所以首先就来看看这个问题, 简单推导一下为啥是负梯度方向。
众所周知,沿梯度方向的方向导数可以来描述函数的最大变化率,即梯度方向是函数变化率最大的方向,这个也是梯度的定义。这里不太明白的小伙伴可以先去看一下这方面的数学知识,在这里我就不搬运教材图片了。这里我们假设函数f ( θ ) 是一个多元函数, 那么我们由泰勒把这个函数进行展开至一阶导数的位置, 就会得到:
我们知道这里的f ( θ ) , f ( )是个值,也就是标量, 而加号后面那两个是向量, 但是点积之后就成了标量。我们可以令θ − =ηv, 即一个向量可以分解为一个长度和一个方向的乘积, 这里的η 表示步长, 这里的v 表示方向, 那么就可以对上面式子进行化简:
再进行化简:
因为我们这是在执行梯度下降, 所以新得到的这个f (θ)要比原来的f()小才符合我们的预期。 所以上面这个是我们所希望的, 即
这里面的步长大于0, 而梯度如果给了确定的点之后,就不变了,所以这里面的变量之后v,也就是方向, 所以我们可以把预期写成下面这样:
这里的 θ 是两个向量的夹角。 所以根据这个等式我们可以得出 v 首先也梯度方向的夹角大于90度且小于270度的时候, 才能保证小于0,而在这里我们需要得到的是 尽可能地使得f ( θ ) , f ( )这两个标量的差值更大,这样我们才能够更有效地进行梯度下降。所以只有两者的夹角是180°的时候,也就是沿着负梯度方向进行下降的时候。 这才有了前面所说的沿着梯度相反方向进行下降是最快的, 也是负梯度这个说法的来历,那么方向有了, 步长呢? 这个就是η 控制了, 所以在进行梯度下降的时候, 我们才有了那个梯度更新公式:
好了解释完原因,接下来就讲解一下有哪几种常见的梯度下降法,并比较他们的优劣和应用场景吧。
批量梯度下降法(Batch Gradient Descent,简称BGD)是梯度下降法最 原始的形式,它的具体思路是在更新每一参数时都使用所有的样本来进行更新,也就是方程中的m表示样本的所有个数。更新公式如下:
从公式中就可以看到是将所有的样本的梯度进行了加和平均,然后进行迭代。这种方法很明显的优点是因为考虑了每个样本的梯度值,因此当损失函数收敛过程比较稳定。对于凸函数可以收敛到全局最小值,对于非凸函数可以收敛到局部最小值。但是缺点也更明显,那就是样本数量很多的时候训练过程非常消耗时间和计算资源,并且不能将新数据进行实时更新模型。
由于批梯度下降每跟新一个参数的时候,要用到所有的样本数,所以训练速度会随着样本数量 的增加而变得非常缓慢。随机梯度下降正是为了解决这个办法而提出的。
它的具体思路是在更新每一参数时都使用一个样本来进行更新,也就是以上批处理方程中的n等于1。每一次跟新参数都用一个随机选择的样本,更新很多次。如果样本量很大的情况(例如几十万),那么可能只用其中几万条或者几千条的样本,就已经将迭代到最优解了,对比上面的批量梯度下降,迭代一次需要用到十几万训练样本,一次迭代不可能最优,所以需要将整体样本迭代很多次,这种更新方式计算复杂度太高。但是,SGD伴随的一个问题是噪音较BGD要多,使得SGD并不是每次迭代都向着整体最优化方向。 更新方式如下:
这个方式的有点是训练速度很快,也适用于数据源源不断到来的在线更新场景。缺点前面已经说过了因为每次都是取一个样本进行计算,对梯度的估计出现偏差,造成目标函数曲线收敛的很不稳定,伴有剧烈波动,有时候甚至不收敛。
我们从上面两种梯度下降法可以看出,其各自均有优缺点,那么能不能在两种方法的性能 之间取得一个折衷呢?即,算法的训练过程比较快,而且也要保证最终参数训练的准确率, 而这正是小批量梯度下降法(Mini-batch Gradient Descent,简称MBGD)的初衷。
小批量梯度下降法(Mini-batch Gradient Descent,简称MBGD):它的具体思路是在更 新每一参数时都使用一部分样本来进行更新,也就是批处理方程中的n的值大于1小于所有 样本的数量。为了克服上面两种方法的缺点,又同时兼顾两种方法的优点。
k表示一个批次里面的样本个数。 这个也是目前常用的方式(注意这里是在训练样本上个数的选择), 但是在用的时候要注意三个问题:
如何选取参数k: 不同应用中, 最优的k通常会不一样,往往需要调参确定。 一般k取2的幂次时能充分利用矩阵运算操作。 所以可以在2的幂次中选取最优值,32,64,128等,如果感觉内存比较小,可以小一点。
如何选择k个训练数据? 为了避免数据的特定顺序对收敛带来的影响,一般在每次遍历训练数据之前,先对数据随机打乱,然后每次迭代时,按顺序挑选k个训练数据。 也就是每个epoch的时候都会随机打乱一次训练集。
如何选取学习速率α: MBGD不能保证很好的收敛性,如果学习率太小,收敛速度会很慢,如果太大,损失函数就会在极小值出不停的震荡甚至偏离,所以通常用衰减学习率的方案: 一开始采用较大学习率,当误差曲线进入平台期后,减小学习率做更精细的调整。 最优的学习速率也通常需要调参。
所以,MBGD是解决训练数据量过大的一个不错的方案, 而SGD更适用于在线的实时更新,BGD一般很少用于实际中。
但是仅仅基于上面的这几种梯度下降方法也是不太好用的,因为无论是经典的梯度下降还是随机梯度下降,都可能陷入局部极值点。这个对于SGD来说,还不是最要命的,毕竟这个现象普遍存在,这种情况可以随机初始化参数,多训练几遍模型试试看。
对SGD来说,最要命的是SGD可能会遇到“峡谷”和“鞍点”两种困境峡谷类似⼀个带有坡度的狭长小道,左右两侧是 “峭壁”;在峡谷中,准确的梯度方向应该沿着坡的方向向下,但粗糙的梯度估计使其稍有偏离就撞向两侧的峭壁,然后在两个峭壁间来回震荡。鞍点的形状类似⼀个马鞍,⼀个方向两头翘,⼀个方向两头垂,而中间区域近似平地;⼀旦优化的过程中不慎落入鞍点,优化很可能就会停滞下来(坡度不明显,很可能走错方向,如果梯度为0的区域,SGD无法准确察觉出梯度的微小变化,结果就停下来)。为了形象,还找了个图:
所以接下来的一些算法,就是针对于SGD的这两个要命问题进行的一系列改进了,首先先把握住改进的两个大方向: 惯性保持和环境感知
惯性保持: 加入动量, 代表:Momentum, Nesterov Accerlerated Gradient
环境感知: 根据不同参数的一些经验性判断, 自适应的确定每个参数的学习速率,这是一种自适应学习率的优化算法。代表:AdaGrad, AdaDelta, RMSProp
还有把上面两个方向结合的: Adam, AdaMax, Nadam
这些就在下一节进行讲解了。
参考:翻滚的小强