如何使用Keras的深度学习模型的dropout正则化

122 阅读8分钟

神经网络和深度学习模型的一个简单而强大的正则化技术是dropout

在这篇文章中,你将发现dropout正则化技术,以及如何用Keras在Python中把它应用于你的模型。

读完这篇文章后,你会知道。

  • Dropout正则化技术是如何工作的。
  • 如何在输入层上使用dropout。
  • 如何在你的隐藏层上使用dropout。
  • 如何在你的问题上调整dropout水平。

神经网络的剔除正则化

Dropout是一种技术,在训练期间,随机选择的神经元被忽略。它们被随机地 "丢弃"。这意味着它们对下游神经元激活的贡献在前向传递时被删除,任何权重更新在后向传递时不应用于该神经元。

随着神经网络的学习,神经元的权重在网络中沉淀为它们的背景。神经元的权重针对特定的特征进行调整,提供一些专业化的服务。邻近的神经元变得依赖这种专业化,如果走得太远会导致一个脆弱的模型对训练数据过于专业化。在训练过程中,神经元对背景的这种依赖被称为复杂的共同适应。

你可以想象,如果神经元在训练过程中被随机地从网络中剔除,那么其他的神经元将不得不介入并处理所需的表征,为缺失的神经元做出预测。这被认为会导致网络学习多个独立的内部表征。

其效果是,网络对神经元的特定权重变得不那么敏感。这反过来又导致了一个能够更好地泛化的网络,不太可能过度适应训练数据。

Keras中的Dropout正则化

通过在每个权重更新周期以给定的概率(例如20%)随机选择要被剔除的节点,可以轻松实现剔除。这就是Keras中Dropout的实现方式。Dropout只在模型的训练过程中使用,在评估模型的技能时不使用。

接下来我们将探索在Keras中使用Dropout的几种不同方式。

这些例子将使用Sonar数据集。这是一个二元分类问题,目标是正确识别声纳鸣叫回波中的岩石和模拟矿井。对于神经网络来说,这是一个很好的测试数据集,因为所有的输入值都是数字的,并且有相同的比例。

该数据集可以从UCI机器学习资源库下载。你可以把声纳数据集放在你当前的工作目录下,文件名为sonar.csv。

我们将使用scikit-learn的10倍交叉验证来评估所开发的模型,以便更好地弄清结果的差异。

有60个输入值和一个输出值,输入值在用于网络之前是标准化的。基线神经网络模型有两个隐藏层,第一个有60个单元,第二个有30个。随机梯度下降法被用来训练模型,学习率和动力相对较低。

完整的基线模型列在下面。

# Baseline Model on the Sonar Dataset
from pandas import read_csv
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import SGD
from scikeras.wrappers import KerasClassifier
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# load dataset
dataframe = 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_shape=(60,), activation='relu'))
	model.add(Dense(30,  activation='relu'))
	model.add(Dense(1, activation='sigmoid'))
	# Compile model
	sgd = SGD(learning_rate=0.01, momentum=0.8)
	model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
	return model

estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(model=create_baseline, epochs=300, batch_size=16, verbose=0)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=10, shuffle=True)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

注意:鉴于算法或评估程序的随机性,或数字精度的差异,你的结果可能会有所不同。考虑多运行几次这个例子,并比较平均结果。

运行这个例子产生的估计分类精度为86%。

Baseline: 86.04% (4.58%)

在可见层上使用Dropout

Dropout可以应用于称为可见层的输入神经元。

在下面的例子中,我们在输入(或可见层)和第一个隐藏层之间添加了一个新的Dropout层。剔除率被设置为20%,这意味着每5个输入中有一个将被随机地排除在每个更新周期之外。

此外,正如关于Dropout的原始论文所建议的那样,对每个隐藏层的权重施加了一个约束,确保权重的最大规范不超过3的值。

学习率提高了一个数量级,动量也增加到了0.9。这些学习率的提高也是原始Dropout论文中所建议的。

继续上面的基线例子,下面的代码对同一个网络进行了输入滤波。

# Example of Dropout on the Sonar Dataset: Visible Layer
from pandas import read_csv
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.constraints import MaxNorm
from tensorflow.keras.optimizers import SGD
from scikeras.wrappers import KerasClassifier
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# load dataset
dataframe = 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)

