從 SGD 到 Adam —— 常見優化算法總結


1 概覽

雖然梯度下降優化算法越來越受歡迎,但通常作為黑盒優化器使用,因此很難對其優點和缺點的進行實際的解釋。本文旨在讓讀者對不同的算法有直觀的認識,以幫助讀者使用這些算法。在本綜述中,我們介紹梯度下降的不同變形形式,總結這些算法面臨的挑戰,介紹最常用的優化算法,回顧並行和分布式架構,以及調研用於優化梯度下降的其他的策略。

 

2 Gradient descent 變體

 
有3種基於梯度下降的方法,主要區別是我們在計算目標函數( objective function)梯度時所使用的的數據量。
 
 

2.1 Batch gradient descent 批梯度下降法

 
計算公式如下:

 

 

其中η表示學習率。
該方法在一次參數更新時,需要計算整個數據集的參數。
 
優點:可以保證在convex error surfaces 條件下取得全局最小值,在non-convex surfaces條件下取得局部極小值。
缺點:由於要計算整個數據集的梯度,因此計算比較慢,當數據量很大時,可能會造成內存不足。另外,該方法也無法在線(online)更新模型。
 
計算的偽代碼如下:
for i in range ( nb_epochs ):
    params_grad = evaluate_gradient ( loss_function , data , params )
    params = params - learning_rate * params_grad

其中,params和params_grad均是向量(vector)。

2.2 Stochastic gradient descent(SGD) 隨機梯度下降

計算公式如下:
隨機梯度下降法每次更新參數時,只計算一個訓練樣本(x(i), y(i))的梯度。
 
優點:計算速度快,可以用於在線更新模型。
缺點:由於每次只根據一個樣本進行計算梯度,因此最終目標函數收斂時曲線波動可能會比較大。 由於SGD的波動性,一方面,波動性使得SGD可以跳到新的和潛在更好的局部最優。另一方面,這使得最終收斂到特定最小值的過程變得復雜,因為SGD會一直持續波動。
然而,已經證明當我們緩慢減小學習率,SGD與批梯度下降法具有相同的收斂行為,對於非凸優化和凸優化,可以分別收斂到局部最小值和全局最小值。

 

 

示例代碼如下:
for i in range(nb_epochs):
    np.random.shuffle(data)
    for example in data:
        params_grad = evaluate_gradient(loss_function, example, params)
        params = params - learning_rate * params_grad

注:每次循環中,我們需要先將樣本打亂。

 

2.3 Mini-batch gradient descent 

小批量梯度下降法結合了上述兩種方法的優點,在每次跟新參數時使用小批量(n個樣本)的訓練樣本。
 
 
優點:1)減少了參數更新時的方差,也就是目標函數收斂時的曲線波動沒那么大了,這樣也得到更加穩定的收斂結果。
          2) 可以利用最新的深度學習庫中高度優化的矩陣優化方法,高效地求解每個小批量數據的梯度。
 
小批量數據n的大小在50到256之間,也可以根據不同的應用有所變化。
當訓練神經網絡模型時,小批量梯度下降法是典型的選擇算法,當使用小批量梯度下降法時,也將其稱為SGD。
 
 
注意:在下文的改進的SGD中,為了簡單,我們省略了參數。
 
示例代碼如下:
for i in range(nb_epochs):
    np.random.shuffle(data)
    for batch in get_batches(data, batch_size=50):
        params_grad = evaluate_gradient(loss_function, batch, params)
        params = params - learning_rate * params_grad

3 Challenges

