我们知道在神经网络训练开始前,需要对输入数据做归一化处理,那么具体为什么需要归一化呢?
同时也是在训练前为什么要把训练数据充分打乱的原因,充分打乱使得每个batch的样本包含各类别的数据,这样通过每个batch的样本训练时各个batch所包含的数据分布更接近,同时和整个训练集的数据分布更接近,更有利于训练出更泛化的模型,同时有利于模型的收敛。
试想不充分打乱数据,若每个batch只包含一个类别的数据,不同的batch数据进行训练时网络就要在每次迭代都去学习适应不同的分布,会使得网络收敛很慢。
归一化层,目前主要有这几个方法,Batch Normalization(2015年)、Layer Normalization(2016年)、Instance Normalization(2017年)、Group Normalization(2018年)、Switchable Normalization(2018年);
将输入的图像shape记为[N, C, H, W],这几个方法主要的区别就是在,
Batch Normalization
https://arxiv.org/pdf/1502.03167.pdf
Layer Normalizaiton
https://arxiv.org/pdf/1607.06450v1.pdf
Instance Normalization
https://arxiv.org/pdf/1607.08022.pdf
https://github.com/DmitryUlyanov/texture_nets
Group Normalization
https://arxiv.org/pdf/1803.08494.pdf
Switchable Normalization
https://arxiv.org/pdf/1806.10779.pdf
https://github.com/switchablenorms/Switchable-Normalization
首先,在进行训练之前,一般要对数据做归一化,使其分布一致,但是在深度神经网络训练过程中,通常以送入网络的每一个batch训练,这样每个batch具有不同的分布;此外,为了解决internal covarivate shift问题,这个问题定义是随着batch normalizaiton这篇论文提出的,在训练过程中,数据分布会发生变化,对下一层网络的学习带来困难。
所以batch normalization就是强行将数据拉回到均值为0,方差为1的正太分布上,这样不仅数据分布一致,而且避免发生梯度消失。
此外,internal corvariate shift和covariate shift是两回事,前者是网络内部,后者是针对输入数据,比如我们在训练数据前做归一化等预处理操作。
加入缩放平移变量的原因是:保证每一次数据经过归一化后还保留原有学习来的特征,同时又能完成归一化操作,加速训练。 这两个参数是用来学习的参数。
import numpy as np
def Batchnorm(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=True0)
x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
results = gamma * x_normalized + beta
# 因为在测试时是单个图片测试,这里保留训练时的均值和方差,用在后面测试时用
running_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
Batch Normalization存在以下缺点:
与Batch Normalization不同,Layer Normalizaiton是针对深度网络的某一层的所有神经元的输入按以下公式进行normalize操作。
BN与LN的区别在于:
所以,LN不依赖于batch的大小和输入sequence的深度,因此可以用于batch_size为1和RNN中对边长的输入sequence的normalize操作。
LN用于RNN效果比较明显,但是在CNN上,不如BN。
def ln(x, b, s):
_eps = 1e-5
output = (x - x.mean(1)[:,None]) / tensor.sqrt((x.var(1)[:,None] + _eps))
output = s[None, :] * output + b[None,:]
return output
用在四维图像上,
def Layernorm(x, gamma, beta):
# x_shape:[B, C, H, W]
results = 0.
eps = 1e-5
x_mean = np.mean(x, axis=(1, 2, 3), keepdims=True)
x_var = np.var(x, axis=(1, 2, 3), keepdims=True0)
x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
results = gamma * x_normalized + beta
return results
Batch Normalization和Layer Normalization的对比:
参考资料:
BatchNormalization、LayerNormalization、InstanceNorm、GroupNorm、SwitchableNorm总结
什么是批标准化 (Batch Normalization)
Batch Normalization和Layer Normalization的对比分析