IID独立同分布假设
:假设训练数据和测试数据是满足相同分布的,这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。
Internal Covariate Shift
Covariate Shift
:训练集和测试集数据分布不一致
Internal
:指网络的隐藏层
Internal Covariate Shift
:当前层输入分布受之前层参数变化的影响。在训练过程中,网络中的参数在不断变化,每一层的输入分布也在不断变化。网络越深影响越大
因此训练过程中学习率不能太大,另外对网络参数的初始化要求也更高。
BatchNorm
Mini-Batch SGD相对于One Example SGD的两个优势:梯度更新方向更准确;并行计算速度快;
BN是基于Mini-Batch SGD,在batch维度操作的
BN使每一层的输入服从0~1正态分布
For a layer with d-dimensional input x = (x(1) . . . x(d)), BN will normalize each dimension
x ^ ( k ) = x ( k ) − E [ x ( k ) ] Var [ x ( k ) ] \widehat{x}^{(k)}=\frac{x^{(k)}-\mathrm{E}\left[x^{(k)}\right]}{\sqrt{\operatorname{Var}\left[x^{(k)}\right]}} x (k)=Var[x(k)]x(k)−E[x(k)]
训练过程
通过前三步简单归一化后每一层的输入服从0~1正态分布,但同时可能改变每一层学习到的特征。为解决此问题,BN使用重构变换(transformation inserted),从而恢复学习到的特征。
测试过程
测试过程每次只有一张数据,其均值和方差分别为训练时所有均值的平均值和方差的无偏估计,论文称其为moving averages
。
E [ x ] ← E B [ μ B ] \mathrm{E}[x] \leftarrow \mathrm{E}_{\mathcal{B}}\left[\mu_{\mathcal{B}}\right] E[x]←EB[μB] Var [ x ] ← m m − 1 E B [ σ B 2 ] \operatorname{Var}[x] \leftarrow \frac{m}{m-1} \mathrm{E}_{\mathcal{B}}\left[\sigma_{\mathcal{B}}^{2}\right] Var[x]←m−1mEB[σB2] y = γ Var [ x ] + ϵ ⋅ x + ( β − γ E [ x ] Var [ x ] + ϵ ) y=\frac{\gamma}{\sqrt{\operatorname{Var}[x]+\epsilon}} \cdot x+\left(\beta-\frac{\gamma \mathrm{E}[x]}{\sqrt{\operatorname{Var}[x]+\epsilon}}\right) y=Var[x]+ϵγ⋅x+(β−Var[x]+ϵγE[x])
BatchNorm总结
优点
1、BN可以防止梯度消失和梯度爆炸,收敛速度快
2、加入BN后,模型可以使用更大的学习率,同时减少模型对参数初始化的依赖
3、BN可以正则化模型(SGD算法引入随机性),从而减小模型对dropout以及l2正则化的需求
缺点
https://www.zhihu.com/question/62599196
1、BN依赖于batch_size,batch_size太小(小于32)模型效果不佳。batch_size减小模型效果急剧下降。
2、对于图片生成任务如:图片超分辨率和风格迁移,效果不佳。因为此类任务更加关注单张图片本身特有的一些细节信息。
而BN更加关注数据整体的分布,在判别模型如图像分类识别方面效果较好。
3、RNN 、LSTM等动态网络使用 BN 效果不佳(应该选择Instance Normalization)
4、BN的测试过程和训练过程不连续。测试过程使用的均值和方差来自于训练集,若测试集与训练集分布不一致,测试集以此均值和方差进行归一化,并不合理。
另外,将加BN的模型作为预训练模型进行迁移学习,后续过程的均值和方差使用的依然是预训练模型训练集中的均值和方差。
python实现
def bn_forward(x, gamma, beta, eps, momentum, bn_param, mode):
# # eps: 除以方差时为了防止方差太小而导致数值计算不稳定
running_mean = bn_param['running_mean'] # shape = [B]
running_var = bn_param['running_var'] # shape = [B]
if mode == 'train':
sample_mean = np.mean(x, axis=0)
sample_var = np.var(x, axis=0)
x_normalized = (x - sample_mean) / np.sqrt(sample_var + eps)
out = gamma * x_normalized + beta
# 滑动平均的方式计算新的均值和方差,训练时计算,为测试数据做准备
running_mean = momentum * running_mean + (1 - momentum) * sample_mean
running_var = momentum * running_var + (1 - momentum) * sample_var
bn_param['running_mean'] = running_mean
bn_param['running_var'] = running_var
else:
x_normalized = (x - running_mean) / np.sqrt(running_var + eps)
out = gamma * x_normalized + beta
return out
参考:
Batch Normalization 学习笔记
深度学习中的Normalization模型
cs231n学习笔记-激活函数-BN-参数优化