运筹系列6:梯度下降法介绍

1. 概念

梯度下降法与现在火热的机器学习、深度学习息息相关,相关的文章非常多。其基本思路可以理解为一种启发式搜索算法,每次迭代都寻找附近一定范围内的最小值。
先定义一些概念:
损失函数求期望得到风险函数(也就是期望损失)。有监督学习要求最小化风险函数。
期望值和理论值的偏差叫期望风险
采样平均后的偏差叫经验风险。一般最小化经验风险代替最小化实际的期望风险。
结构风险=经验风险+正则化

梯度下降基本步骤是:
使用拉格朗日法对一般的凸优化问题进行转化,假设问题为min L ( x ) L(x) L(x),从一个初始解 x 0 x_0 x0出发,计算当前点的一阶导数 L ′ ( x 0 ) L'(x_0) L(x0),然后按照一定的步长 α \alpha α改变 x 0 x_0 x0的值,变为 x 1 = x 0 − α L ′ ( x 0 ) x_1 = x_0 -\alpha L'(x_0) x1=x0αL(x0),目标函数从 L ( x 0 ) L(x_0) L(x0)变为 L ( x 1 ) L(x_1) L(x1)。如此迭代下去,直至 L ( x i ) L(x_i) L(xi)不再减小为止。如果 α \alpha α足够小,不难看出终止条件就是 L ′ ( x i ) = 0 L'(x_i) = 0 L(xi)=0
常见问题:

  1. 病态:输入的轻微改动(比如四舍五入)导致输出的巨大变化
  2. 局部极小值:非凸问题常常有多个局部最优,梯度下降法作为一种“短视”算法,只能找到局部最优解。
  3. 鞍点和高原点:如果问题是非凸的,那么使用一阶导数还不够,然而使用二阶的牛顿法很可能会陷入“鞍点”。高维环境中鞍点激增,导致二阶的牛顿法无法成功取代梯度法。
  4. 悬崖和梯度爆炸、梯度消失

2. 梯度下降法

2.1 普通梯度法

如果我们知道目标函数的表达式和梯度公式,那么可以用普通梯度法。
普通的梯度下降法W -= V中,每次W的更新量V为V = dW * λ;在指数加权迭代训练中为了修正初始值(为0)的的影响,需要做一个偏差修正(除以1-β^t)。
令L为优化函数,LG为函数的导数,x为初始值,delta为步长,tol为精度,则梯度下降的代码为

import numpy as np
def GD(L,LG,x,delta,tol):
    print(str(x)+":"+str(L(x)))
    xn = x - delta * LG(x)
    if L(x)>L(xn)+tol:
        GD(L,LG,xn,delta,tol)

求解的例子为min L = ( x 0 − 2 ) 2 + ( x 1 − 1 ) 2 L=(x_0-2)^2+(x_1-1)^2 L=(x02)2+(x11)2,导数为[ 2 ( x 0 − 2 ) , 2 ( x 1 − 1 ) 2(x_0-2),2(x_1-1) 2(x02),2(x11)],初始值为[0,0],不难看出,最优解为0,在[2,1]处取得。代码为:

def L(x):
    return (x[0]-2)*(x[0]-2) + (x[1]-1)*(x[1]-1)

def LG(x):
    return np.array([2*(x[0]-2),2*(x[1]-1)])

GD(L,LG,np.array([0,0]),0.1,0.0001)

结果输出为:

[0 0]:5
[0.4 0.2]:3.2000000000000006
[0.72 0.36]:2.047999999999999
[0.976 0.488]:1.3107199999999999
[1.1808 0.5904]:0.8388607999999999
[1.34464 0.67232]:0.5368709119999999
[1.475712 0.737856]:0.34359738367999987
[1.5805696 0.7902848]:0.21990232555519995
[1.66445568 0.83222784]:0.1407374883553279
[1.73156454 0.86578227]:0.09007199254740988
[1.78525164 0.89262582]:0.05764607523034231
[1.82820131 0.91410065]:0.03689348814741904
[1.86256105 0.93128052]:0.023611832414348215
[1.89004884 0.94502442]:0.015111572745182858
[1.91203907 0.95601953]:0.009671406556917048
[1.92963126 0.96481563]:0.006189700196426927
[1.943705  0.9718525]:0.003961408125713221
[1.954964 0.977482]:0.0025353012004564663
[1.9639712 0.9819856]:0.0016225927682921462
[1.97117696 0.98558848]:0.0010384593717069706
[1.97694157 0.98847078]:0.0006646139978924637
[1.98155326 0.99077663]:0.00042535295865118083
[1.9852426 0.9926213]:0.00027222589353675247

