常见Normalization汇总
本文主要框架参考https://blog.csdn.net/liuxiao214/article/details/81037416,有许多自己的理解并进行了一定的删改,并且加上了PyTorch提供的各个Normalization的API。
其中,对于batchsize更详细的介绍可参考本人博客:https://blog.csdn.net/qyhaill/article/details/102463870
1 综述
1.1 论文链接
- 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
1.2 Normalization介绍
归一化层,目前主要有这几个方法:Batch Normalization(2015年)、Layer Normalization(2016年)、Instance Normalization(2017年)、Group Normalization(2018年)、Switchable Normalization(2018年);
将输入的图像shape记为 [ N , C , H , W ] [N, C, H, W] [N,C,H,W],这几个方法主要的区别就是在:
- batchNorm是在batch上,对 N H W NHW NHW做归一化,对小batchsize效果不好;
- layerNorm在通道方向上,对 C H W CHW CHW归一化,主要对RNN作用明显;
- InstanceNorm在图像像素上,对 H W HW HW做归一化,用在风格化迁移,因为在图像风格化中,生成结果主要依赖于某个图像实例,所以对整个batch归一化不适合图像风格化中,因而对 H W HW HW做归一化。可以加速模型收敛,并且保持每个图像实例之间的独立;
- GroupNorm将channel分组,然后在每个group内做归一化;
- SwitchableNorm是将BN、LN、IN结合,赋予权重,让网络自己去学习归一化层应该使用什么方法。
从上图可以看出InstanceNorm是GroupNorm的极端情况。、
2 Batch Normalization
首先,在进行训练之前,一般要对数据做归一化,使其分布一致,但是在深度神经网络训练过程中,通常以送入网络的每一个batch训练,这样每个batch具有不同的分布;此外,为了解决internal covarivate shift问题在训练过程中,数据分布会发生变化,对下一层网络的学习带来困难。这个问题定义也是在Batch Normalizaiton这篇论文提出的。
Batch Normalization就是强行将数据拉回到均值为0,方差为1的正太分布上,这样不仅数据分布一致,而且避免发生梯度消失。
此外,internal corvariate shift和covariate shift是两回事,前者是网络内部,后者是针对输入数据,比如我们在训练数据前做归一化等预处理操作。
2.1 算法过程
- 沿着通道计算一个batch的每个channel的均值 μ c \mu^c μc和方差,其中 n = { 1 , . . . , N } , c = { 1 , . . . , C } , h = { 1 , . . . , C } , w = { 1 , . . . , W } n=\{1, ..., N\}, c=\{1, ..., C\}, h=\{1, ..., C\}, w=\{1, ..., W\} n={1,...,N},c={1,...,C},h={1,...,C},w={1,...,W}:
μ c = 1 N H W ∑ n = 1 N ∑ h = 1 H ∑ w = 1 W x n h w c , σ c = 1 N H W ∑ n = 1 N ∑ h = 1 H ∑ w = 1 W ( x n h w c − μ c ) 2 \mu^c=\frac{1}{NHW}\sum_{n=1}^N\sum_{h=1}^H\sum_{w=1}^Wx_{nhw}^c,\sigma^c=\sqrt{\frac{1}{NHW}\sum_{n=1}^N\sum_{h=1}^H\sum_{w=1}^W(x_{nhw}^c-\mu^c)^2} μc=NHW1n=1∑Nh=1∑Hw=1∑Wxnhwc,σc=NHW1n=1∑Nh=1∑Hw=1∑W(xnhwc−μc)2
其中, μ c \mu^c μc和 σ c \sigma^c σc表示这个batch的第 c c c个channel的所有maps的所有值的均值和方差, x n h w c x_{nhw}^c xnhwc表示这个batch的第 c c c个channel的第 n n n个实例所对应的map在 ( h , w ) (h, w) (h,w)处的值。
- 然后做归一化并加入缩放和平移变量 γ \gamma γ和 β \beta β :
y n h w c = x n h w c − μ c σ c + ϵ ∗ γ + β y_{nhw}^c = \frac{x_{nhw}^c - \mu^c}{ \sqrt{\sigma^c + \epsilon}} * \gamma + \beta ynhwc=σc+ϵ xnhwc−μc∗γ+β
其中, y n h w c y_{nhw}^c ynhwc表示这个batch归一化并仿射后的第 c c c个channel的第 n n n个实例所对应的map在 ( h , w ) (h, w) (h,w)处的值。
加入缩放平移变量的原因是:保证每一次数据经过归一化后还保留原有学习来的特征,同时又能完成归一化操作,加速训练。 这两个参数是用来学习的参数。
2.2 pytorch的Batch Normalization
class torch.nn.BatchNorm1d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
class torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
class torch.nn.BatchNorm3d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
参数:
- num_features:即输入的channel;
- eps:就是计算公式中的 ϵ \epsilon ϵ,为保证数值稳定性(分母不能趋近或取0),给分母加上的值,默认为 1 e − 5 1e-5 1e−5;
- momentum:这个参数很多博客都解释错了,上文我们讲过BN在test时没有batch,无法计算均值和标准差,实际的做法是将训练过程中每轮的均值和标准差保存下来,然后按权相加,得到test时使用的均值和标准差。而momentum表示的就是权值。计算过程如下:
假设 x ^ \hat x x^是test时的均值或标准差,
- 第一轮的的 x ^ \hat x x^就是这一轮训练数据计算出的statistic;
- 第二轮到最后一轮的每一轮,假设第 t t t轮的statistic为 x t x_t xt, x ^ \hat x x^都按公式 x ^ new = ( 1 − momentum ) × x ^ + momentum × x t , x ^ = x ^ n e w \hat{x}_\text{new} = (1 - \text{momentum}) \times \hat{x} + \text{momentum} \times x_t, \hat x = \hat{x}_{new} x^new=(1−momentum)×x^+momentum×xt,x^=x^new 进行更新;
- affine:默认为
True
。当设为True
时,使normalization后的均值和标准差(缩放变量 γ \gamma γ和和平移变量 β \beta β)设置为可学习的参数;否则为0和1。缩放加平移就是仿射,affine的意思就是仿射。
pytorch中BN的公式:
y = x − E [ x ] V a r [ x ] + ϵ ∗ γ + β y = \frac{x - \mathrm{E}[x]}{ \sqrt{\mathrm{Var}[x] + \epsilon}} * \gamma + \beta y=Var[x]+ϵ x−E[x]∗γ+β
3. Layer Normalization
batch normalization存在以下缺点:
- 对batchsize的大小比较敏感,由于每次计算均值和方差是在一个batch上,所以如果batchsize太小,则计算的均值、方差不足以代表整个数据分布;
- BN实际使用时需要计算并且保存某一层神经网络batch的均值和方差等统计信息,对于对一个固定深度的前向神经网络(DNN,CNN)使用BN,很方便;但对于RNN来说,sequence的长度是不一致的,换句话说RNN的深度不是固定的,不同的time-step需要保存不同的statics特征,可能存在一个特殊sequence比其他sequence长很多,这样training时,计算很麻烦。(参考于https://blog.csdn.net/lqfarmer/article/details/71439314)
3.1 算法过程
- 与BN不同,LN是针对深度网络的某一层的所有神经元的输入按以下公式进行normalize操作,其中 n = { 1 , . . . , N } , c = { 1 , . . . , C } , h = { 1 , . . . , C } , w = { 1 , . . . , W } n=\{1, ..., N\}, c=\{1, ..., C\}, h=\{1, ..., C\}, w=\{1, ..., W\} n={1,...,N},c={1,...,C},h={1,...,C},w={1,...,W}:
μ n = 1 C H W ∑ c = 1 C ∑ h = 1 H ∑ w = 1 W x c h w n , σ n = 1 C H W ∑ c = n C ∑ h = 1 H ∑ w = 1 W ( x c h w n − μ n ) 2 \mu^n = \frac{1}{CHW}\sum_{c=1}^C\sum_{h=1}^H\sum_{w=1}^W x_{chw}^n , \sigma^n = \sqrt{\frac{1}{CHW}\sum_{c=n}^C\sum_{h=1}^H\sum_{w=1}^W(x_{chw}^n-\mu^n)^2} μn=CHW1c=1∑Ch=1∑Hw=1∑Wxchwn,σn=CHW1c=n∑Ch=1∑Hw=1∑W(xchwn−μn)2
其中, μ n \mu^n μn和 σ n \sigma^n σn表示某一层输出的第n个实例对应的feature maps的均值和方差, C ∗ H ∗ W C*H*W C∗H∗W是这一层神经元的个数,即这一层输出的feature maps共有多少个值, x c h w n x_{chw}^n xchwn表示这一层输出的第n个实例对应的feature maps的第 c c c个map上 ( h , w ) (h, w) (h,w)位置的值。
- 然后做归一化并加入缩放和平移变量 γ \gamma γ和 β \beta β :
y c h w n = x c h w n − μ n σ n + ϵ ∗ γ + β y_{chw}^n = \frac{x_{chw}^n - \mu^n}{ \sqrt{\sigma^n + \epsilon}} * \gamma + \beta ychwn=σn+ϵ xchwn−μn∗γ+β
其中, y c h w n y_{chw}^n ychwn是这一层输出的第n个实例对应的feature maps归一化并仿射后在第 c c c个map上 ( h , w ) (h, w) (h,w)位置的值。
3.2 BN和LN的区别
- LN中同层神经元输入拥有相同的均值和方差,不同的输入样本有不同的均值和方差;
- BN中则针对不同神经元输入计算均值和方差,同一个batch中的输入拥有相同的均值和方差。
所以,LN不依赖于batch的大小和输入sequence的深度,因此可以用于batchsize为1和RNN中对边长的输入sequence的normalize操作。
LN用于RNN效果比较明显,但是在CNN上,不如BN。
3.3 pytorch的Layer Normalization
class torch.nn.LayerNorm(normalized_shape, eps=1e-05, elementwise_affine=True)
参数:
- normalized_shape: 输入尺寸,可以是
int
或list
;
- eps:就是计算公式中的 ϵ \epsilon ϵ,为保证数值稳定性(分母不能趋近或取0),给分母加上的值,默认为 1 e − 5 1e-5 1e−5;
- elementwise_affine: 布尔值,当设为true,给该层添加可学习的仿射变换参数 γ \gamma γ和 β \beta β。
pytorch中LN的公式:
y = x − E [ x ] V a r [ x ] + ϵ ∗ γ + β y = \frac{x - \mathrm{E}[x]}{ \sqrt{\mathrm{Var}[x] + \epsilon}} * \gamma + \beta y=Var[x]+ϵ x−E[x]∗γ+β
4 Instance Normalization
BN注重对每个batch进行归一化,保证数据分布一致,因为判别模型中结果取决于数据整体分布。
但是图像风格化中,生成结果主要依赖于某个图像实例,所以对整个batch归一化不适合图像风格化中,因而对HW做归一化。可以加速模型收敛,并且保持每个图像实例之间的独立。
在计算上可以将IN看做 b a t c h s i z e = 1 batchsize=1 batchsize=1的BN。
4.1 算法过程:
- IN首先对每个实例 H W HW HW维度求均值和标准差,其中 n = { 1 , . . . , N } , c = { 1 , . . . , C } , h = { 1 , . . . , C } , w = { 1 , . . . , W } n=\{1, ..., N\}, c=\{1, ..., C\}, h=\{1, ..., C\}, w=\{1, ..., W\} n={1,...,N},c={1,...,C},h={1,...,C},w={1,...,W}:
μ n c = 1 H W ∑ h = H ∑ w = 1 W x h w n c , σ n c = 1 H W ∑ h = 1 H ∑ w = 1 W ( x h w n c − μ n c ) 2 \mu^{nc}=\frac{1}{HW}\sum_{h=}^H\sum_{w=1}^Wx_{hw}^{nc},\sigma^{nc}=\sqrt{\frac{1}{HW}\sum_{h=1}^H\sum_{w=1}^W(x_{hw}^{nc}-\mu^{nc})^2} μnc=HW1h=∑Hw=1∑Wxhwnc,σnc=HW1h=1∑Hw=1∑W(xhwnc−μnc)2
其中, μ n c \mu^{nc} μnc和 σ n c \sigma^{nc} σnc表示这个batch中的第 n n n个实例对应的feature maps中的第 c c c个map所有值的均值和方差, x h w n c x_{hw}^{nc} xhwnc表示这个batch的第 n n n个实例对应的feature maps中的第 c c c个map在 ( h , w ) (h, w) (h,w)位置的值。
- 然后做归一化并加入缩放和平移变量 γ \gamma γ和 β \beta β :
y h w n c = x h w n c − μ n c σ n c + ϵ ∗ γ + β y_{hw}^{nc} = \frac{x_{hw}^{nc} - \mu^{nc}}{ \sqrt{\sigma^{nc} + \epsilon}} * \gamma + \beta yhwnc=σnc+ϵ xhwnc−μnc∗γ+β
其中, y h w n c y_{hw}^{nc} yhwnc表示这个batch的第 n n n个实例对应的feature maps归一化并仿射后的第 c c c个map在 ( h , w ) (h, w) (h,w)位置的值。
4.2 pytorch中的Instance Normalization
class torch.nn.InstanceNorm1d(num_features, eps=1e-05, momentum=0.1, affine=False, track_running_stats=False)
class torch.nn.InstanceNorm2d(num_features, eps=1e-05, momentum=0.1, affine=False, track_running_stats=False)
class torch.nn.InstanceNorm3d(num_features, eps=1e-05, momentum=0.1, affine=False, track_running_stats=False)
参数:
- num_features:即输入的channel;
- eps:就是计算公式中的 ϵ \epsilon ϵ,为保证数值稳定性(分母不能趋近或取0),给分母加上的值,默认为 1 e − 5 1e-5 1e−5;
- momentum:这个参数很多博客都解释错了,上文我们讲过BN在test时没有batch,无法计算均值和标准差,实际的做法是将训练过程中每轮的均值和标准差保存下来,然后按权相加,得到test时使用的均值和标准差。而momentum表示的就是权值。计算过程如下:
假设 x ^ \hat x x^是test时的均值或标准差,
- 第一轮的的 x ^ \hat x x^就是这一轮训练数据计算出的statistic;
- 第二轮到最后一轮的每一轮,假设第 t t t轮的statistic为 x t x_t xt, x ^ \hat x x^都按公式 x ^ new = ( 1 − momentum ) × x ^ + momentum × x t , x ^ = x ^ n e w \hat{x}_\text{new} = (1 - \text{momentum}) \times \hat{x} + \text{momentum} \times x_t, \hat x = \hat{x}_{new} x^new=(1−momentum)×x^+momentum×xt,x^=x^new 进行更新;
- affine:默认为
False
。当设为True
时,使normalization后的均值和标准差(缩放变量 γ \gamma γ和平移变量 β \beta β)设置为可学习的参数;否则为0和1。缩放加平移就是仿射,affine的意思就是仿射。
pytorch中的IN公式:
y = x − E [ x ] V a r [ x ] + ϵ ∗ γ + β y = \frac{x - \mathrm{E}[x]}{ \sqrt{\mathrm{Var}[x] + \epsilon}} * \gamma + \beta y=Var[x]+ϵ x−E[x]∗γ+β
5 Group Normalization
主要是针对Batch Normalization对小batchsize效果差,GN将channel方向分group,然后每个group内做归一化,算 ( C / / G ) ∗ H ∗ W (C//G)*H*W (C//G)∗H∗W的均值,这样与batchsize无关,不受其约束。
GN计算均值和标准差时,把每一个实例的 feature maps 的 channel 分成G组,每组将有 C / / G C // G C//G 个 channel,然后将这些 channel 中的元素求均值和标准差。各组 channel 用其对应的归一化参数独立地归一化。
5.1 算法过程:
- 对于某个channel组(假设这个组包含的feature maps是从第 g ( C / / G ) g(C//G) g(C//G)个map到第 ( g + 1 ) ( C / / G ) − 1 (g+1)(C//G)-1 (g+1)(C//G)−1个map),首先计算这个channel组中的均值和方差,其中 g = { 0 , . . . , G − 1 } , n = { 1 , . . . , N } , c = { 1 , . . . , C } , h = { 1 , . . . , C } , w = { 1 , . . . , W } g=\{0, ..., G-1\}, n=\{1, ..., N\}, c=\{1, ..., C\}, h=\{1, ..., C\}, w=\{1, ..., W\} g={0,...,G−1},n={1,...,N},c={1,...,C},h={1,...,C},w={1,...,W}:
μ n g = 1 ( C / / G ) H W ∑ c = g ( C / / G ) ( g + 1 ) ( C / / G ) ∑ h = 1 H ∑ w = 1 W x c h w n g , σ n g = 1 ( C / / G ) H W ∑ c = g ( C / / G ) ( g + 1 ) ( C / / G ) ∑ h = 1 H ∑ w = 1 W ( x c h w n g − μ n g ) 2 \mu^{ng}=\frac{1}{(C//G)HW}\sum_{c=g(C//G)}^{(g+1)(C//G)}\sum_{h=1}^H\sum_{w=1}^Wx_{chw}^{ng}, \sigma^{ng}=\sqrt{\frac{1}{(C//G)HW}\sum_{c=g(C//G)}^{(g+1)(C//G)}\sum_{h=1}^H\sum_{w=1}^W(x_{chw}^{ng}-\mu^{ng})^2} μng=(C//G)HW1c=g(C//G)∑(g+1)(C//G)h=1∑Hw=1∑Wxchwng,σng=(C//G)HW1c=g(C//G)∑(g+1)(C//G)h=1∑Hw=1∑W(xchwng−μng)2
其中, μ n g \mu^{ng} μng和 σ n g \sigma^{ng} σng分别是这个batch中第 n n n个实例对应的feature maps的第 g g g个channel组的均值和方差, x c h w n g x_{chw}^{ng} xchwng表示这个batch中第 n n n个实例对应的feature maps的第 g g g个channel组包含的第 c c c个map在 ( h , w ) (h, w) (h,w)位置的值。
- 然后做归一化并加入缩放和平移变量 γ \gamma γ和 β \beta β :
y c h w n g = x c h w n g − μ n g σ n g + ϵ ∗ γ + β y_{chw}^{ng} = \frac{x_{chw}^{ng} - \mu^{ng}}{ \sqrt{\sigma^{ng} + \epsilon}} * \gamma + \beta ychwng=σng+ϵ xchwng−μng∗γ+β
其中, y c h w n g y_{chw}^{ng} ychwng表示这个batch中第 n n n个实例对应的feature maps归一化并仿射后的第 g g g个channel组包含的第 c c c个map在 ( h , w ) (h, w) (h,w)位置的值。
5.2 pytorch中的Group Normalization
class torch.nn.GroupNorm(num_groups, num_channels, eps=1e-05, affine=True)
参数:
- num_groups:需要划分的channel组个数;
- num_features:即输入的channel;
- eps:就是计算公式中的 ϵ \epsilon ϵ,为保证数值稳定性(分母不能趋近或取0),给分母加上的值,默认为 1 e − 5 1e-5 1e−5;
- affine:默认为
True
。当设为True
时,使normalization后的均值和标准差(缩放变量 γ \gamma γ和平移变量 β \beta β)设置为可学习的参数;否则为0和1。缩放加平移就是仿射,affine的意思就是仿射。
pytorch中的GN公式:
y = x − E [ x ] V a r [ x ] + ϵ ∗ γ + β y = \frac{x - \mathrm{E}[x]}{ \sqrt{\mathrm{Var}[x] + \epsilon}} * \gamma + \beta y=Var[x]+ϵ x−E[x]∗γ+β
6 Switchable Normalization
- 归一化虽然提高模型泛化能力,然而归一化层的操作是人工设计的。在实际应用中,解决不同的问题原则上需要设计不同的归一化操作,并没有一个通用的归一化方法能够解决所有应用问题;
- 一个深度神经网络往往包含几十个归一化层,通常这些归一化层都使用同样的归一化操作,因为手工为每一个归一化层设计操作需要进行大量的实验。