一文清晰講解機器學習中梯度下降演算法(包括其變式演算法)

AI科技大本營發表於2017-09-29

本篇文章向大家介紹梯度下降(Gradient Descent)這一特殊的優化技術,我們在機器學習中會頻繁用到。

                                            前言

無論是要解決現實生活中的難題,還是要建立一款新的軟體產品,我們最終的目標都是使其達到最優狀態。作為一名電腦科學專業的學生,我經常需要優化各種程式碼,以便提高其整體的執行速度。

一般情況下,最優狀態會伴隨問題的最佳解決方案。如果閱讀近期發表的關於優化問題的文章的話,你會發現,優化問題在現實生活中扮演著非常重要的作用。

機器學習中的優化問題與我們剛剛提到的內容有些許不同。通常情況下,在優化的過程中,我們非常清楚資料的狀態,也知道我們想要優化哪些區域。但是,在機器學習中,我們本就對“新資料”一無所知,更不要提優化問題了!

因此在機器學習中,我們對訓練資料進行優化,隨後再在全新的驗證資料中檢驗其執行情況。

優化的廣泛應用

目前,優化技術正被廣泛應用於各種不同的領域中,例如:

  • 結構——比如說:決定航天設計的外型。

  • 經濟——比如說:成本最低化。

  • 物理——比如說:優化量子計算時間。

優化還有許多更為高階的應用,例如:提供最優運輸路徑,使貨架空間最合理化等等。

許多受歡迎的機器演算法都源於優化技術,例如:線性迴歸演算法、K-最近鄰演算法、神經網路演算法等等。在學術界以及各行各業中,優化研究比比皆是,優化應用隨處可見。

                                                   目錄

  • 什麼是梯度下降?

  • 運用梯度下降演算法所面臨的挑戰

  • 梯度下降演算法的變式

  • 梯度下降的實現過程

  • 使用梯度下降演算法的實用小貼士

  • 附錄

1. 什麼是梯度下降?

我會以經典的登山案例來解釋梯度下降的含義。

假設你現在在山頂處,必須抵達山腳下(也就是山谷最低處)的湖泊。但讓人頭疼的是,你的雙眼被蒙上了無法辨別前進方向。那麼,你會採取什麼辦法抵達湖泊處呢?

一文清晰講解機器學習中梯度下降演算法(包括其變式演算法)

最好的辦法就是檢視一下週圍的地勢,觀察有下降趨勢的地面,這會幫助你邁出第一步。如果沿著下降的路線前進,那麼你非常有可能到達湖泊。

以圖形的形式呈現該處地勢。注意下面的曲線圖:


一文清晰講解機器學習中梯度下降演算法(包括其變式演算法)

現在讓我們用數學術語把這個情景繪製成地圖吧。

為了學習梯度下降演算法,假設我們需要找出最佳的引數(θ1)和(θ2)。與上述做法相似,在測繪“成本空間”時,我們需要找到相似的山脈和山谷。成本空間是指為引數選定了一個特殊值後,演算法的執行情況。

所以,在Y軸上,我們讓J(θ1)與X軸上的引數(θ1)以及Z軸上的引數(θ2)分別相交。在這裡,數值高的紅色區域代表山峰,數值低的藍色區域代表山谷。

梯度下降演算法的型別有很多種,主要分為兩種:

  • 基於資料的獲取

1. 全批梯度下降演算法

2. 隨機梯度下降演算法

在全批梯度下降演算法中,需要利用全部資料同時計算梯度;然而在隨機梯度下降演算法中,通常只需選取其中一個樣例來計算梯度。

  • 基於微分技術

1. 一階微分

2. 二階微分

梯度下降需要通過成本函式微分來計算梯度。我們可以用一階微分技術或者二階微分技術來計算。

2. 運用梯度下降演算法所面臨的挑戰

在大多數情況下,梯度下降是一種聲音技術。但在很多情況下,梯度下降無法正常工作,甚至不工作。原因有三點:

  1. 資料挑戰

  2. 梯度挑戰

  3. 執行挑戰

2.1 資料挑戰

  • 如果資料按照某種方式進行組合形成了一個非凸的優化問題,那麼就很難利用梯度下降演算法對其進行優化了。梯度下降演算法只能解決那些意義非常明確的凸優化問題。

  • 在優化凸問題時,可能會出現無數的極小點。最低點被稱為全域性最小值,其它的點被稱為區域性極小值。我們的目的是要達到全域性極小值,而非區域性極小值。

  • 還有一個問題就是鞍點。梯度為零時,它是資料中的一個點,但是不是最優點。目前,我們還沒有特定的方法來規避鞍點的出現,是一個新的研究領域。

2.2 梯度挑戰

  • 如果執行梯度下降演算法時出現了錯誤,那麼可能會導致諸如梯度消失或者梯度崩潰等的問題。當梯度太小或者太大時,就會出現這樣的問題。也正因為這些問題,演算法無法收斂。

2.3 執行挑戰

  • 通常情況下,大多數神經網路的開發者不會留意執行情況,但是觀察網路資源利用率是非常重要的。比如,在執行梯度下降演算法時,瞭解需要多少資源是非常重要的。如果應用程式的儲存器太小,那麼網路就會失敗。

  • 跟蹤諸如浮點數的注意事項以及軟/硬體的先決條件,也非常重要。