# dropout in the input layer with weight constraint
def create_model():
	# create model
	model = Sequential()
	model.add(Dropout(0.2, input_shape=(60,)))
	model.add(Dense(60, activation='relu', kernel_constraint=MaxNorm(3)))
	model.add(Dense(30, activation='relu', kernel_constraint=MaxNorm(3)))
	model.add(Dense(1, activation='sigmoid'))
	# Compile model
	sgd = SGD(learning_rate=0.1, momentum=0.9)
	model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
	return model

estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(model=create_model, epochs=300, batch_size=16, verbose=0)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=10, shuffle=True)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Visible: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

注意:鉴于算法或评估程序的随机性,或数字精度的差异,你的结果可能会有所不同。考虑多运行几次这个例子,并比较平均结果。

运行这个例子可以使分类精度小幅下降,至少在一次测试运行中是如此。

Visible: 83.52% (7.68%)

在隐藏层上使用Dropout

Dropout可以应用于你的网络模型主体中的隐藏神经元。

在下面的例子中,Dropout被应用于两个隐藏层之间以及最后一个隐藏层和输出层之间。同样,在这些层上使用了20%的退出率和权重约束。

# Example of Dropout on the Sonar Dataset: Hidden Layer
from pandas import read_csv
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.constraints import MaxNorm
from tensorflow.keras.optimizers import SGD
from scikeras.wrappers import KerasClassifier
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# load dataset
dataframe = 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)

# dropout in hidden layers with weight constraint
def create_model():
	# create model
	model = Sequential()
	model.add(Dense(60, input_shape=(60,), activation='relu', kernel_constraint=MaxNorm(3)))
	model.add(Dropout(0.2))
	model.add(Dense(30, activation='relu', kernel_constraint=MaxNorm(3)))
	model.add(Dropout(0.2))
	model.add(Dense(1, activation='sigmoid'))
	# Compile model
	sgd = SGD(learning_rate=0.1, momentum=0.9)
	model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
	return model

estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(model=create_model, epochs=300, batch_size=16, verbose=0)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=10, shuffle=True)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Hidden: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

注意:鉴于算法或评估程序的随机性,或数字精度的差异,你的结果可能会有所不同。考虑将这个例子运行几次并比较平均结果。

我们可以看到,对于这个问题和所选择的网络配置来说,在隐藏层中使用dropout并没有提高性能。事实上,性能比基线还差。

这可能是需要额外的训练历时或者需要进一步调整学习率。

Hidden: 83.59% (7.31%)

评估模式下的丢弃

Dropout将随机地把一些输入重置为零。如果你想知道在我们完成训练后会发生什么,答案是什么都没有!在Keras中,一个层可以告诉你它是什么。在Keras中,一个层可以分辨模型是否在训练模式下运行。Dropout层只有在模型运行训练时才会随机重置一些输入。否则,Dropout层作为一个标度器工作,将所有输入乘以一个系数,这样下一层就会看到类似标度的输入。准确地说,如果辍学率是rr,输入将被缩放为1-r$的系数。

使用Dropout的提示

关于Dropout的原始论文提供了一套标准机器学习问题的实验结果。因此,他们提供了一些有用的启发式方法,以便在实践中使用Dropout时考虑。

  • 一般来说,使用20%-50%的神经元的小辍学值,其中20%是一个好的起点。太低的概率影响很小,太高的值会导致网络的学习不足。
  • 使用一个更大的网络。当在一个较大的网络上使用dropout时,你可能会得到更好的性能,给模型更多的机会来学习独立的表征。
  • 在传入(可见)和隐藏单元上使用dropout。在网络的每一层应用dropout都显示出良好的效果。
  • 使用一个大的学习率,带有衰减和大的动量。将你的学习率提高10-100倍,并使用0.9或0.99的高动量值。
  • 限制网络权重的大小。大的学习率会导致非常大的网络权重。对网络权重的大小进行约束,如最大正则化,大小为4或5,已被证明可以改善结果。

摘要

在这篇文章中,你发现了深度学习模型的 dropout 正则化技术。你学到了。

  • 什么是dropout,它是如何工作的。
  • 你如何在自己的深度学习模型上使用dropout。
  • 在你自己的模型上从dropout中获得最佳结果的技巧。