美文网首页程序员
机器学习中的几大优化方法

机器学习中的几大优化方法

作者: chiiyu | 来源:发表于2020-07-17 08:44 被阅读0次

python 机器学习 文献学习 原创demo 谢绝转载

  1. Momentum
    借用了物理学中动量的概念,在更新梯度时引入了历史平均动量g_{t}
    \theta_{t} = \theta_{t-1}-\eta g_{t}
    其中\theta为模型参数,\eta为学习率。g_t递归计算公式为
    g_t = \lambda g_{t-1} + (1-\lambda)\nabla L(\theta)
    其中,L为损失函数,\lambda为衰减系数,\lambda\in(0,1)
    带动量的梯度下降法,相比于传统方法的一大优点是可以有效避免振荡。一个典型的例子就是向下倾斜的峡谷型表面。
    Momentum.jpg
  1. NAG
    内斯特洛夫加速梯度,更新公式类似动量下降,区别是在平均梯度下降方向的递推公式
    g_t = \lambda g_{t-1} + (1-\lambda)\nabla L(\theta-\eta\lambda g_{t-1} )
    可以发现等式右边第二项的梯度方向不再是由当前位置计算得到,而是变为依第一项的方向移动后的“预计位置”计算得到。直觉上,通过这种方法修正过的梯度方向对更新结果是有“预见性”的。而事实上,在一些情况中(例如在更新轨迹上损失函数经历先减后增的情况),内斯特洛夫加速梯度确实能够加速收敛。
    NAG.jpg
  1. Adagrad
    即自适应性梯度下降法,该方法能够平衡最大梯度方向的不同分量之间差异,使得参数过程更为稳定。Adagrad相较前几种优化,引入了历史梯度平方和作为衰减因子。具体地,每一步的更新方向由下式决定
    g_t = (G_t+\epsilon)^{-1/2}\odot \nabla L(\theta_{t-1})
    其中G_t=G_{t-1}+diag\{ [\nabla L(\theta_{t-1})]^2\}. 以上公式运算均为element-wise. 有一种说法是Adagrad能够惩罚高频分量,补偿低频分量,从而提高学习效率。

  2. Adadelta (RMSprop)
    是Adagrad的一个直接改进,将历史梯度平方和替换为历史平均平方和,且引入了根据参数尺度决定各分量步长的学习机制。首先,每一步的更新方向由下式决定
    g_t = (\bar{G}_t+\epsilon)^{-1/2}\odot \nabla L(\theta_{t-1})
    其中\bar{G}_t=\lambda G_{t-1}+(1-\lambda)(diag\{ [\nabla L(\theta_{t-1})]^2\}+\epsilon). 容易看出,如此改进可以一定程度解决历史求和导致学习速率衰减过快的问题。其次,关于学习率\eta不再是标量化的统一学习速率,而是改为由下式确定
    \eta_{t}=\lambda \eta_{t-1}+(1-\lambda)(diag\{\Delta\theta_t^2\}+\epsilon)
    其中,\Delta\theta_t = \eta_{t-1}g_t. 更新公式则变为
    \theta_t = \theta_{t-1} - \eta_{t-1} g_t

    Adagrad_Adadelta.jpg
  3. Adam
    即Adaptive Moment Estimation. 类似动量梯度下降的思路,结合了以上方法的优点,引入了两种历史平均动量
    \begin{aligned} m_t &= \lambda_1m_{t-1} + (1-\lambda_1)\nabla L(\theta_{t-1})\\ v_t &= \lambda_1v_{t-1} + (1-\lambda_2)\nabla [L(\theta_{t-1})]^2 \end{aligned}
    更新公式变为
    \theta_t = \theta_{t-1} - \frac{\eta}{\sqrt{\hat{v}_t}+\epsilon} \hat{m}_t
    其中\hat{m_t}=m_t/(1-\lambda_1), \hat{v_t}=v_t/(1-\lambda_2). 是针对初始化时m_0,v_0\approx0作出的修正。

理论和公式部分参考论文(强烈推荐):
An overview of gradient descent optimization algorithms

个人示例源代码(setting):

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def link_points(xs,ys,num=20):
    assert xs.shape == ys.shape
    tempx = []
    tempy = []
    for i in range(len(xs)-1):
        tempx.append(np.linspace(xs[i],xs[i+1],num))
        tempy.append(np.linspace(ys[i],ys[i+1],num))
    return np.hstack(tempx),np.hstack(tempy)

def get_trail(x_init,y_init,steps=100,lr=.1,method="sgd",alpha=.9,epsilon=10**-3):
    xs = np.zeros((steps+1,))
    ys = np.zeros((steps+1,))
    xs[0],ys[0] = x_init,y_init
    if method == "sgd":
        for i in range(1,steps+1):
            grad_x,grad_y = get_grad(xs[i-1],ys[i-1])
            xs[i] = xs[i-1]-lr*grad_x
            ys[i] = ys[i-1]-lr*grad_y 
    if method == "mom":
        moms = np.zeros((steps+1,2))
        for i in range(1,steps+1):
            grad_x,grad_y = get_grad(xs[i-1],ys[i-1])
            moms[i] = alpha*moms[i-1]+(1-alpha)*np.array([grad_x,grad_y])
            xs[i] = xs[i-1]-lr*moms[i,0]
            ys[i] = ys[i-1]-lr*moms[i,1]
    if method == "nag":
        moms = np.zeros((steps+1,2))
        for i in range(1,steps+1):
            grad_x,grad_y = get_grad(xs[i-1]-alpha*moms[i-1,0],ys[i-1]-alpha*moms[i-1,1])
            moms[i] = alpha*moms[i-1]+(1-alpha)*np.array([grad_x,grad_y])
            xs[i] = xs[i-1]-lr*moms[i,0]
            ys[i] = ys[i-1]-lr*moms[i,1]
    if method == "adagrad":
        rss = np.zeros((steps+1,2))
        rss[0] = epsilon*np.ones((2,))
        for i in range(1,steps+1):
            grad_x,grad_y = get_grad(xs[i-1],ys[i-1])
            rss[i] = rss[i-1]+np.array([grad_x,grad_y])**2
            xs[i] = xs[i-1]-lr*(rss[i,0])**(-1/2)*grad_x
            ys[i] = ys[i-1]-lr*(rss[i,1])**(-1/2)*grad_y
    if method == "adadelta":
        rss = np.zeros((steps+1,2))
        rss[0] = epsilon*np.ones((2,))
        eta = np.zeros((steps+1,2))
        eta[0] = epsilon*np.ones((2,))
        for i in range(1,steps+1):
            grad_x,grad_y = get_grad(xs[i-1],ys[i-1])
            rss[i] = alpha*rss[i-1]+(1-alpha)*(np.array([grad_x,grad_y])**2+epsilon)
            delta = (eta[i-1]/rss[i])**(1/2)*np.array([grad_x,grad_y])
            eta[i] = alpha*eta[i-1]+(1-alpha)*delta**2
            xs[i] = xs[i-1]-delta[0]
            ys[i] = ys[i-1]-delta[1]
    return link_points(xs,ys)

def skate_ramp(X,Y):
    return 9.9*X**2+100-Y
def get_grad(x,y):
    return 19.8*x,-1

相关文章

网友评论

    本文标题:机器学习中的几大优化方法

    本文链接:https://www.haomeiwen.com/subject/tcpuhktx.html