模型优化-动量方法

动量梯度下降(Gradient Descent With Momentum),简称为动量方法(Momentum),运行速度几乎总是快于标准的梯度下降算法,并且能够解决随机梯度下降所遇到的山谷震荡以及鞍部停滞问题,这部分内容请阅读上一篇博客梯度下降算法。

根据梯度下降算法的参数更新公式:
w = w − η ∂ L ( w ) ∂ w w = w - \eta\frac{\partial L(w)}{\partial w} w=wηwL(w)
参数的更新仅仅取决于当前位置的梯度以及步长,试想一下这样一个情境:我们将某一个物品往山谷里丢,在梯度下降算法的规则下,该物品仅仅收到当前触碰在它身上的力,而忽略其他的力,例如重力、空气阻力等等。我们可以把它想象成一张纸团。

  • 山谷:在山谷中不可避免地撞在山壁,由于质量小受山壁弹力的干扰大,从一侧山壁反弹回来撞向另一侧山壁,结果来回震荡地滚下。
  • 鞍部:纸团来到鞍部时,由于质量小,速度很快减为零,无法冲出鞍部区域。

如果此时,该物品拥有了大质量,例如是一个铁球,

  • 山谷:那么它沿着山谷滚下时,就不容易受到途中旁力的干扰,轨迹会更稳更直。
  • 鞍部:在惯性的作用下继续滚动,从而有机会冲出鞍部。

在中学物理中,刻画惯性的物理量是动量,这也是该算法名字的由来。沿山谷滚下的铁球会收到沿坡道向下的力和与左右山壁碰撞的弹力。向下的力(重力)稳定不变,产生的动量不断累积,速度越来越快;左右的弹力总是在不停切换,动量累积的结果是相互抵消,减弱了球的来回震荡。因此,与随机梯度下降相比,动量方法的收敛速度更快,收敛曲线也更稳定,见下图。

模型优化-动量方法_第1张图片

相比标准的梯度下降算法,动量梯度下降是算法将动量纳入了参数更新公式中。

【计算公式】:
v t = γ v t − 1 + η ∂ L ( w ) ∂ w w = w − v t v_t = \gamma v_{t-1} + \eta \frac{\partial L(w)}{\partial w} \quad w = w - v_t vt=γvt1+ηwL(w)w=wvt
其中,KaTeX parse error: Expected 'EOF', got '\gammda' at position 1: \̲g̲a̲m̲m̲d̲a̲ 是衰减系数,扮演阻力的作用。前进步伐 v t v_t vt 由两部分组成:

  • 标准的梯度下降算法部分,也就是步长乘上当前位置的梯度: η ∂ L ( w ) ∂ w \eta \frac{\partial L(w)}{\partial w} ηwL(w)
  • 带衰减的前一次步伐 v t − 1 v_{t-1} vt1

在该公式中,惯性就体现在对前一次步伐信息的利用。类比中学物理知识,当前梯度就好比当前时刻受力产生的加速度,而步长则是时间,前一次步伐好比前一时刻的速度。标准梯度下降算法在每次行动时,都忽略前一时刻的速度,而重新根据当前时刻的加速度和时间来行走,因此当加速度趋于零时就很难继续移动。而动量方法则考虑前一时刻速度和当前加速度的共同作用。

不同的文献对于动量方法的计算公式也略有不同,吴恩达老师推荐使用下述的计算公式。
v t = β v t − 1 + ( 1 − β ) ∂ L ( w ) ∂ w w = w − η v t v_t = \beta v_{t-1} + (1 - \beta)\frac{\partial L(w)}{\partial w} \\ w = w - \eta v_t vt=βvt1+(1β)wL(w)w=wηvt
至于孰优孰劣暂无定论,大家可各按喜好进行选择。