停止迭代时,最优值为0.00027222589353675247,在[1.9852426 0.9926213]处取得,离最优点[2,1]很接近了。

2.2 批量梯度法

如果我们不知道梯度公式,那么可以用批量数据来计算梯度。有如下几种方法:

  • 全量梯度下降法BGD:每次使用所有训练集: v = - lr * dx,x = x + v
  • 随机梯度下降SGD:有放回抽取小批量样本进行计算,方差比较大,损失函数会出现跳跃波动。
  • 小批量梯度下降(MBGD):有放回抽取m个小批量样本进行计算,然后取平均值。

全量梯度下降法计算量比较大,我们可以改用SGD,把这些数据拆分成小批小批的, 然后再分批不断放入 NN 中计算, 这就是我们常说的 SGD 的正确打开方式了。每次使用批数据, 虽然不能反映整体数据的情况, 不过却很大程度上加速了 NN 的训练过程, 而且也不会丢失太多准确率。
如下图所示,红色的线是 SGD, 它到达学习目标的时间是在这些方法中最长的一种,我们 有很多其他的途径来加速训练。
在这里插入图片描述

3. 动量类算法

3.1 基础动量算法

固定步长的梯度下降法有很多潜在的问题,首先说一个反复震荡的问题。
在这里插入图片描述
当某个函数在 x 1 x_1 x1轴上是二次函数,在 x 2 x_2 x2轴上是缓慢下降的一次函数时,梯度下降法会不停的在 x 1 x_1 x1轴上震荡。我们来看例子:

def L(x):
    return (x[0]-2)*(x[0]-2) + abs(x[1])

def LG(x):
    if x[1]>0:
        return np.array([2*(x[0]-2),1)])
    else:
        return np.array([2*(x[0]-2),-1)])
%matplotlib inline
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import pyplot as plt
 
fig = plt.figure()
ax = Axes3D(fig)
x1=np.linspace(0,4,50)
x2=np.linspace(-2,2,50)
X1, X2 = np.meshgrid(x1, x2)
Z=L((X1,X2))
plt.xlabel('x1')
plt.ylabel('x2')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow')
plt.show()

在这里插入图片描述

这里引入动量的概念,即将过往的梯度以一定的折扣率加入本次的梯度中,减少不断正负变化的梯度导致的震荡问题。代码如下:

import numpy as np
def MOMENTUM(L,LG,x,delta,discount,tol):
    pre_g = np.zeros_like(x)
    xn = x - delta * LG(x)
    while L(x)>L(xn)+tol:
        print(str(x)+":"+str(L(x)))
        x = xn
        pre_g = delta * LG(x) + pre_g * discount
        xn = x - pre_g

在这里插入图片描述

3.2 AdaGrad

这种方法是在学习率上面动手脚, 使得每一个参数更新都会有自己与众不同的学习率, 他的作用和 momentum 类似, 不过不是给喝醉酒的人安排另一个下坡, 而是给他一双不好走路的鞋子, 使得他一摇晃着走路就脚疼, 鞋子成为了走弯路的阻力, 逼着他往前直着走。他的数学形式是这样的:
在这里插入图片描述
AdaGrad:缩放每个参数反比于所有梯度历史平方和的平方根
G = G + g 2 G = G + g^2 G=G+g2
w = w − g ∗ α / G w = w - g*α/\sqrt{G} w=wgα/G
由于 G G G是累积量,所以会出现梯度消失的现象。

3.3 RMSProp

把下坡和不好走路的鞋子合并起来, 是不是更好呢? 没错, 这样我们就有了 RMSProp 更新方法。有了 momentum 的惯性原则 , 加上 adagrad 的对错误方向的阻力, 我们就能合并成这样,让 RMSProp同时具备他们两种方法的优势。
注意,RMSProp的惯性原则加在了阻力上。
在这里插入图片描述
RMSProp:累计梯度平方和计算使用移动平均,将AdaGrad中G的计算改为使用移动平均:
G = β ∗ G + ( 1 − β ) ∗ g 2 G = β*G+(1-β)*g^2 G=βG+(1β)g2
w = w − g ∗ α / G w = w - g*α/\sqrt{G} w=wgα/G