3. 梯度下降演算法的變式

讓我們來看一下最常用的梯度下降演算法及其執行情況。

3.1 普通的梯度下降

這是梯度下降技術中最簡單的形式。此處的 vanilla 是純淨/不摻雜任何雜質的意思。它的主要特性就是,使我們向著成本函式梯度的最小值又邁進了一小步。

我們來看一下它的虛擬碼。

update = learning_rate * gradient_of_parameters

parameters = parameters - update

在這裡,我們通過引數梯度來更新引數。而後通過學習率使其多樣化,實質上,常數代表著我們期望的達到最小值的速率。學習率是一種超引數,其數值一旦確定,就需要我們認真對待。

一文清晰講解機器學習中梯度下降演算法(包括其變式演算法)

3.2 動量梯度下降

在進行下一步之前,我們先對之前的演算法稍作調整,以便回顧前面的步驟。

這是一組虛擬碼。

update = learning_rate * gradient

velocity = previous_update * momentum

parameter = parameter + velocity – update

此處,更新後的程式碼與普通的梯度下降演算法一樣。但是考慮到之前的更新和常量(動量),我們引進了一個名為速率(velocity)的術語。

一文清晰講解機器學習中梯度下降演算法(包括其變式演算法)

3.3 ADAGRAD 演算法

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 是一個用於抑制學習率產生變動率的常量。

3.4 ADAM 演算法

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 資料庫中看到這種演算法的執行情況。

4. 梯度下降的實現過程

現在我們來看一下利用 python 實現梯度下降的基礎小案例。

在這裡,我們將會利用梯度下降優化演算法找出深度學習模型中影象識別應用問題的最佳引數。我們的問題是影象識別,從已給的28 x 28影象中分辨出其中的數字。我們有一個關於影象的子集,一部分影象用於訓練模型,另一部分影象用於測試模型。在本篇文章中,我們會向大家介紹定義梯度下降演算法的過程以及演算法的執行過程。請參考這篇文章中有關利用 python 實現端到端執行的內容。

這是定義普通梯度下降演算法的主程式碼:

params = [weights_hidden, weights_output, bias_hidden, bias_output]


def sgd(cost, params, lr=0.05):

grads = T.grad(cost=cost, wrt=params)

updates = []


for p, g in zip(params, grads):

updates.append([p, p - g * lr])

return updates

updates = sgd(cost, params)

為了能更好的理解上述程式碼,接下來我們會分成不同的步驟詳細講解。

我們把 sgd 這個含有引數的函式分別定義為 cost、params 和 lr,分別代表上述例子中的 J(θ),θ是深度學習演算法和學習率的引數。我們將預設的學習率設為0.05,但是學習率可以隨著我們的喜好輕易地發生改變。

def sgd(cost, params, lr=0.05):

然後,我們定義關於這個成本函式的梯度引數。在這裡,我們利用 theano 資料庫來尋找梯度,T是我們將匯入的 theano 資料:

grads = T.grad(cost=cost, wrt=params)

最後,通過所有引數的迭代找出所有可能需要更新的引數。大家可以看到,在這裡我們使用的是普通梯度下降演算法。

for p, g in zip(params, grads):

updates.append([p, p - g * lr]

在這個例項中,我們瞭解到利用梯度下降演算法能夠得到深度學習演算法中的最優引數。

5. 使用梯度下降演算法的實用小貼士

對於上述提到的各種梯度下降演算法,各有利弊。接下來,我會介紹一些能夠幫助大家找到正確演算法的實用方法。

  • 如果是為了快速地獲得原型,那就選取諸如Adam/Adagrad這樣的自適應技術,這會讓我們事半功倍,並且無須大量調優超引數。

  • 如果是為了得到最好的結果,那就選取普通的梯度下降演算法或者動量梯度下降演算法。雖然利用梯度下降演算法達到預期效果的過程很緩慢,但是大部分的結果比自適應技術要好得多。

  • 如果你的資料偏小而且能夠適應一次迭代,那麼就可以選擇諸如 l-BFGS這樣的二階技術。這是因為,二階技術雖然速度非常快並且非常準確,但是隻適用於資料偏小的情況。

  • 還有一種是利用學習特性來預測梯度下降學習率的新興方法(雖然我還沒有嘗試過這種新興方法,但是看起來前途無量)。可以仔細地閱讀一下這篇文章。

目前,無法學習神經網路演算法的原因由很多。但是如果你能檢查出演算法出現錯誤的地方,對學習神經網路演算法將會非常有幫助。

當選用梯度下降演算法時,你可以看看這些能幫助你規避問題的小提示:

  • 誤位元速率——特定迭代之後,你應該檢查訓練誤差和測試誤差,並且確保訓練誤差和測試誤差有所減少。如果事實並非如此,那麼可能會出現問題!

  • 隱含層數的梯度風氣流——如果網路沒有出現梯度消失或梯度爆炸問題,那麼請檢查一下網路。

  • 學習率——選用自適應技術時,你應該檢測一下學習率。

6. 附錄


本篇文章參考了梯度下降優化演算法概述

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 研究的發展。

原文連結:

https://www.analyticsvidhya.com/blog/2017/03/introduction-to-gradient-descent-algorithm-along-its-variants/


相關文章