各種 Optimizer 梯度下降優化算法總結

不管是使用PyTorch還是TensorFlow,用多了Optimizer優化器封裝好的函數,對其內部使用的優化算法卻沒有仔細研究過,也很難對其優點和缺點進行實用的解釋。所以打算以這一篇論文為主線并結合多篇優秀博文,回顧和總結目前主流的優化算法,對于沒有深入了解過的算法,正好借這個機會學習一下。

寫在前面

當前使用的許多優化算法,是對梯度下降法的衍生和優化。在微積分中,對多元函數的參數求偏導數,把求得的各個參數的導數以向量的形式寫出來就是梯度。梯度就是函數變化最快的地方。梯度下降是迭代法的一種,在求解機器學習算法的模型參數時,即無約束問題時,梯度下降是最常采用的方法之一。

這里定義一個通用的思路框架,方便我們后面理解各算法之間的關系和改進。首先定義待優化參數,目標函數,學習率為,然后我們進行迭代優化,假設當前的epoch為,則有:

計算目標函數關于當前參數的梯度:

根據歷史梯度計算一階動量和二階動量:,

計算當前時刻的下降梯度:

根據下降梯度進行更新:

其中,為下一個時刻的參數,為當前時刻參數,后面的描述我們都將結合這個框架來進行。

這里提一下一些概念:

鞍點:一個光滑函數的鞍點鄰域的曲線,曲面,或超曲面,都位于這點的切線的不同邊。例如這個二維圖形,像個馬鞍:在x-軸方向往上曲,在y-軸方向往下曲,鞍點就是(0,0)。

指數加權平均、偏差修正:可參見這篇文章

什么是指數加權平均、偏差修正?- 郭耀華 - 博客園

https://www.cnblogs.com/guoyaohua/p/8544835.html

Gradient Descent(GD)

在GD中沒有動量的概念,也就是說在上述框架中:;,則我們在當前時刻需要下降的梯度就是,則使用梯度下降法更新參數為(假設當前樣本為,每當樣本輸入時,參數即進行更新):

梯度下降算法中,模型參數的更新調整,與代價函數關于模型參數的梯度有關,即沿著梯度的方向不斷減小模型參數,從而最小化代價函數。基本策略可以理解為”在有限視距內尋找最快路徑下山“,因此每走一步,參考當前位置最陡的方向(即梯度)進而邁出下一步,更形象的如下圖:

標準的梯度下降主要有兩個缺點:

訓練速度慢:在應用于大型數據集中,每輸入一個樣本都要更新一次參數,且每次迭代都要遍歷所有的樣本,會使得訓練過程及其緩慢,需要花費很長時間才能得到收斂解。

容易陷入局部最優解:由于是在有限視距內尋找下山的反向,當陷入平坦的洼地,會誤以為到達了山地的最低點,從而不會繼續往下走。所謂的局部最優解就是鞍點,落入鞍點,梯度為0,使得模型參數不在繼續更新。

Batch Gradient Descent(BGD)

BGD相對于標準GD進行了改進,改進的地方通過它的名字應該也能看出來,也就是不再是想標準GD一樣,對每個樣本輸入都進行參數更新,而是針對一個批量的數據輸入進行參數更新。我們假設批量訓練樣本總數為,樣本為,則在第對樣本上損失函數關于參數的梯度為, 則使用BGD更新參數為:

從上面的公式我們可以看到,BGD其實是在一個批量的樣本數據中,求取該批量樣本梯度的均值來更新參數,即每次權值調整發生在批量樣本輸入之后,而不是每輸入一個樣本就更新一次模型參數,這樣就會大大加快訓練速度,但是還是不夠,我們接著往下看。

Stochastic Gradient Descent(SGD)

隨機梯度下降法,不像BGD每一次參數更新,需要計算整個數據樣本集的梯度,而是每次參數更新時,僅僅選取一個樣本計算其梯度,參數更新公式為:

