1. 程式人生 > >訓練過程--梯度下降演算法(SGD、adam等)

訓練過程--梯度下降演算法(SGD、adam等)

SGD系列

1)Batch gradient descent(批量梯度下降)

  在整個資料集上
  每更新一次權重,要遍歷所有的樣本,由於樣本集過大,無法儲存在記憶體中,無法線上更新模型。對於損失函式的凸曲面,可以收斂到全域性最小值,對於非凸曲面,收斂到區域性最小值。
  隨機梯度下降(SGD)和批量梯度下降(BGD)的區別。SGD 從資料集中拿出一個樣本,並計算相關的誤差梯度,而批量梯度下降使用所有樣本的整體誤差:「關鍵是,在更新中沒有隨機或擴散性的行為。」

2)stochastic gradient descent(SGD,隨機梯度下降)

  可以線上學習,收斂的更快,可以收斂到更精確的最小值。但是梯度更新太快,而且會產生梯度震盪,使收斂不穩定。
  隨機梯度下降(SGD)和批量梯度下降(BGD)的區別。SGD 從資料集中拿出一個樣本,並計算相關的誤差梯度,而批量梯度下降使用所有樣本的整體誤差:「關鍵是,在更新中沒有隨機或擴散性的行為。」

3)Mini-batch gradient descent(MBGD,小批量梯度下降)

  批量梯度下降演算法和隨機梯度下降演算法的結合體。兩方面好處:一是減少更新的次數,使得收斂更穩定;二是利用矩陣優化方法更有效。
  當訓練集有很多冗餘時(類似的樣本出現多次),batch方法收斂更快。
  以一個極端情況為例,若訓練集前一半和後一半梯度相同。那麼如果前一半作為一個batch,後一半作為另一個batch,那麼在一次遍歷訓練集時,batch的方法向最優解前進兩個step,而整體的方法只前進一個step。

三種SGD的對比

  批量梯度下降法BGD:批量梯度下降法(Batch Gradient Descent,簡稱BGD)是梯度下降法最原始的形式,它的具體思路是在更新每一引數時都使用所有的樣本來進行更新。
  隨機梯度下降法SGD:
  小批量梯度下降法MBGD:有上述的兩種梯度下降法,其各自均有優缺點,那麼能不能在兩種方法的效能之間取得一個折衷呢?即,演算法的訓練過程比較快,而且也要保證最終引數訓練的準確率,而這正是小批量梯度下降法(Mini-batch Gradient Descent,簡稱MBGD)的初衷。

  最後可以總結為:

  • M 等於 N時(就是用了所有的樣本), 就是所謂的batch GD
  • M 等於 1時 (就是用了其中的一個樣本), 就是所謂的SGD
  • M 大於1, 小於 N時, 就是 mini-batch GD.
      所以從expected loss的角度看, 其實batch GD, mini-batch GD, SGD都可以看成SGD的範疇, 只不過區別在於每次取多少的樣本了。

梯度下降優化演算法(非SGD系列)

  AdaDelta, Ada-Grad, Adam, NAG, RMSprop
  參考資料:http://blog.csdn.net/luo123n/article/details/48239963

1)Momentum

  一般,動量項取0.9附近,學習率取0.01。
  作用是使收斂更快,減少震盪。梯度方向不變時,收斂更快,梯度方向改變時,減小震盪。收斂更穩定。
  SGD方法的一個缺點是,其更新方向完全依賴於當前的batch,因而其更新十分不穩定。解決這一問題的一個簡單的做法便是引入momentum。

公式:Δx_t=ρ*Δx_(t-1)−η*g_t

  ρ 即momentum,表示要在多大程度上保留原來的更新方向,這個值在0-1之間,在訓練開始時,由於梯度可能會很大,所以初始值一般選為0.5;當梯度不那麼大時,改為0.9。

2)Nesterov accelerated gradient(NAG)

  即Nesterov Momentum
  一般動量項取0.9附近,學習率取0.01。
  Nesterov提出的加速的梯度下降方法,這是對傳統momentum方法的一項改進。這種基於預測的更新方法,使我們避免過快地前進,並提高了演算法地響應能力(responsiveness),大大改進了 RNN 在一些任務上的表現 。

  首先,按照原來的更新方向更新一步(棕色線),然後在該位置計算梯度值(紅色線),然後用這個梯度值修正最終的更新方向(綠色線)。圖中描述了兩步的更新示意圖,其中藍色線是標準momentum更新路徑。
