優化問題都需要哪些數學基礎

本文轉載自:機器之心  作者:Tivadar Danka

深度學習中的優化是一項極度複雜的任務,本文是一份基礎指南,旨在從數學的角度深入解讀優化器。

一般而言,神經網絡的整體性能取決於幾個因素。通常最受關注的是網絡架構,但這只是衆多重要元素之一。還有一個常常被忽略的元素,就是用來擬合模型的優化器。

爲了說明優化的複雜性,此處以 ResNet 爲例。ResNet18 有 11,689,512 個參數。尋找最佳參數配置,也就是在 11,689,512 維的空間中定位一個點。如果暴力搜索的話,可以把這個空間分割成網格。假設將每個維度分成十格,那麼就要檢查 10^11689512(10 的 11689512 次方)組可能的配置,對每一組配置都要計算損失函數,並找出損失最小的配置。

10 的 11689512 次方是一個什麼概念?已知宇宙中的原子才只有 10^83 個,宇宙的年齡只有 4.32 x 10^17 秒(約 137 億年)。如果從大爆炸開始,每秒檢查 10^83 個原子,我們現在才檢查了 4.32*10^1411 個,遠遠小於上述網格可能的配置數。

所以優化器非常重要。它們就是用來處理這種難以理解的複雜性的。有了它,你就可以將訓練網絡的時間壓縮在幾天內,而不是數十億年間。下文將從數學角度深入研究優化器,並瞭解它們是如何完成這一看似不可能的任務的。

優化的基礎

我們從簡單的地方開始。假設要最大化單變量函數。(在機器學習中,通常以最小化損失函數爲目標,不過最小化就等同於最大化函數的負值。)

定義:

對函數作圖:

最直觀的方法是將這條線劃分成網格,檢查每個點的值,然後選擇函數值最大的點。正如引言中所說,這是不可擴展的,因此要找其他解決方案。將這條線想象成一座要爬到頂峯的山。假設位於紅點處:

如果要到達山峯,該往哪個方向走?當然,應該向斜率增加的地方前進。這個概念對應的是函數的導數。在數學上,導數定義爲:

乍看之下,導數非常神祕,但它的幾何意義非常簡單。仔細看一下求導的點:

對任何 x 和 y,通過 f(x) 和 f(y) 的這條線定義爲:

一般而言,如果用 at+b 定義一條直線,那稱 a 爲這條線的斜率。這個值既可以是正值也可以是負值,斜率爲正,直線向上走;斜率爲負,直線向下走。絕對值越大,直線越陡。如果像導數定義中一樣,讓 y 越來越接近 x,那麼這條線就會成爲 x 處的切線。

(圖注)在 x=-2.0 時,f(x)的切線和逼近線。

切線爲:

切線方向記爲向量(1,f’(x))。

如果從 x_0=-2.0 的位置開始登山,應該沿切線上升的方向前進。如果切線的斜率較大,可以大步邁進;如果斜率接近零,應該小步小步往上爬,以免越過峯值。如果用數學語言表示,我們應該用下面這種方式定義下一個點:

式中 λ 是個參數,設置前進的步長。這就是所謂的學習率。通常,後續步驟定義爲:

正導數意味着斜率在增加,所以可以前進;而負導數意味着斜率在減少,所以要後退。可視化這個過程:

如你所見,這個簡單的算法成功地找到了峯值。但如圖所示,這並非函數的全局最大值。在所有的優化算法中,這都是一個潛在的問題,但還是有解決辦法的。

在這個簡單的例子中,我們只最大化了單變量函數。這樣雖然可以有效地說明這個概念,但在現實生活中,可能存在數百萬變量,神經網絡中就是如此。下一部分將會介紹,如何將這樣簡單的算法泛化到多維函數的優化。

多維優化

在單變量函數中,可以將導數視爲切線的斜率。但遇到多個變量,則不能如此。先來看個具體的例子。定義函數:

這個函數將是這部分的 toy example 。

對 f(x,y)作圖。

這是一個有兩個變量的函數,圖像是一個曲面。馬上可以發現,這樣很難定義切線的概念,因爲與曲面上一個點相切的線有很多。事實上,可以做一個完整的平面。這就是切平面。

f(x,y)在點 (0,0) 處的切平面。

但切平面有兩個非常特別的方向。以點 (0,0) 處的切平面爲例。對每一個多變量函數來說,先固定所有變量只取一個能動的變量,這樣這個函數基本上就變成單變量函數了。示例函數變爲:

