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)

在这里插入图片描述

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