mini-batch梯度下降法雖然有上述的優點,但是仍然還是有一些問題:
1)選擇一個合適的學習率比較困難。學習率太小會導致收斂緩慢,學習率太大會損失函數在最小值附近波動甚至無法收斂。
2)學習率調整( Learning rate schedules)在訓練時,根據預定義的策略(如目標函數的相鄰迭代之間的下降值小於閾值時)減少學習率。這種方法需要提前設置好策略和閾值,而且可能無法適應數據集的特點。
3)所有參數的更新使用同一個學習率。如果我們的數據是稀疏的,同時特征的頻率差異很大,我們可能不想使用同樣的學習率更新所有的的參數,對於那些出現次數較少的特性,我們對其使用更大的學習率。
4)非凸誤差函數普遍出現在神經網絡中,在優化這類函數時,其中一個挑戰就是使函數避免陷入次優的局部最小值。 Dauphin等人指出出現這種困難實際上並不是來自局部最小值,而是來自鞍點,即那些在一個維度上是遞增的,而在另一個維度上是遞減的。這些鞍點通常被具有相同誤差的點包圍,因為在任意維度上的梯度都近似為0,所以SGD很難從這些鞍點中逃開。
 
 
 

4 Gradient descent optimization algorithms

    下面我們將介紹一些在深度學習中廣泛使用的優化算法,來解決上述提到的問題。我們不會討論實際中不適合高維數據集中計算的算法,如牛頓法的二階方法。
 
 

4.1 Momentum 動量法

 
    動量法改進自SGD算法,讓每一次的參數更新方向不僅僅取決於當前位置的梯度,還受到上一次參數更新方向的影響。
 
SGD很難通過陡谷(指在一個維度上的表面彎曲程度遠大於其他維度的區域),這種情況通常出現在局部最優點附近。 在這種情況下,SGD搖擺地通過陡谷的斜坡,同時,沿着底部到局部最優點的路徑上只是緩慢地前進,這個過程如圖2a所示。

 

 

如圖2b所示,動量法[16]是一種幫助SGD在相關方向上加速並抑制搖擺的一種方法。動量法將歷史步長的更新向量的一個分量增加到當前的更新向量中(部分實現中交換了公式中的符號)
 
公式如下:
 
其中,動量項γ一般取值為0.9或者類似的值。
 
從本質上說,動量法,就像我們從山上推下一個球,球在滾下來的過程中累積動量,變得越來越快(直到達到終極速度,如果有空氣阻力的存在,則γ<1)。同樣的事情也發生在參數的更新過程中:對於在梯度點處具有相同的方向的維度,其動量項增大,對於在梯度點處改變方向的維度,其動量項減小。因此,我們可以得到更快的收斂速度,同時可以減少搖擺。

 

4.2 Nesterov accelerated gradient (NAG)

 
NAG是在Momentum的基礎上改進的。 NAG就對Momentum說:“既然我都知道我這一次一定會走 的量,那么我何必還用現在這個位置的梯度呢?我直接先走到 之后的地方,然后再根據那里的梯度再前進一下,豈不美哉?”所以就有了下面的公式:
跟上面Momentum公式的唯一區別在於,梯度不是根據當前參數位置θ,而是根據先走了本來計划要走的一步后,達到的參數位置 計算出來的。
 
對於這個改動,很多文章給出的解釋是,能夠讓算法提前看到前方的地形梯度,如果前面的梯度比當前位置的梯度大,那我就可以把步子邁得比原來大一些,如果前面的梯度比現在的梯度小,那我就可以把步子邁得小一些。這個大一些、小一些,都是相對於原來不看前方梯度、只看當前位置梯度的情況來說的。
但是我個人對這個解釋不甚滿意。你說你可以提前看到,但是我下次到了那里之后不也照樣看到了嗎?最多比你落后一次迭代的時間,真的會造成非常大的差別?可是實驗結果就是表明,NAG收斂的速度比Momentum要快。 
對NAG原來的更新公式進行變換,得到的等效形式如下:
 
注:上述公式對應的原公式為:
 
