1. 程式人生 > 其它 >通過正則化避免過擬合

通過正則化避免過擬合

通過正則化避免過擬合。

深度神經網路通常擁有數萬個引數,有時甚至有數百萬個。這個深度神經網路帶來了難以置信的自由度,意味著它們可以擬合各種各樣的複雜資料集。
但是這種巨大的靈活性也使網路易於過擬合訓練集。此時就需要正則化。

\(\ell_1\)\(\ell_2\)正則化

可以使用\(\ell_2\)正則化來約束神經網路連線權重,如果想要稀疏模型(許多權重等於0)則可以使用\(\ell_1\)正則化。以下是使用0.01的正則化銀子將\(\ell_2\)正則化應用於Keras層的連線權重的方法:

layer = keras.layers.Dense(100,
                           activation='elu',
                           kernel_initializer='he_normal',
                           kernel_regularizer=keras.regularizers.l2(0.01))

l2()函式返回一個正則化函式,在訓練過程中的每個步驟都將呼叫該正則化函式來計算正則化損失。然後將其新增到最終損失中。如果需要\(\ell_1\)正則化,可以只使用keras.regularizers.l1()。如果同時需要\(\ell_1\)\(\ell_2\)正則化,需要使用keras.regularizers.l1_l2()(同時指定兩個正則化因子)

將相同的正則化函式應用與網路中的所有層,並在所有隱藏層中使用相同的啟用函式和相同的初始化策略,可以嘗試用迴圈來重構程式碼。另一種選擇是使用Python的functools.partial()函式,該函式可以為帶有一些預設引數值的任何可呼叫物件建立一個小的包裝函式

from functools import partial

RegularizedDense = partial(keras.layers.Dense,
                           activation='elu',
                           kernel_initializer='he_normal',
                           kernel_regularizer=keras.regularizers.l2(0.01))
model = keras.models.Sequential([
    keras.layers.Flatten(input_shape=[28, 28]),
    RegularizedDense(300),
    RegularizedDense(100),
    RegularizedDense(10,
                     activation='softmax',
                     kernel_initializer='glorot_uniform')
])

dropout

在每個訓練步驟中,每個神經元(包括輸入神經元,但始終不包括輸出神經元)都有暫時“刪除”的概率p,這意味著在這個訓練步驟中它被完全忽略,但在下一步中可能處於活動狀態。超引數p成為dropout率,通常設定為10%到50%:在迴圈神經網路中接近20-30%,在卷積神經網路中接近40-50%。訓練後,神經元不再被刪除。

經過dropout訓練過的神經元不能與其相鄰的神經元相互適應,它必須發揮自己最大的作用。它們也不能過於依賴少數輸入神經元,它們必須注意每個輸入神經元。它們對輸入的微小變化不太敏感。最後,可以獲得一個更有魯棒性的網路,該網路具有更好的泛化效能

技術細節:假設p=50%,在這種情況下,在測試過程中,一個神經元被連線到輸入神經元的數量是訓練期間(平均)的兩倍。為了彌補這一事實,需要在訓練後將每個神經元的輸入連線權重乘以0.5.如果不這麼做,每個神經元得到的總輸入訊號大概是網路訓練時的兩倍,表現可能不會很好。更一般而言,訓練後需要將每個輸入連線權重乘以保留概率(1-p)。或者,可以在訓練過程中將每個神經元的輸出除以保留概率(這些替代方法不是完全等效的,但效果一樣好

要使用Keras實現dropout,可以使用keras.layers.Dropout層。在訓練期間,它會隨機丟棄一些輸入(將它們設定為0),然後將其餘輸入除以保留概率。訓練之後,它什麼都不做,只是將輸入傳遞到下一層。下一程式碼使用0.2的dropout率在每個Dense層之前應用dropout正則化:

model=keras.models.Sequential([
    keras.layers.Flatten(input_shape=[28,28]),
    keras.layers.Dropout(rate=0.2),
    keras.layers.Dense(300,activation='elu',kernel_initializer='he_normal'),
    keras.layers.Dropput(rate=0.2),
    keras.layers.Dense(100,activation='elu',kernel_initializer='he_normal'),
    keras.layers.Dropout(rate=0.2),
    keras.layers.Dense(10,activation='sofrmax')
])

蒙特卡羅(MC)Dropout

MC Dropout的實現,可提升之前訓練的dropout模型,而無需重新訓練:

y_probas=np.stack([model(X_test_scaled,training=True)for sample in range(100)])
y_proba=y_probas.mean(axis=0

對測試集進行100個預測,設定training=True來確保Dropout層處於啟用狀態,然後把預測堆疊起來。由於Dropout處於啟用狀態,因此所有預測都將有所不同。想象一下,predict()返回一個矩陣,每個例項為1行,每個類為1列。因為測試集中有10000個例項和10個類,所以這是一個形狀為[10000,10]的矩陣。然後堆疊了100個這樣的矩陣,因為y_probas是一個形狀為[100,10000,10]的陣列,對第一個維度進行平均(axis=0),得到了y_proba,它是形狀為[10000,10]的矩陣,就像通過單個預測得到的一樣。對於具有dropout功能的多個預測進行平均,這使蒙特卡羅估計通常比關閉dropout的單個預測結果更可靠。

最大範數正則化

對於神經網路而言,另一種流行的正則化技術稱為最大範數正則化,對於每個神經元,它會限制傳入連線的權重\(w\),使得\(||w||_2\le r\),其中r是最大範數超引數,\(||\bullet||_2\)\(\ell_2\)範數

最大範數正則化不會把正則化損失新增到總體損失函式中。取而代之的是,通常在每個訓練步驟後通過計算\(||w||_2\)來實現,如果有需要,重新縮放\(w(w\gets\frac{||w||_2}{r})\)

減小r會增加正則化的數量,並有助於減少過擬合。最大範數正則化還可以幫助環節不穩定的梯度問題(如果未使用“批量梯度歸一化”)

要在Keras中使用最大範數正則化,需要將每個隱藏層的kernel_constraint引數設定為具有適當最大值的max_norm()約束,如下所示:

keras.layers.Dense(100,activation='elu',kernel_initializer='he_normal',
                  kernel_constraint=keras.constraints.max_norm(1.))

每次訓練迭代後,fit()方法會呼叫由max_norm()返回的物件,將層的權重傳遞給該物件,並獲得返回的縮放權重,然後替換該層的權重。還可以自定義約束函式,並將其用作kernel_constraint。還可以設定bias_constraint引數來約束偏置項。

max_norm()函式的引數axis預設為0。Dense層通常具有形狀為[輸入數量,神經元數量]的權重,因此使用axis=0意味著最大範數約束將獨立作用與每個神經元的權重向量。如果最大範數與卷積層一起使用,要確保正確設定max_norm()約束的axis引數

總結

預設的DNN配置

超引數 預設值
核心初始化 He 初始化
啟用函式 ELU
歸一化 淺層網路:不需要;深度網路:批量歸一化
正則化 提前停止(如果需要,可加\(\ell_2\)
優化器 動量優化(或RMSProp或Nadam)
學習率排程 1週期

用於自歸一化網路的DNN配置

超引數 預設值
核心初始化 LeCun 初始化
啟用函式 SELU
歸一化 不需要(自歸一化)
正則化 如果需要:Alpha dropout
優化器 動量優化(或RMSProp或Nadam)
學習率排程 1週期