選自medium,作者:Tivadar Danka,機(jī)器之心編譯,參與:李詩(shī)萌、張倩。
一般而言,神經(jīng)網(wǎng)絡(luò)的整體性能取決于幾個(gè)因素。通常最受關(guān)注的是網(wǎng)絡(luò)架構(gòu),但這只是眾多重要元素之一。還有一個(gè)常常被忽略的元素,就是用來(lái)擬合模型的優(yōu)化器。
為了說(shuō)明優(yōu)化的復(fù)雜性,此處以 ResNet 為例。ResNet18 有 11,689,512 個(gè)參數(shù)。尋找最佳參數(shù)配置,也就是在 11,689,512 維的空間中定位一個(gè)點(diǎn)。如果暴力搜索的話,可以把這個(gè)空間分割成網(wǎng)格。假設(shè)將每個(gè)維度分成十格,那么就要檢查 10^(10 的 次方)組可能的配置,對(duì)每一組配置都要計(jì)算損失函數(shù),并找出損失最小的配置。
10 的 次方是一個(gè)什么概念?已知宇宙中的原子才只有 10^83 個(gè),宇宙的年齡只有 4.32 x 10^17 秒(約 137 億年)。如果從大爆炸開始,每秒檢查 10^83 個(gè)原子,我們現(xiàn)在才檢查了 4.32*10^1411 個(gè),遠(yuǎn)遠(yuǎn)小于上述網(wǎng)格可能的配置數(shù)。
所以優(yōu)化器非常重要。它們就是用來(lái)處理這種難以理解的復(fù)雜性的。有了它,你就可以將訓(xùn)練網(wǎng)絡(luò)的時(shí)間壓縮在幾天內(nèi),而不是數(shù)十億年間。下文將從數(shù)學(xué)角度深入研究?jī)?yōu)化器,并了解它們是如何完成這一看似不可能的任務(wù)的。
優(yōu)化的基礎(chǔ)
我們從簡(jiǎn)單的地方開始。假設(shè)要最大化單變量函數(shù)。(在機(jī)器學(xué)習(xí)中,通常以最小化損失函數(shù)為目標(biāo),不過(guò)最小化就等同于最大化函數(shù)的負(fù)值。)
定義:
對(duì)函數(shù)作圖:
最直觀的方法是將這條線劃分成網(wǎng)格,檢查每個(gè)點(diǎn)的值,然后選擇函數(shù)值最大的點(diǎn)。正如引言中所說(shuō),這是不可擴(kuò)展的,因此要找其他解決方案。將這條線想象成一座要爬到頂峰的山。假設(shè)位于紅點(diǎn)處:
如果要到達(dá)山峰,該往哪個(gè)方向走?當(dāng)然,應(yīng)該向斜率增加的地方前進(jìn)。這個(gè)概念對(duì)應(yīng)的是函數(shù)的導(dǎo)數(shù)。在數(shù)學(xué)上,導(dǎo)數(shù)定義為:
乍看之下,導(dǎo)數(shù)非常神秘,但它的幾何意義非常簡(jiǎn)單。仔細(xì)看一下求導(dǎo)的點(diǎn):
對(duì)任何 x 和 y,通過(guò) f(x) 和 f(y) 的這條線定義為:
一般而言,如果用 at+b 定義一條直線,那稱 a 為這條線的斜率。這個(gè)值既可以是正值也可以是負(fù)值,斜率為正,直線向上走;斜率為負(fù),直線向下走。絕對(duì)值越大,直線越陡。如果像導(dǎo)數(shù)定義中一樣,讓 y 越來(lái)越接近 x,那么這條線就會(huì)成為 x 處的切線。
(圖注)在 x=-2.0 時(shí),f(x)的切線和逼近線。切線為:
切線方向記為向量(1,f’(x))。
如果從 x_0=-2.0 的位置開始登山,應(yīng)該沿切線上升的方向前進(jìn)。如果切線的斜率較大,可以大步邁進(jìn);如果斜率接近零,應(yīng)該小步小步往上爬,以免越過(guò)峰值。如果用數(shù)學(xué)語(yǔ)言表示,我們應(yīng)該用下面這種方式定義下一個(gè)點(diǎn):
式中 λ 是個(gè)參數(shù),設(shè)置前進(jìn)的步長(zhǎng)。這就是所謂的學(xué)習(xí)率。通常,后續(xù)步驟定義為:
正導(dǎo)數(shù)意味著斜率在增加,所以可以前進(jìn);而負(fù)導(dǎo)數(shù)意味著斜率在減少,所以要后退。可視化這個(gè)過(guò)程:
如你所見,這個(gè)簡(jiǎn)單的算法成功地找到了峰值。但如圖所示,這并非函數(shù)的全局最大值。在所有的優(yōu)化算法中,這都是一個(gè)潛在的問(wèn)題,但還是有解決辦法的。
在這個(gè)簡(jiǎn)單的例子中,我們只最大化了單變量函數(shù)。這樣雖然可以有效地說(shuō)明這個(gè)概念,但在現(xiàn)實(shí)生活中,可能存在數(shù)百萬(wàn)變量,神經(jīng)網(wǎng)絡(luò)中就是如此。下一部分將會(huì)介紹,如何將這樣簡(jiǎn)單的算法泛化到多維函數(shù)的優(yōu)化。
多維優(yōu)化
在單變量函數(shù)中,可以將導(dǎo)數(shù)視為切線的斜率。但遇到多個(gè)變量,則不能如此。先來(lái)看個(gè)具體的例子。定義函數(shù):
這個(gè)函數(shù)將是這部分的 toy example 。
對(duì) f(x,y)作圖。這是一個(gè)有兩個(gè)變量的函數(shù),圖像是一個(gè)曲面。馬上可以發(fā)現(xiàn),這樣很難定義切線的概念,因?yàn)榕c曲面上一個(gè)點(diǎn)相切的線有很多。事實(shí)上,可以做一個(gè)完整的平面。這就是切平面。
f(x,y)在點(diǎn) (0,0) 處的切平面。但切平面有兩個(gè)非常特別的方向。以點(diǎn) (0,0) 處的切平面為例。對(duì)每一個(gè)多變量函數(shù)來(lái)說(shuō),先固定所有變量只取一個(gè)能動(dòng)的變量,這樣這個(gè)函數(shù)基本上就變成單變量函數(shù)了。示例函數(shù)變?yōu)椋?/p>
和:
可以用垂直于坐標(biāo)軸的平面分割曲面,來(lái)可視化上面這兩個(gè)函數(shù)。平面和曲面相交處就是 f(x,0) 或 f(0,y),這取決于你用哪個(gè)平面。
用垂直的平面切割曲面,可視化 f(0,x)。對(duì)這些函數(shù),就可以像上文一樣定義導(dǎo)數(shù)了。這就是所謂的偏導(dǎo)數(shù)。要泛化之前發(fā)現(xiàn)峰值的算法,偏導(dǎo)數(shù)起著至關(guān)重要的作用。用數(shù)學(xué)語(yǔ)言定義:
每個(gè)偏導(dǎo)數(shù)表示切平面上的一個(gè)方向。
切平面上偏導(dǎo)數(shù)的方向。偏導(dǎo)數(shù)的值是特殊切線的斜率。最陡的方向根據(jù)梯度確定,定義為:
注意,梯度是參數(shù)空間中的方向??梢暂p松在二維平面中繪制出梯度,如下圖所示:
f(x,y)的梯度。綜上所述,發(fā)現(xiàn)峰值的算法現(xiàn)在成為:
這就是所謂的梯度上升(gra ** nt ascent)。如果要求函數(shù)最小值,就要沿負(fù)梯度的方向邁出一步,也就是下降最陡的方向:
這就是所謂的梯度下降(gra ** nt descent),你可能會(huì)很頻繁地看到它,因?yàn)樵跈C(jī)器學(xué)習(xí)中,實(shí)際上是要最小化損失。
為什么梯度指向最陡的上升方向?
在這種情況下,要知道為什么梯度給出的是最陡峭的上升方向。為了給出精確的解釋,還要做一些數(shù)學(xué)計(jì)算。除了用垂直于 x 軸或 y 軸的垂直平面切割曲面外,還可以用 (a,b) 任意方向的垂直平面切割曲面。對(duì)于偏導(dǎo)數(shù),有
可以將它們視為 f(x,y) 沿 (1,0) 和(0,1)方向的導(dǎo)數(shù)。盡管這些方向特別重要,但也可以任意規(guī)定這些方向。也就是說(shuō),假設(shè)方向?yàn)椋?/p>
這個(gè)方向的導(dǎo)數(shù)定義為:
注意,最后一個(gè)等式就是方向向量和梯度的點(diǎn)積,這可能和高中幾何課堂上遇到的點(diǎn)積是相同的。所以:
問(wèn)題是,哪個(gè)方向的方向?qū)?shù)最大?答案是上升程度最陡峭的方向,所以如果要優(yōu)化,得先知道這個(gè)特定的方向。這個(gè)方向就是之前提過(guò)的梯度,點(diǎn)積可以寫作:
式中的 |.| 表示向量長(zhǎng)度,α是兩向量間的夾角(這在任意維數(shù)上都是成立的,不只是二維)。顯而易見,當(dāng) cosα=1,即 α=0 時(shí),表達(dá)式取最大值。這就意味著這兩個(gè)向量是平行的,所以 e 的方向和梯度方向是相同的。
訓(xùn)練神經(jīng)網(wǎng)絡(luò)
現(xiàn)在要從理論轉(zhuǎn)戰(zhàn)實(shí)踐了,了解如何訓(xùn)練神經(jīng)網(wǎng)絡(luò)。假設(shè)任務(wù)是將有 n 維特征向量的圖像分成 c 類。從數(shù)學(xué)角度看,神經(jīng)網(wǎng)絡(luò)代表將 n 維特征空間映射到 c 維空間的函數(shù) f:
神經(jīng)網(wǎng)絡(luò)本身是參數(shù)化的函數(shù)。方便起見,將參數(shù)標(biāo)記為 m 維向量:
為了表現(xiàn)出對(duì)參數(shù)的依賴,習(xí)慣記為:
將神經(jīng)網(wǎng)絡(luò)的參數(shù)空間映射為實(shí)數(shù)。損失函數(shù)記為:
式中的
是觀測(cè)值為
的第 i 個(gè)數(shù)據(jù)點(diǎn)
L 是損失函數(shù)項(xiàng)。例如,如果 J 是交叉熵?fù)p失,則:
式中
這看似簡(jiǎn)單,但難以計(jì)算。在真實(shí)世界中有數(shù)百萬(wàn)個(gè)數(shù)據(jù)點(diǎn) N,更別說(shuō)參數(shù) m 的數(shù)量了。所以,一共有數(shù)百萬(wàn)項(xiàng),因此要計(jì)算數(shù)百萬(wàn)個(gè)導(dǎo)數(shù)來(lái)求最小值。那么在實(shí)踐中該如何解決這一問(wèn)題?
隨機(jī)梯度下降
要用梯度下降,得先計(jì)算:
如果 N 很大,那么計(jì)算量就很大,而一般都希望 N 大一點(diǎn)(因?yàn)橄胍M量多的數(shù)據(jù))??梢曰?jiǎn)嗎?一種方式是忽略一部分。盡管這看起來(lái)像個(gè)不靠譜的方案,但卻有堅(jiān)實(shí)的理論基礎(chǔ)。要理解這一點(diǎn),首先注意 J 其實(shí)可以寫成期望值:
式中的
是訓(xùn)練數(shù)據(jù)給出的(經(jīng)驗(yàn))概率分布??梢詫⑿蛄袑懗桑?/p>
這樣就成了獨(dú)立同分布的隨機(jī)變量。根據(jù)大數(shù)定律:
式中
是真正的總體分布(這是未知的)。再詳細(xì)點(diǎn)說(shuō),因?yàn)樵黾恿擞?xùn)練數(shù)據(jù),損失函數(shù)收斂到真實(shí)損失。因此,如果對(duì)數(shù)據(jù)二次采樣,并計(jì)算梯度:
對(duì)某些 i,如果計(jì)算足夠,仍然可以得到合理的估計(jì)。這就是所謂的隨機(jī)梯度下降,記為 SGD (Stochastic Gra ** nt Descent)。
我認(rèn)為,研究人員和數(shù)據(jù)科學(xué)家能有效訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)依賴于三個(gè)基礎(chǔ)發(fā)展:將 GPU 作為通用的計(jì)算工具、反向傳播還有隨機(jī)梯度下降??梢钥隙ǖ卣f(shuō),如果沒有 SGD,就無(wú)法廣泛應(yīng)用深度學(xué)習(xí)。
與幾乎所有新方法一樣,SGD 也引入了一堆新問(wèn)題。最明顯的是,二次采樣的樣本量要有多大?太小可能會(huì)造成梯度估計(jì)有噪聲,太大則會(huì)造成收益遞減。選擇子樣本也需要謹(jǐn)慎。例如如果所有子樣本都屬于一類,估計(jì)值可能會(huì)相差甚遠(yuǎn)。但在實(shí)踐中,這些問(wèn)題都可以通過(guò)實(shí)驗(yàn)和適當(dāng)隨機(jī)化數(shù)據(jù)來(lái)解決。
改善梯度下降
梯度下降(以及 SGD 變體)存在一些問(wèn)題,因此這些方法在某些情況下可能會(huì)無(wú)效。例如,學(xué)習(xí)率控制著梯度方向上前進(jìn)的步長(zhǎng)。在這個(gè)參數(shù)上一般會(huì)犯兩個(gè)錯(cuò)誤。第一,步長(zhǎng)太大,以至于損失無(wú)法收斂,甚至可能分散;第二,步長(zhǎng)太小,可能因?yàn)榍斑M(jìn)太慢,永遠(yuǎn)都無(wú)法到達(dá)局部最小值。為了闡明這個(gè)問(wèn)題,以 f(x)=x+sin x 函數(shù)為例進(jìn)行研究:
假設(shè)從 x_0=2.5 開始進(jìn)行梯度下降,學(xué)習(xí)率 α 分別為 1、0.1 和 0.01。
理解起來(lái)可能不夠直觀,所以對(duì)每個(gè)學(xué)習(xí)率的 x-s 繪圖:
當(dāng) α=1 時(shí),圖像在兩點(diǎn)間震蕩,無(wú)法收斂到局部最小值;當(dāng) α=0.01 時(shí),收斂得似乎很慢。在本例中,α=0.1 似乎是合適的。那在一般情況下該如何確定這個(gè)值呢?這里的中心思想是,學(xué)習(xí)率不一定是恒定的。同理,如果梯度幅度很大,就應(yīng)該降低學(xué)習(xí)率,避免跳得太遠(yuǎn)。另一方面,如果梯度幅度較小,那可能意味著接近局部最優(yōu)值了,所以要避免超調(diào)(overshooting)的話,學(xué)習(xí)率絕對(duì)不能再增加了。動(dòng)態(tài)改變學(xué)習(xí)率的算法也就是所謂的自適應(yīng)算法。
最流行的自適應(yīng)算法之一是 AdaGrad。它會(huì)累積存儲(chǔ)梯度幅度和大小,并根據(jù)記錄調(diào)整學(xué)習(xí)率。AdaGrad 定義了累積變量 r_0=0 并根據(jù)規(guī)則進(jìn)行更新:
式中的
表示兩個(gè)向量的分量乘積。將其用于度量學(xué)習(xí)率:
式中的 δ 是為了保持?jǐn)?shù)據(jù)穩(wěn)定的數(shù)值,平方根是根據(jù)分量取的。首先,當(dāng)梯度大時(shí),累積變量會(huì)很快地增長(zhǎng),學(xué)習(xí)率會(huì)下降。當(dāng)參數(shù)接近局部最小值時(shí),梯度會(huì)變小,學(xué)習(xí)率會(huì)停止下降。
當(dāng)然,AdaGrad 是一種可能的解決方案。每一年都會(huì)有越來(lái)越多先進(jìn)的優(yōu)化算法,來(lái)解決梯度下降相關(guān)的問(wèn)題。但即便是最先進(jìn)的方法,使用并調(diào)整學(xué)習(xí)率,都是很有好處的。
另一個(gè)關(guān)于梯度下降的問(wèn)題是要確定全局最優(yōu)值或與之接近的局部最優(yōu)值。看前面的例子,梯度下降通常會(huì)陷入局部最優(yōu)值。為了更好地了解這一問(wèn)題和更好的解決辦法,建議您閱讀 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 所著的《深度學(xué)習(xí)》(Deep Learning)第八章( >deeplearningbook.org/)。
深度神經(jīng)網(wǎng)絡(luò)的損失函數(shù)什么樣?
前面的例子只可視化了非常簡(jiǎn)單的玩具示例,比如 f(x)=25sin x-x^2。這是有原因的:繪制超過(guò)兩個(gè)變量的函數(shù)圖像很難。考慮到固有的局限性,我們最多只能在三個(gè)維度上進(jìn)行觀察和思考。但為了了解神經(jīng)網(wǎng)絡(luò)中的損失函數(shù),可以采取一些技巧。Hao Li 等人發(fā)表的論文《Visualizing the Loss Landscape of Neural Nets》( >arxiv.org/pdf/1712.09913.pdf)就是有關(guān)這個(gè)的,他們選擇兩個(gè)隨機(jī)方向,對(duì)二變量函數(shù)繪圖,從而可視化損失函數(shù)。
(為了避免因尺度不變而引起的失真,他們還在隨機(jī)方向中引入了一些歸一化因素。)他們的研究揭示了在 ResNet 架構(gòu)中,殘差連接是如何影響損失,讓優(yōu)化變得更容易的。
圖像來(lái)源:Hao Li 等人所著《Visualizing the Loss Landscape of Neural Nets》()。無(wú)論殘差連接做出了多顯著的改善,我在這里主要是想說(shuō)明多維優(yōu)化的難度。在圖中的第一部分可以看出,有多個(gè)局部最小值、峰值和平穩(wěn)值等。好的架構(gòu)可以讓優(yōu)化變得更容易,但完善的優(yōu)化實(shí)踐,可以處理更復(fù)雜的損失情況。架構(gòu)和優(yōu)化器是相輔相成的。
總結(jié)
我們?cè)谇拔闹幸呀?jīng)了解了梯度背后的直觀理解,并從數(shù)學(xué)角度以精確的方式定義了梯度??梢钥闯?,對(duì)于任何可微函數(shù),無(wú)論變量數(shù)量如何,梯度總是指向最陡的方向。從概念上來(lái)講非常簡(jiǎn)單,但當(dāng)應(yīng)用在有數(shù)百萬(wàn)變量的函數(shù)上時(shí),存在著很大的計(jì)算困難。隨機(jī)梯度下降可以緩解這個(gè)問(wèn)題,但還存在陷入局部最優(yōu)、選擇學(xué)習(xí)率等諸多問(wèn)題。因此,優(yōu)化問(wèn)題還是很困難的,需要研究人員和從業(yè)人員多加關(guān)注。事實(shí)上,有一個(gè)非常活躍的社區(qū)在不斷地進(jìn)行改善,并取得了非常驚人的成績(jī)!