這個NAG的等效形式與Momentum的區別在於,本次更新方向多加了一個 ,它的直觀含義就很明顯了:如果這次的梯度比上次的梯度變大了,那么有理由相信它會繼續變大下去,那我就把預計要增大的部分提前加進來;如果相比上次變小了,也是類似的情況。這樣的解釋聽起來好像和原本的解釋一樣玄,但是讀者可能已經發現了,這個多加上去的項不就是在近似目標函數的二階導嘛!所以NAG本質上是多考慮了目標函數的二階導信息,怪不得可以加速收斂了!其實所謂“往前看”的說法,在牛頓法這樣的二階方法中也是經常提到的,比喻起來是說“往前看”,數學本質上則是利用了目標函數的二階導信息。
 
 
既然我們能夠使得我們的更新適應誤差函數的斜率以相應地加速SGD,我們同樣也想要使得我們的更新能夠適應每一個單獨參數,以根據每個參數的重要性決定大的或者小的更新。

 

4.3 Adagrad

Adagrad是這樣一種基於梯度的優化算法:它讓學習率適應參數, 對於出現次數較少的特征,我們對其采用更大的學習率,對於出現次數較多的特征,我們對其采用較小的學習率。因此,Adagrad非常適合處理稀疏數據
AdaGrad算法就是將每一個參數的每一次迭代的梯度取平方累加后在開方,用全局學習率除以這個數,作為學習率的動態更新。
 
具體的計算方法如下:
1)計算梯度
2)累計平方梯度
3)計算更新
注:上述計算方法為:逐元素地應用除法和求平方根
 
4)應用更新
 
其中,G為梯度累積變量(是一個d*d的對角矩陣,矩陣中第(i,i)的元素為第i個參數的平方和),ε是一個小的常數,避免分母為0。
 
簡版迭代公式如下:
 
 
經驗上已經發現,對於訓練深度神經網絡模型而言,從訓練開始時積累梯度平方會導致有效學習率過早和過量的減小。Adagrad在某些深度學習模型上效果不錯,但不是全部。
 
Adagrad的其中一個優點就是不需要手動的調整學習率,一般默認使用0.01作為初始學習率。
Adagrad的一個 主要缺點是它在分母中累加梯度的平方:由於沒增加一個正項,在整個訓練過程中,累加的和會持續增長。這會導致學習率變小以至於最終變得無限小,在學習率無限小時,Adagrad算法將無法取得額外的信息。接下來的算法旨在解決這個不足。

 

4.4 Adadelta

 
Adadelta是Adagrad的一種擴展算法,以處理Adagrad學習速率單調遞減的問題。不是計算所有的梯度平方,Adadelta將計算計算歷史梯度的窗口大小限制為一個固定值。
 
在Adadelta中,無需存儲先前的w個平方梯度,而是將梯度的平方遞歸地表示成所有歷史梯度平方的均值。在t時刻的均值只取決於先前的均值和當前的梯度(分量類似於動量項):
一般γ取0.9。
我們將adagrad中的G替換為 ,則有
上述分母相當於梯度的均方根(root mean aquared, RMS),因此可以用RMS簡寫
 
作者指出上述更新公式中的每個部分(與SGD,動量法或者Adagrad)並不一致,即更新規則中必須與參數具有相同的假設單位。為了實現這個要求,作者首次定義了另一個指數衰減均值,這次不是梯度平方,而是參數的平方的更新:

 

 

因此,參數更新的均方根誤差為:
 
由於 是未知的,我們利用參數的均方根誤差來近似更新。利用替換先前的更新規則中的學習率,最終得到Adadelta的更新規則:
 
算法最終實現如下:

 

 

使用Adadelta算法,我們甚至都無需設置默認的學習率,因為更新規則中已經移除了學習率。

 

4.5 RMSprop

 
RMSprop是一個未被發表的自適應學習率的算法,該算法由Geoff Hinton在其Coursera課堂的課程6e中提出。
RMSprop和Adadelta在相同的時間里被獨立的提出,都起源於對Adagrad的極速遞減的學習率問題的求解。實際上,RMSprop是先前我們得到的Adadelta的第一個更新向量的特例:
 

 

 

同樣,RMSprop將學習率分解成一個平方梯度的指數衰減的平均。Hinton建議將γ設置為0.9,對於學習率,一個好的固定值為0.001。

 