在這裡插入圖片描述

3)Adagrad(針對稀疏資料集)

  自適應地為各個引數分配不同學習率的演算法。
  優點:賦予更新頻繁的梯度以較小的學習率,賦予更新不頻繁的梯度以較大的學習率。尤其對於大型網路,可以提高SGD的魯棒性。
  缺點:由於梯度平方和隨著時間的會越來越大,造成訓練後期的學習率會非常小,學習的提前停止。

4)Adadelta

  Adadelta 法是 Adagrad 法的一個延伸,它旨在解決它學習率不斷單調下降的問題。相比計算之前所有梯度值的平方和,Adadelta 法僅計算在一個大小為t的時間區間內梯度值的累積和。

5) RMSprop

  建議學習率 取0.001為好。
  與AdaDelta方法類似(應該只是AdaDelta演算法的特例)。

6)Adam

  計算效率較高,能夠適應較大的資料集,能夠較好的處理稀疏集。
  自適應學習率梯度下降方法中Adam方法的效果比較好,應用的也比較多。
  偏差修正項 很重要,尤其是當 β2趨近於1時,可以防止步長變得過大。
  adam是RMSprop和AdaGrad的更一般形式,對於RMSprop和AdaGrad能夠處理的情形,一般都能處理,而且Adam演算法所需記憶體較少,計算效率高,所以近幾年優化演算法以adam為主。

7)Nadam演算法

  是adam演算法的推廣形式。
  一般情況下,針對adam演算法可以處理的情形,Nadam都能適用。在深度網路中Nadam演算法的表現一般要優於adam演算法。keras框架中包含該演算法。


Adam演算法詳解

  Adam是一種基於一階梯度來優化隨機目標函式的演算法。是目前深度學習中使用最廣泛的優化演算法,適用於多種應用。
  Adam 這個名字來源於 adaptive moment estimation,自適應矩估計。概率論中矩的含義是:如果一個隨機變數 X 服從某個分佈,X 的一階矩是 E(X),也就是樣本平均值,X 的二階矩就是 E(X^2),也就是樣本平方的平均值。Adam 演算法根據損失函式對每個引數的梯度的一階矩估計和二階矩估計動態調整針對於每個引數的學習速率。Adam 也是基於梯度下降的方法,但是每次迭代引數的學習步長都有一個確定的範圍,不會因為很大的梯度導致很大的學習步長,引數的值比較穩定。

  Adam 計算了一個 ν dw^corr 的值,用於加快指數加權移動平均值的變化。它將通過增加它們的值來對它們進行標準化,與當前的迭代次數成反比。

  使用 Adam 時有一些很好的初始值可供嘗試。它最好以 0.9 的 β_1 和 0.999 的 β_2 開頭。
  通過實驗發現,調低β2值,影響了Adam方法中過去平方梯度的指數移動平均值的貢獻度。一般來說,β2的預設值為0.999,設定為0.99或0.9後,在不同任務中表現更好,這表明可能存在指數移動平均值的問題。

  Adam之流雖然說已經簡化了調參,但是並沒有一勞永逸地解決問題,預設的引數雖然好,但也不是放之四海而皆準。因此,在充分理解資料的基礎上,依然需要根據資料特性、演算法特性進行充分的調參實驗。

SGD演算法詳解

  SGD是保證收斂的!
  使用Stochastic Gradient Descent或其變體訓練深度神經網路需要仔細選擇學習速率和批次大小。雖然較小的批量通常在較少的訓練時期收斂,但較大的批量提供了更多的並行性,並因此提高了計算效率。

  我們試過一些其他方法,但是我們發現好像都和SGD差不多。在多機訓練場景下,SGD會更加方便實現。

  一個程式碼上的細節,就是caffe的程式碼實現上選取一個batch的時候似乎是按著資料庫的圖片順序選取輸入圖片的,所以在生成資料庫的時候切記要shuffle一下圖片順序~
  caffe中ImageDataLayer有shuffle引數,生成lmdb時也有shuffle引數不必手動。


