繼續(xù)發(fā)公式。有興趣閱讀能正常顯示公式的版本請(qǐng)移步 http://blog.kamidox.com/neural-networks-2.html
成本函數(shù)
與線(xiàn)性回歸或邏輯回歸類(lèi)似,要使用神經(jīng)網(wǎng)絡(luò)對(duì)訓(xùn)練數(shù)據(jù)進(jìn)行擬合時(shí),需要有成本函數(shù)。這樣只要針對(duì)訓(xùn)練數(shù)據(jù),求解成本函數(shù)的最小值即可得出神經(jīng)網(wǎng)絡(luò)模型參數(shù)。
針對(duì) K 類(lèi)分類(lèi)問(wèn)題的神經(jīng)網(wǎng)絡(luò)的輸出層
$$
h_\Theta(x) \in R^K; \left( h_\Theta(x) \right)_k = k^{th} output
$$
其中 K 是輸出層的的單元個(gè)數(shù),K >= 3。因?yàn)槿绻?K < 3 則可以直接用一個(gè)單元表示。其成本函數(shù)是:
$$
J(\Theta) = - \frac{1}{m} \left[ \sum_{i=1}^m \sum_{k=1}^K y_k^{(i)} log(h_k^{(i)}) + (1 - y_k^{(i)}) log(1 - h_k^{(i)}) \right] + \frac{\lambda}{2m} \sum_{l=1}^{L-1} \sum_{i=1}^{s_l} \sum_{j=1}^{s_{l+1}} (\Theta_{ji}{(l)})2
$$
其中 $h_k^{(i)} = {h_\Theta(x^{(i)})}_k$ 是輸出層的第 $k^{th}$ 個(gè)輸出值。$L$ 是神經(jīng)網(wǎng)絡(luò)的層數(shù),$s_l$ 是指第 $l$ 層的單元個(gè)數(shù)。公式的前半部分是未正則化的成本函數(shù),后半部分是正則項(xiàng),加起來(lái)就是正則化的成本公式。注意正則項(xiàng)部分求和時(shí)是從 $i=1$ 開(kāi)始的,即我們不把偏置變量正則化。
!!! warnning "MathJax 的缺陷"
這個(gè)公式我寫(xiě)了 20 分鐘。它已經(jīng)復(fù)雜到我不得不把 $h_k^{(i)}$ 獨(dú)立寫(xiě)出來(lái)了,如果全部寫(xiě)一個(gè)公式里,公式將無(wú)法正確顯示。不服的人可以試看看。
怎么理解神經(jīng)網(wǎng)絡(luò)的成本公式
實(shí)際上不需要記住這么復(fù)雜的公式,但可以結(jié)合邏輯回歸算法的成本公式來(lái)理解神經(jīng)網(wǎng)絡(luò)的成本公式。我們知道,神經(jīng)網(wǎng)絡(luò)中間層和輸出層的每個(gè)神經(jīng)元,都和其前面一層的神經(jīng)網(wǎng)絡(luò)的神經(jīng)元構(gòu)成邏輯回歸關(guān)系。這個(gè)是神經(jīng)網(wǎng)絡(luò)的定義。而邏輯回歸算法的成本函數(shù)是:
$$
J(\theta) = -\frac{1}{m} \left[ \sum_{i=1}^m y^{(i)} log(h_\theta(x^{(i)})) + (1 - y^{(i)}) log(1 - h_\theta(x^{(i)})) \right]
$$
跟神經(jīng)網(wǎng)絡(luò)成本函數(shù)對(duì)比,你會(huì)發(fā)現(xiàn)神經(jīng)網(wǎng)絡(luò)輸出層有 K 個(gè)神經(jīng)元。所以計(jì)算成本函數(shù)時(shí),需要把輸出層 K 個(gè)神經(jīng)元的邏輯回歸成本累加起來(lái)。
怎么理解正則項(xiàng)呢?
正則項(xiàng)有三個(gè)累加器,最前面那個(gè)是層累加器,典型地,對(duì) 3 層神經(jīng)網(wǎng)絡(luò)模型 $L=3$ ,正則項(xiàng)簡(jiǎn)化為:
$$
reg = \frac{\lambda}{2m} \left( \sum_{i=1}^{s_1} \sum_{j=1}^{s_2} \left( \Theta_{ji}^{(1)} \right)^2 + \sum_{i=1}^{s_2} \sum_{j=1}^{s_3} \left( \Theta_{ji}^{(2)} \right)^2 \right)
$$
向后傳播算法
我們把 $\delta_j^{(l)}$ ( $\delta$ 讀作 delta ) 記作神經(jīng)網(wǎng)絡(luò)中第 $l$ 層,第 $j$ 個(gè)節(jié)點(diǎn)的誤差。針對(duì)輸出層,我們有
$$
\delta_j^{(L)} = a_j^{(L)} - y_j
$$
按照向量化寫(xiě)法,我們得到
$$
\delta^{(L)} = a^{(L)} - y
$$
此由可見(jiàn),$\delta^{(L)}$ 是和 $y$ 一樣維度的向量。針對(duì)第 $L-1$ 層,我們把誤差定義為
$$
\delta^{(L-1)} = (\Theta{(L-1)})T \delta^{(L)} .* g'(z^{(L-1)})
$$
這個(gè)公式的前半部分 $ (\Theta{(L-1)})T \delta^{(L)}$ 樣式很熟悉吧,就是線(xiàn)性回歸算法的預(yù)測(cè)函數(shù)的樣式。中間的 $.*$ 讀作點(diǎn)乘,就是逐個(gè)元素相乘。$z{(L-1)}=\Theta{(L-2)} a^{(L-2)}$,$g'(z)$ 是 Sigmoid 函數(shù)的偏微分。
可以從數(shù)學(xué)上證明 $g'(z^{(L-1)}) = a^{(L-1)} .* (1 - a^{(L-1)})$ 成立。證明過(guò)程可以參閱 常用的微分運(yùn)算法則 里關(guān)于 Sigmoid Function 偏微分的推導(dǎo)過(guò)程。這樣我們算出輸出層的誤差,然后一層層往前推導(dǎo),算出各層的誤差,就是我們向后傳播算法名字的由來(lái)。需要注意的是,不存在 $\delta^{(1)}$,因?yàn)樯窠?jīng)網(wǎng)絡(luò)的第 1 層是我們的輸入項(xiàng),不存在誤差問(wèn)題。
從數(shù)學(xué)上可以證明,如果忽略正則項(xiàng),即 $\lambda = 0$時(shí)
$$
\frac{\partial}{\partial \Theta_{ij}^{(l)}} J(\Theta) = a_j^{(l)} \delta_i^{(l+1)}
$$
注意:
- 計(jì)算微分項(xiàng)時(shí),只需要計(jì)算 1, 2, ..., l+1 層的微分項(xiàng)
- 微分項(xiàng) $\frac{\partial}{\partial \Theta_{ij}^{(l)}} J(\Theta)$ 是個(gè)和 $\Theta^{(l)}$ 尺寸相同的矩陣
針對(duì)訓(xùn)練樣本 ${ (x^{(1)}, y^{(1)}), (x^{(2)}, y^{(2)}), ... (x^{(m)}, y^{(m)}),}$,我們可以把向后傳播算法用偽代碼描述如下:
- 初始化誤差累加值 set $\Delta_{ij}^{(l)} = 0$, for all $l, i, j$
- 遍歷所有的訓(xùn)練樣本 for i = 1 to m
- 設(shè)置輸入層的激勵(lì)為第 $i$ 個(gè)訓(xùn)練樣本的輸入值 set $a^{(1)} = x^{(i)}$
- 使用向前傳播算法 $a^{(l+1)} = g\left( a^{(l)} * \left( \Theta^{(l)} \right)^T \right)$,算出所有層的激勵(lì) $a^{(l)}$ for $l = 2, 3, ... , L$
- 使用輸出層的激勵(lì),計(jì)算輸出層的誤差 $\delta^{(L)} = a^{(L)} - y^{(i)}$
- 使用反向擴(kuò)散的方法 $\delta^{(L-1)} = (\Theta{(L-1)})T \delta^{(L)} .* g'(z^{(L-1)})$ 計(jì)算每一層的誤差 $\delta^{(L-1)}, \delta^{(L-2)}, ..., \delta^{(2)}$。
- 累加 $(x^{(i)}, y^{(i)})$ 訓(xùn)練樣本的誤差 $\Delta_{ij}^{(l)} = \Delta_{ij}^{(l)} + a_j^{(l)} \delta_i^{(l+1)}$。
- endfor
- 累加的值除以 m 即得到無(wú)正則化的微分項(xiàng) $\frac{\Delta_{ij}^{(l)}}{m}$
最后一項(xiàng)可以用向量化的寫(xiě)法:
$$
\Delta^{(l)} = \Delta^{(l)} + \delta^{(l+1)} \left( a^{(l)} \right)^T
$$
注意:
計(jì)算過(guò)程中,需要注意偏置單元。根據(jù)慣例,累加時(shí)不計(jì)算偏置單元。針對(duì)反向擴(kuò)散公式 $\delta^{(L-1)} = (\Theta{(L-1)})T \delta^{(L)} . g'(z^{(L-1)})$,需要特別注意矩陣運(yùn)算時(shí)的維度需要匹配。*
加入正則項(xiàng)后,我們有
$$
D_{ij}^{(l)} = \frac{1}{m} \Delta_{ij}^{(l)} + \frac{\lambda}{m} \Theta_{ij}^{(l)}, if j \ne 0
$$
$$
D_{ij}^{(l)} = \frac{1}{m} \Delta_{ij}^{(l)}, if j = 0
$$
從數(shù)學(xué)上可以證明
$$
\frac{\partial}{\partial \Theta_{ij}^{(l)}} J(\Theta) = D_{ij}^{(l)}
$$
這樣我們就算出來(lái)了神經(jīng)網(wǎng)絡(luò)模型的成本函數(shù)微分項(xiàng)。有了成本函數(shù)和成本函數(shù)微分項(xiàng),我們就可以使用線(xiàn)性回歸或其他高級(jí)算法來(lái)計(jì)算神經(jīng)網(wǎng)絡(luò)成本函數(shù)的最小值,從而求解神經(jīng)網(wǎng)絡(luò)中各層激勵(lì)的參數(shù)。
在具體實(shí)現(xiàn)的時(shí)候,使用向量化的實(shí)現(xiàn)可以大幅提高算法效率。具體可以參考 Neural Network Vectorization。
實(shí)踐中的向后傳播算法
參數(shù)折疊
在線(xiàn)性回歸或邏輯回歸算法里,我們的參數(shù)是向量,我們使用的 fminunc 等函數(shù)也只接受向量作為參數(shù)。而神經(jīng)網(wǎng)絡(luò)算法里,參數(shù)是個(gè)向量,$\Theta^{(l)} \in R^{s_{l+1} \times s_l + 1}$。所以,在訓(xùn)練神經(jīng)網(wǎng)絡(luò)算法時(shí),需要對(duì)參數(shù)進(jìn)行折疊,即把矩陣轉(zhuǎn)換為向量,而在使用時(shí),可以再?gòu)南蛄坷锘謴?fù)矩陣數(shù)據(jù)。
假設(shè) Theta1 是 10x11 的矩陣,它是第一層的參數(shù); Theta2 是 10x11 的矩陣,它是第二層的參數(shù)。可以使用下面的 matlab/octave 來(lái)轉(zhuǎn)換:
ThetaVec = [Theta1(:); Theta2(:)];
在成本函數(shù)函數(shù)里,我們需要轉(zhuǎn)換為矩陣進(jìn)行計(jì)算:
Theta1 = reshape(ThetaVec(1:110), 10, 11);
Theta2 = reshape(ThetaVec(111:220), 10, 11);
同理,針對(duì)成本函數(shù)的微分項(xiàng),$D^{(1)} \in R^{10x11}, D^{(2)} \in R^{10x11}$,我們的成本函數(shù)返回這個(gè)微分項(xiàng)時(shí),也需要把矩陣轉(zhuǎn)換為向量:
DVec = [D1(:); D2(:)]
微分項(xiàng)檢驗(yàn)
神經(jīng)網(wǎng)絡(luò)的微分項(xiàng)特別復(fù)雜,有時(shí)候一些小的錯(cuò)誤可能不會(huì)導(dǎo)致算法失敗,這樣就很難發(fā)現(xiàn)問(wèn)題。這里介紹一個(gè)方法來(lái)驗(yàn)證微分項(xiàng)算法是否正確。我們使用的是微分的數(shù)值估算方法。
$$
\fracu0z1t8os{d\theta} J(\theta) \approx \frac{J(\theta + \varepsilon) + J(\theta - \varepsilon)}{2 \varepsilon}
$$
這里只要 $\varepsilon$ 足夠小,則可以近似地計(jì)算出微分項(xiàng)的值。實(shí)際計(jì)算時(shí),我們一般取 $\varepsilon = 0.0001$ 。這樣算出來(lái)的值和微分項(xiàng)算出來(lái)的值應(yīng)該非常近似,用這個(gè)方法我們可以驗(yàn)證微分項(xiàng)計(jì)算是否準(zhǔn)確。需要特別注意的是,在驗(yàn)證完微分項(xiàng)計(jì)算的正確性后,數(shù)值近似計(jì)算必須關(guān)閉掉。否則會(huì)使算法效率嚴(yán)重降低。因?yàn)閿?shù)值計(jì)算的成本是很高的。
編程時(shí)需要注意
微分項(xiàng)檢查實(shí)際上是一種純數(shù)學(xué)的做法。主要是檢查我們使用向后傳播算法 (backpropagation) 方法算出來(lái)的微分和用數(shù)值計(jì)算算出來(lái)的微分是否相同。它適用于其他算法,如線(xiàn)性回歸或邏輯回歸算法。有幾點(diǎn)需要特別注意。
- 由于計(jì)算很費(fèi)時(shí)間,實(shí)際檢查時(shí),$\theta$ 可以選小一點(diǎn)的矩陣,比如 3 x 5,而不需要使用真正的機(jī)器學(xué)習(xí)時(shí)的 theta。因?yàn)?$\theta$ 太大不但費(fèi)時(shí)間,還不利于觀察。
- 實(shí)際計(jì)算時(shí),$\theta$ 往往是個(gè)列向量。這個(gè)時(shí)候我們需要讓 $\varepsilon$ 也是一個(gè)和 $\theta$ 維度相同的向量,當(dāng)檢查 $\theta(i)$ 元素的偏微分項(xiàng)時(shí),讓 $\varepsilon$ 的的第 i 項(xiàng)的值為 0.0001,其他項(xiàng)都為 0 。這樣進(jìn)行矩陣來(lái)進(jìn)行數(shù)值微分計(jì)算。
用隨機(jī)數(shù)初始化參數(shù)
在進(jìn)行線(xiàn)性回歸和邏輯回歸計(jì)算時(shí),我們把參數(shù)全部初始化為零。但這個(gè)做法在神經(jīng)網(wǎng)絡(luò)里是不可行的,如果我們把參數(shù)全部初始化為零,那么隱藏層的神經(jīng)單元的激勵(lì) $a_i^{(l)}$ 將是相同的,其誤差 $\delta_i^{(l)}$ 也將是相同的,即我們計(jì)算的全部是相同的特征,這樣神經(jīng)網(wǎng)絡(luò)就失去了其特征的覆蓋度和豐富性。
所以,我們需要把神經(jīng)網(wǎng)絡(luò)的每個(gè)參數(shù) $\Theta_{ij}^{(l)}$ 初始化為 $[-\varepsilon, \varepsilon]$ 之間的一個(gè)隨機(jī)數(shù)。例如:
Theta1 = rand(10, 11) .* (2 .* INIT_VAREPSILON) - INIT_VAREPSILON;
Theta2 = rand(10, 11) .* (2 .* INIT_VAREPSILON) - INIT_VAREPSILON;
Theta3 = rand(1, 11) .* (2 .* INIT_VAREPSILON) - INIT_VAREPSILON;
$\varepsilon$ 應(yīng)該選擇小一點(diǎn),這樣神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)最有效率。一個(gè)經(jīng)驗(yàn)做法是
$$
\varepsilon^{(l)} = \frac{\sqrt{6}}{\sqrt{s_l} + \sqrt{s_{l+1}}}
$$
$s_l, s_{l+1}$ 分別表示 $l$ 層和 $l+1$ 層的神經(jīng)單元個(gè)數(shù)。即每層的參數(shù)范圍根據(jù)這層的神經(jīng)單元個(gè)數(shù)及下一層的神經(jīng)單元個(gè)數(shù)。
總結(jié)
使用神經(jīng)網(wǎng)絡(luò)解決問(wèn)題時(shí),需要經(jīng)過(guò)兩個(gè)步驟。一是設(shè)計(jì)神經(jīng)網(wǎng)絡(luò)的架構(gòu);二是訓(xùn)練出對(duì)應(yīng)的神經(jīng)網(wǎng)絡(luò)參數(shù)。
神經(jīng)網(wǎng)絡(luò)架構(gòu)
在進(jìn)行神經(jīng)網(wǎng)絡(luò)計(jì)算時(shí),需要先進(jìn)行神經(jīng)網(wǎng)絡(luò)的架構(gòu)設(shè)計(jì)。架構(gòu)設(shè)計(jì)時(shí)需要考慮以下三個(gè)事情:
- 輸入層的特征數(shù)量 (number of input unit)
- 輸出層的單元個(gè)數(shù) (number of output unit) ,針對(duì)多類(lèi)別的分類(lèi)問(wèn)題,可以把輸出層設(shè)計(jì)成一個(gè)向量
- 隱藏層的個(gè)數(shù)以及每個(gè)隱藏層的單元數(shù)目。一般來(lái)講,隱藏層的個(gè)數(shù)越多越好,但會(huì)增加計(jì)算的工作量。另外,多個(gè)隱藏層的單元數(shù)目一般是相同的。
訓(xùn)練神經(jīng)網(wǎng)絡(luò)
訓(xùn)練神經(jīng)網(wǎng)絡(luò)總共有六個(gè)步驟
- 按照隨機(jī)數(shù)對(duì)初始權(quán)重 (參數(shù)) 進(jìn)行初始化
- 實(shí)現(xiàn)向前傳播算法,以便針對(duì)任何的輸入 $x^{(i)}$ 都能算出相應(yīng)的 $h_\Theta(x^{(i)})$
- 實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)成本函數(shù) $J(\Theta)$ 來(lái)計(jì)算成本
- 實(shí)現(xiàn)向后傳播算法,計(jì)算成本函數(shù)針對(duì)每個(gè)參數(shù)的偏微分 $\frac{\partial}{\partial \Theta_{ij}^{(l)}} J(\Theta)$
- 需要遍歷每個(gè)訓(xùn)練樣本,即有個(gè)從 1 到 m 的循環(huán)
- 針對(duì)每個(gè)訓(xùn)練樣本 $(x^{(i)}, y^{(i)})$ 執(zhí)行向前傳播算法和向后傳播算法,以便算出 $l$ 層的激勵(lì) (Activations) $a^{(l)}$ 和誤差 $\delta^{(l)}$
- 需要針對(duì)神經(jīng)網(wǎng)絡(luò)的每層算出*的值,這些層是 2, 3, ... , L
- 最后,在循環(huán)外,算出成本函數(shù)的偏微分
- 使用數(shù)值估計(jì)算法來(lái)驗(yàn)證神經(jīng)網(wǎng)絡(luò)成本函數(shù)的偏微分是否正確。驗(yàn)證通過(guò)后,關(guān)閉數(shù)值估計(jì)算法。
- 使用梯度下降或其他優(yōu)化過(guò)的高級(jí)算法來(lái)對(duì)成本函數(shù) $J(\Theta)$ 進(jìn)行最小化運(yùn)算