Dropout 是一种简单而强大的神经网络和深度学习模型正则化技术。
在这篇文章中,您将了解 Dropout 正则化技术以及如何使用 Keras 在 Python 中将其应用于您的模型。
阅读本文后,你将了解:
- Dropout 正则化技术的工作原理
- 如何在输入层使用 Dropout
- 如何在隐藏层使用 Dropout
- 如何根据您的问题调整 Dropout 级别
通过我的新书 《Python 深度学习》启动您的项目,其中包括分步教程和所有示例的 Python 源代码文件。
让我们开始吧。
- 2016 年 6 月:首次发布
- 2016 年 10 月更新:更新至 Keras 1.1.0、TensorFlow 0.10.0 和 scikit-learn v0.18
- 2017 年 3 月更新:更新至 Keras 2.0.2、TensorFlow 1.0.1 和 Theano 0.9.0
- 2019 年 9 月更新:更新至 Keras 2.2.5 API
- 2022 年 7 月更新:针对 TensorFlow 2.x API 和 SciKeras 进行了更新

Keras 深度学习模型中的 Dropout 正则化
照片由 Trekking Rinjani 提供,保留部分权利。
神经网络的 Dropout 正则化
Dropout 是 Srivastava 等人在 2014 年论文 “Dropout:一种防止神经网络过拟合的简单方法” (下载 PDF) 中提出的一种神经网络模型正则化技术。
Dropout 是一种在训练过程中忽略随机选择的神经元的技术。它们被随机“丢弃”。这意味着它们对下游神经元激活的贡献在正向传播时被暂时移除,并且在反向传播时不会对神经元应用任何权重更新。
当神经网络学习时,神经元权重会在网络中稳定下来。神经元的权重会针对特定特征进行调整,从而提供一些专业化。相邻神经元开始依赖这种专业化,如果过度,可能会导致模型过于专业化以至于对训练数据变得脆弱。这种神经元在训练期间对上下文的依赖被称为复杂协同适应。
可以想象,如果在训练过程中神经元被随机从网络中丢弃,其他神经元将不得不介入并处理所需的表示,以对缺失的神经元进行预测。这被认为会导致网络学习到多个独立的内部表示。
其结果是网络对神经元的特定权重变得不那么敏感。这反过来又导致网络能够更好地泛化,并且不太可能过拟合训练数据。
Python 深度学习需要帮助吗?
参加我的免费为期两周的电子邮件课程,发现 MLP、CNN 和 LSTM(附代码)。
立即点击注册,还将免费获得本课程的 PDF 电子书版本。
Keras 中的 Dropout 正则化
Dropout 很容易实现,只需在每个权重更新周期中随机选择节点以给定概率(例如 20%)丢弃。这就是 Keras 中实现 Dropout 的方式。Dropout 仅在模型训练期间使用,在评估模型技能时不会使用。
接下来,让我们探索在 Keras 中使用 Dropout 的几种不同方法。
示例将使用 Sonar 数据集。这是一个二元分类问题,旨在正确识别来自声纳脉冲返回的岩石和模拟水雷。它是一个很好的神经网络测试数据集,因为所有输入值都是数值型的并且具有相同的比例。
该数据集可以从 UCI 机器学习存储库下载。您可以将声纳数据集放置在当前工作目录中,文件名为 sonar.csv。
您将使用 scikit-learn 和 10 折交叉验证来评估开发的模型,以便更好地区分结果。
有 60 个输入值和一个输出值。输入值在用于网络之前进行标准化。基线神经网络模型有两个隐藏层,第一个有 60 个单元,第二个有 30 个。使用随机梯度下降来训练模型,学习率相对较低,并具有动量。
完整的基线模型如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# 声纳数据集上的基线模型 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 # 加载数据集 dataframe = read_csv("sonar.csv", header=None) dataset = dataframe.values # 分割为输入 (X) 和输出 (Y) 变量 X = dataset[:,0:60].astype(float) Y = dataset[:,60] # 将类别值编码为整数 编码器 = LabelEncoder() encoder.fit(Y) encoded_Y = encoder.transform(Y) # 基线 def create_baseline(): # 创建模型 model = Sequential() model.add(Dense(60, input_shape=(60,), activation='relu')) model.add(Dense(30, activation='relu')) model.add(Dense(1, activation='sigmoid')) # 编译模型 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% 的估计分类准确率。
1 |
基线:86.04% (4.58%) |
在可见层使用 Dropout
Dropout 可以应用于输入神经元,称为可见层。
在下面的示例中,在输入(或可见层)和第一个隐藏层之间添加了一个新的 Dropout 层。Dropout 率设置为 20%,这意味着每五个输入中将有一个在每个更新周期中被随机排除。
此外,正如 Dropout 原始论文中所建议的,对每个隐藏层的权重施加了一个约束,确保权重的最大范数不超过 3。这是通过在构建层时设置 Dense 类的 kernel_constraint 参数来完成的。
学习率提高了一个数量级,动量增加到 0.9。Dropout 原始论文中也建议了这些学习率的增加。
从上面的基线示例继续,下面的代码使用输入 dropout 运行相同的网络
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# 声纳数据集上的 Dropout 示例:可见层 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 # 加载数据集 dataframe = read_csv("sonar.csv", header=None) dataset = dataframe.values # 分割为输入 (X) 和输出 (Y) 变量 X = dataset[:,0:60].astype(float) Y = dataset[:,60] # 将类别值编码为整数 编码器 = 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(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)) |
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。
运行示例显示分类准确率略有下降,至少在单次测试运行中是这样。
1 |
可见:83.52% (7.68%) |
在隐藏层使用 Dropout
Dropout 可以应用于网络主体中的隐藏神经元。
在下面的示例中,Dropout 应用于两个隐藏层之间以及最后一个隐藏层和输出层之间。同样使用 20% 的 Dropout 率,并对这些层施加权重约束。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# 声纳数据集上的 Dropout 示例:隐藏层 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 # 加载数据集 dataframe = read_csv("sonar.csv", header=None) dataset = dataframe.values # 分割为输入 (X) 和输出 (Y) 变量 X = dataset[:,0:60].astype(float) Y = dataset[:,60] # 将类别值编码为整数 编码器 = LabelEncoder() encoder.fit(Y) encoded_Y = encoder.transform(Y) # 隐藏层中的 dropout 和权重约束 def 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')) # 编译模型 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 并没有提高性能。事实上,性能比基线更差。
可能需要额外的训练周期或需要进一步调整学习率。
1 |
隐藏层:83.59% (7.31%) |
评估模式下的 Dropout
Dropout 会随机将一些输入重置为零。如果您想知道训练完成后会发生什么,答案是什么都不会!在 Keras 中,一个层可以判断模型是否处于训练模式。Dropout 层只会在模型运行时进行训练时才随机重置一些输入。否则,Dropout 层会作为缩放器,将所有输入乘以一个因子,使得下一层看到的输入具有相似的尺度。准确地说,如果 dropout 率为 $r$,输入将按 $1-r$ 的因子进行缩放。
使用 Dropout 的技巧
Dropout 的原始论文提供了针对一系列标准机器学习问题的实验结果。因此,他们在实践中使用 Dropout 时提供了一些有用的启发式方法。
- 通常,使用 20%-50% 的神经元的较小 Dropout 值,其中 20% 是一个很好的起点。概率过低效果最小,过高则导致网络学习不足。
- 使用更大的网络。当在更大的网络上使用 Dropout 时,您可能会获得更好的性能,从而为模型提供更多的机会来学习独立的表示。
- 在输入(可见)单元和隐藏单元上使用 Dropout。在网络的每一层应用 Dropout 已显示出良好的结果。
- 使用带有衰减的大学习率和大动量。将学习率提高 10 到 100 倍,并使用 0.9 或 0.99 的高动量值。
- 限制网络权重的大小。大学习率可能导致非常大的网络权重。对网络权重的大小施加约束,例如最大范数正则化,大小为 4 或 5,已被证明可以改善结果。
更多关于 Dropout 的资源
以下是您可以用来了解更多关于神经网络和深度学习模型中 Dropout 的资源。
- Dropout:一种防止神经网络过拟合的简单方法(原始论文)
- 通过防止特征检测器协同适应来改进神经网络
- Quora 上关于 dropout 方法在深度学习中如何工作?
- TensorFlow 文档中的 Keras 内置方法训练和评估
总结
在这篇文章中,您发现了深度学习模型的 Dropout 正则化技术。您了解了
- 什么是 Dropout 以及它的工作原理
- 如何在您自己的深度学习模型中使用 Dropout。
- 从您自己的模型中获得最佳 Dropout 结果的技巧。
您对 Dropout 或这篇文章有任何疑问吗?请在评论中提出您的问题,我将尽力回答。
你好,
感谢这些非常有用的示例!!
问题:dropout 的目标是降低过拟合的风险,对吗?
我怀疑准确率是否是衡量这一点最好的方法;这里您已经在进行交叉验证,这本身就是一种减少过拟合的方法。既然您正在进行交叉验证*和* dropout,这是否有点 overkill?也许准确率的下降实际上是可用信息量的下降?
很好的问题。
是的,dropout 是一种减少网络对训练数据过拟合的技术。
k 折交叉验证是一种可靠的技术,用于估计模型的技能。它非常适合确定特定的网络配置是否过拟合或欠拟合问题。
您还可以查看训练和验证数据集上损失随 epoch 的诊断图,以确定不同 dropout 配置如何影响过拟合。
非常棒的帖子。只有一个问题,为什么需要结合设置最大范数来提高学习率?
好问题。也许使用 dropout 更新的节点较少,因此每个批次需要更多的更改/更新。
LSTM 在训练数据集上表现良好,但在测试数据集(即预测)上表现不佳。您能给我一些关于这个问题的建议吗?
这听起来像是过拟合。
考虑使用像本文中讨论的 dropout 这样的正则化技术。
有些人提到在 LSTM 单元上应用 dropout 通常会导致糟糕的结果。一个例子在这里:https://arxiv.org/abs/1508.03720
我想知道有没有人对此有任何评论。
感谢您的链接,元良。我确实经常看到更糟糕的结果。不过,我经常看到 dropout 在输出之前的密集层上是有益的。
我的建议是根据您的问题进行实验,看看效果如何。
你好,
首先,感谢您让机器学习变得有趣。
我有一个关于 dropout 的疑问。
即使我们选择的优化器是 adam 而不是 sgd,我们也可以使用 dropout 吗?
在示例中,使用的是 sgd,并且在技巧部分也提到了“
使用具有衰减的大学习率和大的动量。”据我所知,adam 没有动量。那么如果我们使用 dropout,adam 的参数应该是什么?
keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
是的,您可以将 dropout 与其他优化算法一起使用。我建议您尝试参数,看看如何平衡 dropout 提供的学习和正则化。
除了采样,在构建深度学习模型时如何处理罕见事件?
对于浅层机器学习,我可以添加一个效用或成本函数,但在这里我想看看是否已经开发出更优雅的方法。
您也可以对罕见事件进行过采样,也许通过数据增强(随机性)使它们看起来不同。
这里有一些关于处理不平衡数据集的讨论,可能会给您启发
https://machinelearning.org.cn/tactics-to-combat-imbalanced-classes-in-your-machine-learning-dataset/
嗨,Jason,
为什么 Dropout 在这些情况下有效?它可以降低计算量,但它将如何影响增长……我一直在 ANN 和现在的 RNN (LSTM) 上试验 dropout,我只在 LSTM 的输入和输出中使用 dropout,而不是在循环层之间……但验证和训练数据集的准确率保持不变……
有什么评论吗?
你好 Junaid,
我本人没有在 RNN 上使用过 dropout。
也许您需要更多的 dropout 和更少的训练来影响网络的技能或泛化能力。
dropout层在模型存储时是否也被存储了?
如果存储了,为什么?在模型中包含dropout层没有意义吧?除了训练时?
它是一个没有权重的函数。除了它存在于网络拓扑中的特定点之外,没有什么可存储的。
在实际实践中,是否建议为训练固定一个随机种子?
我看到两种选择,要么固定随机种子并使代码可重现,要么运行模型n次(30次?)并取所有运行的平均性能。
后者更稳健。
有关神经网络等机器学习算法的随机性质的更多信息,请参阅此帖子
https://machinelearning.org.cn/randomness-in-machine-learning/
我是机器学习的初学者,正在从您的博客学习神经网络。
在这篇文章中,我理解了dropout的所有概念,但是使用
from sklearn.model_selection import cross_val_score
从 sklearn.model_selection 导入 StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
让代码变得难以理解。您能建议任何不使用这些的方法来编写代码吗?
是的,您可以直接使用keras。我提供了许多关于该主题的教程,请尝试页面顶部的搜索功能。
谢谢Jason,这太有用了!!
不客气!
嗨,Jason,
感谢您提供的出色材料!
我有一个问题,我看到当您对隐藏层使用dropout时,您将其应用于所有隐藏层。
我的问题是,如果对隐藏层应用dropout,那么是否应该将其应用于所有隐藏层?或者更确切地说,我们如何选择在哪里应用dropout?
谢谢!🙂
好问题。我建议您测试您能想到的网络的所有变体,看看哪种方法最适合您的特定问题。
我的Keras猫狗分类器对狗有过拟合现象。我该如何使其无偏?
考虑对猫类别的图像进行数据增强,以拟合一个更稳健的模型。
我已对训练数据集进行了数据增强。但没有帮助。这是我的代码片段。
它正确分类了254只狗中的约246只,246只猫中的83只。
抱歉,我没有现成的建议。
from keras.preprocessing.image import ImageDataGenerator
来自 keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K
# 我们图像的维度。
img_width, img_height = 150, 150
train_data_dir = r’E:\\Interns ! Projects\\Positive Integers\\CatDogKeras\\data\\train’
validation_data_dir = r’E:\\Interns ! Projects\\Positive Integers\\CatDogKeras\\data\\validation’
nb_train_samples = 18000
nb_validation_samples = 7000
epochs = 20
batch_size = 144
if K.image_data_format() == 'channels_first'
input_shape = (3, img_width, img_height)
else
input_shape = (img_width, img_height, 3)
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation(‘sigmoid’))
model.compile(loss=’binary_crossentropy’,
optimizer='rmsprop',
metrics=['accuracy'])
# 这是我们将用于训练的增强配置
train_datagen = ImageDataGenerator(
rescale=1. / 255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
# 这是我们将用于测试的增强配置
# 仅重新缩放
test_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
model.fit_generator(
train_generator,
steps_per_epoch=nb_train_samples // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps=nb_validation_samples // batch_size)
input(“Press enter to exit”)
model.save_weights(‘first_try_v2.h5’)
model.save(‘DogCat_v2.h5’)
另外,是否有可能在最后一个epoch后获得每个训练样本的概率?
是的,在每个epoch结束时为每个样本进行概率预测
非常感谢。这个博客和你的建议真的很有帮助。
不客气,很高兴听到这个消息。
我卡在这里了。我正在使用二元交叉熵。我想看到实际的0到1之间的概率。但我只得到了最大概率,即0或1。无论是测试样本还是训练样本。
在输出层使用softmax,并调用predict_proba()来获取概率。
感谢您对dropout工作原理的深刻见解。我有一个问题:添加dropout层(如您的示例所示)与设置层的dropout参数(例如
model.add(SimpleRNN(…, dropout=0.5))
model.add(LSTM(…, dropout=0.5))
之间有什么区别?
再次感谢您与我们分享您的知识。
Jason Brownlee 2017年8月17日上午6:48 #
你好 Jason,
Guillaume 2017年8月31日晚上11:29 #
谢谢您的教程 🙂
我有一个关于 dropout 实现的问题。
我正在使用 LSTM 预测正弦波的值。在没有 dropout 的情况下,NN 能够相当准确地捕捉信号的频率和幅度。
model = Sequential()
然而,像这样实现 dropout
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(LSTM(neuron, input_shape=(1,1)))
model = Sequential()
与
model.add(Dense(1))
model.add(LSTM(neuron, input_shape=(1,1), dropout=0.5))
的结果不同。在第一种情况下,结果也很好。但在第二种情况下,幅度减少到其原始值的 1/4。
谢谢!
Jason Brownlee 2017年9月1日上午6:48 #
我原以为它们是同一回事,看来我的直觉错了。
嗨,Jason,
James 2017年9月27日凌晨3:15 #
感谢您的所有帖子,它们非常棒!
我的主要问题是一个关于搜索最佳超参数的通用问题;您更喜欢哪种方法(例如 sklearn 的网格/随机搜索方法)?或者您通常只是尝试并观察?
”’
model = Sequential()
此外,我在网上找到了这段代码,并对最佳实践提出了一些问题,我认为这里的每个人都可以从中受益
# 输入层维度为1,隐藏层i有128个神经元。
model.add(Dense(128, input_dim=1, activation=’relu’))
# 20%的神经元Dropout和激活层。
model.add(Activation(“linear”))
model.add(Dropout(.2))
model.add(Dense(64, activation='relu'))
model.add(Activation(“linear”))
# 隐藏层j有64个神经元加激活层。
model.add(Dense(64, activation='relu'))
# 隐藏层k有64个神经元。
model.add(Dense(1))
# 输出层。
# 模型使用均方误差作为损失函数,准确率作为度量标准,梯度下降优化器进行派生和编译。
model.compile(loss=’mse’, optimizer=’adam’, metrics=[“accuracy”])
# 使用训练数据训练模型。固定随机种子
numpy.random.seed(3)
model.fit(X_train, y_train, nb_epoch=256, batch_size=2, verbose=2) ”’
1) 我原以为输入层应该是数据中的特征数量(即列数 – 1),但此代码将其定义为1。
2) 为每个层定义两次激活函数对我来说似乎很奇怪,但我可能误解了代码,但这不只是覆盖了之前定义的激活函数吗?
3) 对于回归问题,最后一个激活函数(在输出层之前)不应该是线性的吗?
来源: http://gonzalopla.com/deep-learning-nonlinear-regression/#comment-290
再次感谢所有精彩的帖子!
James
我自己使用网格搜索。我尽量做到系统化,请看这里
https://machinelearning.org.cn/plan-run-machine-learning-experiments-systematically/
是的,您粘贴的代码有很多问题。
嗨,Jason,感谢您清晰的博客。我有一个问题。在输出层,我们使用了softmax函数,是不是不应用dropout?如果是这样,这背后的原理是什么?
此致,
Azim
不,我们只在输入层和隐藏层使用dropout,不在输出层使用。
这样做的理由是我们不想破坏模型的输出,进而影响误差的计算。
解释得真好,Jason!
谢谢 Alex。
我如何绘制这段代码。我尝试了各种方法,但每次都得到不同的错误。
绘制这段代码的正确语法是什么?
你说的“绘制代码”是什么意思?
你可以通过复制这段代码并粘贴到一个新文件中,以 .py 扩展名保存,然后用 Python 解释器运行来执行它。
如果你是 Python 新手,我建议你先学习一些语言基础。
你好
我想知道在卷积层中合并任意两个核是否是 dropout 技术?
抱歉,我没听懂,您能重新陈述一下您的问题吗?
我在我的笔记本电脑上运行了你的代码,但是每次结果都不同……差了大约15%
这是我在这里回答的一个常见问题
https://machinelearning.org.cn/faq/single-faq/why-do-i-get-different-results-each-time-i-run-the-code
嗨,Jason,
我读过您的许多文章,它们通常都写得很好。
我质疑您在这里的说法
“你可以想象,如果在训练过程中神经元被随机丢弃,那么其他神经元将不得不介入并处理为缺失神经元进行预测所需的表示。这被认为会导致网络学习到多个独立的内部表示。
其效果是网络对神经元的特定权重变得不那么敏感。”
我认为这不正确。目标不是创建更多的表示,而是创建数量更少但更稳健的表示。
(我从未见过对协同适应的特定合理解释。都是空泛之词。)
小提示:您引用的关于 dropout 的“原始”论文并非原始论文,它是他们的第二篇论文。原始论文的标题中包含“协同适应”。
Craig Will
谢谢你的提醒,Craig。
Jason,谢谢你的例子。显然它对每个人都有效。但是,当我运行你的代码时,我遇到了以下错误
estimators.append((‘mlp’, KerasClassifier(build_fn=create_baseline, epochs=300, batch_size=16, verbose=0)))
NameError: name ‘create_baseline’ is not defined
我希望你能帮我解决这个问题,因为我无法在网上找到任何解决方案,也无法自己解决。
请确保您已从教程中复制了所有代码,并且缩进匹配。
这个可能会有帮助
https://machinelearning.org.cn/faq/single-faq/how-do-i-copy-code-from-a-tutorial
谢谢回复!我现在打算尝试用它来处理我自己的数据
很高兴听到。
简单明了的解释……感谢这些文章
很高兴它有帮助。
嗨,Jason,
感谢您的文章。我从中受益匪浅。
顺便说一下,我在相同的数据集上运行了您的代码,在没有dropout层的情况下获得了81.66%(6.89%)的准确率,而仅在输入层使用dropout后,准确率大幅提升至87.54%(7.07%)。我不明白的是,为什么在相同的数据集和相同模型下,我的准确率增加了而您的没有?这是我的情况过拟合了吗?我该如何测试它?
先谢谢您了。
干得不错。
Dropout 减少过拟合。
使用dropout时,结果是否可重现?每次随机丢弃哪些节点可以设定种子以产生相同的结果吗?
这种想法是为了多次评估模型并计算平均性能,您可以在这里了解更多信息
https://machinelearning.org.cn/evaluate-skill-deep-learning-models/
嗨 Jason,非常好的话题!
关于可见层上的 dropout,在您的例子中,这意味着在一个包含 60 张图像的批次中,其中 12 张(20%)将被设置为零吗?
谢谢!
这将是输入变量级别的,例如,每个像素,而不是整个样本。
嗨,Jason,
我在我的数据集中观察到,当我使用dropout来减少深度学习模型过拟合时,它确实减少了过拟合,但它对准确性有影响,即降低了我模型的准确性。那么,在减少过拟合的过程中,我该如何提高模型的准确性呢?
也许尝试不同的 dropout 水平?
嗨,Jason,
如果我获得了96%的训练准确率和86%的测试准确率,那么我想知道这是否是过拟合?
查看训练/验证集上的学习曲线
请问有人能用通俗易懂的语言向我解释一下 kernel_constraint 吗?
我明白它起着某种正则化的作用。
根据 Keras 文档,maxnorm(m) 会在您的权重的 L2 范数超过 m 时,将您的整个权重矩阵按一个因子进行缩放,
从而将范数降至 m。
那么,它与常规的归一化有什么区别呢?
来自 http://cs231n.github.io/neural-networks-2/#reg
最大范数约束。另一种正则化形式是,对每个神经元的权重向量的幅度强制施加一个绝对上限,
并使用投影梯度下降来强制执行该约束。
这种对权重矩阵的边界/缩放是如何工作的?
好问题。
存在权重衰减,它促使节点中的所有权重都变小,例如使用 L1 或 L2 范数(大小)。Keras 似乎将此称为核正则化。
然后是权重约束,它对权重施加了一个硬性规则。一个常见的例子是最大范数,它强制权重的向量范数低于某个值,例如 1、2、3。一旦超过,节点中的所有权重都会被缩小到足以满足约束。
这是一个微妙的区别。衰减是损失函数中的惩罚(软性),约束是优化过程中的 If-Then 语句(硬性)。
这有帮助吗?
谢谢你的分享,这很有帮助
很高兴它有帮助。
嗨 Jason
感谢这些精彩的教程,简直令人难以置信!
快速提问,导入所需库时,您为何采用以下形式导入
“from [moduleX.submoduleY] import [functionalityZ]”
“import [moduleX]” 不会导入整个库吗?或者子模块无法通过这种方式访问?或者我们这样做只是为了节省内存?
作为一名工程师,我被教导只导入所需的内容。
嗨,Jason,
你提到 dropout 在预测时没有使用,但事实并非如此,我们在预测时也使用了 dropout。
我们只需将每个激活函数的输出乘以我们在每个层中使用的概率率。
Dropout 仅在训练期间使用。
嗨,Jason,
我应用了上述技术和您的书中所述的其他技术来减少过拟合,效果很好。然而,模型在一个从未见过的数据集上表现非常差。
根据您的经验,您认为不应用任何减少过拟合的方法可能是训练数据集的最佳方式吗?我知道这可能无法一概而论,但您是否也认为这与我们正在处理的数据集有关?在我的案例中,我正在处理医疗保健数据集。
非常感谢这些精彩的教程和书籍。
Sinan
一些想法
也许样本外数据集不具有代表性?
也许需要其他正则化方法?
也许训练过程也需要调整?
告诉我进展如何。
亲爱的Jason您好,
非常感谢您的精彩帖子。
我有一个关于过拟合的问题。
您能告诉我如何判断我的 CNN 是否过拟合了吗?
据我所知,当训练准确率和验证准确率之间存在显著差异时,就会发生过拟合。
我之所以问这个问题,是因为我设计了一个 CNN,并将 dropout 设置为 0.5。
我的训练准确率约为 99%,最大验证准确率为 89%,当我将 dropout 降至 0.3 时,我的训练准确率保持不变,但验证准确率却出乎意料地增加到 95%。
我不知道我是否能相信这个准确率。
您认为我的 CNN 发生过拟合了吗?
您可以在训练数据集和验证数据集上查看训练期间的学习曲线。
如果验证结果持续变差而训练结果持续变好,则表示您过拟合了。
嗨,Jason,
我们可以在第一个卷积层之前使用 Dropout 吗?在您这里展示的例子中,Dropout 是在密集层之前完成的。但我找到了一段代码,他们在第一个卷积层之前使用了 Dropout。
https://github.com/tzirakis/Multimodal-Emotion-Recognition/blob/master/models.py
如果我没理解错的话,在这段代码中,在“audio_model”内部,“net”的第一个层是 Dropout,然后是 Conv2D 层。
也许可以尝试一下并比较结果?
嗨,Jason,将 Dropout 设置为零对我们的神经网络有影响吗?我的意思是,仅仅添加一个层,但值设置为零,会有任何影响吗?
在 Keras 中,Dropout 率为 0.0 将不起作用。
您好,我训练了一个带有 LSTM、Dropout、LSTM、Dropout 和一个密集层的顺序模型。调整超参数后,我得到的 Dropout 值为 1。这意味着什么?我无法理解。
在 Keras 中,Dropout 为 1 表示完全/始终 Dropout,这可能不起作用。
https://machinelearning.org.cn/how-to-reduce-overfitting-with-dropout-regularization-in-keras/
嗨,Jason!
我回到您明智、广博而深刻的机器学习知识!
我的问题与理解 Dropout 率的极限值有关,所以
1)当 Dropout 率设置为 0 时,是否等同于不添加 Dropout 层?这正确吗?
2)当 Dropout 率设置为 1 时,是否等同于破坏整个网络,使模型无法再学习?这正确吗?
感谢您的工作和时间!
JG
在论文中,Dropout 是一个“保留”百分比,例如 80% 意味着 Dropout 20%。
在 Keras 中,Dropout 意味着 Dropout,80% 保留实现为 20% Dropout (0.2)。
因此,正如您所说,在 Keras 中,0.0 意味着没有 Dropout,1.0 意味着丢弃所有内容。
谢谢 Jason!现在更清楚了!
很高兴听到这个消息。
嗨 Jason,
我可以在哪里获取您使用的数据?
或者您能展示一个数据类型的示例吗,因为我遇到了一些错误,我不知道为什么。特别是在我向模型提供 y 的方式中,它抱怨维度问题。
所有数据集均可在此处获取
https://github.com/jbrownlee/Datasets
您好,我使用了 ModelCheckPoint,相同的 epoch 和 batchsize。找到的最佳配置在第 86 个 epoch。
我绘制了损失函数和准确率,我看到训练曲线和测试曲线之间存在重要的差距。对应于测试数据的损失曲线增加了。
这意味着什么?
谢谢!!
这会有帮助
https://machinelearning.org.cn/learning-curves-for-diagnosing-machine-learning-model-performance/
嗨,Jason,
感谢您的及时帮助!根据损失函数,问题似乎是对应于不具代表性的数据集。
我将训练-测试分割从 30% 减少到 20%。准确率显著提高(90%),但训练损失曲线和验证损失曲线之间的差距仍然存在。
也许尝试 50/50 分割?
嗨,Jason,
首先,感谢您的耐心。结果保持不变:训练和测试损失函数之间的差距仍然存在,并且准确率略有下降(现在为 86%)。
如果训练集更小(从 80% 下降到 50%),它如何更具代表性?
也许模型对训练数据集稍微过拟合了?
嗨,Jason,
这是我正在使用的模型
# 创建模型
model = Sequential()
model.add(Dense(60, input_dim=59, kernel_initializer='uniform', kernel_constraint=max_norm(3.), activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(30, kernel_initializer='uniform', kernel_constraint=max_norm(1.), activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1, kernel_initializer='uniform', kernel_constraint=max_norm(1.), activation='sigmoid'))
# 编译模型
epochs = 150
learning_rate = 0.1
decay_rate = learning_rate / epochs
momentum = 0.9
sgd = SGD(lr=learning_rate, momentum=momentum, decay=decay_rate, nesterov=False)
model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
filepath="weights.best.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='val_accuracy', verbose=1, save_best_only=True, mode='max')
callbacks_list = [checkpoint]
# 拟合模型
history=model.fit(X_train, Y_train, validation_data=(X_test, Y_test), epochs=300, batch_size=16, callbacks=callbacks_list, verbose=0)
干得好!
嗨,Jason,
您能告诉我们,当我们已经使用 Dropout 训练了神经网络时,在使用相同的模型权重进行预测(服务模型)时,如何处理?
据我所知,Dropout 仅在训练期间使用。
嗨,Jason,谢谢您的回复,但是假设我们有 6 个神经元 Dropout,并且概率为 0.5,那么在下一层中信号的权重将是 1/5 的强度,但是当我们在预测网络中时,所有 6 个神经元都将传递信号,这可能会导致额外的输入幅度增加,进而对后续层产生影响。那么它不会相应地调整吗?
不,Dropout 下的训练会导致节点分担负载,达到平衡。
请记住,Dropout 是概率性的。
在测试时,您可以将 Dropout 层的每个权重乘以 Dropout 概率。
如何在预测期间在测试集上实现 Dropout?
基本上,我想对模型在测试集上的预测不确定性进行建模,所以也请提供关于如何最好地实现这一点的任何建议。
Dropout 仅在训练期间使用。
我相信您可以在测试期间强制执行 Dropout。我博客上可能有示例,抱歉我不记得了。
嗨 Jason,如何使用 3 个不同的数据集进行 Dropout?
抱歉,我不明白您的问题,您能详细说明一下吗?
嗨,Jason,我们可以构建一个定制的 Dropout 层吗?如果构建定制的 Dropout 层,那么我们可以在定制的 Dropout 层中添加或更改函数吗?这样我们就可以与常规的 Dropout 层进行比较?这在实践中可能吗?或者我们最好使用常规的 Dropout 层,您能给我一些好的解释吗?这将会有很大的帮助
我看不出为什么不。
抱歉,我没有创建自定义 Dropout 层的示例。我建议查看 API 并进行实验/原型设计。
这是一个自定义的 Dropout,实现起来非常简单。有关更多详细信息,请参阅 CS231 Stanford 网上讲座和 github。
它是用于 torch 的,而不是 keras。
你为什么要分享它?
嗨,杰森,
我正在尝试使用您的部分代码和我的数据进行测试。我尝试在我的代码中使用 Dropout,但不幸的是我的验证损失低于我的训练损失,尽管训练和测试的 MSE 似乎相同,均为 0.007 和 0.008(没有 Dropout)。
此外,使用 Dropout 的 MSE 比不使用 Dropout 的 MSE 更高,如下图所示。
https://ibb.co/ZKxB7fL
https://ibb.co/N3vpDCZ
我尝试在此处找到原因
https://www.pyimagesearch.com/2019/10/14/why-is-my-validation-loss-lower-than-my-training-loss/
原因1:在训练期间应用正则化,但在验证/测试期间不应用(通常默认情况下在验证/测试中不使用 Dropout)
原因2:训练损失在每个 epoch 期间测量,而验证损失在每个 epoch 之后测量
原因3:验证集可能比训练集更容易(或者可能存在泄漏)
我认为在我的情况下,原因 2 更符合逻辑。
X_train=174200 个样本
X_test=85800
y_train=174200
y_test=85800
代码
X = dataset[:,0:20].astype(float)
y = dataset[:,20:22]
scaler = StandardScaler()
X = scaler.fit_transform(X)
y = scaler.fit_transform(y)
# 拆分为训练测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33,random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# 定义 Keras 模型
model = Sequential()
model.add(Dense(20, input_dim=20,kernel_initializer='normal'))
model.add(LeakyReLU(alpha=0.1))
#model.add(Dropout(0.2))
model.add(Dense(7,kernel_initializer='normal'))
model.add(LeakyReLU(alpha=0.1))
#model.add(Dropout(0.2))
model.add(Dense(2, activation=’linear’))
opt = SGD(lr=0.01, momentum=0.9)
# 编译 Keras 模型
model.compile(loss='mean_squared_error', optimizer=opt, metrics=['mse'])
# 在数据集上拟合 Keras 模型
history=model.fit(X, y, validation_data=(X_test, y_test),epochs=25,verbose=0)
# 评估模型
_, train_mse = model.evaluate(X_train, y_train, verbose=0)
_, test_mse = model.evaluate(X_test, y_test, verbose=0)
print(‘训练集:%.3f,测试集:%.3f’ % (train_mse, test_mse))
#绘制训练期间的损失
pyplot.title(‘损失/均方误差’)
pyplot.plot(history.history[‘loss’], label=’训练’)
pyplot.plot(history.history[‘val_loss’], label=’测试’)
pyplot.legend()
pyplot.show()
当您的验证数据集太小或不代表训练数据集时,这种情况很常见。
谢谢您的回答。
我将 test_size 增加到 50%,但结果仍然一样。打印出的 train_mse 和 test_mse 是相同的(看起来不错)。为什么测试损失函数的图比训练损失低?
您有什么建议?
谢谢
也许您应该确认您正在绘制您认为正在绘制的内容(调试)。
也许尝试您的数据集的替代样本。
也许尝试替代模型。
谢谢 Jason 的回答。
我尝试更改数据集。
我尝试将隐藏层中的节点数增加到 25。
我还简化了模型。我只保留了一个隐藏层。
model = Sequential()
model.add(Dense(20,input_dim=20,kernel_constraint=max_norm(3.),kernel_initializer='normal'))
model.add(LeakyReLU(alpha=0.1))
model.add(Dropout(0.2))
model.add(Dense(2, activation=’linear’))
opt =Adadelta(lr=0.01)
# 编译 Keras 模型
model.compile(loss='mean_squared_error', optimizer=opt, metrics=['mse'])
....
得到的结果:训练:0.002,测试:0.003
但是损失函数的图没有变化。验证损失总是低于我的训练损失。
绘制损失函数的代码是
pyplot.title(‘损失/均方误差’)
pyplot.plot(history.history[‘loss’], label=’训练’)
pyplot.plot(history.history[‘val_loss’], label=’测试’)
pyplot.legend()
pyplot.show()
做得好。也许继续尝试这里列出的其他更改。
https://machinelearning.org.cn/start-here/#better
谢谢你,Jason。
您的代码非常有帮助。
我找到了错误。
它就在我的代码里
history=model.fit(X, y, validation_data=(X_test, y_test),epochs=25,verbose=0)
X,y==>X_train ,y_train
干得好!
嗨,Jason,
感谢您的清晰解释。不过我有一个疑问。在我创建的一个模型中,使用极简主义的基线 CNN(只有 4 层 conv+maxpool)获得了非常好的(约 99%)验证准确率。然而,当我增加哪怕 1 层时,验证就会提前停止,因为它趋于平稳。这是否意味着网络正在加深并研究对模型没有积极贡献的东西?由于这不是过拟合的情况(验证和训练几乎同步进行),我也不倾向于使用 Dropout。在这种情况下,增强数据以查看准确率是否会增加有意义吗?准确率达到 99.xxx,我不确定是否真的有必要这样做。希望能听听您的想法。
此致,
James
不客气。
更改模型的容量通常需要相应地调整学习超参数(学习率、批次大小等)。
尝试 Dropout 看看。尝试数据增强看看。实验成本低。
在保留数据集上获得 99% 的准确率可能表明您的预测任务是微不足道的,并且可以使用更简单的方法解决。
谢谢 Jason。对于图像分类,是否有更简单的方法?我通常在处理图像时选择 CNN。我也可以尝试普通的回归或随机森林,看看它们的效果如何。
是的,尝试一个简单的机器学习算法,在标准化像素上拟合。
感谢 Jason 及时回复。我一定会尝试一下。
嗨,Jason,
有什么方法可以在预训练网络中实现 Dropout 吗?谢谢!
当然,您可以向网络添加层,但我认为您必须重新连接网络中的所有层(很麻烦)。
大家好,
有人知道 Dropout 实际提高了神经网络模型测试分数的具体例子吗?我想原始出版物的作者可能提供了示例(我承认我没有读过),但除了原始出版物之外,还有人知道哪些情况下它确实提高了测试分数吗?
谢谢,
Steve
嗨 Steven……以下资源及其中的结果可能对您感兴趣
https://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf
如何为总计 7000 个数据集构建不会过拟合的 LSTM 和 GRU 模型
嗨 Yihun……当您拥有相对较小的数据集(例如 7000 个样本)时,构建一个不会过拟合的 LSTM(长短期记忆)或 GRU(门控循环单元)模型需要仔细的模型设计和正则化策略。以下是一些方法和技巧
### 1. 简化模型架构
– **降低复杂性**:从简单的模型开始。对于小型数据集,具有太多参数的复杂模型很容易过拟合。最初使用一两个循环层,每个层具有中等数量的单元(例如,每个层 50-100 个单元)。
– **尝试 LSTM 和 GRU**:GRU 通常比 LSTM 更简单(参数更少),并且可能更不容易过拟合。比较它们在您特定数据集上的性能。
### 2. 实施正则化技术
– **Dropout**:将 Dropout 应用于 LSTM 或 GRU 层的输入和循环连接。这会在训练期间随机丢弃(设置为零)一部分输出单元,有助于防止过拟合。
– 例如,在循环层之间使用 `Dropout` 层,如果您的输入数据是顺序的(如时间序列),则可能使用 `SpatialDropout1D`。
– **L2 正则化**:向循环层添加 L2 正则化,它根据层参数的平方大小对它们进行惩罚。
### 3. 优化训练过程
– **早期停止**:在训练期间使用早期停止。当验证集上的性能开始恶化时,此技术会停止训练,从而防止在训练数据上过度训练。
– **高原期降低学习率**:如果验证损失停止改善,则降低学习率。这可以导致更精细的训练步骤,从而绕过过拟合陷阱。
### 4. 数据管理
– **交叉验证**:除了简单的训练-测试分割之外,使用 k 折交叉验证以最大化您的模型对不同数据子集的接触。这可以提高模型的泛化能力。
– **数据增强**:对于顺序数据,如果适合您的问题领域,您可以实施窗口化、噪声注入或时间偏移等技术。
– **特征选择**:将特征数量限制为仅最具信息量的特征,从而降低模型复杂性并减少过拟合的可能性。
### 5. 调整模型输入
– **归一化/标准化**:缩放您的输入特征,使它们对学习过程贡献相等,这可以帮助模型更有效地学习并可能减少过拟合。
### 示例代码
这是一个使用 Keras 构建 GRU 模型进行序列分类问题的基本示例,其中实现了一些这些策略
python
from keras.models import Sequential
from keras.layers import GRU, Dropout, Dense
from keras.callbacks import EarlyStopping, ReduceLROnPlateau
from keras.regularizers import l2
model = Sequential()
model.add(GRU(50, return_sequences=True, input_shape=(timesteps, features),
kernel_regularizer=l2(0.001)))
model.add(Dropout(0.2))
model.add(GRU(50, kernel_regularizer=l2(0.001)))
model.add(Dropout(0.2))
model.add(Dense(1, activation='sigmoid')) # 根据您的输出需求调整激活函数和神经元数量
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
early_stopping = EarlyStopping(monitor='val_loss', patience=10)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5)
model.fit(x_train, y_train, epochs=100, batch_size=32, validation_split=0.2,
callbacks=[early_stopping, reduce_lr])
### 最终思考
防止过拟合的关键,尤其是在数据集较小的情况下,是先从简单开始,然后仅在需要且验证性能有所提高时才逐渐增加复杂性。根据性能指标进行监控、测试和迭代是微调模型的关键步骤。