JavaScript DOM
常見優化器SGD-NadaMax
轉載https://zhuanlan.zhihu.com/p/81020717
- SGD
- Momentum
- Nesterov Momentum
- AdaGrad
- RMSProp
- AdaDelta
- Adam
- AdaMax
- Nadam
- NadaMax
SGD
隨機梯度下降演算法,最常用地mSGD,小批量隨機梯度下降求解引數。
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)
公式:
Nesterov Momentum
思想:Nesterov先用當前的速度v_{i}更新一遍引數,得到一個臨時引數 w_{x},然後使用這個臨時引數計算本輪訓練的梯度
公式:
程式碼
AdaGrad
adaptive subgradient,主要特點是不斷累加每次訓練中梯度地平方
公式:
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}的計算不同
公式:
思想 ;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}來累積梯度的資訊之外,該演算法還多了一個 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
公式
思想:可以看作是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
公式
思想 :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組合到一起
公式:
程式碼
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
公式:
程式碼
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