寫給 Web 開發者的深度學習教程 - 資料標準化 & 引數初始化

誠身發表於2018-01-22

上一篇文章中,我們介紹瞭如何將以陣列形式儲存的資料轉換為適合進行深度學習模型訓練的大型矩陣,以及矩陣的相關運算。向量化是一切矩陣運算的基礎,從編碼的角度來講,可以幫助模型在每一次訓練時省下一次與樣本數量相等的 for 迴圈的計算量,即模型可以處理的資料結構將由一維陣列升級為二維陣列(矩陣)。

統計學與機器學習

TensorflowPyTorch 等機器學習框架逐漸成為主流的今天,再回過頭去談論統計學好像已經有些過時了。正如現在資料崗位的從業者更願意把自己稱為資料科學家而不是資料分析師那樣,統計學好像已經在強大的機器學習面前敗下陣來。但事實真的是這樣嗎?對於所有的資料問題,機器學習都是一種比統計學更為優秀的選擇嗎?

在回答這個問題之前,讓我們先來回答一個更為基礎的問題,對於一個分類問題來說,是資料集越小越好分類,還是資料集越大越好分類?

從常識的角度來講,當然是資料集越小越好分類,因為假設極端情況下只有兩個樣本,那麼一定能在空間中劃出一條線將二者分開,但是如果有幾萬個,甚至幾百萬個樣本,好像就很難找出這樣一條分割線了。

但另一方面,許多機器學習結合大資料的優秀案例就擺在我們面前,它們都證明了只有資料樣本足夠大,才能夠訓練出一個較為準確的模型。

讓我們以上一篇專欄中提到的 Iris 資料集為例。

iris

從上圖中我們可以看出,setosa 品種和 versicolor,virginica 品種之間的差別非常大,而後兩個品種之間相對來講就顯得非常難以區分。

假設我們現在想要訓練一個深度學習模型來判斷一朵花是不是 versicolor 品種,你會發現無論如何調整學習率,訓練次數,隱藏層神經元個數,都很難得到一個收斂的結果,常見的損失函式的影象如下圖所示:

cost

學習率:0.01,訓練次數:1000,隱藏層神經元:10

這證明了在 Iris 資料集的原始空間中,versicolor 與 virginica 幾乎是不可分的(有重疊的部分),也就是說在原始空間中,無論你劃一條多麼複雜的曲線都無法做到一邊是 versicolor,另一邊是 virginica。

面對這樣的結果,當初筆者在使用 deeplearning-js 訓練第一個模型時內心是崩潰的,無數次地懷疑是程式碼某個地方出錯導致了模型不收斂。

直到後來與一位資料分析領域的朋友聊天時,才瞭解到原來神經網路在小樣本量的資料集上表現並不好。因為神經網路演算法跳過了傳統統計方法中特徵選擇的過程,直接暴力地在樣本空間進行搜尋,試圖找出一條曲線將樣本分類。這在大樣本量,超高緯度的資料集上,效果是非常好的,因為這些資料集本身資訊量就非常豐富,簡單來講這樣的資料集在超高維空間中樣本是可分的。

再舉一個可能不太恰當的生活中的例子。要將兩百萬個蘋果分成兩類,如果你能準確地捕捉到這兩百萬個蘋果的所有資訊,那麼你一定能夠利用所有的這些資訊,找到一些特徵將這兩百萬個蘋果分類,換句話說想要找到兩百萬個非常相似的蘋果幾乎是不可能的,所以它們一定是可分的。但如果是將二十個蘋果進行分類,那麼最快速的方法是找一個蘋果專家(領域知識),從某幾個特定的維度上對這二十個蘋果進行分類,但也有可能在極端情況下,這二十個蘋果就是非常相似導致完全不可分。

上述例子中的蘋果專家就代表著傳統的統計學,統計學中有許多如主成分分析(PCA)等幫助資料降維的方法。對於傳統統計學來說,高緯度的資料集是無法處理的,光是資料降緯的過程就十分漫長,而且在資料降緯的過程中,還會丟失掉許多原始資料集中包含的資訊。

機器學習則恰好相反,藉助於 GPU 超高的運算效率,它試圖在一個超高維空間捕捉所有可利用的資訊,並最終擬合出一個可用的模型。於是我們也就不難理解,為什麼機器學習在處理非結構化資料(如圖片,文字,語音等)方面表現比結構化資料更為優秀,其根本原因就是這些非結構化資料本身攜帶的資訊量就非常豐富。如一張 256*256 畫素的圖片,其本身就是一個 65,536 維的資料,更別提現在一個普通手機就可以拍出動輒幾千乘以幾千畫素的照片了。

到這裡,我們應該可以對於開始提出的那個問題,即資料集越小越好分類,還是資料集越大越好分類,給出一個較為準確的答案,那就是在你的運算能力範圍之內,一定是資料集越大越好分類,每個樣本的維度越多越好分類。

