作者:Omar U. Florez
參與:Nurhachu Null、張倩
模型的訓(xùn)練、調(diào)參是一項(xiàng)非常費(fèi)時(shí)費(fèi)力的工作,了解神經(jīng)網(wǎng)絡(luò)內(nèi)部的數(shù)學(xué)原理有利于快速找出問題所在。本文作者從零開始,一步一步講解了訓(xùn)練神經(jīng)網(wǎng)絡(luò)時(shí)所用到的數(shù)學(xué)過程。
神經(jīng)網(wǎng)絡(luò)是線性模塊和非線性模塊的巧妙排列。當(dāng)聰明地選擇并連接這些模塊時(shí),我們就得到了一個(gè)強(qiáng)大的工具來逼近任何一個(gè)數(shù)學(xué)函數(shù),如一個(gè)能夠借助非線性決策邊界進(jìn)行分類的神經(jīng)網(wǎng)絡(luò)。
運(yùn)行代碼的步驟如下:
git clone https://github.com/omar-florez/scratch_mlp/
python scratch_mlp/scratch_mlp.py
盡管反向傳播技術(shù)具有直觀、模塊化的特質(zhì),但是它負(fù)責(zé)更新可訓(xùn)練的參數(shù),這是一個(gè)一直未被深入解釋的主題。讓我們以樂高積木為喻,一次增加一塊,從零構(gòu)建一個(gè)神經(jīng)網(wǎng)絡(luò)來一探其內(nèi)部功能。
神經(jīng)網(wǎng)絡(luò)就像是由樂高積木組成的
上圖描述了訓(xùn)練一個(gè)神經(jīng)網(wǎng)絡(luò)時(shí)所用到的部分?jǐn)?shù)學(xué)過程。我們將在本文中解釋這個(gè)。讀者可能感到有趣的一點(diǎn)是:一個(gè)神經(jīng)網(wǎng)絡(luò)就是很多模塊以不同的目標(biāo)堆疊起來。
輸入變量 X 向神經(jīng)網(wǎng)絡(luò)饋送原始數(shù)據(jù),它被存儲(chǔ)在一個(gè)矩陣中,矩陣的行是觀察值,列是維度。
權(quán)重 W_1 將輸入 X 映射到第一個(gè)隱藏層 h_1。然后權(quán)重 W_1 充當(dāng)一個(gè)線性核。
Sigmoid 函數(shù)防止隱藏層中的數(shù)字落到 0-1 的范圍之外。結(jié)果就是一個(gè)神經(jīng)激活的數(shù)組,h_1 = Sigmoid(WX)。
此時(shí),這些運(yùn)算只是組成了一個(gè)一般線性系統(tǒng),無法對(duì)非線性交互建模。當(dāng)我們?cè)侬B加一層,給模塊的結(jié)構(gòu)增加深度的時(shí)候這一點(diǎn)就會(huì)改變。網(wǎng)絡(luò)越深,我們就會(huì)學(xué)到越多微妙的非線性交互,能解決的問題也就越復(fù)雜,或許這也是深度神經(jīng)模型興起的原因之一。
為什么我要讀這篇文章?
如果你理解一個(gè)神經(jīng)網(wǎng)絡(luò)的內(nèi)部部分,你就能夠在遇到問題的時(shí)候快速知道先去改變哪里,并且能夠制定策略來測(cè)試你所知道的這個(gè)算法的部分不變量和預(yù)期的行為。
因?yàn)檎{(diào)試機(jī)器學(xué)習(xí)模型是一項(xiàng)復(fù)雜的任務(wù)。根據(jù)經(jīng)驗(yàn),數(shù)學(xué)模型在首次嘗試的時(shí)候不會(huì)奏效。它們可能會(huì)對(duì)新數(shù)據(jù)給出較低的準(zhǔn)確率,會(huì)耗費(fèi)很長(zhǎng)的訓(xùn)練時(shí)間或者太多的內(nèi)存,返回一個(gè)很大的錯(cuò)誤負(fù)數(shù)值或者 NAN 的預(yù)測(cè)……在有些情況下,了解算法的運(yùn)行機(jī)制可以讓我們的任務(wù)變得更加便利:
如果訓(xùn)練花費(fèi)了太多的時(shí)間,那增加 minibatch 的大小或許是一個(gè)好主意,這能夠減小觀察值的方差,從而有助于算法收斂。
如果你看到了 NAN 的預(yù)測(cè)值,算法可能接收到了大梯度,產(chǎn)生了內(nèi)存溢出??梢詫⑦@個(gè)視為在很多次迭代之后發(fā)生爆炸的矩陣乘法。減小學(xué)習(xí)率可以縮小這些數(shù)值。減少層數(shù)能夠減少乘法的數(shù)量。剪切梯度也能夠明顯地控制這個(gè)問題。
具體的例子:學(xué)習(xí)異或函數(shù)
讓我們打開黑盒子。我們現(xiàn)在要從零開始構(gòu)建一個(gè)學(xué)習(xí)異或函數(shù)的神經(jīng)網(wǎng)絡(luò)。選擇這個(gè)非線性函數(shù)可絕對(duì)不是隨機(jī)的。沒有反向傳播的話,就很難學(xué)會(huì)用一條直線分類。
為了描述這個(gè)重要的概念,請(qǐng)注意下圖中,一條直線是為何不能對(duì)異或函數(shù)輸出中的 0 和 1 進(jìn)行分類?,F(xiàn)實(shí)生活中的問題也是非線性可分的。
這個(gè)網(wǎng)絡(luò)的拓?fù)浣Y(jié)構(gòu)非常簡(jiǎn)單:
輸入變量 X 是二維向量
權(quán)重 W_1 是具有隨機(jī)初始化數(shù)值的 2x3 的矩陣
隱藏層 h_1 包含 3 個(gè)神經(jīng)元。每個(gè)神經(jīng)元接受觀察值的加權(quán)和作為輸入,這就是下圖中綠色高亮的內(nèi)積:z_1 = [x_1, x_2][w_1, w_2]
權(quán)重 W_2 是具有隨機(jī)初始化值的 3x2 的矩陣
輸出層 h_2 包含兩個(gè)神經(jīng)元,因?yàn)楫惢蚝瘮?shù)的輸出要么是 0(y_1=[0,1]),要么是 1(y_2 = [1,0])
下圖更加直觀:
我們現(xiàn)在來訓(xùn)練這個(gè)模型。在我們這個(gè)簡(jiǎn)單的例子中,可訓(xùn)練的參數(shù)就是權(quán)重,但是應(yīng)該知道的是,目前的研究正在探索更多可以被優(yōu)化的參數(shù)類型。例如層之間的快捷連接、正則化分布、拓?fù)浣Y(jié)構(gòu)、殘差、學(xué)習(xí)率等等。
反向傳播是這樣的一種方法:在給定的一批具有標(biāo)簽的觀察值上,朝著將預(yù)定義的錯(cuò)誤指標(biāo)(就是損失函數(shù))最小化的方向(梯度)更新權(quán)重。該算法已經(jīng)多次被重復(fù)發(fā)現(xiàn),這是另一種更通用的被稱為自動(dòng)微分的技術(shù)在反向積累模式下的特例。
網(wǎng)絡(luò)初始化
讓我們用隨機(jī)數(shù)來初始化網(wǎng)絡(luò)權(quán)重
前向步驟:
這一步的目標(biāo)就是把輸入變量 X 向前傳遞到網(wǎng)絡(luò)的每一層,直至計(jì)算出輸出層 h_2 的向量。
這就是其中發(fā)生的計(jì)算過程:
以權(quán)重 W_1 為線性核對(duì)輸入數(shù)據(jù) X 做線性變換:
使用 Sigmoid 激活函數(shù)對(duì)加權(quán)和進(jìn)行縮放,得到了第一個(gè)隱藏層 h_1 的值。請(qǐng)注意,原始的 2D 向量現(xiàn)在映射到了 3D 空間。
第 2 層 h_2 中發(fā)生了類似的過程。讓我們首先來計(jì)算第一個(gè)隱藏層的加權(quán)和 z_2,它現(xiàn)在是輸入數(shù)據(jù)。
然后計(jì)算它們的 Sigmoid 激活函數(shù)。向量 [0.37166596 0.45414264] 代表的是網(wǎng)絡(luò)對(duì)給定的輸入 X 計(jì)算出的對(duì)數(shù)概率或者預(yù)測(cè)向量。
計(jì)算整體損失
也被稱為「實(shí)際值減去預(yù)測(cè)值」,這個(gè)損失函數(shù)的目標(biāo)就是量化預(yù)測(cè)向量 h_2 和人工標(biāo)簽 y 之間的距離。
請(qǐng)注意,這個(gè)損失函數(shù)包括一個(gè)正則項(xiàng),它以嶺回歸的形式懲罰較大的權(quán)重。換言之,平方值比較大的權(quán)重會(huì)增大損失函數(shù),而這正是我們希望最小化的指標(biāo)。
反向步驟:
這一步的目標(biāo)就是沿著最小化損失函數(shù)的方向更新神經(jīng)網(wǎng)絡(luò)的權(quán)重。正如我們將要看到的,這是一個(gè)遞歸算法,它可以重用之前計(jì)算出來的梯度,而且嚴(yán)重依賴微分函數(shù)。因?yàn)檫@些更新減小了損失函數(shù),所以一個(gè)神經(jīng)網(wǎng)絡(luò)便「學(xué)會(huì)了」去逼近具有已知類別的觀察值的標(biāo)簽。這就是被稱作泛化的一種屬性。
與前向步驟不同的是,這個(gè)步驟沿著反向的順序進(jìn)行。它首先計(jì)算出輸出層中損失函數(shù)對(duì)每個(gè)權(quán)重的偏導(dǎo)數(shù) (dLoss/dW_2),然后計(jì)算隱藏層的偏導(dǎo)數(shù) (dLoss/dW1)。讓我們?cè)敿?xì)地解釋每個(gè)導(dǎo)數(shù)吧。
dLoss/dW_2:
鏈?zhǔn)椒▌t表明,我們可以將一個(gè)神經(jīng)網(wǎng)絡(luò)的梯度計(jì)算分解成好多個(gè)微分部分:
為了幫助記憶,下表列出了上面用到的一些函數(shù)定義以及它們的一階導(dǎo)數(shù):
更直觀地,我們?cè)谙聢D中要更新權(quán)重 W_2(藍(lán)色部分)。為了做到這件事,我們需要沿著導(dǎo)數(shù)鏈計(jì)算三個(gè)偏導(dǎo)數(shù)。
將數(shù)值代入到這些偏導(dǎo)數(shù)中,我們就能夠計(jì)算出 W_2 的偏導(dǎo)數(shù),如下所示:
結(jié)果是一個(gè) 3x2 的矩陣 dLoss/dW_2,它將會(huì)沿著最小化損失函數(shù)的方向更新 W_2 的數(shù)值。
dLoss/dW_1:
計(jì)算用于更新第一個(gè)隱藏層 W_1 權(quán)重的鏈?zhǔn)揭?guī)則就展現(xiàn)了重復(fù)使用已有計(jì)算結(jié)果的可能。
更直觀地,從輸出層到權(quán)重 W_1 的路徑會(huì)碰到在后面層中早已計(jì)算出來的偏導(dǎo)數(shù)。
例如,偏導(dǎo)數(shù) dLoss/dh_2 和 dh_2/dz_2 在上一節(jié)中已經(jīng)被計(jì)算為輸出層 dLoss/dW_2 學(xué)習(xí)權(quán)值的依賴項(xiàng)。
將所有的導(dǎo)數(shù)放在一起,我們就能夠再一次執(zhí)行鏈?zhǔn)椒▌t,來為隱藏層的 W_1 更新權(quán)重。
最后,我們給權(quán)重賦予新的數(shù)值,完成了對(duì)神經(jīng)網(wǎng)絡(luò)的一步訓(xùn)練。
實(shí)現(xiàn)
讓我們僅使用 numpy 作為線性代數(shù)引擎來將上面的數(shù)學(xué)方程轉(zhuǎn)換成代碼。神經(jīng)網(wǎng)絡(luò)在一個(gè)循環(huán)中進(jìn)行訓(xùn)練,其中每次迭代會(huì)給神經(jīng)網(wǎng)絡(luò)展示標(biāo)準(zhǔn)的輸入數(shù)據(jù)。在這個(gè)小例子中,我們只考慮每次迭代中的整個(gè)數(shù)據(jù)集。前向步驟、損失函數(shù)和反向步驟的計(jì)算會(huì)得到比較好的泛化,因?yàn)槲覀冊(cè)诿恳淮窝h(huán)中都用它們對(duì)應(yīng)的梯度(矩陣 dL_dw1 和 dL_dw2)來更新可訓(xùn)練的參數(shù)。
代碼保存在這個(gè) repo 中:https://github.com/omar-florez/scratch_mlp
讓我們來運(yùn)行這份代碼!
下面可以看到一些進(jìn)行了好多次迭代訓(xùn)練得到的能夠近似異或函數(shù)的神經(jīng)網(wǎng)絡(luò)。
左圖:準(zhǔn)確率;中間的圖:學(xué)習(xí)到的決策邊界;右圖:損失函數(shù)
首先,我們來看一下隱藏層具有 3 個(gè)神經(jīng)元的神經(jīng)網(wǎng)絡(luò)為何能力較弱。這個(gè)模型學(xué)會(huì)了用一個(gè)簡(jiǎn)單的決策邊界來進(jìn)行二分類,這個(gè)邊界開始是一條直線,但是隨后就表現(xiàn)出了非線性的行為。隨著訓(xùn)練的持續(xù),右圖中的損失函數(shù)也明顯地減小。
隱藏層擁有 50 個(gè)神經(jīng)元的神經(jīng)網(wǎng)絡(luò)明顯地增加了模型學(xué)習(xí)復(fù)雜決策邊界的能力。這不僅僅能夠得到更準(zhǔn)確的結(jié)果,而且也使梯度發(fā)生了爆炸,這是訓(xùn)練神經(jīng)網(wǎng)絡(luò)時(shí)的一個(gè)顯著問題。當(dāng)梯度非常大的時(shí)候,反向傳播中的連乘會(huì)產(chǎn)生很大的更新權(quán)重。這就是最后幾步訓(xùn)練時(shí)損失函數(shù)突然增大的原因(step>90)。損失函數(shù)的正則項(xiàng)計(jì)算出了已經(jīng)變得很大的權(quán)重的平方值(sum(W2)/2N)。
正如你所看到的一樣,這個(gè)問題可以通過減小學(xué)習(xí)率來避免??梢酝ㄟ^實(shí)現(xiàn)一個(gè)能夠隨著時(shí)間減小學(xué)習(xí)率的策略來實(shí)現(xiàn)?;蛘咄ㄟ^強(qiáng)制執(zhí)行一個(gè)更強(qiáng)的正則化來實(shí)現(xiàn),可能是 L1 或者 L2。梯度消失和梯度爆炸是很有趣的現(xiàn)象,我們后續(xù)會(huì)做完整的分析。
原文鏈接:https://medium.com/towards-artificial-intelligence/one-lego-at-a-time-explaining-the-math-of-how-neural-networks-learn-with-implementation-from-scratch-39144a1cf80
市北·GMIS 2019全球數(shù)據(jù)智能峰會(huì)于7月19日-20日在上海市靜安區(qū)舉行。本次峰會(huì)以「數(shù)據(jù)智能」為主題,聚焦最前沿研究方向,同時(shí)更加關(guān)注數(shù)據(jù)智能經(jīng)濟(jì)及其產(chǎn)業(yè)生態(tài)的發(fā)展情況,為技術(shù)從研究走向落地提供借鑒。
聯(lián)系客服