從零開始:教你如何訓(xùn)練神經(jīng)網(wǎng)絡(luò)
作者從神經(jīng)網(wǎng)絡(luò)簡(jiǎn)單的數(shù)學(xué)定義開始,沿著損失函數(shù)、激活函數(shù)和反向傳播等方法進(jìn)一步描述基本的優(yōu)化算法。在理解這些基礎(chǔ)后,本文詳細(xì)描述了動(dòng)量法等當(dāng)前十分流行的學(xué)習(xí)算法。此外,本系列將在后面介紹 Adam 和遺傳算法等其它重要的神經(jīng)網(wǎng)絡(luò)訓(xùn)練方法。
本文引用地址:http://butianyuan.cn/article/201712/372870.htmI. 簡(jiǎn)介
本文是作者關(guān)于如何「訓(xùn)練」神經(jīng)網(wǎng)絡(luò)的一部分經(jīng)驗(yàn)與見解,處理神經(jīng)網(wǎng)絡(luò)的基礎(chǔ)概念外,這篇文章還描述了梯度下降(GD)及其部分變體。此外,該系列文章將在在后面一部分介紹了當(dāng)前比較流行的學(xué)習(xí)算法,例如:
動(dòng)量隨機(jī)梯度下降法(SGD)
RMSprop 算法
Adam 算法(自適應(yīng)矩估計(jì))
遺傳算法
作者在第一部分以非常簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)介紹開始,簡(jiǎn)單到僅僅足夠讓人理解我們所談?wù)摰母拍?。作者?huì)解釋什么是損失函數(shù),以及「訓(xùn)練」神經(jīng)網(wǎng)絡(luò)或者任何其他的機(jī)器學(xué)習(xí)模型到底意味著什么。作者的解釋并不是一個(gè)關(guān)于神經(jīng)網(wǎng)絡(luò)全面而深度的介紹,事實(shí)上,作者希望我們讀者已經(jīng)對(duì)這些相關(guān)的概念早已了然于心。如果讀者想更好地理解神經(jīng)網(wǎng)絡(luò)具體是如何運(yùn)行的,讀者可以閱讀《深度學(xué)習(xí)》等相關(guān)書籍,或參閱文末提供的相關(guān)學(xué)習(xí)資源列表。
本文作者以幾年前在 kaggle 上進(jìn)行的貓狗鑒別競(jìng)賽(https://www.kaggle.com/c/dogs-vs-cats)為例來(lái)解釋所有的東西。在這個(gè)比賽中我們面臨的任務(wù)是,給定一張圖片,判斷圖中的動(dòng)物是貓還是狗。
II. 定義神經(jīng)網(wǎng)絡(luò)
人工神經(jīng)網(wǎng)絡(luò)(ANN)的產(chǎn)生受到了人腦工作機(jī)制的啟發(fā)。盡管這種模擬是很不嚴(yán)格的,但是 ANN 確實(shí)和它們生物意義上的創(chuàng)造者有幾個(gè)相似之處。它們由一定數(shù)量的神經(jīng)元組成。所那么,我們來(lái)看一下一個(gè)單獨(dú)的神經(jīng)元吧。
單個(gè)神經(jīng)元
我們接下來(lái)要談?wù)摰纳窠?jīng)元是一個(gè)與 Frank Rosenblatt 在 1957 年提出的最簡(jiǎn)單的被稱作「感知機(jī),perception」的神經(jīng)元稍微有所不同的版本。我所做的所有修改都是為了簡(jiǎn)化,因?yàn)槲以谶@篇文章中不會(huì)涉及神經(jīng)網(wǎng)絡(luò)的深入解釋。我僅僅試著給讀者給出一個(gè)關(guān)于神經(jīng)網(wǎng)絡(luò)如何工作的直覺認(rèn)識(shí)。
什么是神經(jīng)元呢?它是一個(gè)數(shù)學(xué)函數(shù),并以一定量的數(shù)值作為輸入(隨便你想要多少作為輸入),我在上圖畫出的神經(jīng)元有兩個(gè)輸入。我們將每個(gè)輸入記為 x_k,這里 k 是輸入的索引。對(duì)于每一個(gè)輸入 x_k,神經(jīng)元會(huì)給它分配另一個(gè)數(shù) w_k,由這些參數(shù) w_k 組成的向量叫做權(quán)重向量。正是這些權(quán)值才使得每個(gè)神經(jīng)元都是獨(dú)一無(wú)二的。在測(cè)試的過(guò)程中,權(quán)值是不會(huì)變化的,但是在訓(xùn)練的過(guò)程中,我們要去改變這些權(quán)值以「調(diào)節(jié)」我們的網(wǎng)絡(luò)。我會(huì)在后面的文章中討論這個(gè)內(nèi)容。正如前面提到的,一個(gè)神經(jīng)元就是一個(gè)數(shù)學(xué)函數(shù)。但是它是哪種函數(shù)呢?它是權(quán)值和輸入的一種線性組合,還有基于這種組合的某種非線性函數(shù)。我會(huì)繼續(xù)做進(jìn)一步解釋。讓我們來(lái)看一下首先的線性組合部分。
輸入和權(quán)值的線性組合。
上面的公式就是我提到的線性組合。我們要將輸入和對(duì)應(yīng)的權(quán)值相乘,然后對(duì)所有的結(jié)果求和。結(jié)果就會(huì)一個(gè)數(shù)字。最后一部分—就是給這個(gè)數(shù)字應(yīng)用某種非線性函數(shù)。今天最常用的非線性函數(shù)即一種被稱作 ReLU(rectified linear unit) 的分段線性函數(shù),其公式如下:
線性整流單元的表達(dá)式。
如果我們的數(shù)字大于 0,我們就會(huì)使用這個(gè)數(shù)字,如果它小于 0,我們就會(huì)用 0 去代替它。這個(gè)被用在線性神經(jīng)元上的非線性函數(shù)被稱作激活函數(shù)。我們必須使用某種非線性函數(shù)的原因在后面會(huì)變得很明顯。總結(jié)一下,神經(jīng)元使用固定數(shù)目的輸入和(標(biāo)量),并輸出一個(gè)標(biāo)量的激活值。前面畫出的神經(jīng)元可以概括成一個(gè)公式,如下所示:
將我要寫的內(nèi)容稍微提前一下,如果我們以貓狗鑒別的任務(wù)為例,我們會(huì)把圖片作為神經(jīng)元的輸入。也許你會(huì)疑問(wèn):當(dāng)神經(jīng)元被定義為函數(shù)的時(shí)候,如何向它傳遞圖片。你應(yīng)該記住,我們將圖片存儲(chǔ)在計(jì)算機(jī)中的方式是將它拿一個(gè)數(shù)組代表的,數(shù)組中的每一個(gè)數(shù)字代表一個(gè)像素的亮度。所以,將圖片傳遞到神經(jīng)元的方式就是將 2 維(或者 3 維的彩色圖片)數(shù)組展開,得到一個(gè)一維數(shù)組,然后將這些數(shù)字傳遞到神經(jīng)元。不幸的是,這會(huì)導(dǎo)致我們的神經(jīng)網(wǎng)絡(luò)會(huì)依賴于輸入圖片的大小,我們只能處理由神經(jīng)網(wǎng)絡(luò)定義的某個(gè)固定大小的圖片?,F(xiàn)代神經(jīng)網(wǎng)絡(luò)已經(jīng)發(fā)現(xiàn)了解決這個(gè)問(wèn)題的方法,但是我們?cè)谶@里還是在這個(gè)限制下設(shè)計(jì)神經(jīng)網(wǎng)絡(luò)。
現(xiàn)在我們定義一下神經(jīng)網(wǎng)絡(luò)。神經(jīng)網(wǎng)絡(luò)也是一個(gè)數(shù)學(xué)函數(shù),它就是很多相互連接的神經(jīng)元,這里的連接指的是一個(gè)神經(jīng)元的輸出被用為另一個(gè)神經(jīng)元的輸入。下圖是一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò),希望用這張圖能夠?qū)⑦@個(gè)定義解釋得更加清楚。
一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)。
上圖定義的神經(jīng)網(wǎng)絡(luò)具有 5 個(gè)神經(jīng)元。正如你所看到的,這個(gè)神經(jīng)網(wǎng)絡(luò)由 3 個(gè)全連接層堆疊而成,即每一層的每個(gè)神經(jīng)元都連接到了下一層的每一個(gè)神經(jīng)元。你的神經(jīng)網(wǎng)絡(luò)有多少層、每一層有多少個(gè)神經(jīng)元、神經(jīng)元之間是怎么鏈接的,這這些因素共同定義了一個(gè)神經(jīng)網(wǎng)絡(luò)的架構(gòu)。第一層叫做輸入層,包含兩個(gè)神經(jīng)元。這一層的神經(jīng)元并不是我之前所說(shuō)的神經(jīng)元,從某種意義而言,它并不執(zhí)行任何計(jì)算。它們?cè)谶@里僅僅代表神經(jīng)網(wǎng)絡(luò)的輸入。而神經(jīng)網(wǎng)絡(luò)對(duì)非線性的需求源于以下兩個(gè)事實(shí):1)我們的神經(jīng)元是連在一起的;2)基于線性函數(shù)的函數(shù)還是線性的。所以,如果不對(duì)每個(gè)神經(jīng)元應(yīng)用一個(gè)非線性函數(shù),神經(jīng)網(wǎng)絡(luò)也會(huì)是一個(gè)線性函數(shù)而已,那么它并不比單個(gè)神經(jīng)元強(qiáng)大。最后一點(diǎn)需要強(qiáng)調(diào)的是:我們通常是想讓一個(gè)神經(jīng)網(wǎng)絡(luò)的輸出大小在 0 到 1 之間,所以我們會(huì)將它按照概率對(duì)待。例如,在貓狗鑒別的例子中,我們可以把接近于 0 的輸出視為貓,將接近于 1 的輸出視為狗。為了完成這個(gè)目標(biāo),我們會(huì)在最后一個(gè)神經(jīng)元上應(yīng)用一個(gè)不同的激活函數(shù)。我們會(huì)使用 sigmoid 激活函數(shù)。關(guān)于這個(gè)激活函數(shù),你目前只需要知道它地返回值是一個(gè)介于 0 到 1 的數(shù)字,這正好是我們想要的。解釋完這些之后,我們可以定義一個(gè)和上圖對(duì)應(yīng)的神經(jīng)網(wǎng)絡(luò)了。
定義一個(gè)神經(jīng)網(wǎng)絡(luò)的函數(shù)。w 的上標(biāo)代表神經(jīng)元的索引,下標(biāo)代表輸入的索引。
最后,我們得到了某種函數(shù),它以幾個(gè)數(shù)作為輸入,輸出另一個(gè)介于 0 到 1 之間的數(shù)。實(shí)際上,這個(gè)函數(shù)怎樣表達(dá)并不重要,重要的是我們通過(guò)一些權(quán)重將一個(gè)非線性函數(shù)參數(shù)化了,我們可以通過(guò)改變這些權(quán)重來(lái)改變這個(gè)非線性函數(shù)。
III. 損失函數(shù)
在開始討論神經(jīng)網(wǎng)絡(luò)的訓(xùn)練之前,最后一個(gè)需要定義的就是損失函數(shù)了。損失函數(shù)是一個(gè)可以告訴我們,神經(jīng)網(wǎng)絡(luò)在某個(gè)特定的任務(wù)上表現(xiàn)有多好的函數(shù)。做這件事的最直覺的辦法就是,對(duì)每一個(gè)訓(xùn)練樣本,都沿著神經(jīng)網(wǎng)絡(luò)傳遞得到一個(gè)數(shù)字,然后將這個(gè)數(shù)字與我們想要得到的實(shí)際數(shù)字做差再求平方,這樣計(jì)算出來(lái)的就是預(yù)測(cè)值與真實(shí)值之間的距離,而訓(xùn)練神經(jīng)網(wǎng)絡(luò)就是希望將這個(gè)距離或損失函數(shù)減小。
上式中的 y 代表我們想要從神經(jīng)網(wǎng)絡(luò)得到的數(shù)字,y hat 指的一個(gè)樣本通過(guò)神經(jīng)網(wǎng)絡(luò)得到的實(shí)際結(jié)果,i 是我們的訓(xùn)練樣本的索引。我們還是以貓狗鑒別為例。我們有一個(gè)數(shù)據(jù)集,由貓和狗的圖片組成,如果圖片是狗,對(duì)應(yīng)的標(biāo)簽是 1,如果圖片是貓,對(duì)應(yīng)的標(biāo)簽是 0。這個(gè)標(biāo)簽就是對(duì)應(yīng)的 y,在向神經(jīng)網(wǎng)絡(luò)傳遞一張圖片的時(shí)候我們想通過(guò)神經(jīng)網(wǎng)絡(luò)的得到的結(jié)果。為了計(jì)算損失函數(shù),我們必須遍歷數(shù)據(jù)集中的每一張圖片,為每一個(gè)樣本計(jì)算 y,然后按照上面的定義計(jì)算損失函數(shù)。如果損失函數(shù)比較大,那么說(shuō)明我們的神經(jīng)網(wǎng)絡(luò)性能并不是很好,我們想要損失函數(shù)盡可能的小。為了更深入地了解損失函數(shù)和神經(jīng)網(wǎng)絡(luò)之間的聯(lián)系,我們可以重寫這個(gè)公式,將 y 換成網(wǎng)絡(luò)的實(shí)際函數(shù)。
IV. 訓(xùn)練
在開始訓(xùn)練神經(jīng)網(wǎng)絡(luò)的時(shí)候,要對(duì)權(quán)值進(jìn)行隨機(jī)初始化。顯然,初始化的參數(shù)并不會(huì)得到很好的結(jié)果。在訓(xùn)練的過(guò)程中,我們想以一個(gè)很糟糕的神經(jīng)網(wǎng)絡(luò)開始,得到一個(gè)具有高準(zhǔn)確率的網(wǎng)絡(luò)。此外,我們還希望在訓(xùn)練結(jié)束的時(shí)候,損失函數(shù)的函數(shù)值變得特別小。提升網(wǎng)絡(luò)是有可能的,因?yàn)槲覀兛梢酝ㄟ^(guò)調(diào)節(jié)權(quán)值去改變函數(shù)。我們希望找到一個(gè)比初始化的模型性能好很多的函數(shù)。
問(wèn)題在于,訓(xùn)練的過(guò)程相當(dāng)于最小化損失函數(shù)。為什么是最小化損失而不是最大化呢?結(jié)果證明損失是比較容易優(yōu)化的函數(shù)。
有很多用于函數(shù)優(yōu)化的算法。這些算法可以是基于梯度的,也可以不是基于梯度的,因?yàn)樗鼈兗瓤梢允褂煤瘮?shù)提供的信息,還可以使用函數(shù)梯度提供的信息。最簡(jiǎn)單的基于梯度的算法之一叫做隨機(jī)梯度下降(SGD),這也是我在這篇文章中要介紹的算法。讓我們來(lái)看一下它是如何運(yùn)行的吧。
首先,我們要記住關(guān)于某個(gè)變量的導(dǎo)數(shù)是什么。我們拿比較簡(jiǎn)單的函數(shù) f(x) = x 為例。如果還記得高中時(shí)候?qū)W過(guò)的微積分法則,我們就會(huì)知道,這個(gè)函數(shù)在每個(gè) x 處的導(dǎo)數(shù)都是 1。那么導(dǎo)數(shù)能夠告訴我們哪些信息呢?導(dǎo)數(shù)描述的是:當(dāng)我么讓自變量朝正方向變化無(wú)限小的步長(zhǎng)時(shí),函數(shù)值變化有多快的速率。它可以寫成下面的數(shù)學(xué)形式:
它的意思是:函數(shù)值的變化量(方程的左邊)近似等于函數(shù)在對(duì)應(yīng)的某個(gè)變量 x 處的導(dǎo)數(shù)與 x 的增量的乘積?;氐轿覀儎偛潘e的最簡(jiǎn)單的例子 f(x) = x,導(dǎo)數(shù)處處是 1,這意味著如果我們將 x 朝正方向變化一小步ε,函數(shù)輸出的變化等于 1 和ε的乘積,剛好是ε本身。檢查這個(gè)規(guī)則是比較容易的。實(shí)際上這個(gè)并不是近似值,它是精確的。為什么呢?因?yàn)槲覀兊膶?dǎo)數(shù)對(duì)于每一個(gè) x 都是相同的。但是這并不適用于絕大多數(shù)函數(shù)。讓我們來(lái)看一個(gè)稍微復(fù)雜一點(diǎn)的函數(shù) f(x) = x^2。
通過(guò)微積分知識(shí)我們可以知道,這個(gè)函數(shù)的導(dǎo)數(shù)是 2*x?,F(xiàn)在如果我們從某個(gè) x 開始移動(dòng)某個(gè)步長(zhǎng)的ε,很容易能夠發(fā)現(xiàn)對(duì)應(yīng)的函數(shù)增量并不精確地等于上面的公式中的計(jì)算結(jié)果。
現(xiàn)在,梯度是由偏導(dǎo)數(shù)組成的向量,這個(gè)向量的元素是這個(gè)函數(shù)所依賴的某些變量對(duì)應(yīng)的導(dǎo)數(shù)。對(duì)于我們目前所考慮的簡(jiǎn)單函數(shù)來(lái)說(shuō),這個(gè)向量只有一個(gè)元素,因?yàn)槲覀兯玫暮瘮?shù)只有一個(gè)輸入。對(duì)于更加復(fù)雜的函數(shù)(例如我們的損失函數(shù))而言,梯度會(huì)包含函數(shù)對(duì)應(yīng)的每個(gè)變量的導(dǎo)數(shù)。
為了最小化某個(gè)損失函數(shù),我們可以怎么使用這個(gè)由導(dǎo)數(shù)提供的信息呢?還是回到函數(shù) f(x) = x^2。顯然,這個(gè)函數(shù)在 x=0 的點(diǎn)取得最小值,但是計(jì)算機(jī)如何知道呢?假設(shè)我們開始的時(shí)候得到的 x 的隨機(jī)初始值為 2,此時(shí)函數(shù)的導(dǎo)數(shù)等于 4。這意味著如果 x 朝著正方向改變,函數(shù)的增量會(huì)是 x 增量的 4 倍,因此函數(shù)值反而會(huì)增加。相反,我們希望最小化我們的函數(shù),所以我們可以朝著相反的方向改變 x,也就是負(fù)方向,為了確保函數(shù)值降低,我們只改變一小步。但是我們一步可以改變多大呢? 我們的導(dǎo)數(shù)只保證當(dāng) x 朝負(fù)方向改變無(wú)限小的時(shí)候函數(shù)值才會(huì)減小。因此,我們希望用一些超參數(shù)來(lái)控制一次能夠改變多大。這些超參數(shù)叫做學(xué)習(xí)率,我們后面會(huì)談到。我們現(xiàn)在看一下,如果我們從-2 這個(gè)點(diǎn)開始,會(huì)發(fā)生什么。這里的導(dǎo)數(shù)是-4,這意味著如果朝著正方向改變 x,函數(shù)值會(huì)變小,這正是我們想要的結(jié)果。
注意到這里的規(guī)律了嗎?當(dāng) x>0 的時(shí)候,我們導(dǎo)數(shù)值也大于 0,我們需要朝著負(fù)方向改變,當(dāng) x<0 的時(shí)候,我們導(dǎo)數(shù)值小于 0,我們需要朝著正方向改變,我們總需要朝著導(dǎo)數(shù)的反方向改變 x。讓我們對(duì)梯度也引用同樣的思路。梯度是指向空間某個(gè)方向的向量,實(shí)際上它指向的是函數(shù)值增加最劇烈的方向。由于我們要最小化我們的函數(shù),所以我們會(huì)朝著與梯度相反的方向改變自變量。現(xiàn)在在我們應(yīng)用這個(gè)思想。在神經(jīng)網(wǎng)絡(luò)中,我們將輸入 x 和輸出 y 視為固定的數(shù)。我們要對(duì)其求導(dǎo)數(shù)的變量是權(quán)值 w,因?yàn)槲覀兛梢酝ㄟ^(guò)改變這些權(quán)值類提升神經(jīng)網(wǎng)絡(luò)。如果我們對(duì)損失函數(shù)計(jì)算權(quán)值對(duì)應(yīng)的梯度,然后朝著與梯度相反的方向改變權(quán)值,我們的損失函數(shù)也會(huì)隨之減小,直至收斂到某一個(gè)局部極小值。這個(gè)算法就叫做梯度下降。在每一次迭代中更新權(quán)重的算法如下所示:
每一個(gè)權(quán)重值都要減去它對(duì)應(yīng)的導(dǎo)數(shù)和學(xué)習(xí)率的乘積。
上式中的 Lr 代表的是學(xué)習(xí)率,它就是控制每次迭代中步長(zhǎng)大小的變量。這是我們?cè)谟?xùn)練神經(jīng)網(wǎng)絡(luò)的時(shí)候要調(diào)節(jié)的重要超參數(shù)。如果我么選擇的學(xué)習(xí)率太大,會(huì)導(dǎo)致步進(jìn)太大,以至于跳過(guò)最小值,這意味著你的算法會(huì)發(fā)散。如果你選擇的學(xué)習(xí)率太小,收斂到一個(gè)局部極小值可能會(huì)花費(fèi)太多時(shí)間。人們開發(fā)出了一些很好的技術(shù)來(lái)尋找一個(gè)最佳的學(xué)習(xí)率,然而這個(gè)內(nèi)容超出本文所涉及的范圍了。
不幸的是,我們不能應(yīng)用這個(gè)算法來(lái)訓(xùn)練神經(jīng)網(wǎng)絡(luò),原因在于損失函數(shù)的公式。
正如你可以在我之前的定義中看到的一樣,我們損失函數(shù)的公式是和的平均值。從微積分原理中我們可以知道,微分的和就是和的微分。所以,為了計(jì)算損失函數(shù)的梯度,我們需要遍歷我們的數(shù)據(jù)集中的每一個(gè)樣本。在每一次迭代中進(jìn)行梯度下降是非常低效的,因?yàn)樗惴ǖ拿看蔚鷥H僅以很小的步進(jìn)提升了損失函數(shù)。為了解決這個(gè)問(wèn)題,還有另外一個(gè)小批量梯度下降算法。該算法更新權(quán)值的方法是不變的,但是我們不會(huì)去計(jì)算精確的梯度。相反,我們會(huì)在數(shù)據(jù)集的一個(gè)小批量上近似計(jì)算梯度,然后使用這個(gè)梯度去更新權(quán)值。Mini-batch 并不能保證朝著最佳的方向改變權(quán)值。事實(shí)上,它通常都不會(huì)。在使用梯度下降算法的時(shí)候,如果所選擇的學(xué)習(xí)率足夠小的話,能夠保證你的損失函數(shù)在每一次迭代中都會(huì)減小。但是使用 Mini-batch 的時(shí)候并不是這樣。你的損失函數(shù)會(huì)隨著時(shí)間減小,但是它會(huì)有波動(dòng),也會(huì)具有更多的「噪聲」。
用來(lái)估計(jì)梯度的 batch 大小是你必須選擇的另一個(gè)超參數(shù)。通常,我們希望盡可能地選擇能處理的較大 batch。但是我很少見到別人使用比 100 還大的 batch size。
mini-batch 梯度下降的極端情況就是 batch size 等于 1,這種形式的梯度下降叫做隨機(jī)梯度下降(SGD)。通常在很多文獻(xiàn)中,當(dāng)人們說(shuō)隨機(jī)梯度下降的時(shí)候,實(shí)際上他們指的就是 mini-batch 隨機(jī)梯度下降。大多數(shù)深度學(xué)習(xí)框架都會(huì)讓你選擇隨機(jī)梯度下降的 batch size。
以上是梯度下降和它變體的基本概念。但近來(lái)越來(lái)越多的人在使用更高級(jí)的算法,其中大多數(shù)都是基于梯度的,作者下一部分就主要介紹這些最優(yōu)化方法。
VII. 反向傳播(BP)
關(guān)于基于梯度的算法,剩下的唯一一件事就是如何計(jì)算梯度了。最快速的方法就是解析地給出每一個(gè)神經(jīng)元架構(gòu)的導(dǎo)數(shù)。我想,當(dāng)梯度遇到神經(jīng)網(wǎng)絡(luò)的時(shí)候,我不應(yīng)該說(shuō)這是一個(gè)瘋狂的想法。我們?cè)谇懊娑x的一個(gè)很簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)就已經(jīng)相當(dāng)艱難了,而它只有區(qū)區(qū) 6 個(gè)參數(shù)。而現(xiàn)代神經(jīng)網(wǎng)絡(luò)的參數(shù)動(dòng)輒就是數(shù)百萬(wàn)。
第二種方法就是使用我們從微積分中學(xué)到的下面的這個(gè)公式去近似計(jì)算梯度,事實(shí)上這也是最簡(jiǎn)單的方法?!?
盡管這個(gè)方法是非常容易實(shí)現(xiàn)的,但是它卻是非常耗計(jì)算資源的。
最后一種計(jì)算梯度的方法,是對(duì)解析難度和計(jì)算成本的折中,這個(gè)方法被稱作反向傳小節(jié)。反向傳播不在本文的討論范圍,如果你想了解更多的話,可以查看 Goodfellow《深度學(xué)習(xí)》第六章第五小節(jié),該章節(jié)對(duì)反向傳播算法有非常詳盡的介紹。
VI. 它為什么會(huì)起作用?
當(dāng)我初次了解神經(jīng)網(wǎng)絡(luò)以及它是如何工作的時(shí)候,我理解所有的方程,但是我不是十分確定它們?yōu)樯稌?huì)起作用。這個(gè)想法對(duì)我而言有些怪誕:用幾個(gè)函數(shù),求一些導(dǎo)數(shù),最終會(huì)得到一個(gè)能夠認(rèn)出圖片中是貓還是狗。為什么我不能給你們一個(gè)很好的關(guān)于為啥神經(jīng)網(wǎng)絡(luò)會(huì)如此好的奏效的直覺知識(shí)呢?請(qǐng)注意以下兩個(gè)方面。
1. 我們想要用神經(jīng)網(wǎng)絡(luò)解決的問(wèn)題必須被以數(shù)學(xué)的形式表達(dá)出來(lái)。例如,對(duì)于對(duì)于貓狗鑒別:我們需要找到一個(gè)函數(shù),它能夠把一副圖片中的所有像素作為輸入,然后輸出圖片中的內(nèi)容是狗的概率。你可以用這種方法去定義任何一個(gè)分類問(wèn)題。
2. 或許并不是很清楚,為什么會(huì)有一個(gè)能夠從一副圖片中把貓和狗區(qū)分開來(lái)的函數(shù)。這里的思想是:只要你有一些具有輸入和標(biāo)簽的數(shù)據(jù)集,總會(huì)存在一個(gè)能夠在一個(gè)給定數(shù)據(jù)集上性能良好的函數(shù)。問(wèn)題在于這個(gè)函數(shù)會(huì)相當(dāng)復(fù)雜。這時(shí)候神經(jīng)網(wǎng)絡(luò)就能夠有所幫助了。有一個(gè)「泛逼近性原理,universal approximation theorem」,指的是具有一個(gè)隱藏層的神經(jīng)網(wǎng)絡(luò)可以近似任何一個(gè)你想要的的函數(shù),你想要它近似得多好,就能有多好。
動(dòng)量隨機(jī)梯度下降算法
-這是關(guān)于訓(xùn)練神經(jīng)網(wǎng)絡(luò)和機(jī)器學(xué)習(xí)模型優(yōu)化算法系列的第二部分,第一部分是關(guān)于隨機(jī)梯度下降的。在這一部分,假定讀者對(duì)神經(jīng)網(wǎng)絡(luò)和梯度下降算法已有基本了解。如果讀者對(duì)神經(jīng)網(wǎng)絡(luò)一無(wú)所知,或者不知道神經(jīng)網(wǎng)絡(luò)是如何訓(xùn)練的,可以在閱讀這部分之前閱讀第一部分。
在本節(jié)中,除了經(jīng)典的 SGD 算法外,我們還會(huì)對(duì)動(dòng)量法進(jìn)行討論,這種算法一般比隨機(jī)梯度下降算法更好更快。動(dòng)量法 [1] 或具有動(dòng)量的 SGD 是一種方法,這種方法有助于加速向量向著正確的方向梯度下降,從而使其收斂速度更快。這是最流行的優(yōu)化算法之一,許多各方向上最先進(jìn)的模型都是用這種方法進(jìn)行訓(xùn)練的。在講高級(jí)的算法相關(guān)方程之前,我們先來(lái)看一些有關(guān)動(dòng)量的基礎(chǔ)數(shù)學(xué)知識(shí)。
指數(shù)加權(quán)平均
指數(shù)加權(quán)平均用于處理數(shù)字序列。假設(shè)我們有一些嘈雜的序列 S。在這個(gè)例子中,我繪制了余弦函數(shù)并添加了一些高斯噪聲。如下圖所示:
注意,盡管這些點(diǎn)看起來(lái)非常接近,但它們的 x 坐標(biāo)是不同的。也就是說(shuō),對(duì)每個(gè)點(diǎn)而言,其 x 坐標(biāo)是唯一的標(biāo)識(shí),因此這也是定義序列 S 中每個(gè)點(diǎn)的索引。
我們需要處理這些數(shù)據(jù),而非直接使用它們。我們需要某種「移動(dòng)」的平均值,這個(gè)平均值會(huì)使數(shù)據(jù)「去噪」從而使其更接近原始函數(shù)。指數(shù)加權(quán)平均值可以產(chǎn)生如下所示的圖片:
動(dòng)量——來(lái)自指數(shù)加權(quán)平均的數(shù)據(jù)
如我們所見,這是一個(gè)相當(dāng)不錯(cuò)的結(jié)果。與噪聲很大的數(shù)據(jù)相比,我們得到了更平滑的曲線,這意味著與初始數(shù)據(jù)相比,我們得到了與原始函數(shù)更接近的結(jié)果。指數(shù)加權(quán)平均值用下面的公式定義了新的序列 V:
序列 V 是上面的散點(diǎn)圖中的黃色部分。Beta 是取值為 0 到 1 的另一個(gè)超參數(shù)。在上述例子中,取 Beta = 0.9。0.9 是一個(gè)很好的值,經(jīng)常用于具有動(dòng)量的 SGD 方法。我們可以這樣對(duì) Beta 進(jìn)行直觀理解:我們對(duì)序列后面的 1 /(1- beta)的點(diǎn)進(jìn)行近似平均。讓我們看看 beta 的選擇會(huì)對(duì)新序列 V 產(chǎn)生怎樣的影響。
Beta 取值不同時(shí)的指數(shù)加權(quán)平均結(jié)果。
如我們所見,Beta 取值越小,序列 V 波動(dòng)越大。因?yàn)槲覀兤骄睦痈?,因此結(jié)果與噪聲數(shù)據(jù)更「接近」。隨著 Beta 值越大,比如當(dāng) Beta = 0.98 時(shí),我們得到的曲線會(huì)更加圓滑,但是該曲線有點(diǎn)向右偏移,因?yàn)槲覀內(nèi)∑骄档姆秶兊酶?beta = 0.98 時(shí)取值約為 50)。Beta = 0.9 時(shí),在這兩個(gè)極端間取得了很好的平衡。
數(shù)學(xué)部分
這個(gè)部分對(duì)你在項(xiàng)目中使用動(dòng)量而言不是必要的,所以可以跳過(guò)。但這部分更直觀地解釋了動(dòng)量是如何工作的。
讓我們對(duì)指數(shù)加權(quán)平均新序列 V 的三個(gè)連續(xù)元素的定義進(jìn)行擴(kuò)展。
V——新序列。S——原始序列。
將其進(jìn)行合并,我們可以得到:
再對(duì)其進(jìn)行簡(jiǎn)化,可得:
從這個(gè)等式中可以看出,新序列的第 T 個(gè)值取決于原始序列 S 的所有先前的數(shù)值 1…t。來(lái)自 S 的所有數(shù)值被賦了一定的權(quán)重。這個(gè)權(quán)重是序列 S 的第(t-i)個(gè)值乘以(1- beta)得到的權(quán)重。因?yàn)?Beta 小于 1,所以當(dāng)我們對(duì)某個(gè)正數(shù)的冪取 beta 時(shí),值會(huì)變得更小。所以序列 S 的原始值的權(quán)重會(huì)小得多,也因此序列 S 對(duì)序列 V 產(chǎn)生的點(diǎn)積影響較小。從某些角度來(lái)說(shuō),該權(quán)重小到我們幾乎可以說(shuō)我們「忘記」了這個(gè)值,因?yàn)槠溆绊懶〉綆缀鯚o(wú)法注意到。使用這個(gè)近似值的好處在于當(dāng)權(quán)重小于 1 / e 時(shí),更大的 beta 值會(huì)要求更多小于 1 / e 的權(quán)值。這就是為什么 beta 值越大,我們就要對(duì)更多的點(diǎn)積進(jìn)行平均。下面的圖表顯示的是與 threshold = 1 / e 相比,隨著序列 S 初始值變化,權(quán)重變小的速度,在此我們「忘記」了初始值。
最后要注意的是,第一次迭代得到的平均值會(huì)很差,因?yàn)槲覀儧]有足夠的值進(jìn)行平均。我們可以通過(guò)使用序列 V 的偏差修正版而不是直接使用序列 V 來(lái)解決這一問(wèn)題。
式中 b = beta。當(dāng) t 值變大時(shí),b 的 t 次冪與零無(wú)法進(jìn)行區(qū)分,因此不會(huì)改變 V 值。但是當(dāng) t 取值較小時(shí),這個(gè)方程會(huì)產(chǎn)生較好的結(jié)果。但是因?yàn)閯?dòng)量的存在使得機(jī)器學(xué)習(xí)過(guò)程穩(wěn)定得很快,因此人們通常會(huì)懶得應(yīng)用這一部分。
動(dòng)量 SGD 法
我們已經(jīng)定義了一種方法來(lái)獲得一些序列的「移動(dòng)」平均值,該值會(huì)與數(shù)據(jù)一起變化。我們?cè)撊绾螌⑵鋺?yīng)用于神經(jīng)網(wǎng)絡(luò)的訓(xùn)練中呢?它可以平均我們的梯度。我將在下文中解釋它是如何在動(dòng)量中完成的這一工作,并將繼續(xù)解釋為什么它可能會(huì)得到更好的效果。
我將提供兩個(gè)定義來(lái)定義具有動(dòng)量的 SGD 方法,這幾乎就是用兩種不同的方式表達(dá)同一個(gè)方程。首先,是吳恩達(dá)在 Coursera 深度學(xué)習(xí)專業(yè)化(https://www.deeplearning.ai/)的課程中提出的定義。他解釋的方式是,我們定義一個(gè)動(dòng)量,這是我們梯度的移動(dòng)平均值。然后我們用它來(lái)更新網(wǎng)絡(luò)的權(quán)重。如下所示:
式中 L 是損失函數(shù),三角形符號(hào)是梯度 w.r.t 權(quán)重,α 是學(xué)習(xí)率。另一種最流行的表達(dá)動(dòng)量更新規(guī)則的方式不那么直觀,只是省略了(1 - beta)項(xiàng)。
這與第一組方程式非常相似,唯一的區(qū)別是需要通過(guò)(1 - β)項(xiàng)來(lái)調(diào)整學(xué)習(xí)率。
Nesterov 加速漸變
Nesterov 動(dòng)量是一個(gè)版本略有不同的動(dòng)量更新,最近越來(lái)越受歡迎。在這個(gè)版本中,首先會(huì)得到一個(gè)當(dāng)前動(dòng)量指向的點(diǎn),然后從這個(gè)點(diǎn)計(jì)算梯度。如下圖所示:
Nesterov 動(dòng)量可用下式定義:
動(dòng)量工作原理
在這里我會(huì)解釋為什么在絕大多數(shù)情況下動(dòng)量法會(huì)比經(jīng)典 SGD 法更好用。
使用隨機(jī)梯度下降的方法,我們不會(huì)計(jì)算損失函數(shù)的確切導(dǎo)數(shù)。相反,我們是對(duì)一小批數(shù)據(jù)進(jìn)行估算的。這意味著我們并不總是朝著最佳的方向前進(jìn),因?yàn)槲覀兊玫降慕Y(jié)果是「嘈雜的」。正如我在上文中列出的圖表。所以,指數(shù)的加權(quán)平均可以提供一個(gè)更好的估計(jì)值,該估計(jì)值比通過(guò)嘈雜計(jì)算得到的結(jié)果更接近實(shí)際值的導(dǎo)數(shù)。這就是動(dòng)量法可能比傳統(tǒng) SGD 更好的原因之一。
另一個(gè)原因在于溝谷(ravine)。溝谷是一個(gè)區(qū)域,在其中,曲線在一個(gè)維度比另一個(gè)維度陡得多。在深度學(xué)習(xí)中,溝谷區(qū)可近似視為局部最低點(diǎn),而這一特性無(wú)法用 SGD 方法得到。SGD 傾向于在狹窄的溝谷上擺動(dòng),因?yàn)樨?fù)梯度將沿著陡峭的一側(cè)下降,而非沿著溝谷向最優(yōu)點(diǎn)前進(jìn)。動(dòng)量有助于加速梯度向正確的方向前進(jìn)。如下圖所示:
左圖——沒有動(dòng)量的 SGD,右圖——有動(dòng)量的 SGD(來(lái)源:https://www.willamette.edu/~gorr/classes/cs449/momrate.html)
結(jié)論
希望本節(jié)會(huì)提供一些關(guān)于具有動(dòng)量的 SGD 方法是如何起作用以及為什么會(huì)有用的想法。實(shí)際上它是深度學(xué)習(xí)中最流行的優(yōu)化算法之一,與更高級(jí)的算法相比,這種方法通常被人們更頻繁地使用。
參考資源
fast.ai(http://fast.ai/) :它針對(duì)程序員提供了兩個(gè)很不錯(cuò)的關(guān)于深度學(xué)習(xí)的課程,以及一個(gè)關(guān)于可計(jì)算線性代數(shù)的課程。是開始編寫神經(jīng)網(wǎng)絡(luò)代碼的好地方,隨著課程深度的延伸,當(dāng)你學(xué)到更多理論的時(shí)候,你可以盡快用代碼實(shí)現(xiàn)。
neuralnetworksanddeeplearning.com(http://neuralnetworksanddeeplearning.com/chap1.html):一本關(guān)于基本知識(shí)的很好的在線書籍。關(guān)于神經(jīng)網(wǎng)絡(luò)背后的理論。作者以一種很好的方式解釋了你需要知道的數(shù)學(xué)知識(shí)。它也提供并解釋了一些不使用任何深度學(xué)習(xí)框架從零開始編寫神經(jīng)網(wǎng)絡(luò)架構(gòu)的代碼。
Andrew Ng 的深度學(xué)習(xí)課程(https://www.coursera.org/specializations/deep-learning):coursera 上的課程,也是有關(guān)學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)的。以非常簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)例子開始,逐步到卷積神經(jīng)網(wǎng)絡(luò)以及更多。
3Blue1Brown(https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw):YouTube 上也有一些能夠幫助你理解神經(jīng)網(wǎng)絡(luò)和線性代數(shù)的很好的視頻。它們展示了很棒的可視化形式,以及以非常直覺的方式去理解數(shù)學(xué)和神經(jīng)網(wǎng)絡(luò)。
Stanford CS231 課程(http://cs231n.stanford.edu/):這是關(guān)于用于視覺識(shí)別的卷積神經(jīng)網(wǎng)絡(luò)的課堂,可以學(xué)到很多關(guān)于深度學(xué)習(xí)和卷積神經(jīng)網(wǎng)絡(luò)的具體內(nèi)容。
參考文獻(xiàn)
[1] Ning Qian. On the momentum term in gradient descent learning algorithms . Neural networks : the official journal of the International Neural Network Society, 12(1):145–151, 1999
[2] Distill, Why Momentum really works(https://distill.pub/2017/momentum/)
[3] deeplearning.ai
[4] Ruder(2016). An overview of gradient descent optimization algorithms. arXiv preprint arXiv:1609.04747
[5] Ruder (2017) Optimization for Deep Learning Highlights in 2017.(http://ruder.io/deep-learning-optimization-2017/index.html)
[6] Stanford CS231n lecture notes.(http://cs231n.github.io/neural-networks-3/)(http://cs231n.github.io/neural-networks-3/%EF%BC%89)
[7] fast.ai(http://www.fast.ai/)
評(píng)論