和:

可以用垂直於座標軸的平面分割曲面,來可視化上面這兩個函數。平面和曲面相交處就是 f(x,0) 或 f(0,y),這取決於你用哪個平面。

用垂直的平面切割曲面,可視化 f(0,x)。

對這些函數,就可以像上文一樣定義導數了。這就是所謂的偏導數。要泛化之前發現峯值的算法,偏導數起着至關重要的作用。用數學語言定義:

每個偏導數表示切平面上的一個方向。

切平面上偏導數的方向。

偏導數的值是特殊切線的斜率。最陡的方向根據梯度確定,定義爲:

注意,梯度是參數空間中的方向。可以輕鬆在二維平面中繪製出梯度,如下圖所示:

f(x,y)的梯度。

綜上所述,發現峯值的算法現在成爲:

這就是所謂的梯度上升(gradient ascent)。如果要求函數最小值,就要沿負梯度的方向邁出一步,也就是下降最陡的方向:

這就是所謂的梯度下降(gradient descent),你可能會很頻繁地看到它,因爲在機器學習中,實際上是要最小化損失。

爲什麼梯度指向最陡的上升方向?

在這種情況下,要知道爲什麼梯度給出的是最陡峭的上升方向。爲了給出精確的解釋,還要做一些數學計算。除了用垂直於 x 軸或 y 軸的垂直平面切割曲面外,還可以用 (a,b) 任意方向的垂直平面切割曲面。對於偏導數,有:

可以將它們視爲 f(x,y) 沿 (1,0) 和(0,1)方向的導數。儘管這些方向特別重要,但也可以任意規定這些方向。也就是說,假設方向爲:

這個方向的導數定義爲:

注意,最後一個等式就是方向向量和梯度的點積,這可能和高中幾何課堂上遇到的點積是相同的。所以:

問題是,哪個方向的方向導數最大?答案是上升程度最陡峭的方向,所以如果要優化,得先知道這個特定的方向。這個方向就是之前提過的梯度,點積可以寫作:

式中的 |.| 表示向量長度,α是兩向量間的夾角(這在任意維數上都是成立的,不只是二維)。顯而易見,當 cosα=1,即 α=0 時,表達式取最大值。這就意味着這兩個向量是平行的,所以 e 的方向和梯度方向是相同的。

訓練神經網絡

現在要從理論轉戰實踐了,瞭解如何訓練神經網絡。假設任務是將有 n 維特徵向量的圖像分成 c 類。從數學角度看,神經網絡代表將 n 維特徵空間映射到 c 維空間的函數 f:

神經網絡本身是參數化的函數。方便起見,將參數標記爲 m 維向量:

爲了表現出對參數的依賴,習慣記爲:

將神經網絡的參數空間映射爲實數。損失函數記爲:

式中的是觀測值爲的第 i 個數據點

L 是損失函數項。例如,如果 J 是交叉熵損失,則:

式中

這看似簡單,但難以計算。在真實世界中有數百萬個數據點 N,更別說參數 m 的數量了。所以,一共有數百萬項,因此要計算數百萬個導數來求最小值。那麼在實踐中該如何解決這一問題?

隨機梯度下降

要用梯度下降,得先計算:

如果 N 很大,那麼計算量就很大,而一般都希望 N 大一點(因爲想要儘量多的數據)。可以化簡嗎?一種方式是忽略一部分。儘管這看起來像個不靠譜的方案,但卻有堅實的理論基礎。要理解這一點,首先注意 J 其實可以寫成期望值:

式中的是訓練數據給出的(經驗)概率分佈。可以將序列寫成:

這樣就成了獨立同分布的隨機變量。根據大數定律:

式中是真正的總體分佈(這是未知的)。再詳細點說,因爲增加了訓練數據,損失函數收斂到真實損失。因此,如果對數據二次採樣,並計算梯度:

對某些 i,如果計算足夠,仍然可以得到合理的估計。這就是所謂的隨機梯度下降,記爲 SGD (Stochastic Gradient Descent)。

我認爲,研究人員和數據科學家能有效訓練深度神經網絡依賴於三個基礎發展:將 GPU 作爲通用的計算工具、反向傳播還有隨機梯度下降。可以肯定地說,如果沒有 SGD,就無法廣泛應用深度學習。

