【Keras】减小过拟合的秘诀——Dropout正则化

 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

下图为模型在训练和测试集上的精度图,咱们能够看到过拟合模型的预期性能,其中测试精度增长到必定值之后,再次开始减少。

281d66126bdff3af48652855d6f749af970d56d6

使用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》

博文

1.基于Keras深度学习模型中的Dropout正则化

2.如何使用LSTM网络的Dropout进行时间序列预测

API

1.Keras Regularizers API

2.Keras Core Layers API

3.Keras Convolutional Layers API

4.Keras Recurrent Layers API

5.sklearn.datasets.make_circles API

总结

阅读完本文,你已经了解了如何将深度学习正则化添加到深度学习神经网络模型的API中。具体来讲,有如下几个内容:

1.如何使用Keras API建立Dropout层。

2.如何使用Keras API将Dropout正则化添加到MLP、CNN和RNN层。

3.如何向现有模型中添加Dropout正则化,以此减小过拟合。

原文连接

相关文章
相关标签/搜索