当前位置:   article > 正文

批量归一化

批量归一化

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层

  1. def batch_norm(X, gamma, beta, move_mean, move_var, training=None, move_decay=0.9, eps=1e-5):
  2. if not training:
  3. # 判断是当前模式是训练模式还是预测模式
  4. X_move = (X - move_mean) / np.sqrt(move_var + eps)
  5. else:
  6. # 如果是在预测模式下,直接使用传入的移动平均所得的均值和方差
  7. assert len(X.shape) in (2, 4)
  8. if len(X) == 2:
  9. # 使用全连接层的情况,计算特征维上的均值和方差
  10. X_mean = np.mean(X, axis=0, keepdims=True)
  11. X_var = np.mean((X - X_mean) ** 2, axis=0, keepdims=True)
  12. elif len(X.shape) == 4:
  13. # 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持
  14. X_mean = np.mean(X, axis=(0, 1, 2), keepdims=True)
  15. X_var = np.mean((X - X_mean) ** 2, axis=(0, 1, 2), keepdims=True)
  16. # 移动平均
  17. move_mean = move_mean * move_decay + X_mean * (1 - move_decay)
  18. move_var = move_var * move_decay + X_var * (1 - move_decay)
  19. X_move = (X - move_mean) / np.sqrt(move_var + eps)
  20. Y = gamma * X_move + beta
  21. return Y, move_mean, move_var
  1. class BatchNormalization(keras.layers.Layer):
  2. def __init__(self, momentum=0.9, eps=1e-5, **kwargs):
  3. super(BatchNormalization, self).__init__(**kwargs)
  4. self.momentum = momentum
  5. self.eps = eps
  6. def build(self, batch_input_shape):
  7. self.gamma = self.add_weight(name='gamma', shape=[batch_input_shape[-1],], initializer='ones', trainable=True)
  8. self.beta = self.add_weight(name='beta', shape=[batch_input_shape[-1],], initializer='zeros', trainable=True)
  9. self.move_mean = self.add_weight(name="move_mean", shape=[batch_input_shape[-1], ], initializer='zeros',
  10. trainable=False)
  11. self.move_var = self.add_weight(name="move_mean", shape=[batch_input_shape[-1], ], initializer='ones',
  12. trainable=False)
  13. super().build(batch_input_shape)
  14. def move_mean_variance(self, variable, value):
  15. y = self.momentum * variable + value * (1 - self.momentum)
  16. return variable.assign(y)
  17. @tf.function
  18. def call(self, inputs, training=None):
  19. if training:
  20. means, var = tf.nn.moments(inputs, axes=list(range(len(inputs.shape)-1)))
  21. mean_update = self.move_mean_variance(self.move_mean, means)
  22. var_update = self.move_mean_variance(self.move_var, var)
  23. self.add_update(mean_update)
  24. self.add_update(var_update)
  25. else:
  26. mean_update = self.move_mean
  27. var_update = self.move_var
  28. output = tf.nn.batch_normalization(inputs, mean_update, var_update, offset=self.gamma, scale=self.beta,
  29. variance_epsilon=self.eps)
  30. return output
  31. def get_config(self):
  32. base_config = super(BatchNormalization, self).get_config()
  33. return {**base_config, 'momentum': self.momentum, 'eps': self.eps}


 

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/213477
推荐阅读
相关标签
  

闽ICP备14008679号