Keras 的深度学习模型中的 Dropout 正则化

1 神经网络的 Dropout 正则化

      Dropout 是 Srivastava 等人提出的神经网络模型的正则化技术。 在他们 2014 年的论文 Dropout: A Simple Way to prevent Neural Networks from Overfitting。

      Dropout 是一种在训练过程中忽略随机选择的神经元的技术。 他们是随机“辍学”的。 这意味着它们对下游神经元激活的贡献在正向传递中被暂时移除,并且任何权重更新都不会应用于反向传递中的神经元。

      随着神经网络的学习,神经元的权重会融入网络中的上下文。 神经元的权重针对提供一些专业化的特定特征进行了调整。 相邻的神经元变得依赖于这种特化,如果过度使用,可能会导致脆弱的模型过于特化于训练数据。 这种在训练期间对神经元上下文的依赖被称为复杂的协同适应。

      您可以想象,如果神经元在训练期间随机退出网络,其他神经元将不得不介入并处理对丢失的神经元进行预测所需的表示。 这被认为会导致网络学习多个独立的内部表示。

      效果是网络对神经元的特定权重变得不那么敏感。 这反过来导致网络能够更好地泛化并且不太可能过度拟合训练数据。

2 Keras 中的 Dropout 正则化

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

      接下来我们将探索几种在 Keras 中使用 Dropout 的不同方式。 这些示例将使用 Sonar 数据集。 这是一个二元分类问题,其目标是从声纳啁啾返回中正确识别岩石和模拟地雷。 它是神经网络的一个很好的测试数据集,因为所有输入值都是数字的并且具有相同的比例。

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

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

from pandas import read_csv
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasClassifier
from keras.optimizers import SGD
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
# 加载数据集
dataframe = read_csv("sonar.csv", header=None)
dataset = dataframe.values
# 分割数据集
X = dataset[:,0:60].astype(float)
Y = dataset[:,60]
# 将类别编码为整数
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)

# 基线模型
def create_baseline():
# 创建模型
model = Sequential()
model.add(Dense(60, input_dim=60, activation='relu'))
model.add(Dense(30, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# 编译模型
sgd = SGD(lr=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(build_fn=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%)  

3 在可见层上使用 Dropout

      Dropout 可以应用于称为可见层的输入神经元。 在下面的示例中,我们在输入(或可见层)和第一个隐藏层之间添加了一个新的 Dropout 层。 辍学率设置为 20%,这意味着将在每个更新周期中随机排除五分之一的输入。

      此外,按照关于 Dropout 的原始论文中的建议,对每个隐藏层的权重施加约束,确保权重的最大范数不超过值 3。这是通过在 Dense 上设置 kernel_constraint 参数来完成的构建图层时的类。

      学习率提高了一个数量级,动量增加到 0.9。 原始 Dropout 论文中也推荐了这些学习率的提高。 继续上面的基线示例,下面的代码使用输入 dropout 练习相同的网络。

from pandas import read_csv
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.wrappers.scikit_learn import KerasClassifier
from keras.constraints import maxnorm
from keras.optimizers import SGD
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
# 加载数据集
dataframe = read_csv("sonar.csv", header=None)
dataset = dataframe.values
# 分割数据集
X = dataset[:,0:60].astype(float)
Y = dataset[:,60]
# 将类别编码为整数
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)

# 具有权重约束的输入层中的 dropout
def 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'))
# 编译模型
sgd = SGD(lr=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(build_fn=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%)

4 在隐藏层上使用 Dropout

      Dropout 可以应用于网络模型主体中的隐藏神经元。 在下面的示例中,Dropout 应用于两个隐藏层之间以及最后一个隐藏层和输出层之间。 再次使用 20% 的辍学率作为对这些层的权重约束。

from pandas import read_csv
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.wrappers.scikit_learn import KerasClassifier
from keras.constraints import maxnorm
from keras.optimizers import SGD
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
# 加载数据
dataframe = read_csv("sonar.csv", header=None)
dataset = dataframe.values
# 分割数据
X = dataset[:,0:60].astype(float)
Y = dataset[:,60]
# 将类别编码为整数
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)

# 具有权重约束的隐藏层中的 dropout
def create_model():
# 创建模型
model = Sequential()
model.add(Dense(60, input_dim=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'))
# 编译模型
sgd = SGD(lr=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(build_fn=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%)

5 使用 Dropout 的提示

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

1)通常,使用 20%-50% 的神经元的小的 dropout 值,其中 20% 提供了一个很好的起点。 概率太低影响最小,而值太高会导致网络学习不足。

2)使用更大的网络。 当在更大的网络上使用 dropout 时,您可能会获得更好的性能,从而为模型提供更多学习独立表示的机会。

3)对传入(可见)和隐藏单元使用 dropout。 在网络的每一层应用dropout都显示出很好的效果。

4)使用具有衰减和大动量的大学习率。 将学习率提高 10 到 100 倍,并使用 0.9 或 0.99 的高动量值。

5)限制网络权重的大小。 大的学习率会导致非常大的网络权重。 对网络权重的大小施加约束,例如大小为 4 或 5 的最大范数正则化已被证明可以改善结果。

6 总结

      在这篇文章中,您发现了深度学习模型的 dropout 正则化技术。 本文介绍了:

  • 什么是 dropout 以及它是如何工作的。
  • 如何在自己的深度学习模型上使用 dropout。
  • 在您自己的模型上从 dropout 中获得最佳结果的提示。

下图与本文无关,只是用来迷惑发文小助手的,^^

发表评论

相关文章