假設(shè)你是一名工程師,接到一項(xiàng)從頭開始設(shè)計(jì)計(jì)算機(jī)的任務(wù)。某天,你在工作室工作,設(shè)計(jì)邏輯電路,構(gòu)建 $$AND$$ 門,$$OR$$ 門等等時(shí),老板帶著壞消息進(jìn)來(lái):客戶剛剛添加了一個(gè)奇特的設(shè)計(jì)需求:整個(gè)計(jì)算機(jī)的線路的深度必須只有兩層:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/146.png" alt="兩層線路" />
你驚呆了,跟老板說(shuō)道:“這貨瘋掉了吧!”
老板說(shuō):“他們確實(shí)瘋了,但是客戶的需求比天大,我們要滿足它?!?
實(shí)際上,在某種程度上看,他們的客戶并沒(méi)有太瘋狂。假設(shè)你可以使用貴重特殊的邏輯門可以$$AND$$起來(lái)你想要的那么多的輸入。同樣也能使用多值輸入的 $$NAND$$ 門——可以$$AND$$多個(gè)輸入然后求否定的門。有了這類特殊的門,構(gòu)建出來(lái)的兩層的深度的網(wǎng)絡(luò)便可以計(jì)算任何函數(shù)。 但是僅僅因?yàn)槟臣率抢碚撋峡赡艿?,就代表這是一個(gè)好的想法。在實(shí)踐中,在解決線路設(shè)計(jì)問(wèn)題(或者大多數(shù)的其他算法問(wèn)題)時(shí),我們通常考慮如何解決子問(wèn)題,然后逐步地集成這些子問(wèn)題的解。換句話說(shuō),我們通過(guò)多層的抽象來(lái)獲得最終的解答。 例如,我們來(lái)設(shè)計(jì)一個(gè)邏輯線路來(lái)做兩個(gè)數(shù)的乘法。我們希望在已經(jīng)有了計(jì)算兩個(gè)數(shù)加法的子線路基礎(chǔ)上創(chuàng)建這個(gè)邏輯線路。計(jì)算兩個(gè)數(shù)和的子線路也是構(gòu)建在用語(yǔ)兩個(gè)比特相加的子子線路上的。最終的線路就長(zhǎng)成這個(gè)樣子:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/147.png" alt="加法線路" />
最終的線路包含至少三層線路的單元。實(shí)際上,這個(gè)線路很可能會(huì)超過(guò)三層,因?yàn)槲覀兛梢詫⒆尤蝿?wù)分解成比上述更小的單元。但是基本思想就是這樣。
因此深度線路讓這樣的設(shè)計(jì)過(guò)程變得更加簡(jiǎn)單。但是這對(duì)于設(shè)計(jì)本身幫助并不大。其實(shí),數(shù)學(xué)證明對(duì)于某些函數(shù)設(shè)計(jì)的非常淺的線路可能需要指數(shù)級(jí)的線路單元來(lái)計(jì)算。例如,在1980年代早期的一系列著名的論文已經(jīng)給出了計(jì)算比特的集合的奇偶性通過(guò)淺的線路來(lái)計(jì)算需要指數(shù)級(jí)的門。另一當(dāng)面,如果你使用更深的線路,那么可以使用規(guī)模很小的線路來(lái)計(jì)算奇偶性:僅僅需要計(jì)算比特的對(duì)的奇偶性,然后使用這些結(jié)果來(lái)計(jì)算比特對(duì)的對(duì)的奇偶性,以此類推,構(gòu)建出總共的奇偶性。深度線路這樣就能從本質(zhì)上獲得超過(guò)淺線路的更強(qiáng)的能力。
到現(xiàn)在為止,本書講神經(jīng)網(wǎng)絡(luò)看作是瘋狂的客戶。幾乎我們遇到的所有的網(wǎng)絡(luò)就只包括一層隱含神經(jīng)元(另外還有輸入輸出層):
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/148.png" alt="淺層神經(jīng)網(wǎng)絡(luò)" />
這些簡(jiǎn)單的網(wǎng)絡(luò)已經(jīng)非常有用了:在前面的章節(jié)中,我們使用這樣的網(wǎng)絡(luò)可以進(jìn)行準(zhǔn)確率高達(dá) 98% 的手寫數(shù)字的識(shí)別!而且,直覺上看,我們期望擁有更多隱含層的神經(jīng)網(wǎng)絡(luò)能夠變的更加強(qiáng)大:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/149.png" alt="深度神經(jīng)網(wǎng)絡(luò)" />
這樣的網(wǎng)絡(luò)可以使用中間層構(gòu)建出多層的抽象,正如我們?cè)诓紶柧€路中做的那樣。例如,如果我們?cè)谶M(jìn)行視覺模式識(shí)別,那么在第一層的神經(jīng)元可能學(xué)會(huì)識(shí)別邊,在第二層的神經(jīng)元可以在邊的基礎(chǔ)上學(xué)會(huì)識(shí)別出更加復(fù)雜的形狀,例如三角形或者矩形。第三層將能夠識(shí)別更加復(fù)雜的形狀。依此類推。這些多層的抽象看起來(lái)能夠賦予深度網(wǎng)絡(luò)一種學(xué)習(xí)解決復(fù)雜模式識(shí)別問(wèn)題的能力。然后,正如線路的示例中看到的那樣,存在著理論上的研究結(jié)果告訴我們深度網(wǎng)絡(luò)在本質(zhì)上比淺層網(wǎng)絡(luò)更加強(qiáng)大。
對(duì)某些問(wèn)題和網(wǎng)絡(luò)結(jié)構(gòu),Razvan Pascanu, Guido Montúfar, and Yoshua Bengio 在2014年的這篇文章On the number of response regions of deep feed forward networks with piece-wise linear activations給出了證明。更加詳細(xì)的討論在Yoshua Bengio 2009年的著作Learning deep architectures for AI 的第二部分。
那我們?nèi)绾斡?xùn)練這樣的深度神經(jīng)網(wǎng)絡(luò)呢?在本章中,我們嘗試使用基于 BP 的隨機(jī)梯度下降的方法來(lái)訓(xùn)練。但是這會(huì)產(chǎn)生問(wèn)題,因?yàn)槲覀兊纳疃壬窠?jīng)網(wǎng)絡(luò)并不能比淺層網(wǎng)絡(luò)性能好太多。
這個(gè)失敗的結(jié)果好像與上面的討論相悖。這就能讓我們退縮么,不,我們要深入進(jìn)去試著理解使得深度網(wǎng)絡(luò)訓(xùn)練困難的原因。仔細(xì)研究一下,就會(huì)發(fā)現(xiàn),在深度網(wǎng)絡(luò)中,不同的層學(xué)習(xí)的速度差異很大。尤其是,在網(wǎng)絡(luò)中后面的層學(xué)習(xí)的情況很好的時(shí)候,先前的層次常常會(huì)在訓(xùn)練時(shí)停滯不變,基本上學(xué)不到東西。這種停滯并不是因?yàn)檫\(yùn)氣不好。而是,有著更加根本的原因是的學(xué)習(xí)的速度下降了,這些原因和基于梯度的學(xué)習(xí)技術(shù)相關(guān)。
當(dāng)我們更加深入地理解這個(gè)問(wèn)題時(shí),發(fā)現(xiàn)相反的情形同樣會(huì)出現(xiàn):先前的層可能學(xué)習(xí)的比較好,但是后面的層卻停滯不變。實(shí)際上,我們發(fā)現(xiàn)在深度神經(jīng)網(wǎng)絡(luò)中使用基于梯度下降的學(xué)習(xí)方法本身存在著內(nèi)在不穩(wěn)定性。這種不穩(wěn)定性使得先前或者后面的層的學(xué)習(xí)過(guò)程阻滯。
這個(gè)的確是壞消息。但是真正理解了這些難點(diǎn)后,我們就能夠獲得高效訓(xùn)練深度網(wǎng)絡(luò)的更深洞察力。而且這些發(fā)現(xiàn)也是下一章的準(zhǔn)備知識(shí),我們到時(shí)會(huì)介紹如何使用深度學(xué)習(xí)解決圖像識(shí)別問(wèn)題。
那么,在我們訓(xùn)練深度網(wǎng)絡(luò)時(shí)究竟哪里出了問(wèn)題?
為了回答這個(gè)問(wèn)題,讓我們重新看看使用單一隱藏層的神經(jīng)網(wǎng)絡(luò)示例。這里我們也是用 MNIST 數(shù)字分類問(wèn)題作為研究和實(shí)驗(yàn)的對(duì)象。
這里你也可以在自己的電腦上訓(xùn)練神經(jīng)網(wǎng)絡(luò)?;蛘呔椭苯幼x下去。如果希望實(shí)際跟隨這些步驟,那就需要在電腦上安裝 python 2.7,numpy和代碼,可以通過(guò)下面的命令復(fù)制所需要的代碼
git clone https://github.com/mnielsen/neural-networks-and-deep-learning.git
如果你不使用 $$git$$,那么就直接從這里(here)下載數(shù)據(jù)和代碼。然后需要轉(zhuǎn)入 $$src$$ 子目錄。
接著從 python 的 shell 就可以載入 MNIST 數(shù)據(jù):
>>> import mnist_loader
>>> training_data, validation_data, test_data = \
... mnist_loader.load_data_wrapper()
然后設(shè)置我們的網(wǎng)絡(luò):
>>> import network2
>>> net = network2.Network([784, 30, 10])
這個(gè)網(wǎng)絡(luò)擁有 $$784$$ 個(gè)輸入層神經(jīng)元,對(duì)應(yīng)于輸入圖片的 $$28*28=784$$ 個(gè)像素點(diǎn)。我們?cè)O(shè)置隱藏層神經(jīng)元為 $$30$$ 個(gè),輸出層為 $$10$$ 個(gè)神經(jīng)元,對(duì)應(yīng)于 MNIST 數(shù)字 $$(0, 1, ..., 9)$$。 讓我們訓(xùn)練 $$30$$ 輪,使用 mini batch 大小為 $$10$$, 學(xué)習(xí)率 $$\eta = 0.1$$,正規(guī)化參數(shù) $$\lambda = 5.0$$。在訓(xùn)練時(shí),我們也會(huì)在驗(yàn)證集上監(jiān)控分類的準(zhǔn)確度:
>>> net.SGD(training_data, 30, 10, 0.1, lmbda=5.0,
... evaluation_data=validation_data, monitor_evaluation_accuracy=True)
最終我們得到了分類的準(zhǔn)確率為 $$96.48%$$(也可能不同,每次運(yùn)行實(shí)際上會(huì)有一點(diǎn)點(diǎn)的偏差)這和我們前面的結(jié)果相似。 現(xiàn)在,我們?cè)黾恿硗庖粚与[藏層,同樣地是 $$30$$ 個(gè)神經(jīng)元,試著使用相同的超參數(shù)進(jìn)行訓(xùn)練:
>>> net = network2.Network([784, 30, 30, 10])
>>> net.SGD(training_data, 30, 10, 0.1, lmbda=5.0,
... evaluation_data=validation_data, monitor_evaluation_accuracy=True)
最終的結(jié)果分類準(zhǔn)確度提升了一點(diǎn),$$96.90%$$。這點(diǎn)令人興奮:一點(diǎn)點(diǎn)的深度帶來(lái)了效果。那么就再增加一層同樣的隱藏層:
>>> net = network2.Network([784, 30, 30, 30, 10])
>>> net.SGD(training_data, 30, 10, 0.1, lmbda=5.0,
... evaluation_data=validation_data, monitor_evaluation_accuracy=True)
哦,這里并沒(méi)有什么提升,反而下降到了 96.57%,這與最初的淺層網(wǎng)絡(luò)相差無(wú)幾。再增加一層:
>>> net = network2.Network([784, 30, 30, 30, 30, 10])
>>> net.SGD(training_data, 30, 10, 0.1, lmbda=5.0,
... evaluation_data=validation_data, monitor_evaluation_accuracy=True)
分類準(zhǔn)確度又下降了,$$96.53%$$。這可能不是一個(gè)統(tǒng)計(jì)顯著地下降,但是會(huì)讓人們覺得沮喪。
這里表現(xiàn)出來(lái)的現(xiàn)象看起非常奇怪。直覺地,額外的隱藏層應(yīng)當(dāng)讓網(wǎng)絡(luò)能夠?qū)W到更加復(fù)雜的分類函數(shù),然后可以在分類時(shí)表現(xiàn)得更好吧??梢钥隙ǖ氖?,事情并沒(méi)有變差,至少新的層次增加上,在最壞的情形下也就是沒(méi)有影響。事情并不是這樣子的。
那么,應(yīng)該是怎樣的呢?假設(shè)額外的隱藏層的確能夠在原理上起到作用,問(wèn)題是我們的學(xué)習(xí)算法沒(méi)有發(fā)現(xiàn)正確地權(quán)值和偏差。那么現(xiàn)在就要好好看看學(xué)習(xí)算法本身有哪里出了問(wèn)題,并搞清楚如何改進(jìn)了。
為了獲得一些關(guān)于這個(gè)問(wèn)題直覺上的洞察,我們可以將網(wǎng)絡(luò)學(xué)到的東西進(jìn)行可視化。下面,我畫出了一部分 $$[784, 30, 30, 10]$$ 的網(wǎng)絡(luò),也就是包含兩層各有 $$30$$ 個(gè)隱藏神經(jīng)元的隱藏層。圖中的每個(gè)神經(jīng)元有一個(gè)條形統(tǒng)計(jì)圖,表示這個(gè)神經(jīng)元在網(wǎng)絡(luò)進(jìn)行學(xué)習(xí)時(shí)改變的速度。更大的條意味著更快的速度,而小的條則表示變化緩慢。更加準(zhǔn)確地說(shuō),這些條表示了 每個(gè)神經(jīng)元上的$$\frac{\partial C}{\partial b}$$,也就是代價(jià)函數(shù)關(guān)于神經(jīng)元的偏差更變的速率?;仡櫟诙拢?a rel="nofollow" href="http://neuralnetworksanddeeplearning.com/chap2.html#the_four_fundamental_equations_behind_backpropagation"">Chapter 2),我們看到了這個(gè)梯度的數(shù)值不僅僅是在學(xué)習(xí)過(guò)程中偏差改變的速度,而且也控制了輸入到神經(jīng)元權(quán)重的變量速度。如果沒(méi)有回想起這些細(xì)節(jié)也不要擔(dān)心:目前要記住的就是這些條表示了每個(gè)神經(jīng)元權(quán)重和偏差在神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)時(shí)的變化速率。
為了讓圖里簡(jiǎn)單,我只展示出來(lái)最上方隱藏層上的 $$6$$ 個(gè)神經(jīng)元。這里忽略了輸入層神經(jīng)元,因?yàn)樗麄儾⒉话枰獙W(xué)習(xí)的權(quán)重或者偏差。同樣輸出層神經(jīng)元也忽略了,因?yàn)檫@里我們做的是層層之間的比較,所以比較相同數(shù)量的兩層更加合理啦。在網(wǎng)絡(luò)初始化后立即得到訓(xùn)練前期的結(jié)果如下:
這個(gè)程序給出了計(jì)算梯度的方法generate_gradient.py. 也包含了其他一些在本章后面提到的計(jì)算方法。
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/150.png" alt="比較隱藏層" />
該網(wǎng)絡(luò)是隨機(jī)初始化的,因此看到了神經(jīng)元學(xué)習(xí)的速度差異其實(shí)很大。而且,我們可以發(fā)現(xiàn),第二個(gè)隱藏層上的條基本上都要比第一個(gè)隱藏層上的條要大。所以,在第二個(gè)隱藏層的神經(jīng)元將學(xué)習(xí)得更加快速。這僅僅是一個(gè)巧合么,或者第二個(gè)隱藏層的神經(jīng)元一般情況下都要比第一個(gè)隱藏層的神經(jīng)元學(xué)習(xí)得更快? 為了確定我們的猜測(cè),擁有一種全局的方式來(lái)比較學(xué)習(xí)速度會(huì)比較有效。我們這里將梯度表示為$$\delta_j^l = \partial C/\partial b_j^l$$ 在第 $$l$$ 層的第 $$j$$ 個(gè)神經(jīng)元的梯度。我們可以將 $$\delta^1$$ 看做是一個(gè)向量其中元素表示第一層隱藏層的學(xué)習(xí)速度,$$\delta^2$$ 則是第二層隱藏層的學(xué)習(xí)速度。接著使用這些向量的長(zhǎng)度作為全局衡量這些隱藏層的學(xué)習(xí)速度的度量。因此,$$||\delta^1||$$ 就代表第一層隱藏層學(xué)習(xí)速度,而$$||\delta^2||$$ 就代表第二層隱藏層學(xué)習(xí)速度。 借助這些定義,在和上圖同樣的配置下,$$||\delta^1|| = 0.07$$而$$||\delta^2|| = 0.31$$,所以這就確認(rèn)了之前的疑惑:在第二層隱藏層的神經(jīng)元學(xué)習(xí)速度確實(shí)比第一層要快。
如果我們添加更多的隱藏層呢?如果我們有三個(gè)隱藏層,比如說(shuō)在一個(gè) $$[784, 30, 30, 10]$$ 的網(wǎng)絡(luò)中,那么對(duì)應(yīng)的學(xué)習(xí)速度就是 $$0.012, 0.060, 0.283$$。這里前面的隱藏層學(xué)習(xí)速度還是要低于最后的隱藏層。假設(shè)我們?cè)黾恿硪粋€(gè)包含 30 個(gè)隱藏神經(jīng)元的隱藏層。那么,對(duì)應(yīng)的學(xué)習(xí)速度就是:$$0.003, 0.017, 0.070, 0.285$$。還是一樣的模式:前面的層學(xué)習(xí)速度低于后面的層。
現(xiàn)在我們已經(jīng)看到了訓(xùn)練開始時(shí)的學(xué)習(xí)速度,這是剛剛初始化之后的情況。那么這個(gè)速度會(huì)隨著訓(xùn)練的推移發(fā)生什么樣的變化呢?讓我們看看只有兩個(gè)隱藏層。學(xué)習(xí)速度變化如下:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/151.png" alt="學(xué)習(xí)速度變化圖1" />
為了產(chǎn)生這些結(jié)果,我在 $$1000$$ 個(gè)訓(xùn)練圖像上進(jìn)行了 $$500$$ 輪 batch 梯度下降。這和我們通常訓(xùn)練方式還是不同的——我沒(méi)有使用 minibatch,僅僅使用了 $$1000$$ 個(gè)訓(xùn)練圖像,而不是全部的 $$50,000$$ 幅圖。我并不是想做點(diǎn)新鮮的嘗試,或者蒙蔽你們的雙眼,但因?yàn)槭褂?minibatch 隨機(jī)梯度下降會(huì)在結(jié)果中帶來(lái)更多的噪聲(盡管在平均噪聲的時(shí)候結(jié)果很相似)。使用我已經(jīng)確定的參數(shù)可以對(duì)結(jié)果進(jìn)行平滑,這樣我們可以看清楚真正的情況是怎樣的。 如圖所示,兩層在開始時(shí)就有著不同的速度。然后兩層的學(xué)習(xí)速度在觸底前迅速下落。在最后,我們發(fā)現(xiàn)第一層的學(xué)習(xí)速度變得比第二層更慢了。
那么更加復(fù)雜的網(wǎng)絡(luò)是什么情況呢?這里是一個(gè)類似的實(shí)驗(yàn),但是這次有三個(gè)隱藏層($$[784, 30, 30, 30, 10]$$):
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/152.png" alt="學(xué)習(xí)速度變化圖2" />
同樣,前面的隱藏層要比后面的隱藏層學(xué)習(xí)的更慢。最后一個(gè)實(shí)驗(yàn),就是增加第四個(gè)隱藏層($$[784, 30, 30, 30, 30, 10]$$),看看這里會(huì)發(fā)生什么:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/153.png" alt="學(xué)習(xí)速度變化圖3" />
同樣的情況出現(xiàn)了,前面的隱藏層的學(xué)習(xí)速度要低于后面的隱藏層。這里,第一層的學(xué)習(xí)速度和最后一層要差了兩個(gè)數(shù)量級(jí),也就是比第四層慢了$$100$$倍。難怪我們之前在訓(xùn)練這些網(wǎng)絡(luò)的時(shí)候遇到了大麻煩!
現(xiàn)在我們已經(jīng)有了一項(xiàng)重要的觀察結(jié)果:至少在某些深度神經(jīng)網(wǎng)絡(luò)中,在我們?cè)陔[藏層 BP 的時(shí)候梯度傾向于變小。這意味著在前面的隱藏層中的神經(jīng)元學(xué)習(xí)速度要慢于后面的隱藏層。這兒我們只在一個(gè)網(wǎng)絡(luò)中發(fā)現(xiàn)了這個(gè)現(xiàn)象,其實(shí)在多數(shù)的神經(jīng)網(wǎng)絡(luò)中存在著更加根本的導(dǎo)致這個(gè)現(xiàn)象出現(xiàn)的原因。這個(gè)現(xiàn)象也被稱作是 消失的梯度問(wèn)題(vanishing gradient problem)。
為何消失的梯度問(wèn)題會(huì)出現(xiàn)呢?我們可以通過(guò)什么方式避免它?還有在訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)時(shí)如何處理好這個(gè)問(wèn)題?實(shí)際上,這個(gè)問(wèn)題是可以避免的,盡管替代方法并不是那么有效,同樣會(huì)產(chǎn)生問(wèn)題——在前面的層中的梯度會(huì)變得非常大!這也叫做 爆炸的梯度問(wèn)題(exploding gradient problem),這也沒(méi)比消失的梯度問(wèn)題更好處理。更加一般地說(shuō),在深度神經(jīng)網(wǎng)絡(luò)中的梯度是不穩(wěn)定的,在前面的層中或會(huì)消失,或會(huì)爆炸。這種不穩(wěn)定性才是深度神經(jīng)網(wǎng)絡(luò)中基于梯度學(xué)習(xí)的根本問(wèn)題。這就是我們需要理解的東西,如果可能的話,采取合理的步驟措施解決問(wèn)題。
一種有關(guān)消失的(不穩(wěn)定的)梯度的看法是確定這是否確實(shí)是一個(gè)問(wèn)題。此刻我們暫時(shí)轉(zhuǎn)換到另一個(gè)話題,假設(shè)我們正要數(shù)值優(yōu)化一個(gè)一元的函數(shù) $$f(x)$$。如果其導(dǎo)數(shù) $$f'(x)$$ 很小,這難道不是一個(gè)好消息么?是不是意味著我們已經(jīng)接近極值點(diǎn)了?同樣的方式,在深度神經(jīng)網(wǎng)絡(luò)中前面隱藏層的小的梯度是不是表示我們不需要對(duì)權(quán)重和偏差做太多調(diào)整了?
當(dāng)然,實(shí)際情況并不是這樣的。想想我們隨機(jī)初始網(wǎng)絡(luò)中的權(quán)重和偏差。在面對(duì)任意的一種任務(wù),單單使用隨機(jī)初始的值就能夠獲得一個(gè)較好的結(jié)果是太天真了。具體講,看看 MNIST 問(wèn)題的網(wǎng)絡(luò)中第一層的權(quán)重。隨機(jī)初始化意味著第一層丟失了輸入圖像的幾乎所有信息。即使后面的層能夠獲得充分的訓(xùn)練,這些層也會(huì)因?yàn)闆](méi)有充分的信息而很難識(shí)別出輸入的圖像。因此,在第一層不進(jìn)行學(xué)習(xí)的嘗試是不可能的。如果我們接著去訓(xùn)練深度神經(jīng)網(wǎng)絡(luò),我們需要弄清楚如何解決消失的梯度問(wèn)題。
為了弄清楚為何會(huì)出現(xiàn)消失的梯度,來(lái)看看一個(gè)極簡(jiǎn)單的深度神經(jīng)網(wǎng)絡(luò):每一層都只有一個(gè)單一的神經(jīng)元。下圖就是有三層隱藏層的神經(jīng)網(wǎng)絡(luò):
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/154.png" alt="簡(jiǎn)單的深度神經(jīng)網(wǎng)絡(luò)" />
這里,$$w_1, w_2, ...$$ 是權(quán)重,而 $$b_1, b_2, ...$$ 是偏差,$$C$$ 則是某個(gè)代價(jià)函數(shù)?;仡櫼幌拢瑥牡?$$j$$ 個(gè)神經(jīng)元的輸出 $$a_j = \sigma(z_j)$$,其中 $$\sigma$$ 是通常的 sigmoid 函數(shù),而 $$z_j = wj * a{j-1} + b_j$$是神經(jīng)元的帶權(quán)輸入。我已經(jīng)在最后表示出了代價(jià)函數(shù) $$C$$ 來(lái)強(qiáng)調(diào)代價(jià)是網(wǎng)絡(luò)輸出 $$a_4$$ 的函數(shù):如果實(shí)際輸出越接近目標(biāo)輸出,那么代價(jià)會(huì)變低;相反則會(huì)變高。
現(xiàn)在我們要來(lái)研究一下關(guān)聯(lián)于第一個(gè)隱藏神經(jīng)元梯度 $$\partial C/\partial b_1$$。我們將會(huì)計(jì)算出$$\partial C/\partial b_1$$ 的表達(dá)式,通過(guò)研究表達(dá)式來(lái)理解消失的梯度發(fā)生的原因。
開始就簡(jiǎn)單地給出 $$\partial C/\partial b_1$$ 的表達(dá)式。初看起來(lái)有點(diǎn)復(fù)雜,但是其結(jié)構(gòu)是相當(dāng)簡(jiǎn)單的,我一會(huì)兒會(huì)解釋。下圖給出了具體的表達(dá)式:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/155.png" alt="" />
表達(dá)式結(jié)構(gòu)如下:對(duì)每個(gè)神經(jīng)元有一個(gè) $$\sigma'(z_j)$$ 項(xiàng);對(duì)每個(gè)權(quán)重有一個(gè) $$w_j$$ 項(xiàng);還有一個(gè) $$\partial C/\partial a_4$$項(xiàng),表示最后的代價(jià)函數(shù)。注意,我已經(jīng)將表達(dá)式中的每個(gè)項(xiàng)置于了對(duì)應(yīng)的位置。所以網(wǎng)絡(luò)本身就是表達(dá)式的解讀。
你可以直接認(rèn)可這個(gè)表達(dá)式,直接跳到該表達(dá)式如何關(guān)聯(lián)于小時(shí)的梯度問(wèn)題的。這對(duì)理解沒(méi)有影響,因?yàn)閷?shí)際上上面的表達(dá)式只是前面對(duì)于BP 的討論的特例。但是也包含了一個(gè)表達(dá)式正確的解釋,所以去看看那個(gè)解釋也是很有趣的(也可能更有啟發(fā)性吧)。
假設(shè)我們對(duì)偏差 $$b_1$$ 進(jìn)行了微小的調(diào)整 $$\Delta b_1$$。這會(huì)導(dǎo)致網(wǎng)絡(luò)中剩下的元素一系列的變化。首先會(huì)對(duì)第一個(gè)隱藏元輸出產(chǎn)生一個(gè) $$\Delta a_1$$ 的變化。這樣就會(huì)導(dǎo)致第二個(gè)神經(jīng)元的帶權(quán)輸入產(chǎn)生 $$\Delta z_2$$ 的變化。從第二個(gè)神經(jīng)元輸出隨之發(fā)生 $$\Delta a_2$$ 的變化。以此類推,最終會(huì)對(duì)代價(jià)函數(shù)產(chǎn)生 $$\Delta C$$ 的變化。這里我們有:
$$\frac{\partial C}{\partial b_1}\approx \frac{\Delta C}{\Delta b_1}$$
這表示我們可以通過(guò)仔細(xì)追蹤每一步的影響來(lái)搞清楚 $$\partial C/\partial b_1$$ 的表達(dá)式。 現(xiàn)在我們看看 $$\Delta b_1$$ 如何影響第一個(gè)神經(jīng)元的輸出 $$a_1$$ 的。我們有 $$a_1 = \sigma(z_1) = \sigma(w_1 * a_0 + b1)$$,所以有 $$\Delta a_1 \approx \frac{\partial \sigma(w_1a_0 + b_1)}{\partial b_1} \Delta b_1 = \sigma'(z_1)\Delta b_1$$
$$\sigma'(z_1)$$ 這項(xiàng)看起很熟悉:其實(shí)是我們上面關(guān)于 $$\partial C/\partial b_1$$ 的表達(dá)式的第一項(xiàng)。直覺上看,這項(xiàng)將偏差的改變 $$\Delta b_1$$ 轉(zhuǎn)化成了輸出的變化 $$\Delta a_1$$。$$\Delta a_1$$ 隨之又影響了帶權(quán)輸入 $$z_2 = w_2 * a_1 + b_2$$: $$\Delta z_2 \approx \frac{\partial z_2}{\partial a_1}\Delta a_1 = w_2 \Delta a_1$$
將 $$\Delta z_2$$ 和 $$\Delta a_1$$ 的表達(dá)式組合起來(lái),我們可以看到偏差 $$b_1$$ 中的改變?nèi)绾瓮ㄟ^(guò)網(wǎng)絡(luò)傳輸影響到 $$z_2$$的: $$\Delta \approx \sigma'(z_1)w_2\Delta b_1$$
現(xiàn)在,又能看到類似的結(jié)果了:我們得到了在表達(dá)式 $$\partial C/\partial b_1$$ 的前面兩項(xiàng)。以此類推下去,跟蹤傳播改變的路徑就可以完成。在每個(gè)神經(jīng)元,我們都會(huì)選擇一個(gè) $$\sigma'(z_j)$$ 的項(xiàng),然后在每個(gè)權(quán)重我們選擇出一個(gè) $$w_j$$ 項(xiàng)。最終的結(jié)果就是代價(jià)函數(shù)中變化 $$\Delta C$$ 的相關(guān)于偏差 $$\Delta b_1$$ 的表達(dá)式:
$$\Delta C \approx \sigma'(z_1)w_2\sigma'(z_2)...\sigma'(z_4)\frac{\partial C}{\partial a_4}\Delta b_1$$
除以 $$\Delta b_1$$,我們的確得到了梯度的表達(dá)式:
$$\partial C/\partial b_1 = \sigma'(z_1)w_2\sigma'(z_2)...\sigma'(z_4)\frac{\partial C}{\partial a_4}$$
為何出現(xiàn)梯度消失:現(xiàn)在把梯度的整個(gè)表達(dá)式寫下來(lái):
$$\partial C/\partial b_1 = \sigma'(z_1)w_2\sigma'(z_2)w_3\sigma'(z_3)\sigma'(z_4)\frac{\partial C}{\partial a_4}$$
除了最后一項(xiàng),該表達(dá)式是一系列形如 $$w_j \sigma'(z_j)$$ 的乘積。為了理解每個(gè)項(xiàng)的行為,先看看下面的sigmoid 函數(shù)導(dǎo)數(shù)的圖像:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/156.png" alt="Paste_Image.png" />
該導(dǎo)數(shù)在 $$\sigma'(0)=1/4$$ 時(shí)達(dá)到最高?,F(xiàn)在,如果我們使用標(biāo)準(zhǔn)方法來(lái)初始化網(wǎng)絡(luò)中的權(quán)重,那么會(huì)使用一個(gè)均值為 $$0$$ 標(biāo)準(zhǔn)差為 $$1$$ 的高斯分布。因此所有的權(quán)重通常會(huì)滿足 $$|w_j| < 1$$。有了這些信息,我們發(fā)現(xiàn)會(huì)有 $$w_j \sigma'(z_j) < 1/4$$。并且在我們進(jìn)行了所有這些項(xiàng)的乘積時(shí),最終結(jié)果肯定會(huì)指數(shù)級(jí)下降:項(xiàng)越多,乘積的下降的越快。**這里我們敏銳地嗅到了消失的梯度問(wèn)題的合理解釋。
更明白一點(diǎn),我們比較一下 $$\partial C/\partial b_1$$ 和一個(gè)更后面一些的偏差的梯度,不妨設(shè)為 $$\partial C/\partial b_3$$。當(dāng)然,我們還沒(méi)有顯式地給出這個(gè)表達(dá)式,但是計(jì)算的方式是一樣的。
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/157.png" alt="比較梯度的表達(dá)式" />
兩個(gè)表示式有很多相同的項(xiàng)。但是 $$\partial C/\partial b_1$$ 還多包含了兩個(gè)項(xiàng)。由于這些項(xiàng)都是 $$< 1/4$$ 的。所以 $$\partial C/\partial b_1$$ 會(huì)是 $$\partial C/\partial b_3$$ 的 1/16 或者更小。這其實(shí)就是消失的梯度出現(xiàn)的本質(zhì)原因了。 當(dāng)然,這里并非嚴(yán)格的關(guān)于消失的梯度微調(diào)的證明而是一個(gè)不太正式的論斷。還有一些可能的產(chǎn)生原因了。特別地,我們想要知道權(quán)重 $$w_j$$ 在訓(xùn)練中是否會(huì)增長(zhǎng)。如果會(huì),項(xiàng) $$w_j \sigma'(z_j)$$ 會(huì)不會(huì)不在滿足之前 $$w_j \sigma'(z_j) < 1/4$$ 的約束。事實(shí)上,如果項(xiàng)變得很大——超過(guò) 1,那么我們將不再遇到消失的梯度問(wèn)題。實(shí)際上,這時(shí)候梯度會(huì)在我們 BP 的時(shí)候發(fā)生指數(shù)級(jí)地增長(zhǎng)。也就是說(shuō),我們遇到了梯度爆炸的問(wèn)題。 梯度爆炸問(wèn)題:現(xiàn)在看看梯度爆炸如何出現(xiàn)的把。這里的例子可能不是那么自然:固定網(wǎng)絡(luò)中的參數(shù),來(lái)確保產(chǎn)生爆炸的梯度。但是即使是不自然,也是包含了確定會(huì)產(chǎn)生爆炸梯度(而非假設(shè)的可能)的特質(zhì)的。
共兩個(gè)步驟:首先,我們將網(wǎng)絡(luò)的權(quán)重設(shè)置得很大,比如 $$w_1 = w_2 = w_3 = w_4 = 100$$。然后,我們選擇偏差使得 $$\sigma'(z_j)$$ 項(xiàng)不會(huì)太小。這是很容易實(shí)現(xiàn)的:方法就是選擇偏差來(lái)保證每個(gè)神經(jīng)元的帶權(quán)輸入是 $$z_j = 0$$(這樣 $$sigma'(z_j) = 1/4$$)。比如說(shuō),我們希望 $$z_1 = w_1 a_0 + b_1$$。我們只要把 $$b_1 = -100 a_0$$ 即可。我們使用同樣的方法來(lái)獲得其他的偏差。這樣我們可以發(fā)現(xiàn)所有的項(xiàng) $$w_j \sigma'(z_j)$$ 都等于 $$1001/4 = 25$$。最終,我們就獲得了爆炸的梯度。
不穩(wěn)定的梯度問(wèn)題:根本的問(wèn)題其實(shí)并非是消失的梯度問(wèn)題或者爆炸的梯度問(wèn)題,而是在前面的層上的梯度是來(lái)自后面的層上項(xiàng)的乘積。當(dāng)存在過(guò)多的層次時(shí),就出現(xiàn)了內(nèi)在本質(zhì)上的不穩(wěn)定場(chǎng)景。唯一讓所有層都接近相同的學(xué)習(xí)速度的方式是所有這些項(xiàng)的乘積都能得到一種平衡。如果沒(méi)有某種機(jī)制或者更加本質(zhì)的保證來(lái)達(dá)成平衡,那網(wǎng)絡(luò)就很容易不穩(wěn)定了。簡(jiǎn)而言之,真實(shí)的問(wèn)題就是神經(jīng)網(wǎng)絡(luò)受限于不穩(wěn)定梯度的問(wèn)題。所以,如果我們使用標(biāo)準(zhǔn)的基于梯度的學(xué)習(xí)算法,在網(wǎng)絡(luò)中的不同層會(huì)出現(xiàn)按照不同學(xué)習(xí)速度學(xué)習(xí)的情況。
消失的梯度問(wèn)題普遍存在:我們已經(jīng)看到了在神經(jīng)網(wǎng)絡(luò)的前面的層中梯度可能會(huì)消失也可能會(huì)爆炸。實(shí)際上,在使用 sigmoid 神經(jīng)元時(shí),梯度通常會(huì)消失。為什么?再看看表達(dá)式 $$|w\sigma'(z)|$$。為了避免消失的梯度問(wèn)題,我們需要 $$|w\sigma'(z)| >= 1$$。你可能會(huì)認(rèn)為如果 $$w$$ 很大的時(shí)候很容易達(dá)成。但是這比看起來(lái)還是困難很多。原因在于,$$\sigma'(z)$$ 項(xiàng)同樣依賴于 $$w$$:$$\sigma'(z) = \sigma'(w*a+b)$$,其中 $$a$$ 是輸入的激活函數(shù)。所以我們?cè)谧?$$w$$ 變大時(shí),需要同時(shí)不讓 $$\sigma'(wa+b)$$ 變小。這將是很大的限制了。原因在于我們讓 $$w$$ 變大,也會(huì)使得 $$wa + b$$ 變得非常大。看看 $$\sigma'$$ 的圖,這會(huì)讓我們走到 $$\sigma'$$ 的兩翼,這里會(huì)去到很小的值。唯一避免發(fā)生這個(gè)情況的方式是,如果輸入激活函數(shù)掉入相當(dāng)狹窄的范圍內(nèi)(這個(gè)量化的解釋在下面第一個(gè)問(wèn)題中進(jìn)行)。有時(shí)候,有可能會(huì)出現(xiàn)。但是一般不大會(huì)發(fā)生。所以一般情況下,會(huì)遇到消失的梯度。
現(xiàn)在已經(jīng)研究了簡(jiǎn)單的網(wǎng)絡(luò),每一層只包含一個(gè)神經(jīng)元。那么那些每層包含很多神經(jīng)元的更加復(fù)雜的深度網(wǎng)絡(luò)呢?
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/158.png" alt="Paste_Image.png" />
實(shí)際上,在這樣的神經(jīng)網(wǎng)絡(luò)中,同樣的情況也會(huì)發(fā)生。在前面關(guān)于 BP 的章節(jié)中,我們看到了在一個(gè)共 $$L$$ 層的第 $$l$$ 層的梯度:
$$\delta^l = \Sigma'(z^l)*(w^{l+1})^T\Sigma'(z^{l+1})(w^{l+2})^T...\Sigma'(z^L)\nabla_{a} C$$
這里 $$\Sigma'(z^l)$$是一個(gè)對(duì)角矩陣,每個(gè)元素是對(duì)第 $$l$$ 層的帶權(quán)輸入 $$\sigma'(z)$$。而 $$w^l$$ 是對(duì)不同層的權(quán)值矩陣。$$\nabla_{a} C$$ 是對(duì)每個(gè)輸出激活的偏導(dǎo)數(shù)向量。
這是更加復(fù)雜的表達(dá)式。不過(guò),你仔細(xì)看,本質(zhì)上的形式還是很相似的。主要是包含了更多的形如 $$(w^j)^T \Sigma' (z^j)$$ 的對(duì) (pair)。而且,矩陣 $$\Sigma'(z^j)$$ 在對(duì)角線上的值挺小,不會(huì)超過(guò) $$1/4$$。由于權(quán)值矩陣 $$w^j$$ 不是太大,每個(gè)額外的項(xiàng) $$(w^j)^T \sigma' (z^l)$$ 會(huì)讓梯度向量更小,導(dǎo)致梯度消失。更加一般地看,在乘積中大量的項(xiàng)會(huì)導(dǎo)致不穩(wěn)定的梯度,和前面的例子一樣。實(shí)踐中,一般會(huì)發(fā)現(xiàn)在 sigmoid 網(wǎng)絡(luò)中前面的層的梯度指數(shù)級(jí)地消失。所以在這些層上的學(xué)習(xí)速度就會(huì)變得很慢了。這種減速不是偶然現(xiàn)象:也是我們采用的訓(xùn)練的方法決定的。
本章我們已經(jīng)聚焦在消失的梯度上,并且更加一般地,不穩(wěn)定梯度——深度學(xué)習(xí)的一大障礙。實(shí)際上,不穩(wěn)定梯度僅僅是深度學(xué)習(xí)的眾多障礙之一,盡管這一點(diǎn)是相當(dāng)根本的。當(dāng)前的研究集中在更好地理解在訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)時(shí)遇到的挑戰(zhàn)。這里我不會(huì)給出一個(gè)詳盡的總結(jié),僅僅想要給出一些論文,告訴你人們正在尋覓探究的問(wèn)題。
首先,在 $$2010$$ 年 Glorot 和 Bengio 發(fā)現(xiàn)證據(jù)表明 sigmoid 函數(shù)的選擇會(huì)導(dǎo)致訓(xùn)練網(wǎng)絡(luò)的問(wèn)題。特別地,他們發(fā)現(xiàn) sigmoid 函數(shù)會(huì)導(dǎo)致最終層上的激活函數(shù)在訓(xùn)練中會(huì)聚集在 $$0$$,這也導(dǎo)致了學(xué)習(xí)的緩慢。他們的工作中提出了一些取代 sigmoid 函數(shù)的激活函數(shù)選擇,使得不會(huì)被這種聚集性影響性能。
第二個(gè)例子,在 $$2013$$ 年 Sutskever, Martens, Dahl 和 Hinton 研究了深度學(xué)習(xí)使用隨機(jī)權(quán)重初始化和基于 $$momentum$$ 的 $$SGD$$ 方法。兩種情形下,好的選擇可以獲得較大的差異的訓(xùn)練效果。 這些例子告訴我們,“什么讓訓(xùn)練深度網(wǎng)絡(luò)非常困難”這個(gè)問(wèn)題相當(dāng)復(fù)雜。本章,我們已經(jīng)集中于深度神經(jīng)網(wǎng)絡(luò)中基于梯度的學(xué)習(xí)方法的不穩(wěn)定性。結(jié)果表明了激活函數(shù)的選擇,權(quán)重的初始化,甚至是學(xué)習(xí)算法的實(shí)現(xiàn)方式也扮演了重要的角色。當(dāng)然,網(wǎng)絡(luò)結(jié)構(gòu)和其他超參數(shù)本身也是很重要的。因此,太多因子影響了訓(xùn)練神經(jīng)網(wǎng)絡(luò)的難度,理解所有這些因子仍然是當(dāng)前研究的重點(diǎn)。盡管這看起來(lái)有點(diǎn)悲觀,但是在下一章中我們會(huì)介紹一些好的消息,給出一些方法來(lái)一定程度上解決和迂回所有這些困難。