1.17. 神經網路模型 (監督式)#
警告
此實作不適用於大規模應用。特別是,scikit-learn 不提供 GPU 支援。對於速度更快、基於 GPU 的實作,以及提供更多彈性來建構深度學習架構的框架,請參閱相關專案。
1.17.1. 多層感知器#
多層感知器 (MLP) 是一種監督式學習演算法,透過在資料集上訓練來學習函數 \(f: R^m \rightarrow R^o\),其中 \(m\) 是輸入的維度數,而 \(o\) 是輸出的維度數。給定一組特徵 \(X = {x_1, x_2, ..., x_m}\) 和目標 \(y\),它可以學習用於分類或迴歸的非線性函數逼近器。它與邏輯迴歸不同,在輸入和輸出層之間,可以有一層或多層非線性層,稱為隱藏層。圖 1 顯示具有純量輸出的單個隱藏層 MLP。

圖 1:單個隱藏層 MLP。#
最左邊的層,稱為輸入層,由一組神經元 \(\{x_i | x_1, x_2, ..., x_m\}\) 組成,表示輸入特徵。隱藏層中的每個神經元都會以前一層的值進行加權線性加總 \(w_1x_1 + w_2x_2 + ... + w_mx_m\),然後再進行非線性啟動函數 \(g(\cdot):R \rightarrow R\) (例如雙曲正切函數)。輸出層接收來自最後一個隱藏層的值,並將它們轉換為輸出值。
該模組包含公開屬性 coefs_
和 intercepts_
。coefs_
是權重矩陣的列表,其中索引 \(i\) 處的權重矩陣表示層 \(i\) 和層 \(i+1\) 之間的權重。intercepts_
是偏差向量的列表,其中索引 \(i\) 處的向量表示新增至層 \(i+1\) 的偏差值。
1.17.2. 分類#
類別 MLPClassifier
實作使用反向傳播訓練的多層感知器 (MLP) 演算法。
MLP 在兩個陣列上進行訓練:大小為 (n_samples, n_features) 的陣列 X,其中包含表示為浮點特徵向量的訓練樣本;以及大小為 (n_samples,) 的陣列 y,其中包含訓練樣本的目標值 (類別標籤)
>>> from sklearn.neural_network import MLPClassifier
>>> X = [[0., 0.], [1., 1.]]
>>> y = [0, 1]
>>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
... hidden_layer_sizes=(5, 2), random_state=1)
...
>>> clf.fit(X, y)
MLPClassifier(alpha=1e-05, hidden_layer_sizes=(5, 2), random_state=1,
solver='lbfgs')
在擬合 (訓練) 後,模型可以預測新樣本的標籤
>>> clf.predict([[2., 2.], [-1., -2.]])
array([1, 0])
MLP 可以將非線性模型擬合到訓練資料。clf.coefs_
包含構成模型參數的權重矩陣
>>> [coef.shape for coef in clf.coefs_]
[(2, 5), (5, 2), (2, 1)]
目前,MLPClassifier
僅支援交叉熵損失函數,該函數允許透過執行 predict_proba
方法來估計機率。
MLP 使用反向傳播進行訓練。更準確地說,它使用某種形式的梯度下降進行訓練,並使用反向傳播來計算梯度。對於分類,它會最小化交叉熵損失函數,從而為每個樣本 \(x\) 提供機率估計的向量 \(P(y|x)\)
>>> clf.predict_proba([[2., 2.], [1., 2.]])
array([[1.967...e-04, 9.998...-01],
[1.967...e-04, 9.998...-01]])
MLPClassifier
透過套用Softmax 作為輸出函數來支援多類別分類。
此外,該模型支援多標籤分類,其中一個樣本可以屬於多個類別。對於每個類別,原始輸出會通過邏輯函數。大於或等於 0.5
的值會四捨五入為 1
,否則四捨五入為 0
。對於樣本的預測輸出,值為 1
的索引代表該樣本的指定類別
>>> X = [[0., 0.], [1., 1.]]
>>> y = [[0, 1], [1, 1]]
>>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
... hidden_layer_sizes=(15,), random_state=1)
...
>>> clf.fit(X, y)
MLPClassifier(alpha=1e-05, hidden_layer_sizes=(15,), random_state=1,
solver='lbfgs')
>>> clf.predict([[1., 2.]])
array([[1, 1]])
>>> clf.predict([[0., 0.]])
array([[0, 1]])
請參閱下方的範例和 MLPClassifier.fit
的文件字串,以取得更多資訊。
範例
請參閱MNIST 上 MLP 權重的可視化,以取得已訓練權重的可視化表示。
1.17.3. 迴歸#
類別 MLPRegressor
實作多層感知器 (MLP),該感知器使用反向傳播進行訓練,並且在輸出層中沒有啟動函數,這也可以看作是使用識別函數作為啟動函數。因此,它使用平方誤差作為損失函數,並且輸出是一組連續的值。
MLPRegressor
也支援多輸出迴歸,其中一個樣本可以有多個目標。
1.17.4. 正規化#
MLPRegressor
和 MLPClassifier
都使用參數 alpha
進行正規化 (L2 正規化) 項,該項透過懲罰具有較大值的權重來協助避免過度擬合。以下繪圖顯示隨著 alpha 值的變化而變化的決策函數。

