基於Keras/Python的深度學習模型Dropout正則項

周建丁發表於2016-07-05

原文:Dropout Regularization in Deep Learning Models With Keras
作者:Jason Brownlee
翻譯:趙屹華
責編:周建丁(投稿請聯絡zhoujd@csdn.net)

dropout技術是神經網路和深度學習模型的一種簡單而有效的正則化方式。

本文將向你介紹dropout正則化技術,並且教你如何在Keras中用Python將其應用於你的模型。

讀完本文之後,你將瞭解:

  • dropout正則化的原理
  • 如何在輸入層使用dropout
  • 如何在隱藏層使用dropout
  • 如何針對具體問題對dropout調優

神經網路的Dropout正則化

Dropout是Srivastava等人在2014年的一篇論文中提出的一種針對神經網路模型的正則化方法 Dropout: A Simple Way to Prevent Neural Networks from Overfitting

Dropout的做法是在訓練過程中隨機地忽略一些神經元。這些神經元被隨機地“拋棄”了。也就是說它們在正向傳播過程中對於下游神經元的貢獻效果暫時消失了,反向傳播時該神經元也不會有任何權重的更新。

隨著神經網路模型不斷地學習,神經元的權值會與整個網路的上下文相匹配。神經元的權重針對某些特徵進行調優,具有一些特殊化。周圍的神經元則會依賴於這種特殊化,如果過於特殊化,模型會因為對訓練資料過擬合而變得脆弱不堪。神經元在訓練過程中的這種依賴於上下文的現象被稱為複雜的協同適應(complex co-adaptations)。

你可以想象一下,如果在訓練過程中隨機丟棄網路的一部分,那麼其它神經元將不得不介入,替代缺失神經元的那部分表徵,為預測結果提供資訊。人們認為這樣網路模型可以學到多種相互獨立的內部表徵。

這麼做的效果就是,網路模型對神經元特定的權重不那麼敏感。這反過來又提升了模型的泛化能力,不容易對訓練資料過擬合。

Keras的Dropout 正則化

Dropout的實現很簡單,在每輪權重更新時隨機選擇一定比例(比如20%)的節點拋棄。Keras的Dropout也是這麼實現的。Dropout技術只在模型訓練的階段使用,在評估模型效能的時候不需使用。

Keras入門博文:
Python Keras (一個超好用的神經網路框架)的使用以及例項
易用的深度學習框架Keras簡介

接下來我們看看Dropout在Keras中的一些不同用法。

本例子使用了聲吶資料集(Sonar dataset)。這是一個二分類問題,目的是根據聲吶的回聲來正確地區分岩石和礦區。這個資料集非常適合神經網路模型,因為所有的輸入都是數值型的,且具有相同的量綱。

資料集可以從UCI機器學習程式碼庫下載。然後把聲吶資料集放在當前工作路徑下,檔案命名為sonar.csv。

我們會用scikit-learn來評價模型質量,為了更好地挑揀出結果的差異,採用了十折交叉驗證(10-fold cross validation)方法。

每條資料有60個輸入值和1個輸出值,輸入值在送入模型前做了歸一化。基準的神經網路模型有兩個隱藏層,第一層有60個節點,第二層有30個。使用了隨機梯度下降的方法來訓練模型,選用了較小的學習率和衝量。

