SpatialDropout2D、BatchNormalization和激活函数的正确顺序是什么?

8
对于CNN架构,我想使用SpatialDropout2D层代替Dropout层。此外,我想使用BatchNormalization。到目前为止,我总是在激活函数之前直接在卷积层后设置BatchNormalization,就像Ioffe和Szegedy提到的论文中一样。而且,我总是在MaxPooling2D层之后设置dropout层。
https://machinelearningmastery.com/how-to-reduce-overfitting-with-dropout-regularization-in-keras/中,SpatialDropout2D直接放在Convolutional层后面。我觉得现在应该如何应用这些层有点困惑。我也曾在Keras页面上阅读过,SpatialDropout应该直接放在ConvLayer之后(但我无法再找到这个页面)。
以下顺序是否正确?
ConvLayer - SpatialDropout - BatchNormalization - 激活函数 - MaxPooling
我真的希望能得到一些提示,先谢谢了。
更新 实际上,我的目标是在以下CNN架构中将dropout替换为spatial dropout:
model = Sequential()
model.add(Conv2D(32,(3,3))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32,(3,3))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2))
model.add(Dropout(0.2))

model.add(Conv2D(64, (3,3))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(64,(3,3))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2))
model.add(Dropout(0.2))

model.add(Flatten())
model.add(Dense(512))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dropout(0.4))
model.add(Dense(10))
model.add(Activation('softmax'))
1个回答

18

Dropout与BatchNormalization - 标准偏差问题

当你混合使用这些层时,尤其是在Dropout之后紧跟着BatchNormalization时,会出现一个很大的问题。

Dropouts试图保持输出的平均值不变,但它确实改变了标准偏差,这将导致训练和验证之间BatchNormalization有很大的差异。(在训练期间,BatchNormalization接收到改变的标准偏差,累积并存储它们。在验证期间,关闭dropout,标准偏差不再改变,而是原始的。但是BatchNormalization因为处于验证状态,所以不使用批量统计数据,而是使用存储的统计数据,这将与批量统计数据非常不同)

因此,第一条最重要的规则是: 不要在Dropout(或SpatialDropout)后面放置BatchNormalization

通常,在应用批归一化之前,我会尝试至少保留两个卷积/密集层没有任何dropout,以避免这种情况发生。

Dropout与BatchNormalization - 将零改为另一个值

还要注意的是: Dropout的作用是将下一层的某些权重"归零"。如果在dropout之后应用了规范化,你将不再有"零",而是一个特定的值,这个值将被多个单元重复。而且这个值会因批量而异。因此,虽然会添加噪声,但你并没有像纯的dropout所做的那样杀死单元。

Dropout与MaxPooling

使用常规的Dropout在MaxPooling之前的问题是,您将使一些像素为零,然后MaxPooling将取最大值,有点忽略了您的dropout的部分。如果您的dropout碰巧达到最大像素,则池化将导致第二个最大值,而不是零。
因此,Dropout在MaxPooling之前降低了dropout的效果。
SpatialDropout与MaxPooling
但是,SpatialDropout从不会影响“像素”,它只会影响通道。当它影响通道时,它将使该通道中的所有像素都为零,因此,MaxPooling将有效地产生零。
因此,在池化之前或之后使用空间dropout没有区别。在两种情况下,整个“通道”都将为零。
BatchNormalization与Activation
根据激活函数,使用批量归一化可以是一个很好的优势。
对于relu激活,归一化使模型免受“所有零冻结relu层”的坏运气情况。它还倾向于保证一半的单元为零,另一半为线性。
对于sigmoid或tahn,BatchNormalization将确保值处于健康范围内,避免饱和和消失梯度(距离零太远的值将击中这些函数的几乎平坦区域,导致消失梯度)。

有些人说,如果你做相反的事情,还有其他优点,但我不完全了解这些优点,我非常喜欢我提到的那些。

Dropout vs Activation

使用'relu'时,没有区别,可以证明结果完全相同

对于不是中心化的激活函数,例如'sigmoid',在激活函数之前加入dropout不会导致"零",而是其他值。对于sigmoid,它之前的dropout的最终结果将为0.5。

如果在dropout之后添加'tanh',则会得到零,但是dropout应用于保持相同均值的缩放将被tanh扭曲。(我不知道这是否是一个大问题,但可能是)

MaxPooling vs Activation

我在这里看不出什么。如果激活函数不是非常奇怪,最终结果将是相同的。

结论?

有可能性,但有些麻烦。我认为以下顺序是很好的,并经常使用它们

我会做一些类似的事情

  • 第一组
    • 卷积层
    • 批标准化层
    • 激活函数层
    • 最大池化层
    • Dropout或SpatialDropout层
  • 第二组
    • 卷积层
    • -----(上一组有dropout,这里没有批标准化)
    • 激活函数层
    • 最大池化层
    • Dropout或SpatialDropout层(决定是否使用)
  • 两组无dropout之后
    • 可以再次使用批标准化层

这些都是非常详细的解释,很多都非常有说服力。但我仍在疑惑的是为什么有建议将SpatialDropout直接放在ConvLayer之后?我上面附上了一段代码,实际上我只想用空间随机丢弃代替dropout,并使用这个网络进行图像识别。 - Code Now
@CodeNow 我怀疑 Möller 在 Conv 之后提倡使用 dropout,但如果是这样,我强烈反对;你链接的文章令人失望,尤其是来自一位机器学习博士。Möller 的回答其他部分是正确的,我要补充的是,在 relu 之后使用 BN 值得一试,因为它可以很好地标准化输出作为下一层的输入。此外,请注意,与“Dropout”相比,“SpatialDropout”的收敛时间可能会更长。 - OverLordGoldDragon
@OverLordGoldDragon 哦,如果'SpatialDropout' 收敛需要更长时间的话那真是有趣。或许最好在第一个'MaxPooling'之后再测试'SpatialDropout',因为Keras 在 https://keras.io/layers/core/ 页面上写到'SpatialDropout'应该仅在第一层之后使用,因为在早期卷积层中的特征映射之间强相关。 - Code Now
@CodeNow 这是一个设计决策;相关与非相关并不是明确的,每种方法都有其优缺点。例如,在自编码器中,可以使用SpatialDropout来训练稀疏自编码器,这些自编码器被证明在分类方面比去噪自编码器更好。尽管在我的时间序列实验中,SD在较早的层中的表现确实比Dropout差。另请参见此答案,与CNNs和SD的视觉演示相关。 - OverLordGoldDragon
感谢您提供如此详细的答案。不过,根据以下论文:http://openaccess.thecvf.com/content_CVPR_2019/papers/Li_Understanding_the_Disharmony_Between_Dropout_and_Batch_Normalization_by_Variance_CVPR_2019_paper.pdf,他们建议在整个网络中使用BN,然后在最后一个BN层之后使用Dropout。您对此有什么想法? - skeller88
好的,没问题。BN之后的Dropout不会造成任何伤害。Dropout之后再进行BN会造成伤害。你可以按照他们说的做。我喜欢增加更多的Dropout以减少过拟合,但必须注意不要在BN附近添加太多。 - Daniel Möller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接