公式看起來和上面標準GD一樣,但是注意了,這里的樣本是從批量中隨機選取一個,而標準GD是所有的輸入樣本都進行計算。可以看到BGD和SGD是兩個極端,SGD由于每次參數更新僅僅需要計算一個樣本的梯度,訓練速度很快,即使在樣本量很大的情況下,可能只需要其中一部分樣本就能迭代到最優解,由于每次迭代并不是都向著整體最優化方向,導致梯度下降的波動非常大(如下圖),更容易從一個局部最優跳到另一個局部最優,準確度下降。

論文中提到,當緩慢降低學習率時,SGD會顯示與BGD相同的收斂行為,幾乎一定會收斂到局部(非凸優化)或全局最小值(凸優化)。

SGD的優點:

雖然看起來SGD波動非常大,會走很多彎路,但是對梯度的要求很低(計算梯度快),而且對于引入噪聲,大量的理論和實踐工作證明,只要噪聲不是特別大,SGD都能很好地收斂。

應用大型數據集時,訓練速度很快。比如每次從百萬數據樣本中,取幾百個數據點,算一個SGD梯度,更新一下模型參數。相比于標準梯度下降法的遍歷全部樣本,每輸入一個樣本更新一次參數,要快得多。

SGD的缺點:

SGD在隨機選擇梯度的同時會引入噪聲,使得權值更新的方向不一定正確(次要)。

SGD也沒能單獨克服局部最優解的問題(主要)。

Mini-batch Gradient Descent(MBGD,也叫作SGD)

