赞
踩
损失出现在最后,在反向传播的过程中,后面的层梯度较大,训练较快,数据在最底部,底部层梯度较小,训练较慢。
底部层一变化,所有都得跟着变·最后的那些层需要重新学习多次,导致收敛变慢
·固定小批量输入的分布(均值和方差)
然后再做额外的调整(可学习的参数):
全连接层和卷积层输出上,激活函数前
全连接层和卷积层输入上
●对全连接层,作用在特征维
●对于卷积层,作用在通道维
我们可以将每个像素看做一个样本的话,(这种思想也常用语1*1的卷积),假设输入大小为【批量大小*宽*高*通道数】,样本数就为【批量大小*宽*高】,特征数就为通道数。1*1的卷积就是先将图像拉成上述二维的矩阵,在做全连接。
BN层是对于每个神经元做归一化处理,甚至只需要对某一个神经元进行归一化,而不是对一整层网络的神经元进行归一化。既然BN是对单个神经元的运算,那么在CNN中卷积层上要怎么搞?假如某一层卷积层有6个特征图,每个特征图的大小是100*100,这样就相当于这一层网络有6*100*100个神经元,如果采用BN,就会有6*100*100个参数γ、β,这样岂不是太恐怖了。因此卷积层上的BN使用,其实也是使用了类似权值共享的策略,将像素看为样本,通道数看成特征,一个特征图共享一组权重
●最初论文是想用它来减少内部协变量转移(原论文并没有验证,后续有人验证相差不大)
后续有论文指出它可能就是通过在每个小批量里加入噪音,来控制模型复杂度
因此没必要跟dropout层混合使用
增加速度,但不会改变精度
由于对每一层进行全白化(full whitening)的代价很高,并且也不是处处可微的,因此我们在两个方面做了简化处理。1、与之前联合白化层的输入和输出特征不同的是,我们独立的归一化每个标量特征,使其具有零均值和单位方差。对于某一层输入维度为d维,也即是,我们将归一化每一个维度,公式如下:
这里在整个训练集上计算期望和方差。如LeCun 1998b中陈述,这种归一化可以加速收敛,即使特征是相关的。
值得注意的是,简单的归一化每一个层的输入可能会改变网络层的表达能力。例如,归一化sigmoid的输出会使得值处在非线性变换的线性部分。为了解决这个问题,我们保证嵌入网络内部的变换(下面的等式)可以表达恒等变换。为了达到这个目的,我们为每一个激活值引入一对参数,,它们可以缩放和移动归一化值:
这些参数和模型参数一起学习,并且能够恢复网络本身的表达能力。事实上,如果设置,我们可以恢复原始的激活值(等价于网络本身的表达能力),如果这是最优的选择的话。
在训练批次的设置中,每一步迭代是基于整个训练集,使用整个训练集归一化激活值。但是,这种操作和使用随机优化的方式不好兼容。因此,我们作了第二个简化:2、最小批次随机梯度下降算法,每一个mini-batch产生一个均值和方差的估计。这样,归一化中的统计量可以完全参与到梯度反向传播中。值得注意的是,最小批次计算的是每一个维度的方差,而不是联合协方差;在联合的情况下,由于最小批次的值远远小于需要白化的激活值的数量,会导致奇异协方差矩阵,因此需要正则化。
BN变换可以在网络中操作任何激活值。
表明参数需要学习,但是需要注意的是,BN变换并不是单独处理每一个样本的激活值。而是,BN变换依赖于一个mini-batch的所有样本。经过缩放和移动的值y传到网络的其它层。归一化的激活值是变换的内部值,但是他们的出现是重要的。并且任何值都期望具有零均值和单位方差的分布,如果忽略,每一个mini-batch具有相同的分布。每一个归一化的激活值可以看作是子网络的输入。这些子网络具有固定的均值和方差,在训练的过程中,尽管这些归一化的值的联合分布可能会改变,我们期待这种这种归一化的引入可以加速子网络的收敛速度,那么也就加速了整个网络的收敛速度。
在训练过程中,我们需要计算BN变换的反向传播,并且计算关于BN变换的参数的梯度,根据反向链式传播准则:
训练过程:使用无偏估计值估计均值和方差
在训练过程中,我们需要计算BN变换的反向传播,并且计算关于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网络训练速度更快,观察每一个数据更少,我们使得网络更多的关注真实的图片,也即是更少的扭曲原图片;
- 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。