3.4 Adam 更新方法

在这里插入图片描述
Adam: Adaptive moments, 在缩放后的梯度基础上加上动量(即Momemtum+RMSProp),并对动量和动量导数进行偏置修正(除以 1 − β t 1-β^t 1βt)。
与RMSPromp不同的是,惯性原则加在了梯度上。

计算m 时有 momentum 下坡的属性, 计算 v 时有 adagrad 阻力的属性, 然后再更新参数时 把 m 和 V 都考虑进去. 实验证明, 大多数时候, 使用 adam 都能又快又好的达到目标, 迅速收敛. 所以说, 在加速神经网络训练的时候, 一个下坡, 一双破鞋子, 功不可没.

3.5 Nesterov

Nesterov方法有一些新的变化,差别主要在于先使用上一轮的梯度(带折扣)计算优化后的点大致在什么位置(代码中的xf),然后在新的位置上计算梯度并在原位置(x)进行更新得到新的位置(xn)。动量折扣率discount一般设置为0.9。
与Momentum唯一区别就是,计算梯度的不同,Nesterov先用当前的速度v更新一遍参数,在用更新的临时参数计算梯度。相当于添加了矫正因子的Momentum。
在GD下,Nesterov将误差收敛从O(1/k),改进到O(1/k^2),然而在SGD下,Nesterov并没有任何改进。

Nesterov代码如下:

import numpy as np
def NESTEROV(L,LG,x,delta,discount,tol):
    pre_g = np.zeros_like(x)
    xn = x - delta * LG(x)
    while L(x)>L(xn)+tol:
        print(str(x)+":"+str(L(x)))
        x = xn
        xf = x - pre_g * discount * delta
        pre_g = LG(xf) + pre_g * discount
        xn = x - pre_g * delta

5. 自然梯度法

同样是上面提到的问题,自然梯度法的处理思路是:将参数改进修改为模型改进。
使用KL散度来定义概率模型之间的距离: K L ( f ( x ; θ 1 ) , f ( x ; θ 2 ) ) KL(f(x;\theta_1),f(x;\theta_2)) KL(f(x;θ1),f(x;θ2)),则每一步的约束条件由 ∣ Δ ∣ < ϵ |\Delta|<\epsilon Δ<ϵ变为KL ( f ( w ) , f ( w + Δ ) ) < ϵ (f(w),f(w+\Delta))<\epsilon (f(w),f(w+Δ))<ϵ
这里使用近似公式:KL ( f ( w ) , f ( w + Δ ) ) ≃ 0.5 Δ T F Δ (f(w),f(w+\Delta)) \simeq 0.5\Delta^T F \Delta (f(w),f(w+Δ))0.5ΔTFΔ,其中 F = E ( l l T ) F = E(ll^T) F=E(llT)称为Fisher信息矩阵, l = ∇ l o g f ( x ; w ) l = \nabla logf(x;w) l=logf(x;w)称为Score函数。
将约束条件替换掉之后,并使用拉格朗日乘子法求极值,得到 Δ = − F − 1 ∇ / λ \Delta = -F^{-1}\nabla/\lambda Δ=F1/λ
与原先的 − ∇ -\nabla 相比,多了一个Fisher阵的逆和一个系数。

6. 共轭梯度法

共轭梯度法又叫Powell方法。首先定义共轭方向:
如果对任意 i , j i,j ij S i T A S j = 0 S_i^TAS_j=0 SiTASj=0,则称 S S S关于A共轭。
共轭方向法非常像坐标轮换法,在每一个坐标上依次取到最优值。可以证明,对于正定二次函数 c + b x + x T A x / 2 c+bx+x^TAx/2 c+bx+xTAx/2,每次优化一个坐标轴,一个迭代之内便可以收敛到极小值。
对于非二次的目标函数,迭代次数不一定保证有限,但是二次函数仍然是一个很好的近似。
使用正交化方法得到初始的共轭梯度。在搜索过程中,共轭性质可能会消失,需要对共轭向量不断修改。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值