資料標準化

在瞭解了統計學與機器學習的異同之後,我們能不能從統計學中借鑑一些優秀的資料處理方法來優化深度學習模型呢?當然可以。

資料標準化就是其中一個非常有效的方法,目前 deeplearning-js 支援兩種資料標準化的方式:

Feature scaling:

equation1

Standard score:

equation2

資料標準化的意義又是什麼呢?我們來看下圖:

standard

簡單來說,資料標準化就是在不瞭解資料各個維度之間的關係時,強行將各個維度拉到相同權重的一種統計學方法。從空間變換的角度來講,資料標準化可以將扁平空間變換為類圓形空間,不僅可以消除不同維度的權重對目標函式的影響,還可以加快後續梯度下降的速度,避免其在某一巨大的平面上以非常緩慢的速度下降。

讓我們來對比一下未開啟資料標準化和開啟資料標準化的 Iris 資料集在 deeplearning-js 中的表現:

未開啟資料標準化:

cost2

未開啟資料標準化,學習率:0.01,訓練次數:500,隱藏層神經元:200

模型將所有樣本都判定為不是 versicolor,即完全無法區分三種類別。

開啟資料標準化:

cost3

開啟資料標準化,學習率:0.01,訓練次數:500,隱藏層神經元:200

在 150 個樣本中,模型可以正確判斷 142 個,即只有小部分的 versicolor 與 virginica 仍無法被正確區分。我們可以通過增加訓練次數的方式去繼續逼近 100% 的準確率,但從第一張 Iris 資料集的分佈圖我們可以看出,一部分 versicolor 與 virginica 的樣本幾乎是重合的,所以即使在進行了空間變換後,想要區分他們的難度依然很大。

我們使用的隱藏層神經元個數也證明了這點,想要用數量很少的神經元個數去區分 versicolor 與 virginica 幾乎是不可能的,這也說明即使在變換後的四維空間中也要劃一條非常複雜的曲線才可以將這兩個品種區分開來。

引數初始化

在對資料集進行了預處理之後,讓我們正式開始搭建第一個深度學習模型。

如下圖所示,深度學習模型就是由這樣一層一層的神經網路構成的:

nn

用公式來表示:

equation3

以 Iris 資料集為例,我們的輸入層是一個 [4, 150] 的矩陣,那麼第一個隱藏層的權重值矩陣 W 就需要是一個 [x1, 4] 的矩陣,使得兩個矩陣可以進行點乘計算,這裡的 x1 就是第一個隱藏層的神經元個數。經過第一個層之後,輸出變為了一個 [x1, 150] 的矩陣,也就是說下一個隱藏層的權重矩陣形狀應當是 [x2, x1],列數與前一層相同,行數取決於這一層的神經元個數。以此類推,因為每一層隱藏層的列數都等於前一層的行數,所以我們在初始化引數時就只需要輸入當前層的神經元個數即可。

另一方面,因為偏置 b 與 W·A 之間是加法計算,那麼就意味著 b 的形狀需要與 W·A 相同。

從幾何空間的角度來說,如果 W 是空間中一條複雜曲線, b 則可以幫助這條曲線進行平移,使得最終的曲線不必要必須經過原點,從而對資料集進行更準確的擬合。

以 deeplearning-js 中 initializeParameters API 為例:

const initialParameters = initializeParameters([{
  size: trainSet.input.shape[0], // 輸入層神經元個數等於原始輸入資料集的行數,即輸入資料維度數
}, {
  size: 10, // 第一個隱藏層神經元個數
  activationFunc: 'relu', // 第一個隱藏層啟用函式
}, {
  ... // 第 N 個隱藏層
}, {
  size: trainSet.output.shape[0], // 輸出層神經元個數等於原始輸出資料集的行數,即輸出資料維度數
  activationFunc: 'sigmoid', // 輸出層啟用函式
}],
  0,      // 初始化權重值時使用的平均數,預設為 0
  1,      // 初始化權重值時使用的方差,預設為 1
  0.01,   // 初始化權重值時使用的比例,預設為 1,建議使用 0.01 防止數值膨脹得過快
);

/*
initialParameters = {
  W1: Array2D,
  b1: Array2D,
  W2: Array2D,
  b2: Array2D,
  ...
  Wl: Array2D, // 第 l 層
  bl: Array2D, // 第 l 層
}
*/複製程式碼

小結

在瞭解瞭如何對資料進行必要的預處理並根據需要設計深度學習模型結構後,是時候將資料輸入到我們的模型中,讓模型真正運轉起來了。在下一篇文章中,我們將講到正向傳播,以及隱藏層常用的啟用函式,敬請期待。


相關文章