請參閱下方的範例以取得更多資訊。
範例
1.17.5. 演算法#
MLP 使用隨機梯度下降法 (Stochastic Gradient Descent)、Adam 或 L-BFGS 進行訓練。隨機梯度下降法 (SGD) 使用損失函數相對於需要調整的參數的梯度來更新參數,即:
其中 \(\eta\) 是學習率,它控制參數空間搜尋中的步長。\(Loss\) 是網路使用的損失函數。
更多詳細資訊請參考 SGD 的文件。
Adam 在某種意義上類似於 SGD,它是一種隨機最佳化器,但它可以基於較低階動量的自適應估計自動調整更新參數的量。
使用 SGD 或 Adam 時,訓練支援線上學習和迷你批次學習。
L-BFGS 是一種求解器,它近似黑塞矩陣,該矩陣表示函數的二階偏導數。此外,它會近似黑塞矩陣的逆矩陣以執行參數更新。該實作使用 Scipy 版本的 L-BFGS。
如果選擇的求解器是 ‘L-BFGS’,則訓練不支援線上學習或迷你批次學習。
1.17.6. 複雜度#
假設有 \(n\) 個訓練樣本、\(m\) 個特徵、\(k\) 個隱藏層,每個隱藏層包含 \(h\) 個神經元(為了簡化),以及 \(o\) 個輸出神經元。反向傳播的時間複雜度為 \(O(i \cdot n \cdot (m \cdot h + (k - 1) \cdot h \cdot h + h \cdot o))\),其中 \(i\) 是迭代次數。由於反向傳播的時間複雜度很高,建議從較少數量的隱藏神經元和較少的隱藏層開始進行訓練。
數學公式#
給定一組訓練範例 \((x_1, y_1), (x_2, y_2), \ldots, (x_n, y_n)\),其中 \(x_i \in \mathbf{R}^n\) 且 \(y_i \in \{0, 1\}\),一個隱藏層和一個隱藏神經元的 MLP 學習函數 \(f(x) = W_2 g(W_1^T x + b_1) + b_2\),其中 \(W_1 \in \mathbf{R}^m\) 且 \(W_2, b_1, b_2 \in \mathbf{R}\) 是模型參數。\(W_1, W_2\) 分別表示輸入層和隱藏層的權重;而 \(b_1, b_2\) 分別表示加到隱藏層和輸出層的偏差。\(g(\cdot) : R \rightarrow R\) 是激活函數,預設設定為雙曲正切函數。其表示式如下:
對於二元分類,\(f(x)\) 會通過邏輯函數 \(g(z)=1/(1+e^{-z})\) 以獲得介於 0 和 1 之間的輸出值。閾值設定為 0.5,將輸出大於或等於 0.5 的樣本分配到正類,其餘分配到負類。
如果有兩個以上的類別,\(f(x)\) 本身會是一個大小為 (n_classes,) 的向量。它不會通過邏輯函數,而是通過 softmax 函數,其寫法如下:
其中 \(z_i\) 表示 softmax 輸入的第 \(i\) 個元素,對應於類別 \(i\),而 \(K\) 是類別的數量。結果是一個向量,其中包含樣本 \(x\) 屬於每個類別的機率。輸出是具有最高機率的類別。
在迴歸中,輸出仍為 \(f(x)\);因此,輸出激活函數只是單位函數。
MLP 根據問題類型使用不同的損失函數。分類的損失函數是平均交叉熵,在二元情況下,其表示式如下:
其中 \(\alpha ||W||_2^2\) 是 L2 正規化項(又稱懲罰項),用於懲罰複雜模型;而 \(\alpha > 0\) 是一個非負超參數,控制懲罰的大小。
對於迴歸,MLP 使用均方誤差損失函數;其表示式如下:
從初始隨機權重開始,多層感知器 (MLP) 通過重複更新這些權重來最小化損失函數。計算損失後,反向傳遞會將損失從輸出層傳播到先前的層,為每個權重參數提供一個更新值,旨在減少損失。
在梯度下降中,計算損失相對於權重的梯度 \(\nabla Loss_{W}\),並從 \(W\) 中減去。更正式地說,可以表示為:
其中 \(i\) 是迭代步驟,而 \(\epsilon\) 是學習率,其值大於 0。
當演算法達到預設的最大迭代次數,或者當損失的改善低於某個很小的數值時,演算法就會停止。
1.17.7. 實際使用上的建議#
多層感知器對特徵縮放很敏感,因此強烈建議縮放您的資料。例如,將輸入向量 X 上的每個屬性縮放到 [0, 1] 或 [-1, +1],或者將其標準化為平均值為 0,變異數為 1。請注意,您必須對測試集應用 *相同* 的縮放比例,才能獲得有意義的結果。您可以使用
StandardScaler
進行標準化。>>> from sklearn.preprocessing import StandardScaler >>> scaler = StandardScaler() >>> # Don't cheat - fit only on training data >>> scaler.fit(X_train) >>> X_train = scaler.transform(X_train) >>> # apply same transformation to test data >>> X_test = scaler.transform(X_test)
另一種替代且推薦的方法是在
Pipeline
中使用StandardScaler
。尋找合理的正規化參數 \(\alpha\) 的最佳方法是使用
GridSearchCV
,通常在10.0 ** -np.arange(1, 7)
的範圍內。根據經驗,我們觀察到
L-BFGS
在小型資料集上收斂得更快,並獲得更好的解決方案。然而,對於相對較大的資料集,Adam
非常穩健。它通常會快速收斂並提供相當不錯的效能。另一方面,如果正確調整學習率,具有動量或 Nesterov 動量的SGD
可以表現得比這兩種演算法更好。
1.17.8. 使用 warm_start 進行更多控制#
如果您想要對 SGD 中的停止條件或學習率進行更多控制,或想要進行其他監控,則使用 warm_start=True
和 max_iter=1
並自行迭代可能會有所幫助。
>>> X = [[0., 0.], [1., 1.]]
>>> y = [0, 1]
>>> clf = MLPClassifier(hidden_layer_sizes=(15,), random_state=1, max_iter=1, warm_start=True)
>>> for i in range(10):
... clf.fit(X, y)
... # additional monitoring / inspection
MLPClassifier(...
參考資料#
「透過反向傳播誤差學習表示法。」Rumelhart, David E.、Geoffrey E. Hinton 和 Ronald J. Williams。
「隨機梯度下降法」L. Bottou - 網站,2010 年。
「反向傳播」Andrew Ng、Jiquan Ngiam、Chuan Yu Foo、Yifan Mai、Caroline Suen - 網站,2011 年。
「高效的反向傳播」Y. LeCun、L. Bottou、G. Orr、K. Müller - 於神經網路:交易技巧,1998 年。
「Adam:一種隨機最佳化方法。」Kingma, Diederik 和 Jimmy Ba (2014)