優化SGD的其他策略

  1)每個迭代週期完成後,打亂資料集的順序(Shuffling and Curriculum Learning)
  為了使得學習過程更加無偏,應該在每次迭代中隨機打亂訓練集中的樣本。
  另一方面,在很多情況下,我們是逐步解決問題的,而將訓練集按照某個有意義的順序排列會提高模型的效能和SGD的收斂性,如何將訓練集建立一個有意義的排列被稱為Curriculum Learning。
  Zaremba與Sutskever在使用Curriculum Learning來訓練LSTMs以解決一些簡單的問題中,表明一個相結合的策略或者混合策略比對訓練集按照按照訓練難度進行遞增排序要好。

  2)Batch normalization;

  3)提前停止;

  4)在訓練後期適當減小動量值能夠使網路更穩定的收斂。

  5)在梯度更新時,給梯度新增噪音可以增加網路的泛化能力。即每次迭代計算梯度中加上一個高斯分佈N(0,σ2t)的隨機誤差,高斯誤差的方差需要進行退火。
  對梯度增加隨機誤差會增加模型的魯棒性,即使初始引數值選擇地不好,並適合對特別深層次的負責的網路進行訓練。其原因在於增加隨機噪聲會有更多的可能性跳過區域性極值點並去尋找一個更好的區域性極值點,這種可能性在深層次的網路中更常見。


梯度下降的使用(指導性思路)

  1)當前最常用的是優化演算法有:SGD(帶動量),Adam, RMSprop;建議選擇SGD和Adam。sgd是保證收斂的

  2)現在有論文不用梯度下降優化演算法來訓練神經網路;例如《Training Deep Neural Networks via Optimization Over Graphs》

  3)如果你的資料特徵是稀疏的,那麼你最好使用自適應學習速率SGD優化方法(Adagrad、Adadelta、RMSprop與Adam),因為你不需要在迭代過程中對學習速率進行人工調整。

  4)非同步SGD方法。
  如果你處理的資料集非常大,並且有機器叢集可以利用,那麼並行或分散式SGD是一個非常好的選擇,因為可以大大地提高速度。SGD演算法的本質決定其是序列的(step-by-step)。因此如何進行非同步處理便是一個問題。雖然序列能夠保證收斂,但是如果訓練集大,速度便是一個瓶頸。如果進行非同步更新,那麼可能會導致不收斂。下面將討論如何進行並行或分散式SGD,並行一般是指在同一機器上進行多核並行,分散式是指叢集處理。比如1-bit。

  5)各大演算法孰優孰劣並無定論。如果是剛入門,優先考慮 SGD+Nesterov Momentum或者Adam.(Standford 231n : The two recommended updates to use are either SGD+Nesterov Momentum or Adam)

  6)選擇你熟悉的演算法——這樣你可以更加熟練地利用你的經驗進行調參。

  7)充分了解你的資料——如果模型是非常稀疏的,那麼優先考慮自適應學習率的演算法。

  8)根據你的需求來選擇——在模型設計實驗過程中,要快速驗證新模型的效果,可以先用Adam進行快速實驗優化;在模型上線或者結果釋出前,可以用精調的SGD進行模型的極致優化。

  9)先用小資料集進行實驗。有論文研究指出,隨機梯度下降演算法的收斂速度和資料集的大小的關係不大。(The mathematics of stochastic gradient descent are amazingly independent of the training set size. In particular, the asymptotic SGD convergence rates are independent from the sample size.)因此可以先用一個具有代表性的小資料集進行實驗,測試一下最好的優化演算法,並通過引數搜尋來尋找最優的訓練引數。

  10)考慮不同演算法的組合。先用Adam進行快速下降,而後再換到SGD進行充分的調優。

  11)資料集一定要充分的打散(shuffle)。這樣在使用自適應學習率演算法的時候,可以避免某些特徵集中出現,而導致的有時學習過度、有時學習不足,使得下降方向出現偏差的問題。

  12)訓練過程中持續監控訓練資料和驗證資料上的目標函式值以及精度或者AUC等指標的變化情況。對訓練資料的監控是要保證模型進行了充分的訓練——下降方向正確,且學習率足夠高;對驗證資料的監控是為了避免出現過擬合。

  13)制定一個合適的學習率衰減策略。可以使用定期衰減策略,比如每過多少個epoch就衰減一次;或者利用精度或者AUC等效能指標來監控,當測試集上的指標不變或者下跌時,就降低學習率。

  14)在一些特定任務上,比SGD好的比比皆是。
  例如:隨機加權平均(Stochasitc Average Gradient,SWA)是比SGD更廣泛的最優化,但還是很新。


