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