編譯:AI100,本文經授權發布,轉載請聯系AI100.
英文:https://www.analyticsvidhya.com/blog/2017/03/introduction-to-gradient-descent-algorithm-along-its-variants/
前 言
無論是要解決現實生活中的難題,還是要創建一款新的軟件產品,我們最終的目標都是使其達到最優狀態。作為一名計算機科學專業的學生,我經常需要優化各種代碼,以便提高其整體的運行速度。
一般情況下,最優狀態會伴隨問題的最佳解決方案。如果閱讀近期發表的關于優化問題的文章的話,你會發現,優化問題在現實生活中扮演著非常重要的作用。
機器學習中的優化問題與我們剛剛提到的內容有些許不同。通常情況下,在優化的過程中,我們非常清楚數據的狀態,也知道我們想要優化哪些區域。但是,在機器學習中,我們本就對“新數據”一無所知,更不要提優化問題了!
因此在機器學習中,我們對訓練數據進行優化,隨后再在全新的驗證數據中檢驗其運行情況。
目前,優化技術正被廣泛應用于各種不同的領域中,例如:
結構——比如說:決定航天設計的外型。
經濟——比如說:成本最低化。
物理——比如說:優化量子計算時間。
優化還有許多更為高級的應用,例如:提供最優運輸路徑,使貨架空間最合理化等等。
許多受歡迎的機器算法都源于優化技術,例如:線性回歸算法、K-最近鄰算法、神經網絡算法等等。在學術界以及各行各業中,優化研究比比皆是,優化應用隨處可見。
在本篇文章中,我會向大家介紹梯度下降(GradientDescent)這一特殊的優化技術,在機器學習中我們會頻繁用到。
什么是梯度下降?
運用梯度下降算法所面臨的挑戰
梯度下降算法的變式
梯度下降的實現過程
使用梯度下降算法的實用小貼士
附錄
我會以經典的登山案例來解釋梯度下降的含義。
假設你現在在山頂處,必須抵達山腳下(也就是山谷最低處)的湖泊。但讓人頭疼的是,你的雙眼被蒙上了無法辨別前進方向。那么,你會采取什么辦法抵達湖泊處呢?
最好的辦法就是查看一下周圍的地勢,觀察有下降趨勢的地面,這會幫助你邁出第一步。如果沿著下降的路線前進,那么你非常有可能到達湖泊。
以圖形的形式呈現該處地勢。注意下面的曲線圖:
現在讓我們用數學術語把這個情景繪制成地圖吧。
為了學習梯度下降算法,假設我們需要找出最佳的參數(θ1)和(θ2)。與上述做法相似,在測繪“成本空間”時,我們需要找到相似的山脈和山谷。成本空間是指為參數選定了一個特殊值后,算法的運行情況。
所以,在Y軸上,我們讓J(θ1)與X軸上的參數(θ1)以及Z軸上的參數(θ2)分別相交。在這里,數值高的紅色區域代表山峰,數值低的藍色區域代表山谷。
梯度下降算法的類型有很多種,主要分為兩種:
基于數據的獲取
1.全批梯度下降算法
2.隨機梯度下降算法
在全批梯度下降算法中,需要利用全部數據同時計算梯度;然而在隨機梯度下降算法中,通常只需選取其中一個樣例來計算梯度。
基于微分技術
1.一階微分
2.二階微分
梯度下降需要通過成本函數微分來計算梯度。我們可以用一階微分技術或者二階微分技術來計算。
在大多數情況下,梯度下降是一種聲音技術。但在很多情況下,梯度下降無法正常工作,甚至不工作。原因有三點:
數據挑戰
梯度挑戰
執行挑戰
如果數據按照某種方式進行組合形成了一個非凸的優化問題,那么就很難利用梯度下降算法對其進行優化了。梯度下降算法只能解決那些意義非常明確的凸優化問題。
在優化凸問題時,可能會出現無數的極小點。最低點被稱為全局最小值,其它的點被稱為局部極小值。我們的目的是要達到全局極小值,而非局部極小值。
還有一個問題就是鞍點。梯度為零時,它是數據中的一個點,但是不是最優點。目前,我們還沒有特定的方法來規避鞍點的出現,是一個新的研究領域。
如果執行梯度下降算法時出現了錯誤,那么可能會導致諸如梯度消失或者梯度崩潰等的問題。當梯度太小或者太大時,就會出現這樣的問題。也正因為這些問題,算法無法收斂。
通常情況下,大多數神經網絡的開發者不會留意執行情況,但是觀察網絡資源利用率是非常重要的。比如,在執行梯度下降算法時,了解需要多少資源是非常重要的。如果應用程序的儲存器太小,那么網絡就會失敗。
跟蹤諸如浮點數的注意事項以及軟/硬件的先決條件,也非常重要。
讓我們來看一下最常用的梯度下降算法及其執行情況。
這是梯度下降技術中最簡單的形式。此處的 vanilla 是純凈/不摻雜任何雜質的意思。它的主要特性就是,使我們向著成本函數梯度的最小值又邁進了一小步。
我們來看一下它的偽代碼。
update=learning_rate*gradient_of_parameters
parameters=parameters-update
在這里,我們通過參數梯度來更新參數。而后通過學習率使其多樣化,實質上,常數代表著我們期望的達到最小值的速率。學習率是一種超參數,其數值一旦確定,就需要我們認真對待。
在進行下一步之前,我們先對之前的算法稍作調整,以便回顧前面的步驟。
這是一組偽代碼。
update=learning_rate*gradient
velocity=previous_update*momentum
parameter=parameter+velocity–update
此處,更新后的代碼與普通的梯度下降算法一樣。但是考慮到之前的更新和常量(動量),我們引進了一個名為速率(velocity)的術語。
ADAGRAD 算法使用了自適應技術來更新學習率。在這種算法中,我們會根據前期所有更迭的梯度變化情況,改變學習率。
這是一組偽代碼。
grad_component=previous_grad_component+(gradient*gradient)
rate_change=square_root(grad_component)+epsilon
adapted_learning_rate=learning_rate*rate_change
update=adapted_learning_rate*gradient
parameter=parameter–update
在上述代碼中,epsilon 是一個用于抑制學習率產生變動率的常量。
ADAM 算法是一種以 adagrad 算法為基礎并且能進一步減少其缺點的更加自適應的技術。也就是說,你可以認為 ADAM 算法是動量和 ADAGRAD 算法的綜合體。
這是一組偽代碼。
adapted_gradient=previous_gradient+((gradient–previous_gradient)*(1–beta1))
gradient_component=(gradient_change–previous_learning_rate)
adapted_learning_rate=previous_learning_rate+(gradient_component*(1–beta2))
update=adapted_learning_rate*adapted_gradient
parameter=parameter–update
上述代碼中的 beta1 和 beta2 是用來保持梯度和學習率不變的常量。
與此同時,還存在如 l-BFGS 等這樣的二階微分算法。你可以在 scipy 數據庫中看到這種算法的執行情況。
現在我們來看一下利用 python 實現梯度下降的基礎小案例。
在這里,我們將會利用梯度下降優化算法找出深度學習模型中圖像識別應用問題的最佳參數。我們的問題是圖像識別,從已給的28 x 28圖像中分辨出其中的數字。我們有一個關于圖像的子集,一部分圖像用于訓練模型,另一部分圖像用于測試模型。在本篇文章中,我們會向大家介紹定義梯度下降算法的過程以及算法的運行過程。請參考這篇文章中有關利用 python 實現端到端運行的內容。
這是定義普通梯度下降算法的主代碼:
params=[weights_hidden,weights_output,bias_hidden,bias_output]
defsgd(cost,params,lr=0.05):
grads=T.grad(cost=cost,wrt=params)
updates=[]
forp,ginzip(params,grads):
updates.append([p,p-g*lr])
returnupdates
updates=sgd(cost,params)
為了能更好的理解上述代碼,接下來我們會分成不同的步驟詳細講解。
我們把 sgd 這個含有參數的函數分別定義為 cost、params 和 lr,分別代表上述例子中的 J(θ),θ是深度學習算法和學習率的參數。我們將默認的學習率設為0.05,但是學習率可以隨著我們的喜好輕易地發生改變。
defsgd(cost,params,lr=0.05):
然后,我們定義關于這個成本函數的梯度參數。在這里,我們利用 theano 數據庫來尋找梯度,T是我們將導入的 theano 數據:
grads=T.grad(cost=cost,wrt=params)
最后,通過所有參數的迭代找出所有可能需要更新的參數。大家可以看到,在這里我們使用的是普通梯度下降算法。
forp,ginzip(params,grads):
updates.append([p,p-g*lr]
接下來,我們可以利用這個函數找出神經網絡中的最優參數。通過這個函數,我們發現神經網絡非常擅長在圖片中查找數據,如下圖所示:
Predictionis:8
在這個實例中,我們了解到利用梯度下降算法能夠得到深度學習算法中的最優參數。
對于上述提到的各種梯度下降算法,各有利弊。接下來,我會介紹一些能夠幫助大家找到正確算法的實用方法。
如果是為了快速地獲得原型,那就選取諸如Adam/Adagrad這樣的自適應技術,這會讓我們事半功倍,并且無須大量調優超參數。
如果是為了得到最好的結果,那就選取普通的梯度下降算法或者動量梯度下降算法。雖然利用梯度下降算法達到預期效果的過程很緩慢,但是大部分的結果比自適應技術要好得多。
如果你的數據偏小而且能夠適應一次迭代,那么就可以選擇諸如 l-BFGS這樣的二階技術。這是因為,二階技術雖然速度非常快并且非常準確,但是只適用于數據偏小的情況。
還有一種是利用學習特性來預測梯度下降學習率的新興方法(雖然我還沒有嘗試過這種新興方法,但是看起來前途無量)。可以仔細地閱讀一下這篇文章。
目前,無法學習神經網絡算法的原因由很多。但是如果你能檢查出算法出現錯誤的地方,對學習神經網絡算法將會非常有幫助。
當選用梯度下降算法時,你可以看看這些能幫助你規避問題的小提示:
誤碼率——特定迭代之后,你應該檢查訓練誤差和測試誤差,并且確保訓練誤差和測試誤差有所減少。如果事實并非如此,那么可能會出現問題!
隱含層數的梯度風氣流——如果網絡沒有出現梯度消失或梯度爆炸問題,那么請檢查一下網絡。
學習率——選用自適應技術時,你應該檢測一下學習率。
本篇文章參考了梯度下降優化算法概述(https://arxiv.org/abs/1609.04747)。
梯度下降 CS231n 課程教材(http://cs231n.github.io/neural-networks-3/)。
深度學習這本書的第四章(數值優化算法,http://www.deeplearningbook.org/contents/numerical.html)和第八章(深度學習模型的優化,http://www.deeplearningbook.org/contents/optimization.html)。
我希望你喜歡這篇文章。在閱讀完本篇文章后,你會對梯度下降算法及其變式有一定的了解。與此同時,我還在文章中向大家提供了執行梯度下降算法以及其變式算法的實用小貼士。希望對你有所幫助!
本文作者?Faizan Shaikh?是一名數據科學愛好者,目前正在研究深度學習,目標是利用自己的技能,推動 AI 研究的發展。