算法面试高频知识点:BN层详解(全网最全)
这是我之前写在公众号里的一篇文章,在此分享到牛客上,一来是希望能和牛客上的朋友们一起交流学习CV算法以及相应的知识,也欢迎大家关注我的公众号*********。
一.Batch Normalization基本原理及公式
BN的基本原理
Batch Normalization又称为“批归一化”。
首先,在进行训练之前,一般要对数据做归一化,使其分布一致。
那么为什么要归一化呢?归一化后有什么好处呢?
因为神经网络学习过程本质就是为了学习数据分布,一旦训练数据与测试数据的分布不同,那么网络的泛化能力也大大下降,另一方面,深度神经网络训练过程中,通常以送入网络的每一个Batch训练,一般每一个Batch具有不同的分布,那么网络就要在每次迭代都去学习适应不同的分布,这样将会大大降低网络的训练速度。
此外,为了解决internal covarivate shift问题,这个问题定义是随着Batch Normalization这篇论文提出的,在训练过程中,数据分布会发生变化,对下一层网络的学习带来困难。
所以Batch Normalization就是强行将数据拉回到均值为0,方差为1的正态分布上,这样不仅可以让数据保持相近的分布,而且避免发生梯度消失。
此外,internal corvariate shift和covariate shift是两回事,前者是网络内部,后者是针对输入数据,比如我们在训练数据前做归一化等预处理操作。
BN的公式
上图就是一个标准的数据减均值除方差的归一化流程。
加入缩放和平移变量的原因
可以变换回原始的分布,保证每一次数据经过归一化后还保留原有学习来的特征,同时又能完成归一化操作,提高模型的容纳能力(capacity)。这两个参数是用来学习的参数。
如上图中左边是没有任何处理的输入数据,曲线是激活函数sigmoid的曲线。如果数据如上图所示在梯度很小的区域,那么学习速率就会很慢甚至陷入长时间的停滞。减去均值再除以方差之后,数据被移到了中心区域,如上图右边所示。对于大多数激活函数而言,这个区域的梯度都是最大的或是有梯度的,比如ReLU函数,==这可以看作是一种对抗梯度消失的手段。== 对于一层是如此,如果对于每一层数据都这么操作,那么数据的分布就总是在随输入变化敏感的区域,相当于不用考虑数据分布变来变去了(解决了internal covarivate shift),这样训练起来效率就高多了。不过到这里问题并没有结束,因为减去均值除方差未必是最好的分布。比如数据本身就很不对称,或者激活函数未必是对方差为1的数据有最好的效果。所以要加入缩放及平移变量来完善数据分布以达到比较好的效果。
训练和测试阶段的不同
在训练阶段,BN层是对每一批的训练数据进行归一化,也即用每一批数据的均值和方差。(每一批数据的方差和标准差不同)
而在测试阶段,我们一般只输入一个测试样本,并没有batch的概念。因此这个时候用的均值和方差是整个数据集训练后的均值和方差,可以通过滑动平均法求得:
上面式子简单理解就是:对于均值来说直接计算所有batch u值的平均值;然后对于标准偏差采用每个batch σB的无偏估计。
在测试时,BN使用的公式是:
二.BN训练时为什么不用整个训练集的均值和方差?
因为用整个训练集的均值和方差容易过拟合,对于BN,其实就是对每一批数据进行归一化到一个相同的分布,而每一批数据的均值和方差会有一定的差别,而不是固定的值,这个差别能够==增加模型的鲁棒性==,也会在一定程度上减少过拟合。
三.BN用在哪里?
在CNN中,BN层应该用在非线性激活函数前面,即对做归一化。由于神经网络隐藏层的输入是上一层非线性激活函数的输出,在训练初期其分布还在剧烈改变,此时约束其一阶矩和二阶矩无法很好地缓解 Covariate Shift;而BN的分布更接近正态分布,限制其一阶矩和二阶矩能使输入到激活函数的值分布更加稳定。
四.BN层的参数量
我们知道和
是需要学习的参数,所以其实BN的本质就是利用优化改变方差大小和均值的位置。在CNN中,因为网络的特征是对应到一整张特征图上的,所以做BN的时候也是以特征图为单位而不是按照各个维度。比如在某一层,Batch大小为
,那么做BN的参数量为
。
五.BN的反向传播算法
接下来我们详细的解释一下各个式子的推导过程:
对于上图第二个式子:
对于第三个式子:
对于第四个式子:
六.BN的优缺点
优点:
- 可以选择较大的初始学习率。因为这个算法收敛很快。
- 可以不用dropout,L2正则化。
- 不需要使用局部响应归一化。
- 可以把数据集彻底打乱。
- 模型更加健壮。
缺点:
Batch Normalization非常依赖Batch的大小,当Batch值很小时,计算的均值和方差不稳定。
所以BN不适用于以下几个场景:
- 小Batch
- RNN
七.Python代码实现
import numpy as np def Batchmorm(x, gamma, beta, bn_param): #x_shape:[B,C,H,W] running_mean = bn_param['running_mean'] running_var = bn_param['running_var'] results = 0 eps = 1e-5 x_mean = np.mean(x, axis=(0, 2 ,3), keepdims=True) x_var = np.var(x, axis=(0, 2, 3), keepdims=True) x_normalized = (x - x_mean) / np.sqrt(x_var + eps) results = gamma * x_normalized + beta #因为在测试时是单个图片测试,这里保留训练时的均值和方差,用在后面测试时用 runnng_mean = momentum * running_mean + (1 - momentum) * x_mean running_var = momentum * running_var + (1 - momentum) * x_var bn_param['running_mean'] = running_mean bn_param['running_var'] = running_var return results, bn_param#面经##秋招##实习##面试八股文##面霸的自我修养#