與幾乎所有新方法一樣,SGD 也引入了一堆新問題。最明顯的是,二次採樣的樣本量要有多大?太小可能會造成梯度估計有噪聲,太大則會造成收益遞減。選擇子樣本也需要謹慎。例如如果所有子樣本都屬於一類,估計值可能會相差甚遠。但在實踐中,這些問題都可以通過實驗和適當隨機化數據來解決。

改善梯度下降

梯度下降(以及 SGD 變體)存在一些問題,因此這些方法在某些情況下可能會無效。例如,學習率控制着梯度方向上前進的步長。在這個參數上一般會犯兩個錯誤。第一,步長太大,以至於損失無法收斂,甚至可能分散;第二,步長太小,可能因爲前進太慢,永遠都無法到達局部最小值。爲了闡明這個問題,以 f(x)=x+sin x 函數爲例進行研究:

假設從 x_0=2.5 開始進行梯度下降,學習率 α 分別爲 1、0.1 和 0.01。

理解起來可能不夠直觀,所以對每個學習率的 x-s 繪圖:

當 α=1 時,圖像在兩點間震盪,無法收斂到局部最小值;當 α=0.01 時,收斂得似乎很慢。在本例中,α=0.1 似乎是合適的。那在一般情況下該如何確定這個值呢?這裏的中心思想是,學習率不一定是恆定的。同理,如果梯度幅度很大,就應該降低學習率,避免跳得太遠。另一方面,如果梯度幅度較小,那可能意味着接近局部最優值了,所以要避免超調(overshooting)的話,學習率絕對不能再增加了。動態改變學習率的算法也就是所謂的自適應算法。

最流行的自適應算法之一是 AdaGrad。它會累積存儲梯度幅度和大小,並根據記錄調整學習率。AdaGrad 定義了累積變量 r_0=0 並根據規則進行更新:

式中的

表示兩個向量的分量乘積。將其用於度量學習率:

式中的 δ 是爲了保持數據穩定的數值,平方根是根據分量取的。首先,當梯度大時,累積變量會很快地增長,學習率會下降。當參數接近局部最小值時,梯度會變小,學習率會停止下降。

當然,AdaGrad 是一種可能的解決方案。每一年都會有越來越多先進的優化算法,來解決梯度下降相關的問題。但即便是最先進的方法,使用並調整學習率,都是很有好處的。

另一個關於梯度下降的問題是要確定全局最優值或與之接近的局部最優值。看前面的例子,梯度下降通常會陷入局部最優值。爲了更好地瞭解這一問題和更好的解決辦法,建議您閱讀 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 所著的《深度學習》(Deep Learning)第八章(https://www.deeplearningbook.org/)。

深度神經網絡的損失函數什麼樣?

前面的例子只可視化了非常簡單的玩具示例,比如 f(x)=25sin x-x^2。這是有原因的:繪製超過兩個變量的函數圖像很難。考慮到固有的侷限性,我們最多隻能在三個維度上進行觀察和思考。但爲了瞭解神經網絡中的損失函數,可以採取一些技巧。Hao Li 等人發表的論文《Visualizing the Loss Landscape of Neural Nets》(https://arxiv.org/pdf/1712.09913.pdf)就是有關這個的,他們選擇兩個隨機方向,對二變量函數繪圖,從而可視化損失函數。

(爲了避免因尺度不變而引起的失真,他們還在隨機方向中引入了一些歸一化因素。)他們的研究揭示了在 ResNet 架構中,殘差連接是如何影響損失,讓優化變得更容易的。

圖像來源:Hao Li 等人所著《Visualizing the Loss Landscape of Neural Nets》(https://arxiv.org/pdf/1712.09913.pdf)。

無論殘差連接做出了多顯著的改善,我在這裏主要是想說明多維優化的難度。在圖中的第一部分可以看出,有多個局部最小值、峯值和平穩值等。好的架構可以讓優化變得更容易,但完善的優化實踐,可以處理更復雜的損失情況。架構和優化器是相輔相成的。

總結

我們在前文中已經瞭解了梯度背後的直觀理解,並從數學角度以精確的方式定義了梯度。可以看出,對於任何可微函數,無論變量數量如何,梯度總是指向最陡的方向。從概念上來講非常簡單,但當應用在有數百萬變量的函數上時,存在着很大的計算困難。隨機梯度下降可以緩解這個問題,但還存在陷入局部最優、選擇學習率等諸多問題。因此,優化問題還是很困難的,需要研究人員和從業人員多加關注。事實上,有一個非常活躍的社區在不斷地進行改善,並取得了非常驚人的成績!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章