Dropout 和 批次标准化
加入这些特殊的层来避免过拟合并稳定训练过程
简介
- 深度学习的世界可不止有密度层。你可以在模型中添加各种各样的层,(看看Keras官方文档你就知道)其中,有一些跟密度层差不多,是定义在神经元之间的,另一些是可做预处理或转换等其他类。
- 这节课,我们将学习两种特殊的特殊的层,他们本身不包含任何神经元,但是加入一些功能,他们可以在很多方面来帮助模型构建。这两个在现代模型的结构中都十分常见。
Dropout
- 第一个是“Dropout层”,这个方法可以帮助修正过拟合。
- 上节课我们讨论过过拟合是由于网络学习了训练集中虚假的数据规律。要辨识出这些虚假的规律需要有一个非常特殊的权重组合。这些权重组合非常精妙,以至于他们非常脆弱,缺一个都不行。
- 这就是 dropout 的原理,要想打破这种组合,我们就需要训练步骤中随机剔除掉一些输入的部分,使得网络更难学习这些错误的规律,从而不得不学习广泛的规律,这样学习得到的权重值会更强大。
- 你可以把dropout看作他创建了一系列的网络,预测不再是单个大型网络的产物,而是一系列相似的网络的共同决策。每一个网络在预测中都会出现一些错误,但是他们一起就可以做出正确的决策,使得网络构成的集合要比任何一个单一网络要做的好。(这和随机森林是一个道理)
加入 Dropout
- 在Keras中,剔除率表示为参数
rate
,它定义了关闭输入的百分比。只要将Dropout
层加在你想加的层前面即可。
keras.Sequential([
# ...
layers.Dropout(rate=0.3), # apply 30% dropout to the next layer
layers.Dense(16),
# ...
])
批次标准化
- 下一个特殊的层叫“批次标准化”(或batchnorm),它可以解决训练缓慢或不稳定的情况。
- 对于神经网络来说,大部分情况下,使用相同范围内的输入,模型表现会好一些,通常使用scikit-learn的 StandardScaler或者MinMaxScaler。原因是SGD会根据数据的激活值大小成比例的改变网络中的权重,特征倾向于产生不同大小的激活值,使得训练行为变得不稳定。
- 那么如果在数据进入网络之前标准化是很有效的,那么在网络中进行标准化会不会更好?我们有一个专门的层可以做这个—— 批次标准化层。一个批次标准化层查看每个批次的输入,首先首先将本批次根据他的平均值和标准差进行标准化。批次标准化最终的结果是得到一种协调后的重新调节的输入。
- 批次标准化最常见是用于辅助优化过程(即使他有的时候能够帮助预测)。有了批次标准化的模型往往需要更少的阶段数来完成训练。此外,它还可以修复众多可能导致训练“卡壳的”情况。要记得考虑加入批次标准化,尤其是在你训练时遇到问题了。
添加批次标准化
- 批次标准化几乎可以用在神经网络的任何位置,你可以放在一层后面……
layers.Dense(16, activation='relu'),
layers.BatchNormalization(),
- ……或者放在层之间,外加激活函数
layers.Dense(16),
layers.BatchNormalization(),
layers.Activation('relu'),
- 而且,如果你将它作为第一层加入模型作为之种适应性预处理,那么就可以作为一种类似Sci-Kit Learn的
StandardScaler
的角色。
案例:使用剔除和批次标准化
- 我们接着提升红酒检测的模型。现在,我们将大幅度提升模型的能力,只是使用的是剔除来控制过拟合,使用批次标准化来加快优化。这次,我们就省略了数据加载的过程,详情见上期。
- 当你加入剔除时,你可能还需要增大密度层的数量:
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Dense(1024, activation='relu', input_shape=[11]),
layers.Dropout(0.3),
layers.BatchNormalization(),
layers.Dense(1024, activation='relu'),
layers.Dropout(0.3),
layers.BatchNormalization(),
layers.Dense(1024, activation='relu'),
layers.Dropout(0.3),
layers.BatchNormalization(),
layers.Dense(1),
])
- 这次没有在训练过程中的改动。
model.compile(
optimizer='adam',
loss='mae',
)
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=256,
epochs=100,
verbose=0,
)
# Show the learning curves
history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot();
2021-09-13 20:12:33.800093: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:116] None of the MLIR optimization passes are enabled (registered 2)
2021-09-13 20:12:33.815943: I tensorflow/core/platform/profile_utils/cpu_utils.cc:112] CPU Frequency: 2199995000 Hz
- 你如果在训练前将数据进行了标准化处理,那么获得的模型性能会更好。如果我们使用了完全未加工的数据你就会发现批次标准化能够建立在更复杂的数据集上。