梯度降低
算法是
機器學習中使用很是普遍的優化算法,也是衆多機器學習算法中最經常使用的優化方法。幾乎當前每個先進的(state-of-the-art)機器學習庫或者
深度學習庫都會包括梯度降低算法的不一樣變種實現。可是,它們就像一個黑盒優化器,很可貴到它們優缺點的實際解釋。這篇文章旨在提供梯度降低算法中的不一樣變種的介紹,幫助使用者根據具體須要進行使用。
這篇文章首先介紹梯度降低算法的三種框架,而後介紹它們所存在的問題與挑戰,接着介紹一些如何進行改進來解決這些問題,隨後,介紹如何在並行環境中或者分佈式環境中使用梯度降低算法。最後,指出一些有利於梯度降低的策略。
目錄
三種梯度降低優化框架
批量梯度降低
隨機梯度降低
小批量梯度降低
問題與挑戰
梯度降低優化算法
Momentum
Nesterov accelerated gradient
Adagrad
Adadelta
RMSprop
Adam
算法的可視化
選擇哪一種優化算法?
並行與分佈式SDG
Hogwild!
Downpour SGD
Delay-tolerant Algorithms for SGD
TensorFlow
Elastic Averaging SGD
更多的SDG優化策略
訓練集隨機洗牌與課程學習
批規範化
Early Stopping
Gradient noise
總結
引用
三種梯度降低優化框架
梯度降低算法是經過沿着目標函數J(θ)參數θ∈R的梯度(一階導數)相反方向−∇θJ(θ)來不斷更新模型參數來到達目標函數的極小值點(收斂),更新步長爲η。
有三種梯度降低算法框架,它們不一樣之處在於每次學習(更新模型參數)使用的樣本個數,每次更新使用不一樣的樣本會致使每次學習的準確性和學習時間不一樣。
批量梯度降低(Batch gradient descent)
每次使用全量的訓練集樣原本更新模型參數,即: θ=θ−η⋅∇θJ(θ)
其代碼以下:
epochs 是用戶輸入的最大迭代次數。經過上訴代碼能夠看出,每次使用所有訓練集樣本計算損失函數 loss_function 的梯度 params_grad,而後使用學習速率 learning_rate 朝着梯度相反方向去更新模型的每一個參數params。通常各現有的一些機器學習庫都提供了梯度計算api。若是想本身親手寫代碼計算,那麼須要在程序調試過程當中驗證梯度計算是否正確。
批量梯度降低每次學習都使用整個訓練集,所以其優勢在於每次更新都會朝着正確的方向進行,最後可以保證收斂於極值點(凸函數收斂於全局極值點,非凸函數可能會收斂於局部極值點),可是其缺點在於每次學習時間過長,而且若是訓練集很大以致於須要消耗大量的內存,而且全量梯度降低不能進行在線模型參數更新。
隨機梯度降低(Stochastic gradient descent)
隨機梯度降低算法每次從訓練集中隨機選擇一個樣原本進行學習,即: θ=θ−η⋅∇θJ(θ;xi;yi)
批量梯度降低算法每次都會使用所有訓練樣本,所以這些計算是冗餘的,由於每次都使用徹底相同的樣本集。而隨機梯度降低算法每次只隨機選擇一個樣原本更新模型參數,所以每次的學習是很是快速的,而且能夠進行在線更新。
其代碼以下:
隨機梯度降低最大的缺點在於每次更新可能並不會按照正確的方向進行,所以能夠帶來優化波動(擾動),以下圖:
圖1 SGD擾動
不過從另外一個方面來看,隨機梯度降低所帶來的波動有個好處就是,對於相似盆地區域(即不少局部極小值點)那麼這個波動的特色可能會使得優化的方向從當前的局部極小值點跳到另外一個更好的局部極小值點,這樣即可能對於非凸函數,最終收斂於一個較好的局部極值點,甚至全局極值點。
因爲波動,所以會使得迭代次數(學習次數)增多,即收斂速度變慢。不過最終其會和全量梯度降低算法同樣,具備相同的收斂性,即凸函數收斂於全局極值點,非凸損失函數收斂於局部極值點。
小批量梯度降低(Mini-batch gradient descent)
Mini-batch 梯度降低綜合了 batch 梯度降低與 stochastic 梯度降低,在每次更新速度與更新次數中間取得一個平衡,其每次更新從訓練集中隨機選擇 m,m<n 個樣本進行學習,即:
θ=θ−η⋅∇θJ(θ;xi:i+m;yi:i+m)
其代碼以下:
相對於隨機梯度降低,Mini-batch梯度降低下降了收斂波動性,即下降了參數更新的方差,使得更新更加穩定。相對於全量梯度降低,其提升了每次學習的速度。而且其不用擔憂內存瓶頸從而能夠利用矩陣運算進行高效計算。通常而言每次更新隨機選擇[50,256]個樣本進行學習,可是也要根據具體問題而選擇,實踐中能夠進行屢次試驗,選擇一個更新速度與更次次數都較適合的樣本數。mini-batch梯度降低能夠保證收斂性,經常使用於
神經網絡中。
問題與挑戰
雖然梯度降低算法效果很好,而且普遍使用,但同時其也存在一些挑戰與問題須要解決:
選擇一個合理的學習速率很難。若是學習速率太小,則會致使收斂速度很慢。若是學習速率過大,那麼其會阻礙收斂,即在極值點附近會振盪。
學習速率調整(又稱學習速率調度,Learning rate schedules)[11]試圖在每次更新過程當中,改變學習速率,如退火。通常使用某種事先設定的策略或者在每次迭代中衰減一個較小的閾值。不管哪一種調整方法,都須要事先進行固定設置,這邊便沒法自適應每次學習的數據集特色[10]。
模型全部的參數每次更新都是使用相同的學習速率。若是數據特徵是稀疏的或者每一個特徵有着不一樣的取值統計特徵與空間,那麼便不能在每次更新中每一個參數使用相同的學習速率,那些不多出現的特徵應該使用一個相對較大的學習速率。
對於非凸目標函數,容易陷入那些次優的局部極值點中,如在神經網路中。那麼如何避免呢。Dauphin[19]指出更嚴重的問題不是局部極值點,而是鞍點。
梯度降低優化算法
下面將討論一些在深度學習社區中常用用來解決上訴問題的一些梯度優化方法,不過並不包括在高維數據中不可行的算法,如牛頓法。
Momentum
若是在峽谷地區(某些方向較另外一些方向上陡峭得多,常見於局部極值點)[1],SGD會在這些地方附近振盪,從而致使收斂速度慢。這種狀況下,動量(Momentum)即可以解決[2]。
動量在參數更新項中加上一次更新量(即動量項),即: νt=γνt−1+η ∇θJ(θ),θ=θ−νt
其中動量項超參數γ<1通常是小於等於0.9。
其做用以下圖所示:
圖2 沒有動量
圖3 加上動量
加上動量項就像從山頂滾下一個球,求往下滾的時候累積了前面的動量(動量不斷增長),所以速度變得愈來愈快,直到到達終點。同理,在更新模型參數時,對於那些當前的梯度方向與上一次梯度方向相同的參數,那麼進行增強,即這些方向上更快了;對於那些當前的梯度方向與上一次梯度方向不一樣的參數,那麼進行削減,即這些方向上減慢了。所以能夠得到更快的收斂速度與減小振盪。
Nesterov accelerated gradient(NAG)
從山頂往下滾的球會盲目地選擇斜坡。更好的方式應該是在遇到傾斜向上以前應該減慢速度。
Nesterov accelerated gradient(NAG,涅斯捷羅夫梯度加速)不只增長了動量項,而且在計算參數的梯度時,在損失函數中減去了動量項,即計算∇θJ(θ−γνt−1),這種方式預估了下一次參數所在的位置。即:
νt=γνt−1+η⋅∇θJ(θ−γνt−1),θ=θ−νt
以下圖所示:
圖4 NAG更新
詳細介紹能夠參見Ilya Sutskever的PhD論文[9]。假設動量因子參數γ=0.9,首先計算當前梯度項,如上圖小藍色向量,而後加上動量項,這樣便獲得了大的跳躍,如上圖大藍色的向量。這即是隻包含動量項的更新。而NAG首先來一個大的跳躍(動量項),而後加上一個小的使用了動量計算的當前梯度(上圖紅色向量)進行修正獲得上圖綠色的向量。這樣能夠阻止過快更新來提升響應性,如在RNNs中[8]。
經過上面的兩種方法,能夠作到每次學習過程當中可以根據損失函數的斜率作到自適應更新來加速SGD的收斂。下一步便須要對每一個參數根據參數的重要性進行各自自適應更新。
Adagrad
Adagrad[3]也是一種基於梯度的優化算法,它可以對每一個參數自適應不一樣的學習速率,對稀疏特徵,獲得大的學習更新,對非稀疏特徵,獲得較小的學習更新,所以該優化算法適合處理稀疏特徵數據。Dean等[4]發現Adagrad可以很好的提升SGD的魯棒性,google便用起來訓練大規模神經網絡(看片識貓:recognize cats in Youtube videos)。Pennington等[5]在GloVe中便使用Adagrad來訓練獲得詞向量(Word Embeddings), 頻繁出現的單詞賦予較小的更新,不常常出現的單詞則賦予較大的更新。
Adagrad主要優點在於它可以爲每一個參數自適應不一樣的學習速率,而通常的人工都是設定爲0.01。同時其缺點在於須要計算參數梯度序列平方和,而且學習速率趨勢是不斷衰減最終達到一個很是小的值。下文中的Adadelta即是用來解決該問題的。
Adam
Adaptive Moment Estimation (Adam) 也是一種不一樣參數自適應不一樣學習速率方法,與Adadelta與RMSprop區別在於,它計算曆史梯度衰減方式不一樣,不使用歷史平方衰減,其衰減方式相似動量,以下:
mt=β1mt−1+(1−β1)gt
vt=β2vt−1+(1−beta2)g2t
mt與vt分別是梯度的帶權平均和帶權有偏方差,初始爲0向量,Adam的做者發現他們傾向於0向量(接近於0向量),特別是在衰減因子(衰減率)β1,β2接近於1時。爲了改進這個問題,
對mt與vt進行誤差修正(bias-corrected):
mt^=mt1−betat1
vt^=vt1−betat2
最終,Adam的更新方程爲:
θt+1=θt−ηvt^−−√+ϵmt^
論文中建議默認值:β1=0.9,β2=0.999,ϵ=10−8。論文中將Adam與其它的幾個自適應學習速率進行了比較,效果均要好。
算法的可視化
下面兩幅圖可視化形象地比較上述各優化方法,如圖:
圖5 SGD各優化方法在損失曲面上的表現
從上圖能夠看出, Adagrad、Adadelta與RMSprop在損失曲面上可以當即轉移到正確的移動方向上達到快速的收斂。而Momentum 與NAG會致使偏離(off-track)。同時NAG可以在偏離以後快速修正其路線,由於其根據梯度修正來提升響應性。
圖6 SGD各優化方法在損失曲面鞍點處上的表現
從上圖能夠看出,在鞍點(saddle points)處(即某些維度上梯度爲零,某些維度上梯度不爲零),SGD、Momentum與NAG一直在鞍點梯度爲零的方向上振盪,很難打破鞍點位置的對稱性;Adagrad、RMSprop與Adadelta可以很快地向梯度不爲零的方向上轉移。
從上面兩幅圖能夠看出,自適應學習速率方法(Adagrad、Adadelta、RMSprop與Adam)在這些場景下具備更好的收斂速度與收斂性。
如何選擇SGD優化器
若是你的數據特徵是稀疏的,那麼你最好使用自適應學習速率SGD優化方法(Adagrad、Adadelta、RMSprop與Adam),由於你不須要在迭代過程當中對學習速率進行人工調整。
RMSprop是Adagrad的一種擴展,與Adadelta相似,可是改進版的Adadelta使用RMS去自動更新學習速率,而且不須要設置初始學習速率。而Adam是在RMSprop基礎上使用動量與誤差修正。RMSprop、Adadelta與Adam在相似的情形下的表現差很少。Kingma[15]指出收益於誤差修正,Adam略優於RMSprop,由於其在接近收斂時梯度變得更加稀疏。所以,Adam多是目前最好的SGD優化方法。
有趣的是,最近不少論文都是使用原始的SGD梯度降低算法,而且使用簡單的學習速率退火調整(無動量項)。現有的已經代表:SGD可以收斂於最小值點,可是相對於其餘的SGD,它可能花費的時間更長,而且依賴於魯棒的初始值以及學習速率退火調整策略,而且容易陷入局部極小值點,甚至鞍點。所以,若是你在乎收斂速度或者訓練一個深度或者複雜的網絡,你應該選擇一個自適應學習速率的SGD優化方法。
並行與分佈式SGD
若是你處理的數據集很是大,而且有機器集羣能夠利用,那麼並行或分佈式SGD是一個很是好的選擇,由於能夠大大地提升速度。SGD算法的本質決定其是串行的(step-by-step)。所以如何進行異步處理即是一個問題。雖然串行可以保證收斂,可是若是訓練集大,速度即是一個瓶頸。若是進行異步更新,那麼可能會致使不收斂。下面將討論如何進行並行或分佈式SGD,並行通常是指在同一機器上進行多核並行,分佈式是指集羣處理。
Hogwild
Niu[23]提出了被稱爲Hogwild的並行SGD方法。該方法在多個CPU時間進行並行。處理器經過共享內存來訪問參數,而且這些參數不進行加鎖。它爲每個cpu分配不重疊的一部分參數(分配互斥),每一個cpu只更新其負責的參數。該方法只適合處理數據特徵是稀疏的。該方法幾乎能夠達到一個最優的收斂速度,由於cpu之間不會進行相同信息重寫。
Downpour SGD
Downpour SGD是Dean[4]提出的在DistBelief(Google TensorFlow的前身)使用的SGD的一個異步變種。它在訓練子集上訓練同時多個模型副本。這些副本將各自的更新發送到參數服務器(PS,parameter server),每一個參數服務器只更新互斥的一部分參數,副本之間不會進行通訊。所以可能會致使參數發散而不利於收斂。
Delay-tolerant Algorithms for SGD
McMahan與Streeter[12]擴展AdaGrad,經過開發延遲容忍算法(delay-tolerant algorithms),該算法不只自適應過去梯度,而且會更新延遲。該方法已經在實踐中代表是有效的。
TensorFlow
TensorFlow[13]是Google開源的一個大規模機器學習庫,它的前身是DistBelief。它已經在大量移動設備上或者大規模分佈式集羣中使用了,已經通過了實踐檢驗。其分佈式實現是基於圖計算,它將圖分割成多個子圖,每一個計算實體做爲圖中的一個計算節點,他們經過Rend/Receive來進行通訊。
Elastic Averaging SGD
Zhang等[14]提出Elastic Averaging SGD(EASGD),它經過一個elastic force(存儲參數的參數服務器中心)來鏈接每一個work來進行參數異步更新。
更多的SGD優化策略
接下來介紹更多的SGD優化策略來進一步提升SGD的性能。另外還有衆多其它的優化策略,能夠參見[22]。
Shuffling and Curriculum Learning
爲了使得學習過程更加無偏,應該在每次迭代中隨機打亂訓練集中的樣本。
另外一方面,在不少狀況下,咱們是逐步解決問題的,而將訓練集按照某個有意義的順序排列會提升模型的性能和SGD的收斂性,如何將訓練集創建一個有意義的排列被稱爲Curriculum Learning[16]。
Zaremba與Sutskever[17]在使用Curriculum Learning來訓練LSTMs以解決一些簡單的問題中,代表一個相結合的策略或者混合策略比對訓練集按照按照訓練難度進行遞增排序要好。(表示不懂,衰)
Batch normalization
爲了方便訓練,咱們一般會對參數按照0均值1方差進行初始化,隨着不斷訓練,參數獲得不一樣程度的更新,這樣這些參數會失去0均值1方差的分佈屬性,這樣會下降訓練速度和放大參數變化隨着網絡結構的加深。
Batch normalization[18]在每次mini-batch反向傳播以後從新對參數進行0均值1方差標準化。這樣可使用更大的學習速率,以及花費更少的精力在參數初始化點上。Batch normalization充當着正則化、減小甚至消除掉Dropout的必要性。
Early stopping
在驗證集上若是連續的屢次迭代過程當中損失函數再也不顯著地下降,那麼應該提早結束訓練,詳細參見NIPS 2015 Tutorial slides,或者參見防止過擬合的一些方法。
Gradient noise
Gradient noise[21]即在每次迭代計算梯度中加上一個高斯分佈N(0,σ2t)的隨機偏差,即
gt,i=gt,i+N(0,σ2t)
高斯偏差的方差須要進行退火:
σ2t=η(1+t)γ
對梯度增長隨機偏差會增長模型的魯棒性,即便初始參數值選擇地很差,並適合對特別深層次的負責的網絡進行訓練。其緣由在於增長隨機噪聲會有更多的可能性跳過局部極值點並去尋找一個更好的局部極值點,這種可能性在深層次的網絡中更常見。
總結
在上文中,對梯度降低算法的三種框架進行了介紹,而且mini-batch梯度降低是使用最普遍的。隨後,咱們重點介紹了SGD的一些優化方法:Momentum、NAG、Adagrad、Adadelta、RMSprop與Adam,以及一些異步SGD方法。最後,介紹了一些提升SGD性能的其它優化建議,如:訓練集隨機洗牌與課程學習(shuffling and curriculum learning)、batch normalization、early stopping 與 Gradient noise。
|