完整的基準模型程式碼如下所示。

    import numpy
    import pandas
    from keras.models import Sequential
    from keras.layers import Dense
    from keras.layers import Dropout
    from keras.wrappers.scikit_learn import KerasClassifier
    from keras.constraints import maxnorm
    from keras.optimizers import SGD
    from sklearn.cross_validation import cross_val_score
    from sklearn.preprocessing import LabelEncoder
    from sklearn.cross_validation import StratifiedKFold
    from sklearn.preprocessing import StandardScaler
    from sklearn.grid_search import GridSearchCV
    from sklearn.pipeline import Pipeline
    from sklearn.grid_search import GridSearchCV
    # fix random seed for reproducibility
    seed = 7
    numpy.random.seed(seed)
    # load dataset
    dataframe = pandas.read_csv("sonar.csv", header=None)
    dataset = dataframe.values
    # split into input (X) and output (Y) variables
    X = dataset[:,0:60].astype(float)
    Y = dataset[:,60]
    # encode class values as integers
    encoder = LabelEncoder()
    encoder.fit(Y)
    encoded_Y = encoder.transform(Y)

    # baseline
    def create_baseline():
        # create model
        model = Sequential()
        model.add(Dense(60, input_dim=60, init='normal',     activation='relu'))
         model.add(Dense(30, init='normal', activation='relu'))
        model.add(Dense(1, init='normal', activation='sigmoid'))
        # Compile model
        sgd = SGD(lr=0.01, momentum=0.8, decay=0.0, nesterov=False)
        model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
        return model

    numpy.random.seed(seed)
    estimators = []
    estimators.append(('standardize', StandardScaler()))
    estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0)))
    pipeline = Pipeline(estimators)
    kfold = StratifiedKFold(y=encoded_Y, n_folds=10, shuffle=True, random_state=seed)
    results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
    print("Accuracy: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

執行程式碼,分類的準確率大概為82%。

Accuracy: 82.68% (3.90%)

在可見層使用Dropout

Dropout可用於輸入神經元,即可見層。

在下面這個例子裡,我們在輸入(可見層)和第一個隱藏層之間加入一層Dropout。丟棄率設為20%,就是說每輪迭代時每五個輸入值就會被隨機拋棄一個。

另外,正如Dropout那篇論文中所推薦的,每個隱藏層的權重值都做了限制,確保權重範數的最大值不超過3。在構建模型層的時候,可以通過設定Dense Class的W_constraint引數實現。

學習率提高了一個數量級,衝量增加到0.9。這也是那篇Dropout論文的原文中所推薦的做法。

順著上面基準模型的例子,下面的程式碼是包含輸入層dropout的網路模型。

    # dropout in the input layer with weight constraint
    def create_model1():
        # create model
        model = Sequential()
        model.add(Dropout(0.2, input_shape=(60,)))
        model.add(Dense(60, init='normal', activation='relu', W_constraint=maxnorm(3)))
        model.add(Dense(30, init='normal', activation='relu', W_constraint=maxnorm(3)))
        model.add(Dense(1, init='normal', activation='sigmoid'))
        # Compile model
        sgd = SGD(lr=0.1, momentum=0.9, decay=0.0, nesterov=False)
        model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
        return model

    numpy.random.seed(seed)
    estimators = []
    estimators.append(('standardize', StandardScaler()))
    estimators.append(('mlp', KerasClassifier(build_fn=create_model1, nb_epoch=300, batch_size=16, verbose=0)))
    pipeline = Pipeline(estimators)
    kfold = StratifiedKFold(y=encoded_Y, n_folds=10, shuffle=True, random_state=seed)
    results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
    print("Accuracy: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

執行這段程式碼,分類準確率完美地提升到了86%。

Accuracy: 86.04% (6.33%)

在隱藏層使用Dropout

Dropout也可用於模型內的隱藏層節點。

下面這個例子裡,Dropout被用於兩個隱藏層之間和隱藏層與輸出層之間。丟棄率同樣設為20%,且使用權重限制。

    # dropout in hidden layers with weight constraint
    def create_model2():
        # create model
        model = Sequential()
        model.add(Dense(60, input_dim=60, init='normal', activation='relu', W_constraint=maxnorm(3)))
        model.add(Dropout(0.2))
        model.add(Dense(30, init='normal', activation='relu', W_constraint=maxnorm(3)))
        model.add(Dropout(0.2))
        model.add(Dense(1, init='normal', activation='sigmoid'))
        # Compile model
        sgd = SGD(lr=0.1, momentum=0.9, decay=0.0, nesterov=False)
        model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
        return model

    numpy.random.seed(seed)
    estimators = []
    estimators.append(('standardize', StandardScaler()))
    estimators.append(('mlp', KerasClassifier(build_fn=create_model2, nb_epoch=300, batch_size=16, verbose=0)))
    pipeline = Pipeline(estimators)
    kfold = StratifiedKFold(y=encoded_Y, n_folds=10, shuffle=True, random_state=seed)
    results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
    print("Accuracy: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

我們觀察到,對於這個問題以及所設定的模型配置引數,在隱藏層使用dropout並不能提升模型效果。事實上,效果反而比基準更差。

有可能需要增加訓練迭代次數,或者是更多地調優學習率。

Accuracy: 82.16% (6.16%)

使用Dropout的小技巧

提出Dropout的那篇論文提供了一些在標準機器學習問題上得到的實踐性結論。這些結論在dropout的實際應用中會帶來幫助。

  • 通常丟棄率控制在20%~50%比較好,可以從20%開始嘗試。如果比例太低則起不到效果,比例太高則會導致模型的欠學習。
  • 在大的網路模型上應用。當dropout用在較大的網路模型時更有可能得到效果的提升,模型有更多的機會學習到多種獨立的表徵。
  • 在輸入層(可見層)和隱藏層都使用dropout。在每層都應用dropout被證明會取得好的效果。
  • 增加學習率和衝量。把學習率擴大10~100倍,衝量值調高到0.9~0.99.
  • 限制網路模型的權重。大的學習率往往導致大的權重值。對網路的權重值做最大範數正則化等方法被證明會提升效果。

有關Dropout的更多資源

下面這些資料也是關於dropout在神經網路和深度學習模型中應用。

總結

通過本文,我們討論了dropout正則化技術在深度學習模型中的應用。你應該掌握了:

  • dropout的含義和原理
  • 如何在自己的深度學習模型中使用dropout
  • 使用dropout的小技巧

如果你對dropout或者對本文有任何問題,請留言。


CCAI 2016中國人工智慧大會將於8月26-27日在京舉行,AAAI主席,多位院士,MIT、微軟、大疆、百度、滴滴專家領銜全球技術領袖和產業先鋒打造國內人工智慧前沿平臺,6大主題報告,人機互動、機器學習、模式識別、產業實戰相關4大專題論壇,1000+高質量參會嘉賓。門票限時六折優惠中

圖片描述

相關文章