繼續(xù)發(fā)公式哮翘。有興趣閱讀能正常顯示公式的版本請移步 http://blog.kamidox.com/neural-networks-2.html
成本函數(shù)
與線性回歸或邏輯回歸類似监嗜,要使用神經(jīng)網(wǎng)絡對訓練數(shù)據(jù)進行擬合時嫉柴,需要有成本函數(shù)瓮顽。這樣只要針對訓練數(shù)據(jù)翔横,求解成本函數(shù)的最小值即可得出神經(jīng)網(wǎng)絡模型參數(shù)癞谒。
針對 K 類分類問題的神經(jīng)網(wǎng)絡的輸出層
$$
h_\Theta(x) \in R^K; \left( h_\Theta(x) \right)_k = k^{th} output
$$
其中 K 是輸出層的的單元個數(shù)藤滥,K >= 3鳖粟。因為如果 K < 3 則可以直接用一個單元表示。其成本函數(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}$ 個輸出值拙绊。$L$ 是神經(jīng)網(wǎng)絡的層數(shù)向图,$s_l$ 是指第 $l$ 層的單元個數(shù)。公式的前半部分是未正則化的成本函數(shù)标沪,后半部分是正則項榄攀,加起來就是正則化的成本公式。注意正則項部分求和時是從 $i=1$ 開始的金句,即我們不把偏置變量正則化檩赢。
!!! warnning "MathJax 的缺陷"
這個公式我寫了 20 分鐘。它已經(jīng)復雜到我不得不把 $h_k^{(i)}$ 獨立寫出來了违寞,如果全部寫一個公式里贞瞒,公式將無法正確顯示偶房。不服的人可以試看看。
怎么理解神經(jīng)網(wǎng)絡的成本公式
實際上不需要記住這么復雜的公式憔狞,但可以結合邏輯回歸算法的成本公式來理解神經(jīng)網(wǎng)絡的成本公式蝴悉。我們知道,神經(jīng)網(wǎng)絡中間層和輸出層的每個神經(jīng)元瘾敢,都和其前面一層的神經(jīng)網(wǎng)絡的神經(jīng)元構成邏輯回歸關系。這個是神經(jīng)網(wǎng)絡的定義尿这。而邏輯回歸算法的成本函數(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)絡成本函數(shù)對比簇抵,你會發(fā)現(xiàn)神經(jīng)網(wǎng)絡輸出層有 K 個神經(jīng)元。所以計算成本函數(shù)時射众,需要把輸出層 K 個神經(jīng)元的邏輯回歸成本累加起來碟摆。
怎么理解正則項呢?
正則項有三個累加器叨橱,最前面那個是層累加器典蜕,典型地,對 3 層神經(jīng)網(wǎng)絡模型 $L=3$ 罗洗,正則項簡化為:
$$
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)絡中第 $l$ 層愉舔,第 $j$ 個節(jié)點的誤差。針對輸出層伙菜,我們有
$$
\delta_j^{(L)} = a_j^{(L)} - y_j
$$
按照向量化寫法轩缤,我們得到
$$
\delta^{(L)} = a^{(L)} - y
$$
此由可見,$\delta^{(L)}$ 是和 $y$ 一樣維度的向量贩绕。針對第 $L-1$ 層火的,我們把誤差定義為
$$
\delta^{(L-1)} = (\Theta{(L-1)})T \delta^{(L)} .* g'(z^{(L-1)})
$$
這個公式的前半部分 $ (\Theta{(L-1)})T \delta^{(L)}$ 樣式很熟悉吧,就是線性回歸算法的預測函數(shù)的樣式淑倾。中間的 $.*$ 讀作點乘馏鹤,就是逐個元素相乘。$z{(L-1)}=\Theta{(L-2)} a^{(L-2)}$娇哆,$g'(z)$ 是 Sigmoid 函數(shù)的偏微分湃累。
可以從數(shù)學上證明 $g'(z^{(L-1)}) = a^{(L-1)} .* (1 - a^{(L-1)})$ 成立。證明過程可以參閱 常用的微分運算法則 里關于 Sigmoid Function 偏微分的推導過程迂尝。這樣我們算出輸出層的誤差脱茉,然后一層層往前推導,算出各層的誤差垄开,就是我們向后傳播算法名字的由來琴许。需要注意的是,不存在 $\delta^{(1)}$溉躲,因為神經(jīng)網(wǎng)絡的第 1 層是我們的輸入項榜田,不存在誤差問題益兄。
從數(shù)學上可以證明,如果忽略正則項箭券,即 $\lambda = 0$時
$$
\frac{\partial}{\partial \Theta_{ij}^{(l)}} J(\Theta) = a_j^{(l)} \delta_i^{(l+1)}
$$
注意:
- 計算微分項時净捅,只需要計算 1, 2, ..., l+1 層的微分項
- 微分項 $\frac{\partial}{\partial \Theta_{ij}^{(l)}} J(\Theta)$ 是個和 $\Theta^{(l)}$ 尺寸相同的矩陣
針對訓練樣本 ${ (x^{(1)}, y^{(1)}), (x^{(2)}, y^{(2)}), ... (x^{(m)}, y^{(m)}),}$,我們可以把向后傳播算法用偽代碼描述如下:
- 初始化誤差累加值 set $\Delta_{ij}^{(l)} = 0$, for all $l, i, j$
- 遍歷所有的訓練樣本 for i = 1 to m
- 設置輸入層的激勵為第 $i$ 個訓練樣本的輸入值 set $a^{(1)} = x^{(i)}$
- 使用向前傳播算法 $a^{(l+1)} = g\left( a^{(l)} * \left( \Theta^{(l)} \right)^T \right)$辩块,算出所有層的激勵 $a^{(l)}$ for $l = 2, 3, ... , L$
- 使用輸出層的激勵蛔六,計算輸出層的誤差 $\delta^{(L)} = a^{(L)} - y^{(i)}$
- 使用反向擴散的方法 $\delta^{(L-1)} = (\Theta{(L-1)})T \delta^{(L)} .* g'(z^{(L-1)})$ 計算每一層的誤差 $\delta^{(L-1)}, \delta^{(L-2)}, ..., \delta^{(2)}$。
- 累加 $(x^{(i)}, y^{(i)})$ 訓練樣本的誤差 $\Delta_{ij}^{(l)} = \Delta_{ij}^{(l)} + a_j^{(l)} \delta_i^{(l+1)}$废亭。
- endfor
- 累加的值除以 m 即得到無正則化的微分項 $\frac{\Delta_{ij}^{(l)}}{m}$
最后一項可以用向量化的寫法:
$$
\Delta^{(l)} = \Delta^{(l)} + \delta^{(l+1)} \left( a^{(l)} \right)^T
$$
注意:
計算過程中国章,需要注意偏置單元。根據(jù)慣例豆村,累加時不計算偏置單元液兽。針對反向擴散公式 $\delta^{(L-1)} = (\Theta{(L-1)})T \delta^{(L)} . g'(z^{(L-1)})$,需要特別注意矩陣運算時的維度需要匹配掌动。*
加入正則項后四啰,我們有
$$
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ù)學上可以證明
$$
\frac{\partial}{\partial \Theta_{ij}^{(l)}} J(\Theta) = D_{ij}^{(l)}
$$
這樣我們就算出來了神經(jīng)網(wǎng)絡模型的成本函數(shù)微分項。有了成本函數(shù)和成本函數(shù)微分項粗恢,我們就可以使用線性回歸或其他高級算法來計算神經(jīng)網(wǎng)絡成本函數(shù)的最小值柑晒,從而求解神經(jīng)網(wǎng)絡中各層激勵的參數(shù)。
在具體實現(xiàn)的時候适滓,使用向量化的實現(xiàn)可以大幅提高算法效率敦迄。具體可以參考 Neural Network Vectorization。
實踐中的向后傳播算法
參數(shù)折疊
在線性回歸或邏輯回歸算法里凭迹,我們的參數(shù)是向量罚屋,我們使用的 fminunc
等函數(shù)也只接受向量作為參數(shù)。而神經(jīng)網(wǎng)絡算法里嗅绸,參數(shù)是個向量脾猛,$\Theta^{(l)} \in R^{s_{l+1} \times s_l + 1}$。所以鱼鸠,在訓練神經(jīng)網(wǎng)絡算法時猛拴,需要對參數(shù)進行折疊,即把矩陣轉換為向量蚀狰,而在使用時愉昆,可以再從向量里恢復矩陣數(shù)據(jù)。
假設 Theta1 是 10x11 的矩陣麻蹋,它是第一層的參數(shù)跛溉; Theta2 是 10x11 的矩陣,它是第二層的參數(shù)》际遥可以使用下面的 matlab/octave 來轉換:
ThetaVec = [Theta1(:); Theta2(:)];
在成本函數(shù)函數(shù)里专肪,我們需要轉換為矩陣進行計算:
Theta1 = reshape(ThetaVec(1:110), 10, 11);
Theta2 = reshape(ThetaVec(111:220), 10, 11);
同理,針對成本函數(shù)的微分項堪侯,$D^{(1)} \in R^{10x11}, D^{(2)} \in R^{10x11}$嚎尤,我們的成本函數(shù)返回這個微分項時,也需要把矩陣轉換為向量:
DVec = [D1(:); D2(:)]
微分項檢驗
神經(jīng)網(wǎng)絡的微分項特別復雜伍宦,有時候一些小的錯誤可能不會導致算法失敗芽死,這樣就很難發(fā)現(xiàn)問題。這里介紹一個方法來驗證微分項算法是否正確雹拄。我們使用的是微分的數(shù)值估算方法收奔。
$$
\fracozokv71{d\theta} J(\theta) \approx \frac{J(\theta + \varepsilon) + J(\theta - \varepsilon)}{2 \varepsilon}
$$
這里只要 $\varepsilon$ 足夠小,則可以近似地計算出微分項的值滓玖。實際計算時,我們一般取 $\varepsilon = 0.0001$ 质蕉。這樣算出來的值和微分項算出來的值應該非常近似势篡,用這個方法我們可以驗證微分項計算是否準確。需要特別注意的是模暗,在驗證完微分項計算的正確性后禁悠,數(shù)值近似計算必須關閉掉。否則會使算法效率嚴重降低兑宇。因為數(shù)值計算的成本是很高的碍侦。
編程時需要注意
微分項檢查實際上是一種純數(shù)學的做法。主要是檢查我們使用向后傳播算法 (backpropagation) 方法算出來的微分和用數(shù)值計算算出來的微分是否相同隶糕。它適用于其他算法瓷产,如線性回歸或邏輯回歸算法。有幾點需要特別注意枚驻。
- 由于計算很費時間濒旦,實際檢查時,$\theta$ 可以選小一點的矩陣再登,比如 3 x 5尔邓,而不需要使用真正的機器學習時的 theta。因為 $\theta$ 太大不但費時間锉矢,還不利于觀察梯嗽。
- 實際計算時,$\theta$ 往往是個列向量沽损。這個時候我們需要讓 $\varepsilon$ 也是一個和 $\theta$ 維度相同的向量灯节,當檢查 $\theta(i)$ 元素的偏微分項時,讓 $\varepsilon$ 的的第 i 項的值為 0.0001,其他項都為 0 显晶。這樣進行矩陣來進行數(shù)值微分計算贷岸。
用隨機數(shù)初始化參數(shù)
在進行線性回歸和邏輯回歸計算時,我們把參數(shù)全部初始化為零磷雇。但這個做法在神經(jīng)網(wǎng)絡里是不可行的偿警,如果我們把參數(shù)全部初始化為零,那么隱藏層的神經(jīng)單元的激勵 $a_i^{(l)}$ 將是相同的唯笙,其誤差 $\delta_i^{(l)}$ 也將是相同的螟蒸,即我們計算的全部是相同的特征,這樣神經(jīng)網(wǎng)絡就失去了其特征的覆蓋度和豐富性崩掘。
所以七嫌,我們需要把神經(jīng)網(wǎng)絡的每個參數(shù) $\Theta_{ij}^{(l)}$ 初始化為 $[-\varepsilon, \varepsilon]$ 之間的一個隨機數(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$ 應該選擇小一點苞慢,這樣神經(jīng)網(wǎng)絡的學習最有效率诵原。一個經(jīng)驗做法是
$$
\varepsilon^{(l)} = \frac{\sqrt{6}}{\sqrt{s_l} + \sqrt{s_{l+1}}}
$$
$s_l, s_{l+1}$ 分別表示 $l$ 層和 $l+1$ 層的神經(jīng)單元個數(shù)。即每層的參數(shù)范圍根據(jù)這層的神經(jīng)單元個數(shù)及下一層的神經(jīng)單元個數(shù)挽放。
總結
使用神經(jīng)網(wǎng)絡解決問題時绍赛,需要經(jīng)過兩個步驟。一是設計神經(jīng)網(wǎng)絡的架構辑畦;二是訓練出對應的神經(jīng)網(wǎng)絡參數(shù)吗蚌。
神經(jīng)網(wǎng)絡架構
在進行神經(jīng)網(wǎng)絡計算時,需要先進行神經(jīng)網(wǎng)絡的架構設計纯出。架構設計時需要考慮以下三個事情:
- 輸入層的特征數(shù)量 (number of input unit)
- 輸出層的單元個數(shù) (number of output unit) 蚯妇,針對多類別的分類問題,可以把輸出層設計成一個向量
- 隱藏層的個數(shù)以及每個隱藏層的單元數(shù)目暂筝。一般來講箩言,隱藏層的個數(shù)越多越好,但會增加計算的工作量乖杠。另外分扎,多個隱藏層的單元數(shù)目一般是相同的。
訓練神經(jīng)網(wǎng)絡
訓練神經(jīng)網(wǎng)絡總共有六個步驟
- 按照隨機數(shù)對初始權重 (參數(shù)) 進行初始化
- 實現(xiàn)向前傳播算法胧洒,以便針對任何的輸入 $x^{(i)}$ 都能算出相應的 $h_\Theta(x^{(i)})$
- 實現(xiàn)神經(jīng)網(wǎng)絡成本函數(shù) $J(\Theta)$ 來計算成本
- 實現(xiàn)向后傳播算法畏吓,計算成本函數(shù)針對每個參數(shù)的偏微分 $\frac{\partial}{\partial \Theta_{ij}^{(l)}} J(\Theta)$
- 需要遍歷每個訓練樣本,即有個從 1 到 m 的循環(huán)
- 針對每個訓練樣本 $(x^{(i)}, y^{(i)})$ 執(zhí)行向前傳播算法和向后傳播算法卫漫,以便算出 $l$ 層的激勵 (Activations) $a^{(l)}$ 和誤差 $\delta^{(l)}$
- 需要針對神經(jīng)網(wǎng)絡的每層算出*的值菲饼,這些層是 2, 3, ... , L
- 最后,在循環(huán)外列赎,算出成本函數(shù)的偏微分
- 使用數(shù)值估計算法來驗證神經(jīng)網(wǎng)絡成本函數(shù)的偏微分是否正確宏悦。驗證通過后,關閉數(shù)值估計算法。
- 使用梯度下降或其他優(yōu)化過的高級算法來對成本函數(shù) $J(\Theta)$ 進行最小化運算