批量归一化

1.解决问题

损失出现在最后,在反向传播的过程中,后面的层梯度较大,训练较快,数据在最底部,底部层梯度较小,训练较慢。

底部层一变化,所有都得跟着变·最后的那些层需要重新学习多次,导致收敛变慢

2.批量归一化的思想

·固定小批量输入的分布(均值和方差)

然后再做额外的调整(可学习的参数):

3.作用在

全连接层和卷积层输出上,激活函数前

全连接层和卷积层输入上

●对全连接层,作用在特征维

●对于卷积层,作用在通道维

我们可以将每个像素看做一个样本的话,(这种思想也常用语1*1的卷积),假设输入大小为【批量大小*宽*高*通道数】,样本数就为【批量大小*宽*高】,特征数就为通道数。1*1的卷积就是先将图像拉成上述二维的矩阵,在做全连接。

BN层是对于每个神经元做归一化处理,甚至只需要对某一个神经元进行归一化,而不是对一整层网络的神经元进行归一化。既然BN是对单个神经元的运算,那么在CNN中卷积层上要怎么搞?假如某一层卷积层有6个特征图,每个特征图的大小是100*100,这样就相当于这一层网络有6*100*100个神经元,如果采用BN,就会有6*100*100个参数γ、β,这样岂不是太恐怖了。因此卷积层上的BN使用,其实也是使用了类似权值共享的策略,将像素看为样本,通道数看成特征,一个特征图共享一组权重

4.BN是在做什么?

●最初论文是想用它来减少内部协变量转移(原论文并没有验证,后续有人验证相差不大)

后续有论文指出它可能就是通过在每个小批量里加入噪音,来控制模型复杂度

因此没必要跟dropout层混合使用 

增加速度,但不会改变精度

5.计算过程

由于对每一层进行全白化(full whitening)的代价很高,并且也不是处处可微的,因此我们在两个方面做了简化处理。1、与之前联合白化层的输入和输出特征不同的是,我们独立的归一化每个标量特征,使其具有零均值和单位方差。对于某一层输入维度为d维,也即是,我们将归一化每一个维度,公式如下:

这里在整个训练集上计算期望和方差。如LeCun 1998b中陈述,这种归一化可以加速收敛,即使特征是相关的。

值得注意的是,简单的归一化每一个层的输入可能会改变网络层的表达能力。例如,归一化sigmoid的输出会使得值处在非线性变换的线性部分。为了解决这个问题,我们保证嵌入网络内部的变换(下面的等式)可以表达恒等变换。为了达到这个目的,我们为每一个激活值引入一对参数,,它们可以缩放和移动归一化值:

这些参数和模型参数一起学习,并且能够恢复网络本身的表达能力。事实上,如果设置,我们可以恢复原始的激活值(等价于网络本身的表达能力),如果这是最优的选择的话。

在训练批次的设置中,每一步迭代是基于整个训练集,使用整个训练集归一化激活值。但是,这种操作和使用随机优化的方式不好兼容。因此,我们作了第二个简化:2、最小批次随机梯度下降算法,每一个mini-batch产生一个均值和方差的估计。这样,归一化中的统计量可以完全参与到梯度反向传播中。值得注意的是,最小批次计算的是每一个维度的方差,而不是联合协方差;在联合的情况下,由于最小批次的值远远小于需要白化的激活值的数量,会导致奇异协方差矩阵,因此需要正则化。

 BN变换可以在网络中操作任何激活值。

表明参数需要学习,但是需要注意的是,BN变换并不是单独处理每一个样本的激活值。而是,BN变换依赖于一个mini-batch的所有样本。经过缩放和移动的值y传到网络的其它层。归一化的激活值是变换的内部值,但是他们的出现是重要的。并且任何值都期望具有零均值和单位方差的分布,如果忽略,每一个mini-batch具有相同的分布。每一个归一化的激活值可以看作是子网络的输入。这些子网络具有固定的均值和方差,在训练的过程中,尽管这些归一化的值的联合分布可能会改变,我们期待这种这种归一化的引入可以加速子网络的收敛速度,那么也就加速了整个网络的收敛速度。

在训练过程中,我们需要计算BN变换的反向传播,并且计算关于BN变换的参数的梯度,根据反向链式传播准则:

 训练过程:使用无偏估计值估计均值和方差

 在训练过程中,我们需要计算BN变换的反向传播,并且计算关于BN变换的参数的梯度,根据反向链式传播准则:

 4.BN的优势

