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)