優化器演算法Optimizer詳解(BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam)
轉自:https://www.cnblogs.com/guoyaohua/p/8542554.html
在機器學習、深度學習中使用的優化演算法除了常見的梯度下降,還有 Adadelta,Adagrad,RMSProp 等幾種優化器,都是什麼呢,又該怎麼選擇呢?
在 Sebastian Ruder 的這篇論文中給出了常用優化器的比較,今天來學習一下:
https://arxiv.org/pdf/1609.04747.pdf
本文將梳理:
- 每個演算法的梯度更新規則和缺點
- 為了應對這個不足而提出的下一個演算法
- 超引數的一般設定值
- 幾種演算法的效果比較
- 選擇哪種演算法
0.梯度下降法深入理解
以下為個人總結,如有錯誤之處,各位前輩請指出。
對於優化演算法,優化的目標是網路模型中的引數θ(是一個集合,θ1、θ2、θ3 ......)目標函式為損失函式L = 1/N ∑ Li (每個樣本損失函式的疊加求均值)。這個損失函式L變數就是θ,其中L中的引數是整個訓練集,換句話說,目標函式(損失函式)是通過整個訓練集來確定的,訓練集全集不同,則損失函式的影象也不同。那麼為何在mini-batch中如果遇到鞍點/區域性最小值點就無法進行優化了呢?因為在這些點上,L對於θ的梯度為零,換句話說,對θ每個分量求偏導數,帶入訓練集全集,導數為零。對於SGD/MBGD而言,每次使用的損失函式只是通過這一個小批量的資料確定的,其函式影象與真實全集損失函式有所不同,所以其求解的梯度也含有一定的隨機性,在鞍點或者區域性最小值點的時候,震盪跳動,因為在此點處,如果是訓練集全集帶入即BGD,則優化會停止不動,如果是mini-batch或者SGD,每次找到的梯度都是不同的,就會發生震盪,來回跳動。
一.優化器演算法簡述
首先來看一下梯度下降最常見的三種變形 BGD,SGD,MBGD,這三種形式的區別就是取決於我們用多少資料來計算目標函式的梯度,這樣的話自然就涉及到一個 trade-off,即引數更新的準確率和執行時間。
1.Batch Gradient Descent (BGD)
梯度更新規則:
BGD 採用整個訓練集的資料來計算 cost function 對引數的梯度:
缺點:
由於這種方法是在一次更新中,就對整個資料集計算梯度,所以計算起來非常慢,遇到很大量的資料集也會非常棘手,而且不能投入新資料實時更新模型。
for i in range(nb_epochs): params_grad = evaluate_gradient(loss_function, data, params) params = params - learning_rate * params_grad
我們會事先定義一個迭代次數 epoch,首先計算梯度向量 params_grad,然後沿著梯度的方向更新引數 params,learning rate 決定了我們每一步邁多大。
Batch gradient descent 對於凸函式可以收斂到全域性極小值,對於非凸函式可以收斂到區域性極小值。
2.Stochastic Gradient Descent (SGD)
梯度更新規則:
和 BGD 的一次用所有資料計算梯度相比,SGD 每次更新時對每個樣本進行梯度更新,對於很大的資料集來說,可能會有相似的樣本,這樣 BGD 在計算梯度時會出現冗餘,而 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
看程式碼,可以看到區別,就是整體資料集是個迴圈,其中對每個樣本進行一次引數更新。
隨機梯度下降是通過每個樣本來迭代更新一次,如果樣本量很大的情況,那麼可能只用其中部分的樣本,就已經將theta迭代到最優解了,對比上面的批量梯度下降,迭代一次需要用到十幾萬訓練樣本,一次迭代不可能最優,如果迭代10次的話就需要遍歷訓練樣本10次。缺點是SGD的噪音較BGD要多,使得SGD並不是每次迭代都向著整體最優化方向。所以雖然訓練速度快,但是準確度下降,並不是全域性最優。雖然包含一定的隨機性,但是從期望上來看,它是等於正確的導數的。
缺點:
SGD 因為更新比較頻繁,會造成 cost function 有嚴重的震盪。
BGD 可以收斂到區域性極小值,當然 SGD 的震盪可能會跳到更好的區域性極小值處。
當我們稍微減小 learning rate,SGD 和 BGD 的收斂性是一樣的。
3.Mini-Batch Gradient Descent (MBGD)
梯度更新規則:
MBGD 每一次利用一小批樣本,即 n 個樣本進行計算,這樣它可以降低引數更新時的方差,收斂更穩定,另一方面可以充分地利用深度學習庫中高度優化的矩陣操作來進行更有效的梯度計算。
和 SGD 的區別是每一次迴圈不是作用於每個樣本,而是具有 n 個樣本的批次。
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
超引數設定值: n 一般取值在 50~256
缺點:(兩大缺點)
- 不過 Mini-batch gradient descent 不能保證很好的收斂性,learning rate 如果選擇的太小,收斂速度會很慢,如果太大,loss function 就會在極小值處不停地震盪甚至偏離。(有一種措施是先設定大一點的學習率,當兩次迭代之間的變化低於某個閾值後,就減小 learning rate,不過這個閾值的設定需要提前寫好,這樣的話就不能夠適應資料集的特點。)對於非凸函式,還要避免陷於區域性極小值處,或者鞍點處,因為鞍點周圍的error是一樣的,所有維度的梯度都接近於0,SGD 很容易被困在這裡。(會在鞍點或者區域性最小點震盪跳動,因為在此點處,如果是訓練集全集帶入即BGD,則優化會停止不動,如果是mini-batch或者SGD,每次找到的梯度都是不同的,就會發生震盪,來回跳動。)
- SGD對所有引數更新時應用同樣的 learning rate,如果我們的資料是稀疏的,我們更希望對出現頻率低的特徵進行大一點的更新。LR會隨著更新的次數逐漸變小。
鞍點就是:一個光滑函式的鞍點鄰域的曲線,曲面,或超曲面,都位於這點的切線的不同邊。例如這個二維圖形,像個馬鞍:在x-軸方向往上曲,在y-軸方向往下曲,鞍點就是(0,0)。
為了應對上面的兩點挑戰就有了下面這些演算法。
前期知識:指數加權平均,請參看博文《什麼是指數加權平均、偏差修正?》
[應對挑戰 1]
4.Momentum
SGD 在 ravines 的情況下容易被困住, ravines 就是曲面的一個方向比另一個方向更陡,這時 SGD 會發生震盪而遲遲不能接近極小值:
梯度更新規則:
Momentum 通過加入 γv_t−1 ,可以加速 SGD, 並且抑制震盪
當我們將一個小球從山上滾下來時,沒有阻力的話,它的動量會越來越大,但是如果遇到了阻力,速度就會變小。
加入的這一項,可以使得梯度方向不變的維度上速度變快,梯度方向有所改變的維度上的更新速度變慢,這樣就可以加快收斂並減小震盪。
超引數設定值: 一般 γ 取值 0.9 左右。
缺點:
這種情況相當於小球從山上滾下來時是在盲目地沿著坡滾,如果它能具備一些先知,例如快要上坡時,就知道需要減速了的話,適應性會更好。
5.Nesterov Accelerated Gradient
梯度更新規則:
用 θ−γv_t−1 來近似當做引數下一步會變成的值,則在計算梯度時,不是在當前位置,而是未來的位置上
超引數設定值: 一般 γ 仍取值 0.9 左右。
效果比較:
藍色是 Momentum 的過程,會先計算當前的梯度,然後在更新後的累積梯度後會有一個大的跳躍。
而 NAG 會先在前一步的累積梯度上(brown vector)有一個大的跳躍,然後衡量一下梯度做一下修正(red vector),這種預期的更新可以避免我們走的太快。
NAG 可以使 RNN 在很多工上有更好的表現。
目前為止,我們可以做到,在更新梯度時順應 loss function 的梯度來調整速度,並且對 SGD 進行加速。
我們還希望可以根據引數的重要性而對不同的引數進行不同程度的更新。
[應對挑戰 2]
6.Adagrad (Adaptive gradient algorithm)
這個演算法就可以對低頻的引數做較大的更新,對高頻的做較小的更新,也因此,對於稀疏的資料它的表現很好,很好地提高了 SGD 的魯棒性,例如識別 Youtube 視訊裡面的貓,訓練 GloVe word embeddings,因為它們都是需要在低頻的特徵上有更大的更新。
梯度更新規則:
其中 g 為:t 時刻引數 θ_i 的梯度
如果是普通的 SGD, 那麼 θ_i 在每一時刻的梯度更新公式為:
但這裡的 learning rate η 也隨 t 和 i 而變:
其中 G_t
是個對角矩陣, (i,i) 元素就是 t 時刻引數 θ_i
的梯度平方和。
Adagrad 的優點是減少了學習率的手動調節
超引數設定值:一般η選取0.01
缺點:
它的缺點是分母會不斷積累,這樣學習率就會收縮並最終會變得非常小。
7.Adadelta
這個演算法是對 Adagrad 的改進,
和 Adagrad 相比,就是分母的 G 換成了過去的梯度平方的衰減平均值,指數衰減平均值
這個分母相當於梯度的均方根 root mean squared (RMS),在資料統計分析中,將所有值平方求和,求其均值,再開平方,就得到均方根值 ,所以可以用 RMS 簡寫:
其中 E 的計算公式如下,t 時刻的依賴於前一時刻的平均和當前的梯度:
梯度更新規則:
此外,還將學習率 η 換成了 RMS[Δθ],這樣的話,我們甚至都不需要提前設定學習率了:
超引數設定值: γ 一般設定為 0.9
7.RMSprop
RMSprop 是 Geoff Hinton 提出的一種自適應學習率方法。
RMSprop 和 Adadelta 都是為了解決 Adagrad 學習率急劇下降問題的,
梯度更新規則:
RMSprop 與 Adadelta 的第一種形式相同:(使用的是指數加權平均,旨在消除梯度下降中的擺動,與Momentum的效果一樣,某一維度的導數比較大,則指數加權平均就大,某一維度的導數比較小,則其指數加權平均就小,這樣就保證了各維度導數都在一個量級,進而減少了擺動。允許使用一個更大的學習率η)
超引數設定值:
Hinton 建議設定 γ 為 0.9, 學習率 η 為 0.001。
8.Adam:Adaptive Moment Estimation
這個演算法是另一種計算每個引數的自適應學習率的方法。相當於 RMSprop + Momentum
除了像 Adadelta 和 RMSprop 一樣儲存了過去梯度的平方 vt 的指數衰減平均值 ,也像 momentum 一樣保持了過去梯度 mt 的指數衰減平均值:
如果 mt 和 vt 被初始化為 0 向量,那它們就會向 0 偏置,所以做了偏差校正,通過計算偏差校正後的 mt 和 vt 來抵消這些偏差:
梯度更新規則:
超引數設定值:
建議 β1 = 0.9,β2 = 0.999,ϵ = 10e−8
實踐表明,Adam 比其他適應性學習方法效果要好。
二.效果比較
下面看一下幾種演算法在鞍點和等高線上的表現:
SGD optimization on saddle point
SGD optimization on loss surface contours
上面兩種情況都可以看出,Adagrad, Adadelta, RMSprop 幾乎很快就找到了正確的方向並前進,收斂速度也相當快,而其它方法要麼很慢,要麼走了很多彎路才找到。
由圖可知自適應學習率方法即 Adagrad, Adadelta, RMSprop, Adam 在這種情景下會更合適而且收斂性更好。
三.如何選擇優化演算法
如果資料是稀疏的,就用自適用方法,即 Adagrad, Adadelta, RMSprop, Adam。
RMSprop, Adadelta, Adam 在很多情況下的效果是相似的。
Adam 就是在 RMSprop 的基礎上加了 bias-correction 和 momentum,
隨著梯度變的稀疏,Adam 比 RMSprop 效果會好。
整體來講,Adam 是最好的選擇。
很多論文裡都會用 SGD,沒有 momentum 等。SGD 雖然能達到極小值,但是比其它演算法用的時間長,而且可能會被困在鞍點。
如果需要更快的收斂,或者是訓練更深更復雜的神經網路,需要用一種自適應的演算法。
資料:
http://sebastianruder.com/optimizing-gradient-descent/index.html#fn:24
http://www.redcedartech.com/pdfs/Select_Optimization_Method.pdf
https://stats.stackexchange.com/questions/55247/how-to-choose-the-right-optimization-algorithm