看了七七八八的博客,没有统一的说法。
列举一些:
A.
BN层是真的吊,简直神器,除了会使网络搭建的时间和每个epoch的时间延长一点之外,但是关于这个问题我看到了无数的说法,对于卷积和池化层的放法,又说放中间的,也有说池化层后面的,对于dropout层,有说放在它后面的,也有说放在它前面的,对于这个问题我的说法还是试!虽然麻烦。。。但是DL本来不就是一个偏工程性的学科吗。。。还有一点是需要注意的,就是BN层的参数问题,我一开始也没有注意到,仔细看BN层的参数:
keras.layers.normalization.BatchNormalization(epsilon=1e-06, mode=0, axis=-1, momentum=0.9, weights=None, beta_init='zero', gamma_init='one')
mode:整数,指定规范化的模式,取0或1
0:按特征规范化,输入的各个特征图将独立被规范化。**规范化的轴由参数axis指定。**注意,如果输入是形如(samples,channels,rows,cols)的4D图像张量,则应设置规范化的轴为1,即沿着通道轴规范化。输入格式是‘tf’同理。
1:按样本规范化,该模式默认输入为2D
我们大都使用的都是mode=0也就是按特征规范化,对于放置在卷积和池化之间或之后的4D张量,需要设置axis=1,而Dense层之后的BN层则直接使用默认值就好了。
FROM https://blog.csdn.net/gdh756462786/article/details/79214099
B.
If your input image’s data format is “channels_last” and the input_shape is Image_Height x Image_Width x Image_Channel then try using BatchNormalization(axis = 3)
FROM https://stackoverflow.com/questions/41818654/keras-batchnormalization-uninitialized-value
C.
翻看keras BN 的源码, 原来keras 的BN层的call函数里面有个默认参数traing, 默认是None。此参数意义如下:
training=False/0, 训练时通过每个batch的移动平均的均值、方差去做批归一化,测试时拿整个训练集的均值、方差做归一化
training=True/1/None,训练时通过当前batch的均值、方差去做批归一化,测试时拿整个训练集的均值、方差做归一化
当training=None时,训练和测试的批归一化方式不一致,导致validation的输出指标翻车。
当training=True时,拿训练完的模型预测一个样本和预测一个batch的样本的差异非常大,也就是预测的结果根据batch的大小会不同!导致模型结果无法准确评估!也是个坑!
用keras的BN时切记要设置training=False!!!
(1)加速收敛
(2)控制过拟合,可以少用或不用Dropout和正则
(3)降低网络对初始化权重不敏感
(4)允许使用较大的学习率
批量归一化(Batch Normalization)并不能算作是一种最优化算法,但其却是近年来优化深度神经网络最有用的技巧之一,并且这种方法非常的简洁方便,可以和其他算法兼容使用,大大加快了深度模型的训练时间。
那什么叫批量归一化呢?首先,归一化就是将数据的输入值减去其均值然后除以数据的标准差,几乎所有数据预处理都会使用这一步骤。而深度学习也可以认为是逐层特征提取的过程,那每一层的输出其实都可以理解为经过特征提取后的数据。因此,批量归一化方法的“归一化”所做的其实就是在网络的每一层都进行数据归一化处理,但每一层对所有数据都进行归一化处理的计算开销太大,因此就和使用最小批量梯度下降一样,批量归一化中的“批量”其实是采样一小批数据,然后对该批数据在网络各层的输出进行归一化处理 。
更多数学推导公式,请参考https://blog.csdn.net/weixin_42398658/article/details/84560411
应用的局限:
局限 1:如果 Batch Size 太小,则 BN 效果明显下降。 BatchSize 小于 8算小。
局限2 :对于有些像素级图片生成任务来说,BN 效果不佳;
对于图片分类等任务,只要能够找出关键特征,就能正确分类,这算是一种粗粒度的任务,在这种情形下通常 BN 是有积极效果的。但是对于有些输入输出都是图片的像素级别图片生成任务,比如图片风格转换等应用场景,使用 BN 会带来负面效果,这很可能是因为在 Mini-Batch 内多张无关的图片之间计算统计量,弱化了单张图片本身特有的一些细节信息。
局限 3:RNN 等动态网络使用 BN 效果不佳且使用起来不方便。
Batch Normalization Layer Normalization、Instance Normalization 及 Group Normalization的应用:
https://mp.weixin.qq.com/s/4CeNg-w-ULK7ZM1HjfXHzg
BN层会在每一个Mini-Batch的训练过程中,计算这个Mini-Batch的batch_mean和batch_variance(均值和均方差),再通过exponential weighted moving average (EWMA)方法更新这两个参数。
momentum参数是一个控制EWMA更新比例的一个参数:
momentum越接近于1,每次更新时的batch_mean和batch_variance占有的比例就越小。这样的好处是整体的moving_mean和moving_variance很稳定,缺点是需要进行非常多次epoch才能稳定到真实的population_mean和population_variance的附近;
momentum越接近于0,每次更新时的batch_mean和batch_variance占有的比例就越大。这样的好处是能比较快(较少的epoch)的接近真实的population_mean和population_variance,缺点是不太稳定,可能在结束训练的时候离真实值有一定偏差。
Keras对momentum参数的默认值设置为0.99,通常情况下需要进行几百次epoch才能稳定到真实值附近。而我的实际应用其实只需要几十次epoch就能达到不错的性能。然而训练次数太少会使moving_mean以及moving_variance有较大的偏差,以致于整个网络的权重也会有偏差,所以在使用模型进行evaluate和predict的效果非常差。解决的方法自然是有两种:
1.增加训练epoch次数,意味着增加训练时间;
2.减小momentum参数,e.g. momentum=0.5
显然第一种方法训练的效果会更好,但是会有巨大的时间消耗;第二种方法是一个trade-off。
FROM https://www.dazhuanlan.com/2019/10/07/5d9afd58d424f/
1.只在encoder阶段使用,目前个人只使用ResNet做encoder,所以在后面自己写的层中,暂时不用BN层。
在ResNet中,BN是在Conv和ReLU之间用的,training是false,然后其他参数都使用的是默认的。
2.可以在训练得差不多之后,在多尺度提取阶段加上BN试试。
3.BN层的写法参照MASK RCNN中何凯明的写法。
自己定义BN类,这样可以通过调用这个类来更改call方法中的trianing这个参数。
对于training这个参数,不能设置成true,batchsize小于8时,最好设置成false,大于8可以设置成None。
#扩展了keras batchnormalization类,以允许中心位置在需要时进行更改。
class BatchNorm(KL.BatchNormalization):
"""Extends the Keras BatchNormalization class to allow a central place
to make changes if needed.
Batch normalization has a negative effect on training if batches are small
so this layer is often frozen (via setting in Config class) and functions
as linear layer.
扩展了keras batchnormalization类,以允许中心位置在需要时进行更改。
如果批量较小,则批量规范化对培训有负面影响。
所以这个层经常被冻结(通过在config类中设置)并作为线性层发挥作用。
"""
def call(self, inputs, training=None):
"""
Note about training values:
None: Train BN layers. This is the normal mode
False: Freeze BN layers. Good when batch size is small
True: (don't use). Set layer in training mode even when making inferences
"""
return super(self.__class__, self).call(inputs, training=training)
调用时:
x = BatchNorm(name=bn_name_base + '2a')(x, training=train_bn)
config.py中
# Train or freeze batch normalization layers
# None: Train BN layers. This is the normal mode
# False: Freeze BN layers. Good when using a small batch size
# True: (don't use). Set layer in training mode even when predicting
TRAIN_BN = False # Defaulting to False since batch size is often small