筆者曾於Coursera觀看過臺灣大學資工系林軒田教授授課的「機器學習基石(Machine Learning Foundations)」教學影片,同時也是筆者初次接觸Coursera線上教育平臺。當時上完了四週的課程後,即使可以粗淺地認識機器學習(ML)的概念,卻發現在上此門課時,需要花上許多時間來理解數學證明的過程,因此找到史丹佛大學Andrew教授授課的「Machine Learning」課程。雖然該課程採全英文教學,但因內容淺顯易懂,加上附有中文字幕,更重要的是在每周課程結束後,會有一份實作作業,藉由一步步的coding驗證,來評量自己是否已經理解課程上的內容。經過約兩個月的學習,直覺上搜尋Andrew教授在Coursera的其他課程,便找到了另一門深度學習專項課程「Deep Learning Specialization」,該課程共分成五個主要章節,如下:
- Neural Networks and Deep Learning
介紹神經網路的基本架構 - Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization
說明優化神經網路的方法 - Structuring Machine Learning Projects
以Andrew教授自身的經驗,討論執行ML專案時有哪些重要步驟,及應注意的要點 - Convolutional Neural Networks
如何透過建立卷積神經網路,以解決影像辨識的問題 - Sequence Models
如何利用循環神經網路,處理具有連續性的資料
以下將依上述課程編排的順序,記錄筆者學習的過程和實作成果。
神經網路(neural network)
首先引用在Machine Learning課程上學習到的概念,將預測市場上的房價訂為假想目標,而我們相信房價必然會與某些特徵(如:房子的坪數、房間的數量、屋齡等等)有著某種「關係」,只要透過監督式訓練模型找出這層關係,未來只需簡單輸入特徵與發現的關係,就能達成預測房價之目標。
若從數學的表達來探討,通常將特徵表示為「x(feature)」,即我們手上握有的資料或是需要蒐集的資料,而這層想要求得的關係,通常稱為權重「w(weight)」,這間房子的實際房價則稱為「y(label)」,每項特徵x都會對實際房價y有著一定的影響或稱某種關係w,在數學上可以表達如公式一。其中b為偏差項,可以理解為當w或x皆為0時y的初始值,或是此直線方程式的截距。
不過需要注意,在神經網路使用的符號會略有不同,在這裡會先將每個權重乘上每個特徵的結果,先以z替代,透過啟動函數(activation function),即g,將z映射到新的節點a,構成一層(layer)只有一個節點(node)的神經網路,如圖一及公式二所示。
神經網路的概念源自於人類中樞神經系統,神經元於人體構成網路,傳遞信息,使人體做出反應。如同人類神經系統,神經網路將各個神經元以節點的方式,連結各個節點,並產生欲計算的結果,進而形成多層、多節點的神經網路,如圖二所示。
向前傳播(forward propagation)
每一層網路裡面的每個節點,都會如圖一所示,把前一層所有的節點視為特徵,並將每個特徵乘上權重後得到z,再經由啟動函數得到a,形成新的節點。而為了區分每一層網路和每個節點間的差異,在符號的使用有一通則,如下:
- 輸入的x視為第0層節點,又稱輸入層(input layer);最後的輸出視為第L層,又稱輸出層(output layer));而在輸入與輸出層之間,稱為隱藏層l(hidden layer)。
- 各符號的上標以中括號表示第l層隱藏層,下標表示在第l層下的第n個節點。
- w和b表示第l層的節點和前一層l–1層的節點之間的關係。
注意w的下標第一個數字代表第l層下的第n個節點,n會等於第l層的節點數量;第二個數字代表前一層的第n節點,而這裡的n會等於l–1層的節點數量。 - 輸出層的a會等於預測的結果 ŷ(y-hat),以和實際上的標籤y區別。
以圖三為例,可以將每個節點的符號呈現如公式三。
數學運算會利用矩陣來簡化各個節點的計算,舉第一層的節點為例,把連續加法以矩陣相乘來替代,如公式四。
而最終的目標即是找出節點和節點之間的關係,也就是計算出每一層隱藏層的每個w和b這兩個矩陣所填入的值。從公式二中第0層到第 1層例子中可以發現,層和層之間矩陣維度的關係與該層和前一層的節點數量有關,以此類推到第l層和l-1層的關係如公式五。
啟動函數(activation function)
公式四以矩陣相乘簡化z的計算式後,接下來介紹啟動函數的種類:
- sigmoid function
值域在1和0之間,最終預測時可加上閾值令大於閾值的輸出為1反之為0,因此通常使用的時機為二元分類問題的輸出層。 - tanh function
CNN較常使用(後續會介紹)。 - ReLU function
值域在0和z之間,常為隱藏層使用的啟動函數。 - linear function(identity function)
不改變z的啟動函數,較少使用。
以圖像辨識的應用為例,若利用前文圖三的神經網路來判斷圖片內的動物是否為一隻貓,則x代表一張圖片中每一個子像素的灰階,如果此為32 × 32像素的圖片,則會有32 × 32 × 3(R、G、B三原色)個特徵;如果每個子像素的色彩深度是6位元,則每個特徵的範圍會在0到63(64色)之間,請參考圖四。此例中的神經網路具有一層輸入層、兩層隱藏層、一層輸出層,每層的節點數量如圖四所示。因為最後的答案只有兩種可能,故在輸出層只會有一個節點,並且用sigmoid函數作為最後的啟動函數,而在隱藏層裡面的啟動函數則皆使用ReLU函數。經過神經網路的運算,最後的預測結果a會等於ŷ,在深度學習中有個專有名詞來表示此過程,稱為「向前傳播(forward propagation)」。
損失函數(loss function)
接下來會使用稱為「損失函數 (cost/loss function)」的函數來評估預測的結果是否準確(公式六)。損失函數會根據預測的目標有不同的公式,目的都是為了合理的評估向前傳播的輸出ŷ與標籤y之間的差距,藉此嘗試不同的w和b,以最小化損失函數,能最小化代價函數的w與b即為我們所尋找的答案。常見的評估方式有線性回歸,以最小平方法計算ŷ和y的距離當作損失函數,而以二元分類的問題為例,常使用「交叉熵 (cross-entropy loss function)」作為損失函數。
向後傳播(back propagation)
而如何嘗試不同的w和b最小化損失函數,則要運用深度學習的核心演算法「向後傳播(back propagation)」。將向前傳播計算出的輸出當成輸入,利用微積分中的連鎖率以及偏微分,計算損失函數對每一個w和b的偏導數,以圖五的「梯度下降(gradient descent)」來更新w和b的值,算式如公式七所示。其中, α為學習速率,代表每次梯度下降時移動幅度的常數。
另外,在計算各項偏微分時,為了簡化符號會省略偏微分的分子,以圖四的神經網路為例,計算最後一層節點da和dz的偏微分如公式八。
根據公式四,z是w、a和b的函數,利用連鎖率和偏微分對w、a和b取偏微分,如公式九。
完成第三層的向後傳播得到 dw 和 db,以圖五的梯度下降來更新第三層的w及b,接著透過第二層的da計算第二層的dz、dw及 db,以此類推直到第一層,找到每一層隱藏層內的dw和db。另外,從原始的輸入經由向前傳播得到損失函數的結果,再經由向後傳播和梯度下降更新隱藏層的w和b,稱作一次「迭代(iteration)」。
新的w和b再透過第二次向前傳播得到新的損失函數之結果,理想狀況為第二次得到的損失函數結果會比第一次來的低,之後再做第二次向後傳播更新w和b。透過一次又一次的迭代,最小化損失函數,讓輸入的x可以透過此過程找到最佳w和b,使得預測的結果ŷ非常接近實際的y,期待未來只要輸入任意的x,都能有把握其預測出的結果ŷ,會非常接近實際的結果y。
而經過只有一筆資料不斷迭代後找到的w和b,是否真的能很有把握未來任意輸入x所計算出的ŷ都很接近y?直觀上答案是沒有辦法的,只經過一筆資料所迭代出的w和b在此資料上所預測出的結果也許很準確,但若輸入另一筆不同的資料,所得到的損失函數有極大機率變得很高,這類的問題在深度學習有個專有名詞來形容,稱為過度耦合「(overfitting)」,因此在迭代時,不會只輸入一筆資料。假設輸入的資料有m筆,輸入的x則可改寫成一個n×m的矩陣,且在上標以小括號()標上第m筆資料,根據公式三與圖四的神經網路,會輸出一個1×m矩陣的ŷ,損失函數為平均每筆資料的L。每層隱藏層的偏微分如公式十,而.shape為python中呼叫矩陣維度的指令,可幫助確認矩陣相乘時的維度匹配是否正確。
總結建立一個監督式學習神經網路解決二元分類問題的步驟,並以python內的numpy實作如下:
1.設定深度學習的超參數(hyperparameters),如網路深度、隱藏層的節點數量、學習速率、迭代次數,會在下一章談到更多的超參數,以及如何設定適合的超參數。
2.根據設定的深度以及節點數量初始化各個隱藏層內的w和b,注意到若將w初始為0,因為對稱性,使得每一層的輸出都相同,偏微分也相同,導致dw也相同,即無法學習到w,因此先使用隨機亂數初始化w(會於下一章會談到如何更有效率初始化)。
3.建立向前傳播中所使用的三個函數:線性函數、ReLU函數、sigmoid函數。且如公式十所示,在每次迭代中,計算向後傳播時會需要前傳播所計算的結果,因此在向前傳播時,需要建立一個快取列表記錄每次迭代時的a、z、 w和 b 。
4.完成向前傳播。
5.以交叉熵作為損失函數來計算損失值。
6.利用快取列表計算損失函數對各層隱藏層內的a、z、w和 b的偏微分。
7.完成向後傳播得到dw和db。
8.以梯度下降更新w和b。
9.完成模型得到訓練過的w和b。
深度學習,換句話說其實就是更深層更多節點的神經網路,根據不同超參數的設定,會訓練出不同的w和b,而如何挑選超參數? 如何優化學習的結果增加準確率?將會在下一個章節繼續分享。