文章目錄
1.介紹
在機器學習模型訓練時,模型優化算法是必不可少的,例如常見的梯度下降優化算法SGD,這也是大多數機器學習’煉丹師‘第一次接觸機器學習時使用的優化算法,也是最容易理解的,但是機器學習任務中模型千變萬化,很難做到一種優化算法“通吃”所有模型。因此對於不同的模型,需要對原始的梯度下降優化算法不斷的改進優化。下面就對梯度下降優化等常見的優化算法及其改進算法做一一介紹。
2.常見優化算法
2.1 梯度下降法及其變種
2.1.1 批梯度下降法
批梯度下降法(batch gradient descent)是指在整個訓練數據集上求解損失函數關於參數θ的梯度:
- η表示學習率,通常是一個較小的值,例如0.001,其決定我們將以多大的步長更新參數;
- ▽θJ(θ)表示損失函數在整個數據集上對參數θ計算一階導數(取平均值)。因爲是更新參數θ,所以計算θ的一階導,一階導方向是參數變化最快的方向。
由於每次更新時使用整個數據集計算所有梯度,因此計算速度非常慢,同時批梯度下降法不能在線更新模型,無法在運行過程中,增加新的樣本。批梯度下降法代碼如下:
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params)
params = params - learning_rate * params_grad
注意:
- 對於損失函數爲凸函數的情況,批梯度下降法能夠收斂到全局最小值;
- 對於損失函數爲非凸函數的情況,批梯度下降法則能夠收斂到局部最小值。
2.1.2 隨機梯度下降法
批梯度下降法(stochastic gradient descent)是指使用每一條數據來計算梯度值更新參數:
- η表示學習率,通常是一個較小的值,例如0.001,其決定我們將以多大的步長更新參數;
- ▽θJ(θ;xi;yi)表示損失函數在每一條數據上對參數θ計算一階導數。因爲是更新參數θ,所以計算θ的一階導,一階導方向是參數變化最快的方向。
通常,隨機梯度下降法相比於批梯度下降法具有更快的速度,可用於在線學習,SGD以高方差頻繁地更新,因此容易出現下列劇烈波動的情況。
SGD優化算法的特點:
- 相比於批梯度下降法可能使得損失函數陷入局部的缺點,SGD的波動性使得其有可能收斂到更好的局部最優,
- 這也使得SGD收斂到局部最小值的過程變得更加複雜,因爲SGD一直在震盪。
與批梯度下降法的優化代碼相比,SGD只是在訓練的輪次中,每次選擇一個訓練樣本時多了一個for循環。
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.1.3 小批量梯度下降法
小批量梯度下降法(mini-batch gradient descent)綜合了上述兩種方法的優點,在每次訓練時使用 n 個小批量樣本進行更新:
該方法的特點:
- 可以以更小的方差來更新參數,參數收斂的過程波動更小;
- 獲得比批梯度下降法更快的運行速度。
訓練神經網絡模型,當使用小批量梯度下降法時,也將其稱爲SGD。
⚠️ 在下文提到的SGD,爲了簡單起見,我們省略了參數xi:i+n;yi:i+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_grd
從上面三種基本的梯度下降法可以看出,即使是小批量下降法也並不能保證模型參數達到很好的收斂效果,目前具有下面的問題(這也是後來的很多改進的優化算法改進的動力和方向):
- 選擇一個合適的學習率是困難的。學習率太小會導致收斂太慢,太大會影響模型的收斂,有可能在最小值附近不斷波動甚至偏離最小值。
- 對於不同的參數使用相同的學習率更新是不合理的。如果數據是稀疏的,就不能使用相同的學習率來更新了,對於出現次數少的特徵,我們對其執行更大的學習率;
- 高度非凸誤差函數普遍出現在神經網絡中,在優化這類函數時,另一個關鍵的挑戰是使函數避免陷入無數次優的局部最小值。Dauphin等人指出出現這種困難實際上並不是來自局部最小值,而是來自鞍點,即那些在一個維度上是遞增的,而在另一個維度上是遞減的。這些鞍點通常被具有相同誤差的點包圍,因爲在任意維度上的梯度都近似爲0,所以SGD很難從這些鞍點中逃開。
2.2 梯度下降法的優化算法
在正式學習各種SGD的改進的優化算法之前,可以先通過這中動圖感受下各個優化算法收斂速度和收斂效果。
2.2.1 Momentum-動量法
SGD很難通過陡谷,即在一個維度的表面彎曲程度遠大於其他維度的區域,這種情況通常出現在局部最優點附近,這種情況下,SGD在不斷波動下通過陡谷的斜坡,在沿着谷底到局部最優點的路徑上緩慢前進,過程如下圖(a)所示:
如上圖(b)所示,動量法是一種幫助SGD在相關方向上加速並抑制搖擺的方法,利於處理非平穩梯度,動量法是將上一次更新量的一個分量γ增加到當前的更新量中,公式如下:
- 上面公式(1)等號後面,γ表示使用上次更新量的權重,決定了動量的大小,η部分跟前面SGD參數更新量完全相同;
- 公式(2)中,不再像前面SGD公式中直接將學習率大小體現出來了,而是整個的包含在νt中了。在後面的其他改進SGD的優化算法中也是類似的做法。
動量項γ通常可以設置成0.9。
可以這樣來理解動量。參考文獻[1]中這樣的比喻很好:從山坡上往下推一個球,在往下滾動的過程中累積動量,速度越來越快,如果有空氣阻力,則γ<1。對於參數更新也是如此,對於在當前梯度點處有相同方向的維度,動量項增加,對於在梯度點處改變方向的維度,其動量項減小,因此我們可以獲得更快的收斂速度,同時可以減小頻繁的波動。
2.2.2 Nesterov-加速梯度下降法
接着上面舉的例子,如果球盲目的沿着斜率方向向下滾動,結果也不一定總是令人滿意,我們希望有一個智能的球,能夠知道它將要去哪,如果遇到斜率將要上升時,能夠知道減速。
Nesterov加速梯度下降法(Nesterov accelerated gradient,NAG)是一種能夠給動量項γνt−1
一種預知能力的方法。我們使用動量項更新參數,通過計算θ - γνt−1
能夠告訴我們參數未來位置的一個近似值,也就是告訴我們參數將大致變爲多少。通過計算參數未來的近似位置的梯度,即使用θ - γνt−1
計算梯度,而不是使用θ
來計算梯度,我們可以更加高效的求解(我自己理解爲:這裏的一次參數更新近似於動量法的兩次更新,所以是加速了):
上面公式(3)中,η部分,表示假設更新量爲上次梯度上的動量大小,這是個近似更新量,然後再基於這個更新後的損失函數對於參數θ的一階導數作爲當前新的梯度,即公式(3)中η後面的部分。到這裏就可以直接套用動量優化算法中公式(1)了,因此上面我理解爲這種方式的一次參數更新的效果近似於動量法的兩次參數更新的效果,所以理論上是加速了。
因爲NAG-加速梯度下降法跟Momentum-動量法相似之處比較多,所以可以通過下面的一幅圖對比兩者的關係:
一般設置動量項γ的大小爲0.9左右!
- 動量法:首先計算當前的梯度值(箭頭線1),然後在更新的累積梯度上前進一大步(箭頭線2);
- 加速梯度下降法:首先作一個預見性的更新,即在先前累積梯度方向上前進一大步(箭頭線3),並計算出梯度作爲一個修正(箭頭線4),修正後爲箭頭線5。這裏的預見性更新增強了算法的響應能力(即加速),同時通過修正防止了前進地太快。這一點對於很多RNN的任務的性能提升有着重要的意義。
對於上面的動量法和NAG法,是通過使參數更新適應損失函數的斜率以加速SGD;那麼爲了進一步優化,考慮使得參數的更新適應每一個單獨參數,以根據每一個參數來決定是大的更新還是小的更新。這也是後面的優化算法設計的初衷。
2.2.3 Adagrad-自適應梯度
Adagrad是一種適應參數的梯度下降優化算法,其自適應性可以個性化到特徵級別,出現次數較少的特徵的,會使用更大的學習率,出現次數較多的特徵,會使用較小的學習率,因此Adagrad適合於稀疏數據的深度神經網絡模型。
- Dean等人[4]發現Adagrad能夠極大提高了SGD的魯棒性並將其應用於Google的大規模神經網絡的訓練,其中包含了YouTube視頻中的貓的識別;
- Pennington等人[15]利用Adagrad訓練Glove詞向量,因爲低頻詞比高頻詞需要更大的步長。
Agagrad在每次更新所有的參數θ
時,對於每個參數使用不同的學習率,我們先看下如何對不同的參數進行更新的。下面公式(5)表示在t時刻損失函數關於參數θi
的梯度:
如果受用固定步長的學習率,則參數更新公式爲:
現在加入對不同參數個性化的步長因子,即在t時刻,基於對不同參數計算過的歷史梯度,Adagrad修正了每一個參數的學習率:
其中,Gt
是一個對角矩陣,對角線上的元素ii
是從開始截止到t
時刻爲止,所有關於θi
的梯度的平方和,Gt
具體計算數值如下公式:
(Duchi等人將該矩陣作爲包含所有先前梯度的外積的完整矩陣的替代,因爲即使是對於中等數量的參數d,矩陣的均方根的計算都是不切實際的。)。ϵ是平滑項,用於防止除數爲0(通常大約設置爲1e−8)。
Adagrad優化算法中[6],如果沒有平方根的計算,那麼效果將會比較差。
現在我們將上面的公式向量化,主要爲是爲了簡單。主要是將G
和g
之間的計算操作向量化,如下:
Adagrad算法的優缺點如下:
- 優點:主要優點就是無需手動調整學習率,基本上採用 0.01 即可。
- 缺點:由於其在分母中累加梯度的平方,每次增加一個正項,隨着訓練過程積累,會導致學習率越來越小,當學習率變得無限小時Adagrad算法將無法獲得額外的信息更新。
下面將要介紹算法也是針對Adagrad的缺點進行改進的。
2.2.4 Adadelta
Adadelta算法完全移除了學習率,不再需要人工設置學習率參數。
Adadelta算法是Adagrad的一種擴展,以解決Adagrad學習速率單調遞減的缺點。Adadelta算法無需存儲歷史梯度的平方和,而是將梯度的平方遞歸地表示成所有歷史梯度的均值,因此在t
時刻的均值只取決於先前的均值和當前的梯度:
其中γ與動量項相似,可以設置成0.9。
對於參數更新向量我們可以表示成:
那麼,我們直接將Gt
替換成歷史梯度均值則爲:
上述公式中由於分母就是均方根,所以可以直接簡寫爲:
Adadelta[7]直接指出了上述幾種優化算法中更新規則與參數的單位不一致的問題,爲此Adadelta實現了這個要求,類似於梯度的動量形式的均值,作者首次提出了參數的動量形式的均值,如下公式所示:
那麼參數更新的均方根爲:
因爲RMS[Δθ]t是未知的,所以近似取到t-1
時刻的均方根來RMS[Δθ]t-1近似更新,並替換之前的固定值形式的學習率η
,可以得到Adadelta的更新向量爲:
使用Adadelta優化算法,我們無需設置學習率,因爲公式中已經移除了學習率的超參數。
2.2.5 RMSprop
RMSprop優化算法是Geoff Hinton提出來的一種自適應學習率的算法,與Adadelta幾乎同時提出來的,是Adadelta的一個特例。
RMSprop與Adadelta一樣,都是去解決Adagrad的學習率下降太快的問題的,參數更新公式如下:
因此,RMSprop也是將學習率分解成平方梯度的指數衰減的平均,對於學習率η,建議選擇 0.001。
2.2.6 Adam-自適應矩估計
自適應矩估計(Adaptive Moment Estimation, Adam)也是一種會對每一個參數會計算出自適應學習率的算法。它一個動量算法和RMSprop算法的結合體,既考慮到了利用動量項來加速訓練過程,又考慮到對於學習率的約束。Adam也會計算出來一個指數衰減的歷史平方梯度的平均vt ,Adam同時還計算一個指數衰減的歷史梯度的平均mt,類似於動量:
因此,mt
是對梯度的一階矩的估計,νt
是對梯度的二階矩(非確定性誤差)的估計。
但是當mt
和νt
都初始化爲0時,特別是在初始化的步驟和衰減率都很小時(β1
和β2接近於1
),Adam比較接近於0,這對於參數更新並不友好(更新太慢),Adam中是通過計算偏差矯正的一階矩估計和二階矩估計來抵消偏差的,公式如下:
至此,生成Adam的參數更新公式如下:
Adam作者建議β1
、β2
分別取默認值0.9、0.999就好,ϵ爲10−8。
從經驗上來看,Adam在實際任務中表現更好(哈哈,其他人的經驗)。
通過上面對Adam的理解,可以看出來,Adam結合了Adagrad善於處理稀疏梯度和Momentum善於處理非平穩目標的優點,相較於其他幾種優化器效果更好。
2.2.7 AdaMax
AdaMax優化算法是對Adam算法的更新。
Adam算法中,使用到了參數的指數衰減的梯度平方的平均,即:
對上面的公式進行擴展到ℓp
範數,同時也將β2
擴展到βp2
,上面公式變爲:
在這裏,AdaMax用到了範數的相關形性質,即通常大p
值的範數通常具有數值不穩定性,因此我們更常見到的是1範數和2範數,但是無窮範數除外,當p
趨於無窮時,範數具有較好的數值穩定性。
因此,AdaMax的作者提出了使用無窮範數的AdaMax優化算法,並且使用了ℓ∞
的vt
能夠收斂到一個外穩定的值,爲了避免和上面的Adam優化算法搞混淆,我們使用ut
來代替vt
作爲參數更新的表示:
根據上面的參數更新向量放到前面Adam的參數更新公式中,即爲:
對公式(28)中,由於取的是最大值的計算操作,因此不用像在Adam中擔心參數更新量趨近於0的問題,因此在AdaMax中也不需要進行偏差矯正的操作。
AdaMax中的超參數,一般比較好的默認是η=0.002
、β1=0.9
、β2=0.999
。
2.2.8 Nadam-加速自適應矩估計
Adam算法結合了RMSprop優化算法和動量優化算法的優點:
- RMSprop產生指數衰減的平方梯度的均值vt;
- 動量算法產生指數衰減的平方梯度的均值mt。
在上面介紹到的各種優化算法中,我們可以看到NAG算法優於動量優化算法。
基於此,Nadam結合了Adam算法和NAG算法,爲了能夠將NAG算法應用於Adam公式中,我們需要修改NAG算法的動量部分mt。
這裏我們再來看下動量算法、NAG的對動量的改進算法的邏輯:
先是動量優化算法-Momentum:
將公式(31)帶入公式(32)得到如下:
從公式(33)容易看出,Momentum優化算法包括在歷史累積梯度方向上前進一步、在當前梯度方向上前進一步。
再是NAG加速動量優化算法:
NAG算法在計算梯度前就先使用動量步驟來更新參數,因此NAG跟Momentum的區別就是計算梯度gt上的差別。
基於上面兩個基本的動量方向的優化算法的邏輯,引出Nadam算法:
相比於NAG算法的有兩個使用動量的步驟-其一是更新梯度gt,其二是更新參數θt+1,我們現在使用look-ahead方式的動量直接更新當前參數:
可以對比和公式(39)和公式(33),可以看到他們唯一的區別是look-ahead方式中的動量更新中使用了截止到當前t的動量mt
,而在NAG的參數更新規則中使用的截止到t-1的動量mt−1
。我們可以通過類比將歷史動量向量替換爲當前動量向量的方式,來將NAG算法特點應用在Adam算法中,Adam的原始更新規則爲:
將上面公式(41)中的mt
帶入得到公式(42)的展開式如下:
上面的公式(44)模塊爲上一步驟的動量估計的偏差修正,儘管公式(45)纔是準確的對於上一步驟的動量估計的偏差修正,但是爲了簡單起見,此處我們忽略掉公式(44)和(45)在分母上的區別,所以公式(43)可以轉化爲:
到這裏,可以對比一下公式(46)和公式(39)了,類比於在公式(39)中用當前動量替代前一個步驟的動量的做法,我們將Nesterov Momentum的思想引入到Adam中了,最終參數更新規則如下:
2.2.9 Lookahead
Geoffrey Hinton 的研究團隊近期剛發表出來一篇 Lookahead 優化算法,大佬的研究成果自然要多關注呀,畢竟站在巨人的肩膀上。這週會算法核心內容更新進來。。。敬請期待!