Dropout vs BatchNormalization

Dropout
Dropout是神經網絡中防止模型過擬合的重要正則化方式。2014年 Hinton 提出了一個神器,
《Dropout: A Simple Way to Prevent Neural Networks from Overfitting 》。原文:(http://jmlr.org/papers/v15/srivastava14a.html)。
dropout 是指在深度學習網絡的訓練過程中,按照一定的概率將一部分神經網絡單元暫時從網絡中丟棄,相當於從原始的網絡中找到一個更瘦的網絡。
在這裏插入圖片描述
一般情況下,我們只需要在網絡存在過擬合風險時才需要實現正則化。如果網絡太大,如果訓練時間太長,或者沒有足夠的數據,就會發生這種情況。如果在卷積網絡末端有全連接層,那麼實現Dropout是很容易的。

在大規模的神經網絡中有這樣兩個缺點:1. 費時;2. 容易過擬合

對於一個有 N 個節點的神經網絡,有了 dropout後,就可以看做是 2^N 個模型的集合了,但此時要訓練的參數數目卻是不變的,這就緩解了費時的問題。

Dropout層只適用於CNN的全連接層,放在激活函數之後,對於其它層,不應該使用Dropout層。相反,應該在卷積之間插入批量標準化處理,BatchNormalization層,使得模型在訓練期間更加穩定。

Batch Normalization
Batch Normalization是批量正則化,也是正則化的一個重要方式。原文:(http://de.arxiv.org/pdf/1502.03167)。BN重新調整數據的分佈,使數據服從均值爲0,方差爲1的正態分佈。在正則化效果的基礎上,批處理規範化還可以減少卷積網絡在訓練過程中的梯度彌散。這樣可以減少訓練時間,提升結果。在CNN使用BN層時需要在卷積層和激活層之間插入BN層,(BN層的位置:CONV / FC - > Batch Normalization- > ReLu(或其他激活) - > Dropout - > CONV / FC)或者(BN層的位置:CONV / FC - > ReLu(或其他激活) - > Dropout - > Batch Normalization - > CONV / FC)

BN層的作用

1、可以使用更高的學習率
如果每層的scale不一致,實際上每層需要的學習率是不一樣的,同一層不同維度的scale往往也需要不同大小的學習率,通常使用小的學習率才能保證損失函數有效下降,BN將每層、每維的scale保持一致,那麼可以使用較高的學習率進行優化。

2、移除或者使用較小的dropout
dropout是常用來防止過擬合的方法,而導致過擬合的位置往往在數據邊界位置,如果初始權重就已經落在數據內部,過擬合的現象就可以得到一定的緩解。

3、降低L2權重衰減係數
邊界處的局部最優往往有幾維的權重(斜率)較大,使用L2衰減可以緩解這一問題,現在使用BN層,就可以把這個係數降低。

4、取消Local Response Normalization層
由於使用了一種Normalization層,再使用LRN就沒必要了。

5、BN調整了數據分佈,不考慮激活函數,它讓每層的輸出歸一化到均值爲0,方差爲1的分佈,這保證了梯度的有效性,可以解決反向傳播過程中梯度問題。

用手寫數字數據集來展示dropout和batchnormalization的區別。

import keras
from keras.datasets import mnist
from keras.layers import Dense, Conv2D, Flatten, MaxPooling2D, Dropout, Activation, BatchNormalization
from keras.models import Sequential
from keras.utils import np_utils
import matplotlib.pyplot as plt

(X_train, y_train),(X_test, y_test) =  mnist.load_data()

X_train  = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32')
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1).astype('float32')

X_train /= 255
X_test /= 255

def model_cnn():
    #  使用dropout
    model = Sequential()
    model.add(Conv2D(filters=32, kernel_size=5, strides=(1, 1), padding='SAME', input_shape=(28, 28, 1), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), padding='SAME'))
    model.add(Conv2D(filters=64, kernel_size=5, strides=(1, 1), padding='SAME', activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), padding='SAME'))
    model.add(Flatten())
    model.add(Dense(120, activation='relu'))
    model.add(Dropout(0.4))
    model.add(Dense(84, activation='relu'))
    model.add(Dropout(0.4))
    model.add(Dense(10, activation='softmax'))
    
    model.summary()
    
    return model
    
def model_cnn_BN():
	# 使用batch normalization
    model = Sequential()
    model.add(Conv2D(filters=32, kernel_size=5, strides=(1, 1), padding='SAME', input_shape=(28, 28, 1)))
    model.add(BatchNormalization())
    model.add(Activation(activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), padding='SAME'))
    
    model.add(Conv2D(filters=64, kernel_size=5, strides=(1, 1), padding='SAME'))
    model.add(BatchNormalization())
    model.add(Activation(activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), padding='SAME'))
    
    model.add(Flatten())
    model.add(Dense(120, activation='relu'))
    model.add(Dense(84, activation='relu'))
    model.add(Dense(10, activation='softmax'))
    
    model.summary()
    
    return model
    
def plot_p(model_train, model_BN_train):
    
    plt.figure(figsize=(10, 6))
    plt.subplots_adjust(wspace=0.3, hspace=0.3)
    plt.subplot(121)
    plt.plot(model_train.history['acc'], c='k', label='train with Dopout')
    plt.plot(model_train.history['val_acc'], c='gray', label='validation with Dopout')
    plt.plot(model_BN_train.history['acc'], c='k', label='train with BN', ls='--')
    plt.plot(model_BN_train.history['val_acc'], c='gray', label='validation with BN', ls='--')
    plt.legend()
    plt.xlabel('epoch')
    plt.xticks([0, 2, 4 ,6, 8, 10, 12, 14, 16, 18, 20], [0, 2, 4 ,6, 8, 10, 12, 14, 16, 18, 20])
    plt.ylabel('accuracy')
    plt.title('model accuracy')

    plt.subplot(122)
    plt.plot(model_train.history['loss'], c='k', label='train with Dopout')
    plt.plot(model_train.history['val_loss'], c='gray', label='validation with Dopout')
    plt.plot(model_BN_train.history['loss'], c='k', label='train with BN', ls='--')
    plt.plot(model_BN_train.history['val_loss'], c='gray', label='validation with BN', ls='--')
    plt.legend()
    plt.xlabel('epoch')
    plt.xticks([0, 2, 4 ,6, 8, 10, 12, 14, 16, 18, 20], [0, 2, 4 ,6, 8, 10, 12, 14, 16, 18, 20])
    plt.ylabel('loss')
    plt.title('model loss')
    
model = model_cnn()
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model_train = model.fit(X_train, y_train, epochs=20, batch_size=100, validation_split=0.1)

model_BN = model_cnn_BN()
model_BN.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model_BN_train = model_BN.fit(X_train, y_train, epochs=20, batch_size=100, validation_split=0.1)

plot_p(model_train, model_BN_train)

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章