深度學習中各類優化器的選擇總結
Batch gradient descent
每次更新我們需要計算整個資料集的梯度,因此使用批量梯度下降進行優化時,計算速度很慢,而且對於不適合記憶體計算的資料將會非常棘手。批量梯度下降演算法不允許我們實時更新模型。
但是批量梯度下降演算法能確保收斂到凸平面的全域性最優和非凸平面的區域性最優。
SGD(Stochastic gradient descent)
隨機梯度下降演算法引數更新針對每一個樣本集x(i) 和y(i) 。批量梯度下降演算法在大資料量時會產生大量的冗餘計算,比如:每次針對相似樣本都會重新計算。這種情況時,SGD演算法每次則只更新一次。因此SGD演算法通過更快,並且適合online。
但是SGD以高方差進行快速更新,這會導致目標函數出現嚴重抖動的情況。一方面,正是因為計算的抖動可以讓梯度計算跳出區域性最優,最終到達一個更好的最優點;另一方面,SGD演算法也會因此產生過調。
Min-batch gradient descent
該演算法有兩個好處,1):減少了引數更新的變化,這可以帶來更加穩定的收斂。2:可以充分利用矩陣優化,最終計算更加高效。但是Min-batch梯度下降不保證好的收斂性。
Batch gradient descent、SGD、min-batch gradient descent演算法都需要預先設定學習率,並且整個模型計算過程中都採用相同的學習率進行計算。這將會帶來一些問題,比如
1):選擇一個合適的學習率是非常困難的事情。學習率較小,收斂速度將會非常慢;而學習率較大時,收斂過程將會變得非常抖動,而且有可能不能收斂到最優。
2):預先制定學習率變化規則。比如,計算30輪之後,學習率減半。但是這種方式需要預先定義學習率變化的規則,而規則的準確率在訓練過程中並不能保證。
3):上述三種演算法針對所有資料採用相同的學習速率,但是當我們的資料非常稀疏的時候,我們可能不希望所有資料都以相同的方式進行梯度更新,而是對這種極少的特徵進行一次大的更新。
4):高度非凸函式普遍出現在神經網路中,在優化這類函式時,另一個關鍵的挑戰是使函式避免陷入無數次優的區域性最小值。
Momentum
動量可以加速SGD演算法的收斂速度,並且降低SGD演算法收斂時的震盪。
通過新增一個衰減因子到歷史更新向量,並加上當前的更新向量。當梯度保持相同方向時,動量因子加速引數更新;而梯度方向改變時,動量因子能降低梯度的更新速度。
NAG(Nesterov accelerated gradient)
滾雪球遊戲中,我們希望有一個智慧的雪球,它能夠預知運動的方向,以至於當它再次遇到斜坡的時候會減慢速度。我們可以通過計算來漸進估計下一個位置的引數(梯度並不是完全更新),即為
Adagrad
Adagrad優化演算法是一種自適應優化演算法,針對高頻特徵更新步長較小,而低頻特徵更新較大。因此該演算法適合應用在特徵稀疏的場景。
先前的演算法對每一次引數更新都是採用同一個學習率,而adagrad演算法每一步採用不同的學習率進行更新。我們計算梯度的公式如下:
SGD演算法進行引數更新的公式為:
Adagrad演算法在每一步的計算的時候,根據歷史梯度對學習率進行修改
這裡G是一個對角矩陣,對角線元素是截止當前時刻的歷史梯度的平方和,eta是一個平方項。如果不執行均方根操作,演算法的效能將會變得很差。
G包含了針對所有歷史梯度的平方和,因此我們可以用矩陣元素乘的形式來表達上式:
Adagrad演算法的主要優點是它避免了手動調整學習率的麻煩,大部分的實現都採用預設值0.01。
Adagrad演算法主要的缺點在於,其分母梯度平方的累加和。因為每次加入的都是一個正數,隨著訓練的進行,學習率將會變得無限小,此時演算法將不能進行引數的迭代更新。
Adadelta
Adadelta演算法是adagrad演算法的改進版,它主要解決了adagrad演算法單調遞減學習率的問題。通過約束歷史梯度累加來替代累加所有歷史梯度平方。這裡通過在歷史梯度上新增衰減因子,並通過迭代的方式來對當前的梯度進行計算,最終距離較遠的梯度對當前的影響較小,而距離當前時刻較近的梯度對當前梯度的計算影響較大。
通常,我們設定lambda引數為0.9。為了清楚的表達,這裡我們再次列出SGD演算法的計算公式:
而adagrad演算法的計算公式為:
這裡我們簡單的替換對角矩陣G為E(帶衰減的歷史梯度累加)
上式分母正好是均方誤差根(RMS),這裡我們用簡寫來表達:
作者提到引數更新應該有相同的假設,因此我們定義另一個指數衰減平均,這裡採用的是引數更新的平方
因為t時刻,RMS[]項未知,因此我們採用先前的引數RMS對當前時刻進行漸進表示。最終我們有如下表達式:
採用Adadelta演算法作為模型優化器演算法時,我們已經不需要設定預設學習率。
RMSprop
RMSPprop演算法和adadelta演算法都是adagrad演算法的優化版,用於解決adagrad演算法學習率消失的問題,從最終的計算公式來看,RMSProp演算法和Adadelta演算法有相似的計算表示式
Adam
Adam演算法是另一種自適應引數更新演算法。和Adadelta、RMSProp演算法一樣,對歷史平方梯度v(t)乘上一個衰減因子,adam演算法還儲存了一個歷史梯度m(t)。
mt和vt分別是梯度一階矩(均值)和二階矩(方差)。當mt和vt初始化為0向量時,adam的作者發現他們都偏向於0,尤其是在初始化的時候和衰減率很小的時候(例如,beta1和beta2趨近於1時)。
通過計算偏差校正的一階矩和二階矩估計來抵消偏差:
利用上述的公式更新引數,得到adam的更新公式:
AdaMax
Adam演算法對歷史梯度的二範數進行計算
這裡我們可以改為計算曆史梯度的p範數
較大的p,將會使數值計算不穩定,這也是實際中大量使用1範數和2範數的原因。然而,無窮範數則是穩定的。鑑於此,作者提出Adamax演算法,通過計算無窮範數,使矩估計收斂到穩定。為了和adam演算法區分開,這裡用u(t)表示:
替換adam演算法引數更新公式分母,可得:
Nadam
Adam演算法可以看作是RMSProp演算法和Momentum的結合版。RMSProp演算法通過對歷史梯度平方乘上衰減因子來計算v(t),動量則計算曆史梯度。我們知道NAG演算法優於momentum演算法。這裡nadam結合了adam演算法和NAG演算法,為了使用NAG演算法,我們需要修改動量表達式m(t)。
首先,回憶動量更新表示式
將第二項代入第三項中有
從上述分析可知,動量考慮了歷史動量方向和當前梯度方向。NAG演算法通過在梯度計算項中加入歷史動量資訊來達到一個更精確的計算,因此我們修改公式為:
Dozat提出對NAG進行如下修改:不再進行兩次動量計算(一次更新梯度,一次更新引數),而是採用直接更新當前的引數:
注意這裡我們沒有采用前一時刻的動量m(t-1),而是採用當前的動量m(t)。為了加入NGA演算法,我們同樣可以替換先前的動量向量為當前的動量向量。首先,我們回憶adam更新規則
將上式1、2帶入式3中可得
通過使用動量的偏差校正估計,可得
現在我們加入nesterov 動量,採用當前動量的偏差校正估計替換前一時刻動量的偏差校正估計,可得:
總結
當訓練資料特徵較為稀疏的時候,採用自適應的優化器通常能獲得更好的效能,而且我們採用自適應優化器的預設值即可獲得較優的效能。
RMSprop演算法是adagrad演算法的優化版,它解決了學習率趨近於零的問題。Adadelta演算法和RMSprop演算法類似,區別在於Adadelta用引數的RMS作為更新規則的分子。最後,Adam則是在RMSprop的基礎上加入了偏差校正和動量。綜上來看,Adam可能是最佳的選擇。
最近很多paper都採用不帶動量的SGD演算法,輔助一些簡單的學習率退火策略。如上所述,SGD演算法能夠找到極小值,但是比其他優化器花費的時間更多。和其他演算法相比,SGD演算法更加依賴於初始化引數的設定和退火策略,而且SGD演算法更加容易陷入鞍點。所以,如果你想模型更快的收斂或者訓練一個深層次、複雜度較高的網路,自適應的優化器應該是首選優化器。
參考文獻
作者:lirainbow0
連結:https://www.jianshu.com/p/0acd30a23e4e
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。