小批量梯度下降法就是結合BGD和SGD的折中,對于含有個訓練樣本的數據集,每次參數更新,選擇一個大小為 $m(m

小批量梯度下降法即保證了訓練的速度,又能保證最后收斂的準確率,目前的SGD默認是小批量梯度下降算法。常用的小批量尺寸范圍在50到256之間,但可能因不同的應用而異。

MBGD的缺點:

Mini-batch gradient descent 不能保證很好的收斂性,learning rate 如果選擇的太小,收斂速度會很慢,如果太大,loss function 就會在極小值處不停地震蕩甚至偏離(有一種措施是先設定大一點的學習率,當兩次迭代之間的變化低于某個閾值后,就減小 learning rate,不過這個閾值的設定需要提前寫好,這樣的話就不能夠適應數據集的特點)。對于非凸函數,還要避免陷于局部極小值處,或者鞍點處,因為鞍點所有維度的梯度都接近于0,SGD 很容易被困在這里(會在鞍點或者局部最小點震蕩跳動,因為在此點處,如果是BGD的訓練集全集帶入,則優化會停止不動,如果是mini-batch或者SGD,每次找到的梯度都是不同的,就會發生震蕩,來回跳動)。

SGD對所有參數更新時應用同樣的 learning rate,如果我們的數據是稀疏的,我們更希望對出現頻率低的特征進行大一點的更新, 且learning rate會隨著更新的次數逐漸變小。

Momentum

momentum算法思想:參數更新時在一定程度上保留之前更新的方向,同時又利用當前batch的梯度微調最終的更新方向,簡言之就是通過積累之前的動量來加速當前的梯度。從這里開始,我們引入一階動量的概念(在mini-batch SGD的基礎之上),也就是說,在最開始說的框架中,,而不變,參數更新公式如下:

一階動量是各個時刻梯度方向的指數移動平均值,約等于最近個時刻的梯度向量和的平均值(移動平均是啥看最上面的文章)。也就是說,時刻的下降方向,不僅由當前點的梯度方向決定,而且由此前累積的下降方向決定。的經驗值為0.9,這就意味著下降方向主要是此前累積的下降方向,并略微偏向當前時刻的下降方向。在梯度方向改變時,momentum能夠降低參數更新速度,從而減少震蕩,在梯度方向相同時,momentum可以加速參數更新, 從而加速收斂,如下圖:

動量主要解決SGD的兩個問題:

隨機梯度的方法(引入的噪聲)

Hessian矩陣病態問題(可以理解為SGD在收斂過程中和正確梯度相比來回擺動比較大的問題)。

Nesterov Accelerated Gradient

NAG(Nesterov accelerated gradient)算法,是Momentum動量算法的變種。momentum保留了上一時刻的梯度,對其沒有進行任何改變,NAG是momentum的改進,在梯度更新時做一個矯正,具體做法就是在當前的梯度上添加上一時刻的動量,梯度改變為,參數更新公式如下:

加上nesterov項后,梯度在大的跳躍后,進行計算對當前梯度進行校正。下圖是momentum和nesterrov的對比表述圖如下:

Nesterov動量梯度的計算在模型參數施加當前速度之后,因此可以理解為往標準動量中添加了一個校正因子。在凸批量梯度的情況下,Nesterov動量將額外誤差收斂率從(k步后)改進到,然而,在隨機梯度情況下,Nesterov動量對收斂率的作用卻不是很大。

Momentum和Nexterov都是為了使梯度更新更靈活。但是人工設計的學習率總是有些生硬,下面介紹幾種自適應學習率的方法。

Adagrad

Adagrad其實是對學習率進行了一個約束,對于經常更新的參數,我們已經積累了大量關于它的知識,不希望被單個樣本影響太大,希望學習速率慢一些;對于偶爾更新的參數,我們了解的信息太少,希望能從每個偶然出現的樣本身上多學一些,即學習速率大一些。而該方法中開始使用二階動量,才意味著“自適應學習率”優化算法時代的到來。

我們前面都沒有好好的討論二階動量,二階動量是個啥?它是用來度量歷史更新頻率的,二階動量是迄今為止所有梯度值的平方和,即,在最上面的框架中(在這里), 也就是說,我們的學習率現在是(一般為了避免分母為0,會在分母上加一個小的平滑項),從這里我們就會發現是恒大于0的,而且參數更新越頻繁,二階動量越大,學習率就越小,這一方法在稀疏數據場景下表現非常好,參數更新公式如下:

細心的小伙伴應該會發現Adagrad還是存在一個很明顯的缺點:

仍需要手工設置一個全局學習率, 如果設置過大的話,會使regularizer過于敏感,對梯度的調節太大

中后期,分母上梯度累加的平方和會越來越大,使得參數更新量趨近于0,使得訓練提前結束,無法學習

Adadelta

由于AdaGrad調整學習率變化過于激進,我們考慮一個改變二階動量計算方法的策略:不累積全部歷史梯度,而只關注過去一段時間窗口的下降梯度,即Adadelta只累加固定大小的項,并且也不直接存儲這些項,僅僅是近似計算對應的平均值(指數移動平均值),這就避免了二階動量持續累積、導致訓練過程提前結束的問題了,參數更新公式如下:

觀察上面的參數更新公式,我們發現還是依賴于全局學習率,但是原作者在此基礎之上做出了一定的處理,上式經過牛頓迭代法之后,得到Adadelta最終迭代公式如下式,其中:

此時可以看出Adadelta已經不依賴全局learning rate了,Adadelta有如下特點:

訓練初中期,加速效果不錯,很快

訓練后期,反復在局部最小值附近抖動

RMSprop

RMSProp算法修改了AdaGrad的梯度平方和累加為指數加權的移動平均,使得其在非凸設定下效果更好。設定參數:全局初始率, 默認設為0.001,decay rate,默認設置為0.9,一個極小的常量,通常為10e-6,參數更新公式如下,其中:

其實RMSprop依然依賴于全局學習率

RMSprop算是Adagrad的一種發展,和Adadelta的變體,效果趨于二者之間

適合處理非平穩目標(包括季節性和周期性)——對于RNN效果很好

Adaptive Moment Estimation(Adam)

其實有了前面的方法,Adam和Nadam的出現就很理所當然的了,因為它們結合了前面方法的一階動量和二階動量。我們看到,SGD-M和NAG在SGD基礎上增加了一階動量,AdaGrad和AdaDelta在SGD基礎上增加了二階動量,參數更新公式如下(按照最開始總結的計算框架):

通常情況下,默認值為、和,Adam通常被認為對超參數的選擇相當魯棒,特點如下:

Adam梯度經過偏置校正后,每一次迭代學習率都有一個固定范圍,使得參數比較平穩。

結合了Adagrad善于處理稀疏梯度和RMSprop善于處理非平穩目標的優點

為不同的參數計算不同的自適應學習率

也適用于大多非凸優化問題——適用于大數據集和高維空間。

AdaMax

Adamax是Adam的一種變體,此方法對學習率的上限提供了一個更簡單的范圍,即使用無窮范式,參數更新公式如下:

通常情況下,默認值為、和

Nadam

其實如果說要集成所有方法的優點于一身的話,Nadam應該就是了,Adam遺漏了啥?沒錯,就是Nesterov項,我們在Adam的基礎上,加上Nesterov項就是Nadam了,參數更新公式如下:

可以看出,Nadam對學習率有更強的約束,同時對梯度的更新也有更直接的影響。一般而言,在使用帶動量的RMSprop或Adam的問題上,使用Nadam可以取得更好的結果。

來張直觀的動態圖展示上述優化算法的效果:

下圖描述了在一個曲面上,6種優化器的表現:

下圖在一個存在鞍點的曲面,比較6中優化器的性能表現:

下圖圖比較了6種優化器收斂到目標點(五角星)的運行過程

總結

那種優化器最好?該選擇哪種優化算法?目前還沒能夠達達成共識。Schaul et al (2014)展示了許多優化算法在大量學習任務上極具價值的比較。雖然結果表明,具有自適應學習率的優化器表現的很魯棒,不分伯仲,但是沒有哪種算法能夠脫穎而出。

目前,最流行并且使用很高的優化器(算法)包括SGD、具有動量的SGD、RMSprop、具有動量的RMSProp、AdaDelta和Adam。在實際應用中,選擇哪種優化器應結合具體問題;同時,也優化器的選擇也取決于使用者對優化器的熟悉程度(比如參數的調節等等)。

對于稀疏數據,盡量使用學習率可自適應的優化方法,不用手動調節,而且最好采用默認值

SGD通常訓練時間更長,但是在好的初始化和學習率調度方案的情況下,結果更可靠

如果在意更快的收斂,并且需要訓練較深較復雜的網絡時,推薦使用學習率自適應的優化方法。

Adadelta,RMSprop,Adam是比較相近的算法,在相似的情況下表現差不多。

在想使用帶動量的RMSprop,或者Adam的地方,大多可以使用Nadam取得更好的效果

如果驗證損失較長時間沒有得到改善,可以停止訓練。

添加梯度噪聲(高斯分布)到參數更新,可使網絡對不良初始化更加健壯,并有助于訓練特別深而復雜的網絡。

參考文獻:

An overview of gradient descent optimization algorithms(https://ruder.io/optimizing-gradient-descent/)

深度學習最全優化方法總結比較(SGD,Adagrad,Adadelta,Adam,Adamax,Nadam)(https://zhuanlan.zhihu.com/p/22252270)

visualize_optimizers(https://github.com/snnclsr/visualize_optimizers)

lossfunctions(https://lossfunctions.tumblr.com/)

優化算法Optimizer比較和總結(https://zhuanlan.zhihu.com/p/55150256)

一個框架看懂優化算法之異同 SGD/AdaGrad/Adam(https://zhuanlan.zhihu.com/p/32230623)

深度學習——優化器算法Optimizer詳解(BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam)(https://www.cnblogs.com/guoyaohua/p/8542554.html)

機器學習:各種優化器Optimizer的總結與比較(https://blog.csdn.net/weixin_40170902/article/details/80092628)

optimizer優化算法總結(https://blog.csdn.net/muyu709287760/article/details/62531509#%E4%B8%89%E7%A7%8Dgradient-descent%E5%AF%B9%E6%AF%94)

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容