keras BatchNormalization的坑(training参数和 momentum参数)

之前写了一篇讲解keras实现BatchNormalization的文章Keras防止过拟合(四) Batch Normalization代码实现,以为自己已经将keras实现BatchNormalization的细节完全明白了,突然看到了一篇文章keras BatchNormalization 之坑,其中写道了一个坑:训练时和测试时的均值mean和方差var差异太大,影响结果。而其文中提出,training参数设置为0或者False可以解决。但通过我自己分析和浏览一些资料后,发现这个说法是错误的。要解决这个问题,不能改变training参数

首先先解释一下,为啥直接使用keras.layers.BatchNormalization时会出现训练时和测试时的mean和var差异太大,原因在于:

keras.layers.BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001, center=True, scale=True, beta_initializer='zeros', gamma_initializer='ones', moving_mean_initializer='zeros', moving_variance_initializer='ones', beta_regularizer=None, gamma_regularizer=None, beta_constraint=None, gamma_constraint=None)

训练时是一个一个批次训练的,mean和var使用的是各个批次的mean和var,归一化也是针对各个批次。而测试时使用的并不是测试集的所有数据的mean和var,而是在训练时利用权重滑动平均法更新而得(权重滑动平均法定义可以参考这篇吴恩达深度学习公开课,这篇文章有讲解指数加权移动平均法(EWMA)),公式如下:
self.moving_mean = momentum * self.moving_mean + (1-momentum) * mean
其中mean是训练时每个批次的均值,momentum为衰减率,self.moving_mean是测试使用的mean.

使用权重滑动平均法时,若将衰减率momentum设置为0.99,最后moving_mean的值越约等于最后100个mean的加权,若我们设置的batch数量远远小于100时,momentum还使用默认值0.99的话,几乎不会通过每个批次更新,也就导致了训练集使用的mean是每个批次的均值,而测试集使用的mean几乎等于初值,产生很大差异!(方差也一样),训练时和测试时的mean和var差异太大这个坑就是因为这个原因。 所以,在这种情况下,减小momentum的值就可以解决此问题。

当然,你也可以增加batch数量,即减少batch_size,但使用BN时,batch_size不能小,如果你的样本数量很少(假设训练集只有几百个),最好还是减小momentum的值。

momentum的值设置为多少合适:
根据你的batch数决定,若你的batch只有10组,设置为0.9;若为50,设置为0.98;若大于100,甚至可以设置的再大一点(但建议就使用默认值)。
在这里插入图片描述
引用自指数加权移动平均法(EWMA),图中最后的 0. 9 50 0.9^{50} 0.950应该是 0.9 8 50 0.98^{50} 0.9850.
M B = 1 e M^{B} = \frac{1}{e} MB=e1时, ln ⁡ M B = ln ⁡ 1 e \ln M^{B} =\ln\frac{1}{e} lnMB=lne1, B ln ⁡ M = − 1 B\ln M =-1 BlnM=1, ln ⁡ M = − 1 B \ln M = -\frac{1} {B} lnM=B1,
M = e − 1 B M = e^{-\frac{1} {B}} M=eB1,其中M是momentum值,B是batch数量。

至于该文章中说是将training参数一定要设置为0或者False。其实我一开始并没有注意到training这个参数,因为它都不是在init中定义的,而是在call函数中定义:

def call(self, inputs, training=None):#BN层实现函数call中有一个参数training,默认值为None
    if training in {0, False}:
        return normalize_inference()

如果设置为0或者False,则在训练时直接返回inference时的操作。keras BatchNormalization 之坑这篇文章中写道:

翻看keras BN 的源码, 原来keras 的BN层的call函数里面有个默认参数traing, 默认是None。此参数意义如下:

training=False/0, 训练时通过每个batch的移动平均的均值、方差去做批归一化,测试时拿整个训练集的均值、方差做归一化

training=True/1/None,训练时通过当前batch的均值、方差去做批归一化,测试时拿整个训练集的均值、方差做归一化

文中还建议说是最后将training定义为0或False:

当training=None时,训练和测试的批归一化方式不一致,导致validation的输出指标翻车。

当training=True时,拿训练完的模型预测一个样本和预测一个batch的样本的差异非常大,也就是预测的结果根据batch的大小会不同!导致模型结果无法准确评估!也是个坑!

用keras的BN时切记要设置training=False!!!

其文章意思是,training设置为0或False时,训练通过每个batch的移动平均的均值、方差去做批归一化,测试时拿整个训练集的均值、方差做归一化。这样两者的差异较小。

但根据我个人看完源码的理解,加上一些资料,发现这是错误的!

源码中,如果我们将training设置为0或False,则normalize_inference()中使用的均值self.moving_mean,方差self.moving_variance将只会使用其初始化的值(默认初始化方法:均值moving_mean为’zero’,即设置为全0,方差moving_variance为’ones’,即设置为全1),而不会更新。这意味着,训练时和测试时使用的mean和var都是初值,不是通过各个批次计算而得,在这种情况下,使用BN没有意义。

关于这点,不管是keras中文文档还是官方文档都没有提到,源码中也没有相应的注释予以描述,我搜了一些文章,也没有对这点进行讲解。但tensorflow中有一个类似的layer,tf.layers.batch_normalization()方法,其中有training的描述。

文章Batch Normalization的正确打开方式中有tf.layers.batch_normalization()方法的讲解:

tf.layers.batch_normalization(
    inputs,
    axis=-1,
    momentum=0.99,
    epsilon=0.001,
    center=True,
    scale=True,
    beta_initializer=tf.zeros_initializer(),
    gamma_initializer=tf.ones_initializer(),
    moving_mean_initializer=tf.zeros_initializer(),
    moving_variance_initializer=tf.ones_initializer(),
    beta_regularizer=None,
    gamma_regularizer=None,
    beta_constraint=None,
    gamma_constraint=None,
    training=False,
    trainable=True,
    name=None,
    reuse=None,
    renorm=False,
    renorm_clipping=None,
    renorm_momentum=0.99,
    fused=None,
    virtual_batch_size=None,
    adjustment=None
)

在这里插入图片描述
在这里插入图片描述

对于keras的Batch Normalization来说也是这样,如果在训练时将raining设置为0或False时,不会滑动更新,都是初值!
这确实会使训练和测试的mean和var完全一致(因为都是初值啊),以至于该作者认为这样设置会更好,但其实这就相当于未使用BN。

Keras Batch Normalization是一种数据归一化方法,它是在神经网络的激活层之前使用的。这种方法可以通过对输入数据进行归一化处理来提高神经网络的训练速度和性能。[3] Keras中的Batch Normalization方法可以通过对每个小批量的输入数据进行归一化处理来减小训练中的内部协变量移动。这样可以使得神经网络在训练过程中更稳定,加快了训练速度,并且还有助于防止过拟合。 Batch Normalization的工作原理是对每个小批量的输入数据进行正态化处理,即将数据转换为均值为0和标准差为1的分布。这样可以使得输入数据在激活函数之前具有相似的分布,从而增加了网络的鲁棒性和泛化能力。 总结来说,Keras Batch Normalization是一种在神经网络中使用的数据归一化方法,它可以通过对输入数据进行归一化处理来提高神经网络的训练速度和性能,增加网络的鲁棒性和泛化能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【Python-Keraskeras.layers.BatchNormalization解析与使用](https://blog.csdn.net/weixin_43935696/article/details/112214007)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [BatchNormalization_Keras:“通过批处理规范化快速训练Keras模型的一个简单技巧”的源代码-one source code](https://download.csdn.net/download/weixin_42117340/16078358)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值