批量归一化和 dropout 的顺序如何安排?

242

原问题涉及 Tensorflow 实现,但是回答适用于一般实现。这个通用的回答同样适用于TensorFlow。

在使用TensorFlow(特别是使用 contrib.layers)时,使用批量归一化和丢弃操作时,我需要担心顺序吗?

如果我在丢弃操作之后立即使用批量归一化,可能会出现问题。例如,如果批量归一化中的偏移训练到更大规模的输出数量,但在测试期间,由于有更多的输出,对较小规模的数字进行补偿而没有使用丢弃操作,则该偏移可能不准确。TensorFlow 批量归一化层是否会自动进行补偿?或者出于某种我没注意到的原因,这种情况不会发生?

另外,在同时使用这两个操作时,还有其他要注意的问题吗?例如,假设我按照上述正确的顺序使用它们(假设有正确的顺序),在连续的多个层上同时使用批量归一化和丢弃操作会有问题吗?我并没有立即看到其中的问题,但也许是我遗漏了什么。

非常感谢!

更新:

一次实验性测试似乎表明顺序确实很重要。我用相同的网络分别运行了两次,只是批量归一化和丢弃操作的顺序相反。当丢弃操作在批量归一化之前时,验证损失似乎会随着训练损失下降而上升。在另一种情况下,它们都在下降。但是我的情况变化缓慢,因此在更多训练后可能会改变,这只是一个单独的测试。仍然需要一个更确定和知情的答案。

9个回答

252
Ioffe and Szegedy 2015中,作者指出“我们希望确保对于任何参数值,网络始终产生具有所需分布的激活”。因此,批量归一化层实际上是在卷积层/全连接层之后插入的,但在馈送到ReLu(或任何其他类型的)激活之前。有关详细信息,请参见this video,大约在53分钟左右。 就dropout而言,我认为dropout应用于激活层之后。在dropout paper图3b中,隐藏层l的dropout因子/概率矩阵r(l)应用于y(l),其中y(l)是应用激活函数f后的结果。 因此,批量归一化和dropout的使用顺序如下:

-> CONV/FC -> 批量归一化 -> ReLu(或其他激活函数) -> Dropout -> CONV/FC ->


116
看起来连Christian Szegedy现在也喜欢在ReLU之后执行BatchNorm(而不是在它之前)。Keras的作者F. Chollet说:“我没有回去检查他们在原始论文中建议什么,但我可以保证,Christian编写的最近代码在应用BN之前应用了ReLU。尽管如此,这仍然偶尔是一个讨论话题。” - pseudomarvin
10
池化层放在批归一化和激活函数之间吗? - wordsforthewise
6
看起来在激活后使用批归一化可能会提高准确性:https://github.com/cvjena/cnn-models/issues/3 - wordsforthewise
1
视频不知何故被删除了! - blitu12345
20
这篇论文表明,通常情况下在使用批归一化时加入随机失活会导致更糟糕的结果,除非进行某些调节以避免方差偏移的风险。 - Arka Mallick
显示剩余3条评论

68

正如评论中所指出的,关于层顺序的一个很好的资源在这里。我已经读过评论了,这是我在互联网上找到的最好的相关主题资源。

我的2分钱:

Dropout旨在完全阻止某些神经元的信息流通以确保神经元不会共同适应。 因此,批归一化必须在dropout之后进行,否则将通过归一化统计量传递信息。

如果你想想,对于典型的机器学习问题,这就是我们不会在整个数据集上计算平均值和标准差,然后将其拆分为训练、测试和验证集的原因。我们将其拆分,然后在训练集上计算统计量,并使用它们来归一化和居中验证和测试数据集。

因此,我建议Scheme 1(这考虑了pseudomarvin评论中的接受答案)

-> CONV / FC-> ReLu(或其他激活)-> Dropout-> BatchNorm-> CONV / FC

而不是Scheme 2

