最近一直疑惑, BatchNorm(以下简称BN)应该放在激活函数之前, 还是激活函数之后? 今天看到了before-or-after-relu 以后铁了心要 BN 放在激活函数之后了!

BN放在RELU之后, 精度更优

这里简单放一张评估结果

其它一些测试结果还可以查看原文连接把BN放在 ReLU 之后精度略有提升.

把BN放在激活函数之后, 像是一种经验结论(确实用实验证明的), 从理论上分析, 也应该站得住脚. BN原作者提出是为了克服网络的Internal Covariate Shift, 作者的做法是在激活函数之前加入BN层. 然而在引入RELU激活函数之后, 导致Internal Covariate Shift最为显著的应该是RELU, 把BN放在RELU之后, 应该说是克服Internal Covariate Shift最为有效的方式

论文回顾

Motivation

作者认为:网络训练过程中参数不断改变导致后续每一层输入的分布也发生变化,而学习的过程又要使每一层适应输入的分布,因此我们不得不降低学习率、小心地初始化。作者将分布发生变化称之为 internal covariate shift

解读Batch Normalization

BN是基于 mini batch 训练的, 原文还一顿跨了它的好处

  1. 在梯度下降法中, mini batch 的梯度是对整个训练集的估计
  2. 计算效率上得到提升. 并行计算, 避免逐个样本进行串行计算

为了克服internal covariate shift, 作者便提出如下的归一化:

但是迫于作者当时的局限性(作者将BN放在激活函数之前), 为了不减弱激活函数的非线性能力, 又引入了缩放和平移两个学习参数.

为什么要 scale 和 bias 参数

作者将BN放在激活函数之前, 如果只是简单地用如下方式进行归一化, 那么对于sigmoid激活函数, 只能用到中间的接近线性的部分, 也就是说降低了网络的非线性能力.

所以最终的BN形式如下:

现在看来, 如果把BN放在RELU之后, 那么 scale 和 bias 则必要性不是很大了. caffe对BN的实现把这两个操作抽出来单独成为 scale 层和 bias 层, 将选择的自由度提升到了最大!

参考链接