动量方法可以嵌入到标准的梯度下降算法中,例如使用动量的随机梯度下降、使用动量的批量梯度下降等等。无论对哪个梯度下降算法,加入动量后都可以加快收敛速度。对于随机梯度下降而言,还可以在一定程度上解决鞍部停滞问题。

【代码实现】:

def BatchGradientDescentM(x, y, step=0.001, iter_count=500, beta=0.9):
    length, features = x.shape
    
    # 初始化参数和动量以及整合 x'
    data = np.column_stack((x, np.ones((length, 1))))
    w = np.zeros((features + 1, 1))
    v = np.zeros((features + 1, 1))
    
    # 开始迭代
    for i in range(iter_count):
        # 计算动量
        v = (beta * v + (1 - beta) * np.sum((np.dot(data, w) - y) * data, axis=0).reshape((features + 1, 1))) / length    
        # 更新参数
        w -= step * v        
    return w

同样,增量方法也可以嵌入到小批量梯度下降以及随机梯度下降算法中,具体代码请参考 传送门

我们也可以将这些算法都整合到一块,通过 batch_size 的大小来判断是批量梯度下降算法,还是随机梯度下降算法。

【代码实现】:

def Momentum(x, y, step=0.01, iter_count=1000, batch_size=4, beta=0.9):
    length, features = x.shape
    
    # 初始化参数和动量以及整合 x'
    data = np.column_stack((x, np.ones((length, 1))))
    w = np.zeros((features + 1, 1))
    v = np.zeros((features + 1, 1))
    start, end = 0, batch_size
    
    # 开始迭代
    for i in range(iter_count):
        v = (beta * v + (1 - beta) * np.sum((np.dot(data[start:end], w) - y[start:end]) * data[start:end], axis=0).reshape((features + 1, 1))) / length         
        w -= step * v
        start = (start + batch_size) % length
        if start > length:
            start -= length
        end = (end + batch_size) % length
        if end > length:
            end -= length
    return w
    

# 批量梯度下降
print(Momentum(x, y, batch_size=(x.shape[0] - 1)))
# 输出:
array([[5.00311478],
       [0.8307453 ]])
       
# 小批量梯度下降
Momentum(x, y, batch_size=5)
# 输出:
array([[4.98144568],
       [1.43164128]])
       
# 随机梯度下降
Momentum(x, y, batch_size=1)
# 输出:
array([[4.99294353],
       [0.83128473]])

牛顿动量

受 Nesterov 加速梯度算法启发,Sutskever 提出动量方法的一个变种。与 Momentum 不同的是,Nesterov 先用当前的速度更新参数,再用更新后的临时参数计算梯度。

【代码实现】:

def Nesterov(x, y, step=0.01, iter_count=1000, batch_size=4, beta=0.9):
    length, features = x.shape
    data = np.column_stack((x, np.ones((length, 1))))
    w = np.zeros((features + 1, 1))
    v = np.zeros((features + 1, 1))
    start, end = 0, batch_size
    for i in range(iter_count):
        # 先更新参数
        w_temp = w - step * v
        # 再计算梯度与速度
        v = (beta * v + (1 - beta) * np.sum((np.dot(data[start:end], w_temp) - y[start:end]) * data[start:end], axis=0).reshape((features + 1, 1))) / length         
        w -= step * v
        start = (start + batch_size) % length
        if start > length:
            start -= length
        end = (end + batch_size) % length
        if end > length:
            end -= length
    return w

牛顿增量相当于添加了矫正因子的 Momentum 方法,在批量梯度下降算法中能进一步缩小误差,但对于随机梯度下降而言,牛顿增量没有任何改进。

参考

  • 吴恩达老师的深度学习课程
  • 《百面机器学习》- 深度学习中的动量
  • 深度学习中的动量:https://blog.csdn.net/qq_29462849/article/details/80625063
    • Deep Learning 最优化方法之Nesterov(牛顿动量):https://blog.csdn.net/bvl10101111/article/details/72615961

你可能感兴趣的:(机器学习)