Dropout正則化是最簡單的神經網絡正則化方法。其原理很是簡單粗暴:任意丟棄神經網絡層中的輸入,該層能夠是數據樣本中的輸入變量或來自先前層的激活。它可以模擬具備大量不一樣網絡結構的神經網絡,而且反過來使網絡中的節點更具備魯棒性。html
閱讀完本文,你就學會了在Keras框架中,如何將深度學習神經網絡Dropout正則化添加到深度學習神經網絡模型裏,具體內容以下:如何使用Keras API建立Dropout層;如何使用Keras API將Dropout正則化添加到MLP、CNN和RNN層;在現有模型中,如何使用Dropout正則化減小過擬合。算法
Keras中的Dopout正則化網絡
在Keras深度學習框架中,咱們可使用Dopout正則化,其最簡單的Dopout形式是Dropout核心層。app
在建立Dopout正則化時,能夠將 dropout rate的設爲某一固定值,當dropout rate=0.8時,實際上,保留機率爲0.2。下面的例子中,dropout rate=0.5。框架
layer = Dropout(0.5)
Dropout層dom
將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正則化案例
在本節中,咱們將演示如何使用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.《使用卷積神經網絡進行高效的對象本地化,2015》
2.《遞歸神經網絡中的理論Dropout應用,2016》
博文
API
3.Keras Convolutional Layers API
5.sklearn.datasets.make_circles API
總結
閱讀完本文,你已經瞭解瞭如何將深度學習正則化添加到深度學習神經網絡模型的API中。具體來講,有如下幾個內容:
1.如何使用Keras API建立Dropout層。
2.如何使用Keras API將Dropout正則化添加到MLP、CNN和RNN層。
3.如何向現有模型中添加Dropout正則化,以此減小過擬合。