-> CONV / FC-> BatchNorm-> ReLu(或其他激活)-> Dropout-> CONV / FC-> 在接受的答案中

请注意,这意味着方案2下的网络与方案1下的网络相比应该会出现过拟合,但OP进行了一些测试,如问题中所述,并且它们支持方案2。

有关BatchNorm位置的相关Reddit讨论:https://www.reddit.com/r/MachineLearning/comments/67gonq/d_batch_normalization_before_or_after_relu/ - saetch_g
16
这不会破坏你的批归一化统计数据吗?因为你是在应用 dropout 之后进行计算,而在测试时这种情况并不成立。 - ZakJ
3
@ZakJ是正确的。请参考Mohammed Adel的答案和这篇论文:https://arxiv.org/pdf/1801.05134.pdf。实际上,批量归一化层学习对抗数据中的协变量偏移,而在测试时关闭Dropout后该偏移已不存在。 - skeller88
3
@skeller88 我还没有看过这篇论文。就我个人的想法而言,如果你在 dropout 之前使用 BN,那么这实际上会破坏 BN 层的意图,因为 BN 的功能是为下一层提供标准化数据。 - figs_and_nuts
2
我在验证准确度方面遇到了问题,但是通过方案1进行了规范化。 - wanjiku
显示剩余2条评论

30

多层感知器(MLPs)有哪些方面是将它们组合在一起有用的? - DINA TAKLIT
1
在我的看法中,当你确实没有足够的训练数据时,是的。 - xtluo
2
@DINATAKLIT 在您之前的评论中,“关于MLPs,它们是否有用组合起来”,您是指“在使用MLPs时,组合Dropout和BN是否有用”? 我的感觉是这主要取决于您的模型大小和训练数据量。 - xtluo
1
即使有BN,您仍然可以使用dropout。这取决于设计。这是一项正在进行的研究。您可以查看此论文:https://arxiv.org/abs/1506.02142 - salehinejad
只有在您拥有足够的数据时,才能应用批量归一化。想象一个极端情况,即您只有10个样本的数据集。在这种情况下,批量归一化无法帮助您。 - York Yang
显示剩余2条评论

27

卷积 - 激活 - 随机失活 - 批量归一化 - 池化 --> 测试损失:0.04261355847120285

卷积 - 激活 - 随机失活 - 池化 - 批量归一化 --> 测试损失:0.050065308809280396

卷积 - 激活 - 批量归一化 - 池化 - 随机失活 --> 测试损失:0.04911309853196144

卷积 - 激活 - 批量归一化 - 随机失活 - 池化 --> 测试损失:0.06809622049331665

卷积 - 批量归一化 - 激活 - 随机失活 - 池化 --> 测试损失:0.038886815309524536

卷积 - 批量归一化 - 激活 - 池化 - 随机失活 --> 测试损失:0.04126095026731491

卷积 - 批量归一化 - 随机失活 - 激活 - 池化 --> 测试损失:0.05142546817660332

卷积 - 随机失活 - 激活 - 批量归一化 - 池化 --> 测试损失:0.04827788099646568

卷积 - 随机失活 - 激活 - 池化 - 批量归一化 --> 测试损失:0.04722036048769951

卷积 - 随机失活 - 批量归一化 - 激活 - 池化 --> 测试损失:0.03238215297460556


在MNIST数据集上进行训练(20个时期),使用2个卷积模块(如下所示),每次后跟随

model.add(Flatten())
model.add(layers.Dense(512, activation="elu"))
model.add(layers.Dense(10, activation="softmax"))
卷积层的核大小为(3,3),默认填充,激活函数为elu。池化是poolside(2,2)的MaxPooling。损失函数为categorical_crossentropy,优化器为adam。 相应的丢失概率分别为0.2或0.3。特征映射的数量分别为32或64。 编辑:当我删除了Dropout(一些答案中建议),它收敛得更快,但泛化能力较差,而当我使用BatchNorm Dropout时,则有更好的泛化能力。