4.6 Adam
 
 
自適應矩估計(Adaptive Moment Estimation,Adam)[9]是另一種自適應學習率的算法,Adam對每一個參數都計算自適應的學習率。除了像Adadelta和RMSprop一樣存儲一個指數衰減的歷史平方梯度的平均,Adam同時還保存一個歷史梯度的指數衰減均值,類似於動量:
 
 
分別是對梯度的一階矩(均值)和二階矩(非確定的方差)的估計,正如該算法的名稱。當 ​和 ​初始化為0向量時,Adam的作者發現它們都偏向於0,尤其是在初始化的步驟和當衰減率很小的時候(例如β1和β2趨向於1)。
 
通過計算偏差校正的一階矩和二階矩估計來抵消偏差
正如我們在Adadelta和RMSprop中看到的那樣,他們利用上述的公式更新參數,由此生成了Adam的更新規則:
 
作者建議β1取默認值為0.9,β2為0.999,ε ​為1e-8。他們從經驗上表明Adam在實際中表現很好,同時,與其他的自適應學習算法相比,其更有優勢。

 

4.7 AdaMax

 
見原文
 

4.8 Nadam

 
見原文
 
 
 
 

4.9 Visualization of algorithms

下面兩張圖給出了上述優化算法的優化行為的直觀理解。(還可以看看這里關於Karpathy對相同的圖片的描述以及另一個簡明關於算法討論的概述)。
在圖4a中,我們看到不同算法在損失曲面的等高線上走的不同路線。所有的算法都是從同一個點出發並選擇不同路徑到達最優點。注意:Adagrad,Adadelta和RMSprop能夠立即轉移到正確的移動方向上並以類似的速度收斂,而動量法和NAG會導致偏離,想像一下球從山上滾下的畫面。然而,NAG能夠在偏離之后快速修正其路線,因為NAG通過對最優點的預見增強其響應能力。
圖4b中展示了不同算法在鞍點出的行為,鞍點即為一個點在一個維度上的斜率為正,而在其他維度上的斜率為負,正如我們前面提及的,鞍點對SGD的訓練造成很大困難。這里注意,SGD,動量法和NAG在鞍點處很難打破對稱性,盡管后面兩個算法最終設法逃離了鞍點。而Adagrad,RMSprop和Adadelta能夠快速想着梯度為負的方向移動,其中Adadelta走在最前面。

 

              

 

 

正如我們所看到的,自適應學習速率的方法,即 Adagrad、 Adadelta、 RMSprop 和Adam,最適合這些場景下最合適,並在這些場景下得到最好的收斂性。
 

4.10 Which optimizer to use?

 
那么,我們應該選擇使用哪種優化算法呢?如果輸入數據是稀疏的,選擇任一自適應學習率算法可能會得到最好的結果。選用這類算法的另一個好處是無需調整學習率,選用默認值就可能達到最好的結果。
 
總的來說,RMSprop是Adagrad的擴展形式,用於處理在Adagrad中急速遞減的學習率。RMSprop與Adadelta相同,所不同的是Adadelta在更新規則中使用參數的均方根進行更新。最后,Adam是將偏差校正和動量加入到RMSprop中。在這樣的情況下,RMSprop、Adadelta和Adam是很相似的算法並且在相似的環境中性能都不錯。Kingma等人[9]指出在優化后期由於梯度變得越來越稀疏,偏差校正能夠幫助Adam微弱地勝過RMSprop。綜合看來,Adam可能是最佳的選擇。
有趣的是,最近許多論文中采用不帶動量的SGD和一種簡單的學習率的退火策略。已表明,通常SGD能夠找到最小值點,但是比其他優化的SGD花費更多的時間,與其他算法相比,SGD更加依賴魯棒的初始化和退火策略,同時,SGD可能會陷入鞍點,而不是局部極小值點。因此,如果你關心的是快速收斂和訓練一個深層的或者復雜的神經網絡,你應該選擇一個自適應學習率的方法。
 
 

參考:

An overview of gradient descent optimization algorithms
Nesterov accelerated gradient 深入理解: https://zhuanlan.zhihu.com/p/22810533/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM