Dropout正則化是最簡單的神經網絡正則化方法。其原理非常簡單粗暴:任意丢棄神經網絡層中的輸入,該層可以是資料樣本中的輸入變量或來自先前層的激活。它能夠模拟具有大量不同網絡結構的神經網絡,并且反過來使網絡中的節點更具有魯棒性。
閱讀完本文,你就學會了在Keras架構中,如何将深度學習神經網絡Dropout正則化添加到深度學習神經網絡模型裡,具體内容如下:如何使用Keras API建立Dropout層;如何使用Keras API将Dropout正則化添加到MLP、CNN和RNN層;在現有模型中,如何使用Dropout正則化減少過拟合。

在Keras深度學習架構中,我們可以使用Dopout正則化,其最簡單的Dopout形式是Dropout核心層。
在建立Dopout正則化時,可以将 dropout rate的設為某一固定值,當dropout rate=0.8時,實際上,保留機率為0.2。下面的例子中,dropout rate=0.5。
layer = Dropout(0.5)
Dropout 層 将Dropout層添加到模型的現有層和之前的輸出層之間,神經網絡将這些輸出回報到後續層中。用dense()方法指定兩個全連接配接網絡層:
...
model.append(Dense(32))
model.append(Dense(32))
...
在這兩層中間插入一個dropout層,這樣一來,第一層的輸出将對第二層實作Dropout正則化,後續層與此類似。現在,我們對第二層實作了Dropout正則化。
...
model.append(Dense(32))
model.append(Dropout(0.5))
model.append(Dense(32))
...
Dropout也可用于可見層,如神經網絡的輸入。在這種情況下,就要把Dropout層作為網絡的第一層,并将input_shape參數添加到層中,來制定預期輸入。
...
model.add(Dropout(0.5, input_shape=(2,)))
...
下面,我們來看看Dropout正則化如何與常見的網絡類型一起使用。
MLP Dropout在兩個全連接配接層之間添加Dropout正則化,代碼如下所示:
# example of dropout between fully connected layers
from keras.layers import Dense
from keras.layers import Dropout
...
model.add(Dense(32))
model.add(Dropout(0.5))
model.add(Dense(1))
...
CNN Dropout 我們可以在卷積層和池化層後使用Dropout正則化。一般來說,Dropout僅在池化層後使用。
# example of dropout for a CNN
from keras.layers import Dense
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Dropout
...
model.add(Conv2D(32, (3,3)))
model.add(Conv2D(32, (3,3)))
model.add(MaxPooling2D())
model.add(Dropout(0.5))
model.add(Dense(1))
...
在這種情況下,我們要将Dropout應用于特征圖的每個單元中。
在卷積神經網絡中使用Dropout正則化的另一個方法是,将卷積層中的整個特征圖都丢棄,然後在池化期間也不再使用。這種方法稱為空間丢棄,即Spatial Dropout。
“我們建立了一個新的Dropout正則化方法,我們将其稱為Spatial Dropout。在這個方法中,我們将Dropout值擴充到整個特征映射中。”
——《
使用卷積神經網絡有效的進行對象本地化,2015》
在Keras中,通過SpatialDropout2D層提供Spatial Dropout正則化。
# example of spatial dropout for a CNN
from keras.layers import Dense
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import SpatialDropout2D
...
model.add(Conv2D(32, (3,3)))
model.add(Conv2D(32, (3,3)))
model.add(SpatialDropout2D(0.5))
model.add(MaxPooling2D())
model.add(Dense(1))
...
RNN Dropout 我們在LSTM循環層和全連接配接層之間使用Dropout正則化,代碼如下所示:
# example of dropout between LSTM and fully connected layers
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
...
model.add(LSTM(32))
model.add(Dropout(0.5))
model.add(Dense(1))
...
在這裡,将Dropout應用于LSTM層的32個輸出中,這樣,LSTM層就作為全連接配接層的輸入。
還有一種方法可以将Dropout與LSTM之類的循環層一起使用。LSTM可以将相同的Dropout掩碼用于所有的輸入中。這個方法也可用于跨樣本時間步長的循環輸入連接配接。這種使用遞歸模型進行Dropout正則化則稱為變分循環神經網絡(Variational RNN)。
“變分循環神經網絡在每個時間步長使用相同的Dropout掩碼,包括循環層。這與在RNN中實作Dropout正則化一樣,在每個時間步長丢棄相同的神經網絡單元,并且随意的丢棄輸入、輸出和循環連接配接。這和現有的技術形成對比,在現有的技術中,不同的神經網絡單元将在不同的時間步長被丢棄,并且不會對全連接配接層進行丢棄。”
循環神經網絡中Dropout的基礎應用,2016》
Keras通過循環層上的兩個參數來支援變分神經網絡(輸入和循環輸入樣本時間步長的一緻性丢棄),這稱為 輸入“Dropout”和循環輸入的“recurrent_dropout”。
# example of dropout between LSTM and fully connected layers
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
...
model.add(LSTM(32))
model.add(Dropout(0.5))
model.add(Dense(1))
...
正則化案例 在本節中,我們将示範如何使用Dropout正則化來減少MLP在簡單二進制分類問題上的過拟合。在這裡,我們提供了一個在神經網絡上應用Dropout正則化的模闆,你也可以将其用于分類和回歸問題。
二進制分類問題在這裡,我們使用一個标準的二進制分類問題,即定義兩個二維同心圓,每個類為一個圓。
每個觀測值都有兩個輸入變量,它們具有相同的比例,類輸出值為0或1。這個資料集就是 “圓”資料集。
我們可以使用make_circles()方法生成觀測結果。我們為資料添加噪聲和随機數生成器,以防每次運作代碼時使用相同的樣本。
# generate 2d classification dataset
X, y = make_circles(n_samples=100, noise=0.1, random_state=1)
我們可以用x和y坐标繪制一個資料集,并将觀察到的顔色定義為類值。生成和繪制資料集的代碼如下:
# generate two circles dataset
from sklearn.datasets import make_circles
from matplotlib import pyplot
from pandas import DataFrame
# generate 2d classification dataset
X, y = make_circles(n_samples=100, noise=0.1, random_state=1)
# scatter plot, dots colored by class value
df = DataFrame(dict(x=X[:,0], y=X[:,1], label=y))
colors = {0:'red', 1:'blue'}
fig, ax = pyplot.subplots()
grouped = df.groupby('label')
for key, group in grouped:
group.plot(ax=ax, kind='scatter', x='x', y='y', label=key, color=colors[key])
pyplot.show()
運作以上代碼,會建立一個散點圖,散點圖展示每個類中觀察到的同心圓形狀。我們可以看到,因為噪聲,圓圈并不明顯。
這是一個特别好的測試問題,因為類不可能用一條直線表示,比如它不是線性可微分的,在這種情況下,就需要使用非線性方法來解決,比如神經網絡。
在這裡,我們隻生成了100個樣本,這對于神經網絡來說,樣本是相當少了。但是它提供了訓練資料集的過拟合現象,并且在測試資料及上的誤差更大:這是使用正則化的一個特别好的例子。除此之外,這個樣本集中有噪聲,這就使神經網絡模型有機會學習不一緻樣本的各個方面。
多層感覺器的過拟合我們可以建立一個MLP模型來解決這個二進制分類問題。
該模型将具有一個隐藏層,它的節點比解決該問題所需節點要多得多,進而産生過拟合。另外,我們訓練模型的時間也大大超過正常訓練模型所需要的時間。
在定義模型之前,我們将資料集拆分為訓練集和測試集:30個訓練資料來訓練模型和70個測試資料來評估拟合模型性能。
# generate 2d classification dataset
X, y = make_circles(n_samples=100, noise=0.1, random_state=1)
# split into train and test
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
接下來,我們可以定義模型。
在隐藏層中使用500個節點和矯正過得線性激活函數;在輸出層中使用S型激活函數預測類的值(0或1)。
該模型使用二進制交叉熵損失函數進行優化,這個函數适用于二進制分類問題和梯度下降到有效Adam問題。
# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
将訓練資料訓練4000次,預設每次訓練次數為32。 然後用測試資料集驗證該模型性能,代碼如下。
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)
測試的方法如下。
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
最後,在每次訓練的時候繪制模型的性能。
如果模型在訓練資料集時的确是過拟合,那麼我們訓練集上的準确度線圖更加準确,并且準确度随着模型學習訓練資料集中的統計噪聲而再次下降。
# plot history
pyplot.plot(history.history['acc'], label='train')
pyplot.plot(history.history['val_acc'], label='test')
pyplot.legend()
pyplot.show()
将以上所有代碼組合起來,如下所示。
# mlp overfit on the two circles dataset
from sklearn.datasets import make_circles
from keras.layers import Dense
from keras.models import Sequential
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_circles(n_samples=100, noise=0.1, random_state=1)
# split into train and test
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot history
pyplot.plot(history.history['acc'], label='train')
pyplot.plot(history.history['val_acc'], label='test')
pyplot.legend()
pyplot.show()
運作以上代碼,我們可以看到模型在訓練和測試資料集上的性能:模型在訓練資料集上的性能優于測試資料集,這是過度拟合的一個可能标志。
鑒于神經網絡和訓練算法的随機性,模型的測試結果可能會有所不同。由于該模型嚴重過拟合,該模型在同一資料集上運作的結果差異并不會很大。
Train: 1.000, Test: 0.757
下圖為模型在訓練和測試集上的精度圖,我們可以看到過拟合模型的預期性能,其中測試精度增加到一定值以後,再次開始減小。
使用Dropout正則化減少MLP過拟合
我們使用Dropout正則化更新這個示例,即在隐藏層和輸出層之間插入一個新的Dropout層來實作。在這裡,指定Dropout rate=0.4。
# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
下面列出了隐藏層後添加了dropout層的完整更新示例。
# mlp with dropout on the two circles dataset
from sklearn.datasets import make_circles
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_circles(n_samples=100, noise=0.1, random_state=1)
# split into train and test
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot history
pyplot.plot(history.history['acc'], label='train')
pyplot.plot(history.history['val_acc'], label='test')
pyplot.legend()
pyplot.show()
運作以上代碼,檢視模型在訓練和測試集上的性能。你所得到的結果可能會有所不同,在這種情況下,該模型具有較高的方差。在這裡,我們可以看到,Dropout導緻訓練集的準确度有所下降,從100%降至96%,而測試集的準确度從75%提高到81%。
Train: 0.967, Test: 0.814
從這裡我們可以看出,該模型已經不再适合訓練資料集了。
盡管使用Dropout正則化時會産生很多噪音,訓練資料集和測試資料集的模型精度持續增加。
在後續學習中,你可以進一步探索以下這些問題:
1.輸入Dropout。在輸入變量上使用Dropout正則化,更新示例,并比較結果。
2.權重限制。在隐藏層添加max-norm權重限制,更新示例,并比較結果。
3.反複評估。更新示例,重複評估過拟合和Dropout模型,總結并比較平均結果。
4.網格搜尋率。建立Dropout機率的網格搜尋,并報告Dropout rate和測試資料集準确度二者之間的關系。
拓展閱讀 論文1.《
使用卷積神經網絡進行高效的對象本地化2.《
遞歸神經網絡中的理論Dropout應用 博文1.
基于Keras深度學習模型中的Dropout正則化2.
如何使用LSTM網絡的Dropout進行時間序列預測 API Keras Regularizers Keras Core Layers3.
Convolutional Layers API4.
Recurrent Layers API5.
sklearn.datasets.make_circles 總結閱讀完本文,你已經了解了如何将深度學習正則化添加到深度學習神經網絡模型的API中。具體來說,有以下幾個内容:
1.如何使用Keras API建立Dropout層。
2.如何使用Keras API将Dropout正則化添加到MLP、CNN和RNN層。
3.如何向現有模型中添加Dropout正則化,以此減少過拟合。
本文由北郵
@愛可可-愛生活老師推薦,
阿裡雲雲栖社群組織翻譯。
文章原标題《How to Reduce Overfitting With Dropout Regularization in Keras》
譯者:Mags,審校:袁虎。
文章為簡譯,更為詳細的内容,請檢視
原文