梯度下降的使用(具體引數設定)

  1)原文中輸入的batch數目是256,應該Alex經過調節後的結果,我實際用到的機器效能比較低,記憶體8G,視訊記憶體4G,所以不得不就將batch數目往下調到64,以免產生out of memory的錯誤。這樣就需要調節其他的引數來保證資料的收斂。原因是batch比較小,導致本文開篇提到的樣本覆蓋面過低,產生了非常多的區域性極小點,在步長和方向的共同作用下,導致資料產生了震盪,導致了不收斂。

  2)在這種情況下,把learning rate調節到了0.02,相當於加大了步長,這樣可以在一定程度上避免震盪,可以越過區域性極小點往比較大的極值點行走。

  3)對於每一層的bias從1設定為了0.1,在一定程度上限制了啟用的大小,這樣就限制了某一過大的誤差的影響,這樣可以避免迭代方向出現過大的變化。

  4)經過1)和2)後,系統終於收斂了,但帶來的不良後果就是整個收斂速度變慢,因此還需要增加最大迭代次數,經過測試迭代次數成了從45w修改成了70w。

  5)在整個執行過程中,出現了幾次平穩點,20w以及40w左右的時候,因此迭代的learning rate應該隨著迭代的接近平穩點的時候有意的減小一些,目前是以每10w次減小為1/10,調引數用了5天,最後執行時間為15天。

  6)關於調參策略,上面只是按照一些簡單的理解設定的,如果沒有一個合理的解釋,調參就變成了一個很low的工作。還好發現了好幾篇關於調參的論文,主要是優化演算法理論方面的,學習完再回來測試一下。

實際地用alexnet和googlenet訓練

  1)針對AlexNet這種網路結構相對簡單的網路,在epoch相同的情形下,SGD和其他演算法的時間沒有太多差別,但是SGD和NAG演算法比其他演算法收斂的要快,精度也要高。建議選擇SGD演算法。

  2)對於GoogleNet等網路結構較為複雜的網路,SGD也可以收斂到很高的精度,adam演算法的收斂速度要快一點而且收斂更穩定;建議選擇adam演算法。

  3)建議引數設定(batchsize可以根據情況選擇28,64和128)

  SGD:     學習率,  動量,學習規則設為step就好;  
  NAG:      學習率,動量,學習規則設為step就好;
  AdaGrad:  學習率=0.001,   學習規則為INV 引數設定power 0.75 gama0.5;
  AdaDelta:學習率=1 ,      學習規則fix
  RMSprop:學習率=0.001,   學習規則 INV or poly
  adam:   學習率=0.001,   學習規則 INV or poly, sgmoid

  4)在GoogleNet上對adam演算法嘗試不同的學習規則(INV,poly,exp,sigmoid),實驗結果沒有明顯差別。原因有可能是訓練集較小。

  5)在GoogleNet上嘗試不同的優化方法和策略時,一般都可以收斂到較高的精度,影響演算法收斂和精度的主要因素還是學習率。

  6)在訓練網路時,建議先選擇引數預設值,和step學習規則進行嘗試,然後根據訓練結果調整引數。

  ADD演算法的初始學習率預設為1,SGD,NAG的預設學習率為0.01,其餘演算法的預設學習率為0.001;

  目前應用較多的優化演算法為SGD和Adam演算法。從在Alex-net上的結果看NAG要比SGD演算法精度高近一個百分點;

  RMSprop演算法對學習率十分敏感,比較難收斂,建議少用;

  當訓練網路不穩定時,建議第一次epoch先用較小的學習率,然後再調大學習率;

  學習率的設定不僅要考慮網路結構,還要考慮batchsize的大小,batchsize變小,學習率相應要減小一點(論文中有這種變化,沒有試驗,不一定都是這樣),隨著硬體的提高,一般選擇128和256;

  從論文來看,採用SGD時一般訓練中會採用兩個學習率的值,學習率變化太頻繁可能也會對網路精度造成一定的影響;

  從演算法出發,Adam演算法能適用稀疏資料和非平穩目標資料,所以近兩年論文多采用此方法;

  對於動量和weight-decay一般都為0.9和0.0005,,很少有實驗改動這兩個值;

  Alex就在2012年的AlexNet中,把所有Tanh/Logistic全換成了ReLu(卷積+隱層,Softmax要取概率沒辦法)

  對於使用ImageNet訓練AlexNet模型,每個GPU的最佳批量大小為512。

實際地用alexnet和VGG16訓練

  both AlexNet and VGG16 variants are trained for 30 epochs using the Adam optimizer with momentum of β1 = 0.9, β2 = 0.999, and weight decay of 0.0005. The learning rate is 0.0001 and is held constant during the pre-training stage.