13
由于神经网络的随机性,仅进行一次训练是不够的。当进行约100次训练并取平均值时,结果将更加准确。 - GensaGames
2
这是与权重初始化相关的度量,几乎就是如此。 - Union find
2
请预设您的随机种子并运行至少10次以上,否则一次训练的结果是不可靠的。 - Nico
1
真正的问题并不是关于权重初始化(如果有足够的迭代次数,通常不会太大的问题);而是这种排序是否适用于MNIST之外的其他数据集。 - legel

17
我找到了一篇论文,解释了Dropout和Batch Norm(BN)之间的不协调。关键思想是他们所称的"方差偏移"。这是由于在训练和测试阶段,dropout具有不同的行为方式,而这会导致BN学习的输入统计数据发生变化。 主要思想可以从这张图片中找到,该图片摘自这篇论文. enter image description here 一个小的演示效果可以在这个notebook中找到。

6
这个回答如何回答问题? - nbubis
2
这篇论文提供了两种潜在的策略:
  • 在所有BN层之后仅应用Dropout
  • 将Dropout转换为更具方差稳定性的形式
- user3641187
1
@nbubis 我认为它间接回答了这个问题。它似乎暗示着根本不要同时使用它们(“解释了Dropout和Batch Norm(BN)之间的不协调”)。 - NelsonGon
这是问题的答案。在训练期间,Dropout 会改变分布的“标准差”,但不会改变验证期间的分布。批量归一化确实取决于分布的统计数据。因此,如果您在批量归一化之前使用了 Dropout,则批量归一化在训练和验证期间将产生不同的结果。 - Daniel Möller

16

我阅读了答案和评论中推荐的论文https://dev59.com/Z1kS5IYBdhLWcg3wj3fP#40295999

从Ioffe和Szegedy(2015)的观点来看,只在网络结构中使用BN。Li等人(2018)给出了统计和实验分析,当从业者在BN之前使用Dropout时会出现方差偏移。因此,Li等人(2018)建议在所有BN层之后应用Dropout。

从Ioffe和Szegedy(2015)的观点来看,BN位于激活函数内部/之前。然而,Chen等人(2019)使用了一个IC层,将dropout和BN组合起来,并建议在ReLU之后使用BN。

在安全背景下,我仅在网络中使用Dropout或BN。

陈广勇、陈鹏飞、史煜军、谢昌宇、廖本本和张圣宇。2019。“重新思考批量归一化和深度神经网络训练中的Dropout使用。”CoRR abs/1905.05928. http://arxiv.org/abs/1905.05928

Ioffe,Sergey和Christian Szegedy。2015。“批量归一化:通过减少内部协变量移位加速深度网络训练。”CoRR abs/1502.03167。http://arxiv.org/abs/1502.03167

李翔、陈硕、胡晓林和杨健。2018。“通过方差偏移理解Dropout和批量归一化之间的不协调。”CoRR abs/1801.05134。http://arxiv.org/abs/1801.05134


3
根据这篇研究论文,为了获得更好的性能,我们应该在应用Dropouts之前使用BN。

答案没有回答问题中涉及到的整个技术栈。 - salehinejad

-1
阅读了多篇答案并进行了一些测试后,这是我的假设: a) 始终是BN -> AC,它们之间没有东西。 b) BN -> Dropout优于Dropout -> BN,但两者都要尝试。[最新的研究发现第一个更好] c) BN消除了使用Dropout的必要性,不需要使用Dropout。 d) 最后使用池化。 e) 在Dropout之前使用BN是数据泄漏。 f) 最好尝试每种组合。

所谓的最佳方法 -

-> BN -> AC -> Dropout -> 池化 ->


-1

ConV/FC - BN - Sigmoid/tanh - dropout。 如果激活函数是Relu或其他,则归一化和dropout的顺序取决于您的任务。


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