1. 程式人生 > 實用技巧 >JavaScript DOM

JavaScript DOM

技術標籤:機器學習機器學習演算法

常見優化器SGD-NadaMax

轉載https://zhuanlan.zhihu.com/p/81020717

  • SGD
  • Momentum
  • Nesterov Momentum
  • AdaGrad
  • RMSProp
  • AdaDelta
  • Adam
  • AdaMax
  • Nadam
  • NadaMax

SGD

隨機梯度下降演算法,最常用地mSGD,小批量隨機梯度下降求解引數。

\Delta W = -\eta *J(W)

\Delta W = -\eta*g_i

g_i = \frac{1}{m} \sum_{i}^{m} J_i(w)

Momentum

動量梯度下降演算法

程式碼

import numpy as np  
class Momentum(object):
    def __init__(self,alpha=0.0,lr=1e-3):
        self.alpha = alpha 
        self.lr = lr 
        self.v = 0 
    def update(self,g:np.ndarray):
        self.v = self.alpha*self.v-self.lr*g 
        return self.v 

思想:梯度下降不僅與當前所求梯度有關,還與上次該引數所求梯度有關,按照一定關係合併 (\alpha)

公式:

v_i = \alpha *v_{i-1} +(1-\alpha)*g_{i} \\ \Delta w = -\eta*v_{i}

Nesterov Momentum

思想:Nesterov先用當前的速度v_{i}更新一遍引數,得到一個臨時引數 w_{x},然後使用這個臨時引數計算本輪訓練的梯度

公式:

w_x = w +\alpha v_{i-1} \\ g_{i} = J(w_x) \\ v_{i} = \alpha*v_{i-1} -\eta*g_{i} \\ w = w+v_{i}

程式碼

AdaGrad

adaptive subgradient,主要特點是不斷累加每次訓練中梯度地平方

公式:

r_{i} = r_{i-1} +g_{i}^2 \\\ \Delta w = -\frac{\eta}{\varepsilon +\sqrt(r_{i})} * g_{i} \\\ w = w+\Delta

g_{i}^2 表示地是 矩陣地哈達瑪積

思想:隨著演算法迭代,r會越來越大,整體地學習率會越來越小,故一開始是激勵收斂,後面變成懲罰收斂。

程式碼:

class AdaGrad(object):
    def __init__(self, eps=1e-8, lr=1e-3):
        self.r = eps    # r_0 = epsilon
        self.lr = lr

    def update(self, g: np.ndarray):
        r = r + np.square(g)
        return -self.lr * g / np.sqrt(r)

RMSProp

RMSProp是AdaGrad的改進演算法,其公式和AdaGrad的區別只有 r_{i}的計算不同

公式:

r_{i} = \beta * r_{i-1} +(1-\beta)*g_{i}^2 \\\ \Delta = -\frac{\eta}{\varepsilon +\sqrt(r_{i})} * g_{i} \\\ w = w+\Delta w

思想 ;RMSProp只會累積近期的梯度資訊,對於“遙遠的歷史”會以指數衰減的形式放棄,AdaGrad演算法雖然在凸函式(Convex Functions)上表現較好,但是當目標函式非凸時,演算法梯度下降的軌跡所經歷的結構會複雜的多,早期梯度對當前訓練沒有太多意義。

程式碼

class RMSProp(object):
    def __init__(self,lr=1e-3,beta=0.999,eps=1e-8):
        self.r = eps 
        self.lr = lr 
        self.beta = beta 
    def update(self,g:np.bdarray):
        r =r*self.beta+(1-self.beta)*np.square(g) 
        return -self.lr*g/np.sqrt(r) 

AdaDelta

AdaDelta是與RMSProp相同時間對立發展出來的一個演算法

公式:

r_{i} = \beta*r_{i-1} +(1-\beta)g_{i}^2 \\ \Delta w = -\frac{sqrt(\varepsilon +s_{i-1})}{\sqrt{\varepsilon +r_[I]}} *g_{i} \\\\ s_{i} = \beta*s_{i-1} +(1-\beta) \Delta w^2 \\ w = w+\Delta w

思想:演算法不需要設定學習率,同樣以 r_{i}來累積梯度的資訊之外,該演算法還多了一個 s_{i}以指數衰減的形式來累積 \Delta w的資訊

初始化r,s最小值

程式碼

class AdaDelta(object):
    def __init__ (self,beta=0.999,eps = 1e-8):
        self.r =eps 
        self.s = eps 
        self.beta = beta 
    def update(self,g:np.ndarray):
        g_square = (1-self.beta)*np.square(g) 
        r =r * self.beta+g_square 
        frac = s/r 
        res = -np.sqrt(frac) *g 
        s = s*self.beta+frac*g_squeare 
        return res 

Adam

Adam的名稱來自Adaptive Momentum

公式s_{i} = \alpha * s_{i-1} +(1-\alpha) *g_{i} \\\ r_{i} \beta*r_{i-1} +(1-\beta)*g_{i}^2 \\ s_{ix} = \frac{s_{i}}{1-\alpha^{i}} \\ r_{ix} = \frac{r_{i}}{1-\beta^i} \\ \Delta w = - \eta* \frac{s_{ix}}{\sqrt(r_ix +\varepsilon)} \\ w = w +\Delta w