Increase Learning Rate:在添加BN的网络中,我们可以使用较大的学习率,因此加速了网络的训练,而且没有副作用。
Remove Dropout: 正如3.4描述的那样,BN可以达到Dropout的效果,用BN替代Dropout,可以增加训练速度,并且不会增加过拟合。
Reduce the L2 Weight Regularization: 在Inception模型中,L2损失可以控制模型的过拟合,在修改的BN-Inception模型中,该损失降低5倍。结果表明,测试集精度有改善。
Accelerate the Learning Rate Decay: 在训练Inception模型中,学习率呈现指数衰减。由于我们的网络比Inception训练更快,我们减低了6倍的学习率速度。
Remove Local Repose Normalization: LRN对于网络有好处,但是BN可以取代他。
Shuffle Training Examples More Thoroughly: 我们尽可能打乱训练数据,防止同样的数据总是出现在一个batch中。这会导致验证集精度提高1%,这与BN可以作为正则化方法相符合。
Reduce The Photometric Distortions: 因为BN网络训练速度更快,观察每一个数据更少,我们使得网络更多的关注真实的图片,也即是更少的扭曲原图片;

使用Tensorflow实现BN层

def batch_norm(X, gamma, beta, move_mean, move_var, training=None, move_decay=0.9, eps=1e-5):
    if not training:
        # 判断是当前模式是训练模式还是预测模式
        X_move = (X - move_mean) / np.sqrt(move_var + eps)
    else:
        # 如果是在预测模式下,直接使用传入的移动平均所得的均值和方差
        assert len(X.shape) in (2, 4)
        if len(X) == 2:
            # 使用全连接层的情况,计算特征维上的均值和方差
            X_mean = np.mean(X, axis=0, keepdims=True)
            X_var = np.mean((X - X_mean) ** 2, axis=0, keepdims=True)
        elif len(X.shape) == 4:
            # 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持
            X_mean = np.mean(X, axis=(0, 1, 2), keepdims=True)
            X_var = np.mean((X - X_mean) ** 2, axis=(0, 1, 2), keepdims=True)
        # 移动平均
        move_mean = move_mean * move_decay + X_mean * (1 - move_decay)
        move_var = move_var * move_decay + X_var * (1 - move_decay)
        X_move = (X - move_mean) / np.sqrt(move_var + eps)

    Y = gamma * X_move + beta
    return Y, move_mean, move_var
class BatchNormalization(keras.layers.Layer):
    def __init__(self, momentum=0.9, eps=1e-5, **kwargs):
        super(BatchNormalization, self).__init__(**kwargs)
        self.momentum = momentum
        self.eps = eps

    def build(self, batch_input_shape):
        self.gamma = self.add_weight(name='gamma', shape=[batch_input_shape[-1],], initializer='ones', trainable=True)
        self.beta = self.add_weight(name='beta', shape=[batch_input_shape[-1],], initializer='zeros', trainable=True)
        self.move_mean = self.add_weight(name="move_mean", shape=[batch_input_shape[-1], ], initializer='zeros',
                                         trainable=False)
        self.move_var = self.add_weight(name="move_mean", shape=[batch_input_shape[-1], ], initializer='ones',
                                        trainable=False)
        super().build(batch_input_shape)

    def move_mean_variance(self, variable, value):
        y = self.momentum * variable + value * (1 - self.momentum)
        return variable.assign(y)

    @tf.function
    def call(self, inputs, training=None):
        if training:
            means, var = tf.nn.moments(inputs, axes=list(range(len(inputs.shape)-1)))
            mean_update = self.move_mean_variance(self.move_mean, means)
            var_update = self.move_mean_variance(self.move_var, var)
            self.add_update(mean_update)
            self.add_update(var_update)
        else:
            mean_update = self.move_mean
            var_update = self.move_var

        output = tf.nn.batch_normalization(inputs, mean_update, var_update, offset=self.gamma, scale=self.beta,
                                           variance_epsilon=self.eps)
        return output

    def get_config(self):
        base_config = super(BatchNormalization, self).get_config()
        return {**base_config, 'momentum': self.momentum, 'eps': self.eps}


 

参考资源:https://blog.csdn.net/kxh123456/article/details/100512998

(BN)批量归一化全面解析_Paulzhao6518的博客-CSDN博客_批量归一化

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

樱花的浪漫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值