思想:可以看作是Momentum與RMSProp的一個結合體,該演算法通過計算梯度的一階矩估計和二階矩估計而為不同的引數設計獨立的自適應性學習率

程式碼:

class Adam(object):
    def __init__(self, lr=1e-3, alpha=0.9, beta=0.999, eps=1e-8):
        self.s = 0
        self.r = eps
        self.lr = lr
        self.alpha = alpha
        self.beta = beta
        self.alpha_i = 1
        self.beta_i = 1

    def update(self, g: np.ndarray):
        self.s = self.s * self.alpha + (1-self.alpha) * g
        self.r = self.r * self.beta + (1-self.beta) * np.square(g)
        self.alpha_i *= self.alpha
        self.beta_i *= self.beta_i
        lr = -self.lr * (1-self.beta_i)**0.5 / (1-self.alpha_i)
        return lr * self.s / np.sqrt(self.r)

AdaMax

公式

s_{i} = \alpha*s_{i-1} +(1-\alpha)*g_i \\ s_{ix} = \frac{s_i}{1-\alpha^i} \\ r_{i} = max(\beta*r_{i-1},|g_{i}|) \\ \Delta = - \eta * \frac{s_{ix}}{r_{i}} \\ w = w +\Delta w

思想 :max比較的是梯度各個維度上的當前值和歷史最大值

w的各維度的增量是根據該維度上梯度的 L_2範數的累積量進行縮放的。如果用 L_p範數替代就得到了Adam的不同變種,不過其中 L_p範數對應的變種演算法簡單且穩定

程式碼

class AdaMax(object):
    def __init__(self, lr=1e-3, alpha=0.9, beta=0.999):
        self.s = 0
        self.r = 0
        self.lr = lr
        self.alpha = alpha
        self.alpha_i = 1
        self.beta = beta

    def update(self, g: np.ndarray):
        self.s = self.s * self.alpha + (1-self.alpha) * g
        self.r = np.maximum(self.r*self.beta, np.abs(g))
        self.alpha_i *= self.alpha
        lr = -self.lr / (1-self.alpha_i)
        return lr * self.s / self.r

Nadam

思想:Adam可以看作是Momentum與RMSProp的結合,既然Nesterov的表現較Momentum更優,那麼自然也就可以把Nesterov Momentum與RMSProp組合到一起

公式:
s_{i} = \alpha*s_{i-1} +(1-\alpha)g_i \\ r_i = \beta*r_{i-1} +(1-\beta)*g_i^2 \\ s_{ix} = \frac{s_i}{1-\alpha^i} \\ r_{ix} = \frac{r_i}{1-\beta^i} \\ \Delta = - \frac{\eta}{sqrt(r_{ix}+\varepsilon )}*(\alpha*s_{ix} +\frac{(1-\alpha)*g_i}{1-\alpha^i})

程式碼

class Nadam(object):
    def __init__(self, lr=1e-3, alpha=0.9, beta=0.999, eps=1e-8):
        self.s = 0
        self.r = eps
        self.lr = lr
        self.alpha = alpha
        self.beta = beta
        self.alpha_i = 1
        self.beta_i = 1

    def update(self, g: np.ndarray):
        self.s = self.s * self.alpha + (1-self.alpha) * g
        self.r = self.r * self.beta + (1-self.beta) * np.square(g)
        self.alpha_i *= self.alpha
        self.beta_i *= self.beta_i
        lr = -self.lr * (1-self.beta_i)**0.5 / (1-self.alpha_i)
        return lr * (self.s * self.alpha + (1-self.alpha) * g) / np.sqrt(self.r) 

NadaMax

思想:Nesterov與AdaMax結合變成NadaMax

公式:

s_i = \alpha*s_{i-1} +(1-\alpha)g_i \\ r_i = max(\beta*r_(i-1),|g_i|) \\ s_{ix} = \frac{s_i}{1-\alpha^i} \Delta = - \frac{\eta}{1-\alpha^i}*\frac{1}{r_i}(\alpha*s_i +(1-\alpha)*g_i)

程式碼

class NadaMax(object):
    def __init__(self, lr=1e-3, alpha=0.9, beta=0.999):
        self.s = 0
        self.r = 0
        self.lr = lr
        self.alpha = alpha
        self.alpha_i = 1
        self.beta = beta

    def update(self, g: np.ndarray):
        self.s = self.s * self.alpha + (1-self.alpha) * g
        self.r = np.maximum(self.r*self.beta, np.abs(g))
        self.alpha_i *= self.alpha
        lr = -self.lr / (1-self.alpha_i)
        return lr * (self.s * self.alpha + (1-self.alpha) * g) / self.r

參考資料

[1]: 《機器學習演算法背後的理論與優化》 ISBN 978-7-302-51718-4

[2]:Adam: A Method for Stochastic Optimization

[3]:Incorporating Nesterov Momentum into Adam

[4]:An overview of gradient descent optimization algorithms