【Pytorch学习笔记】Normlization

1. 前言

深度学习的目的不是搭建怎样的模型,而是在准确的前提下,用尽可能精简的模型来学习训练数据集的分布。因此,深度学习作为数据驱动的方法,对数据集的要求高。在概率论与数理统计中独立同分布是大家最喜欢的条件,但在深度学习中数据往往都不是独立同分布的,比如当数据为图片时,相邻像素点具有相关性,减少数据的相关性的方法有PCA等;Normlization则是将数据变换成 同分布

2. Pytorch中的Normlization

2.1 BatchNorm

1). torch.nn.BatchNorm1d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
1d表示序列数据,对整个batch中的数据计算均值和方差,参数说明如下:
num_features :输入特征(通道)数
eps :常数(避免分母为零)。
momentum :动态均值和动态方差所使用的动量。 x ^ new  = ( 1 − \hat{x}_{\text {new }}=(1- x^new =(1 momentum ) × x ^ + ) \times \hat{x}+ )×x^+ momentum × x t \times x_{t} ×xt,其中X是统计估计,Xt是当前的观察值。
affine :是否添加可学习的放射变换。
track_running_stats :“True”,表示记录训练过程中的均值和方差

输入 :(N,C)或(N,C,L),其中N为batchsize,C为num_channels,L为len_sequence。
输出 :与输入相同

# With Learnable Parameters
m = nn.BatchNorm1d(100)
# Without Learnable Parameters
m = nn.BatchNorm1d(100, affine=False)
input = torch.randn(20, 100)
output = m(input)

2). torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
对图像数据的BatchNorm ,参数说明与计算方法同BatchNorm1d。
输入 :(N,C,H,W),其中N为batchsize,C为num_channels,H为图片的高,W为图片的宽。
输出 :与输入相同。

# With Learnable Parameters
m = nn.BatchNorm2d(100)
# Without Learnable Parameters
m = nn.BatchNorm2d(100, affine=False)
input = torch.randn(20, 100, 35, 45)
output = m(input)

3). torch.nn.BatchNorm3d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
对3D数据的BatchNorm,参数说明同BatchNorm2d。
输入 :(N,C,D,H,W),其中N为batchsize,C为num_channels,D,H,W为数据的三个维度。
输出 :与输入相同。

# With Learnable Parameters
m = nn.BatchNorm3d(100)
# Without Learnable Parameters
m = nn.BatchNorm3d(100, affine=False)
input = torch.randn(20, 100, 35, 45, 10)
output = m(input)

2.1.1 LazyBatchNorm

torch.nn.LazyBatchNorm1d(eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
相比BatchNorm1d多增加了一个”延迟模块“,延迟初始化参数。对应的还有LazyBatchNorm2d 和 LazyBatchNorm3d。

2.1.2 SyncBatchNorm

torch.nn.SyncBatchNorm(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, process_group=None, device=None, dtype=None)
官方文档的解释:The mean and standard-deviation are calculated per-dimension over all mini-batches of the same process groups. 也就是说计算同一步的所有mini_batch的均值方差,我的理解如下:
当使用 N N N个GPU训练时,使用BatchNorm只能计算每个设备输入数据的均值和方差。使用SyncBatchNorm则计算 N ∗ B a t c h S i z e N*BatchSize NBatchSize 个数据计算均值和方差。SyncBatchNorm就是Pytorch提供的具有同步能力的BN层。

2.2 GroupNorm

torch.nn.GroupNorm(num_groups, num_channels, eps=1e-05, affine=True, device=None, dtype=None)
num_groups :channel分出来的组数
BatchNorm是对每一个channel进行均值和方差的计算,GroupNorm则是将channel分为几组计算均值和方差,比如说有6个通道,分为3组。

2.3 InstanceNorm

torch.nn.InstanceNorm1d(num_features, eps=1e-05, momentum=0.1, affine=False, track_running_stats=False, device=None, dtype=None)
BatchNorm是对整个batch的每个channel计算均值和方差,InstanceNorm表示对batch中的每个数据的每个channel,分别计算均值和方差。与BatchNorm一样他也有相应的 torch.nn.InstanceNorm2dtorch.nn.InstanceNorm3d

2.3.1 LazyInstanceNorm

参考 LazyBatchNorm,只是将整个batch计算均值和方差改为分别计算每个数据的均值和方差。

2.4 LayerNorm

torch.nn.LayerNorm(normalized_shape, eps=1e-05, elementwise_affine=True, device=None, dtype=None)
normalized:为list或int或torch.Size,如果输入为int则这个数等于input的最后一维;list和torch.Size时一般为(C, H, W)。
LayerNorm :计算每个样本的所有通道的均值和方差。

2.5 LocalResponseNorm

torch.nn.LocalResponseNorm(size, alpha=0.0001, beta=0.75, k=1.0)
size:用于归一化的通道数
alpha:乘积因子
beta:指数
k:附加因子
b c = a c ( k + α n ∑ c ′ = max ⁡ ( 0 , c − n / 2 ) min ⁡ ( N − 1 , c + n / 2 ) a c ′ 2 ) − β b_{c}=a_{c}\left(k+\frac{\alpha}{n} \sum_{c^{\prime}=\max (0, c-n / 2)}^{\min (N-1, c+n / 2)} a_{c^{\prime}}^{2}\right)^{-\beta} bc=ack+nαc=max(0,cn/2)min(N1,c+n/2)ac2β

3. 总结

以一个batch的图像数据 ( N , C , H , W ) (N,C,H,W) (N,C,H,W)为例。

3.1 解释

BatchNorm:在batch上对 ( N , H , W ) (N,H,W) (N,H,W)做归一化,对小batchsize效果不好,当batchsize太小时,计算的均值和方差不足以代表整个数据分布;
GroupNorm:将channel分组,然后对每个组再做归一化,也就是对 ( ( C / / G ) , H , W ) ((C//G),H,W) ((C//G),H,W)进行归一化;
InstanceNorm:对于每一个channel内归一化,也就是对 ( H , W ) (H,W) (H,W)进行归一化,用在风格化迁移,保持每个图像实例之间的独立;
LayerNorm:在channel上对,对 ( C , H , W ) (C,H,W) (C,H,W)做归一化,主要对RNN作用明显。

3.2 mean与var计算公式

上述方法都是减去均值除以标准差,再进行线性变换,不同点在于计算均值和标准差的公式
y = x − E [ x ] Var ⁡ [ x ] + ϵ ∗ γ + β y=\frac{x-\mathrm{E}[x]}{\sqrt{\operatorname{Var}[x]+\epsilon}} * \gamma+\beta y=Var[x]+ϵ xE[x]γ+β
BatchNorm的均值与标准差
μ c ( x ) = 1 N H W ∑ n = 1 N ∑ h = 1 H ∑ w = 1 W x n c h w \mu_{c}(x)=\frac{1}{N H W} \sum_{n=1}^{N} \sum_{h=1}^{H} \sum_{w=1}^{W} x_{n c h w} μc(x)=NHW1n=1Nh=1Hw=1Wxnchw
σ c ( x ) = 1 N H W ∑ n = 1 N ∑ h = 1 H ∑ w = 1 W ( x n c h w − μ c ( x ) ) 2 + ϵ \sigma_{c}(x)=\sqrt{\frac{1}{N H W} \sum_{n=1}^{N} \sum_{h=1}^{H} \sum_{w=1}^{W}\left(x_{n c h w}-\mu_{c}(x)\right)^{2}+\epsilon} σc(x)=NHW1n=1Nh=1Hw=1W(xnchwμc(x))2+ϵ
GroupNorm的均值与标准差
μ n g ( x ) = 1 ( C / G ) H W ∑ c = g C / G ( g + 1 ) C / G ∑ h = 1 H ∑ w = 1 W x n c h w \mu_{n g}(x)=\frac{1}{(C / G) H W} \sum_{c=g C / G}^{(g+1) C / G} \sum_{h=1}^{H} \sum_{w=1}^{W} x_{n c h w} μng(x)=(C/G)HW1c=gC/G(g+1)C/Gh=1Hw=1Wxnchw
σ n g ( x ) = 1 ( C / G ) H W ∑ c = g C / G ( g + 1 ) C / G ∑ h = 1 H ∑ w = 1 W ( x n c h w − μ n g ( x ) ) 2 + ϵ \sigma_{n g}(x)=\sqrt{\frac{1}{(C / G) H W} \sum_{c=g C / G}^{(g+1) C / G} \sum_{h=1}^{H} \sum_{w=1}^{W}\left(x_{n c h w}-\mu_{n g}(x)\right)^{2}+\epsilon} σng(x)=(C/G)HW1c=gC/G(g+1)C/Gh=1Hw=1W(xnchwμng(x))2+ϵ
InstanceNorm的均值与标准差
μ n c ( x ) = 1 H W ∑ h = 1 H ∑ w = 1 W x n c h w \mu_{n c}(x)=\frac{1}{H W} \sum_{h=1}^{H} \sum_{w=1}^{W} x_{n c h w} μnc(x)=HW1h=1Hw=1Wxnchw
σ n c ( x ) = 1 H W ∑ h = 1 H ∑ w = 1 W ( x n c h w − μ n c ( x ) ) 2 + ϵ \sigma_{n c}(x)=\sqrt{\frac{1}{H W} \sum_{h=1}^{H} \sum_{w=1}^{W}\left(x_{n c h w}-\mu_{n c}(x)\right)^{2}+\epsilon} σnc(x)=HW1h=1Hw=1W(xnchwμnc(x))2+ϵ
LayerNorm的均值与方差
μ n ( x ) = 1 C H W ∑ c = 1 C ∑ h = 1 H ∑ w = 1 W x n c h w \mu_{n}(x)=\frac{1}{C H W} \sum_{c=1}^{C} \sum_{h=1}^{H} \sum_{w=1}^{W} x_{n c h w} μn(x)=CHW1c=1Ch=1Hw=1Wxnchw
σ n ( x ) = 1 C H W ∑ c = 1 C ∑ h = 1 H ∑ w = 1 W ( x n c h w − μ n ( x ) ) 2 + ϵ \sigma_{n}(x)=\sqrt{\frac{1}{C H W} \sum_{c=1}^{C} \sum_{h=1}^{H} \sum_{w=1}^{W}\left(x_{n c h w}-\mu_{n}(x)\right)^{2}+\epsilon} σn(x)=CHW1c=1Ch=1Hw=1W(xnchwμn(x))2+ϵ

3.3 检验

1). BatchNorm:

import torch
import torch.nn as nn

input = torch.randn(5,3,16,16)*100
BN = nn.BatchNorm2d(num_features=3, eps=1e-05, momentum=0, affine=False, track_running_stats=False)
def BN_custom(input):
    # 变形(3, 5*16*16)
    input1 = input.permute(1,0,2,3).contiguous().view(3, -1)
    # 均值(每一个通道均值)
    mu = input1.mean(dim=1).view(1,3,1,1)
    # 标准差(每一个通道标准差)
    std = input1.std(dim=1, unbiased=False).view(1,3,1,1)
    output = (input-mu) / (std.pow(2)+1e-05).pow(1/2)
    return output

err = BN(input) - BN_custom(input)
print(err.abs().sum())

输出:tensor(9.7361e-05)。
误差的一范数为9.7361e-05可以认为方法正确。
2).GroupNorm: 把相邻的通道分为一组

import torch
import torch.nn as nn

input = torch.randn(5,6,16,16)*100
GN = nn.GroupNorm(3, 6, eps=1e-05, affine=False)
def GN_custom(input):
    # 变形(5, 3, 2*16*16)
    input1 = input.view(5, 3, -1)
    # 均值(5, 3, 1)
    mu = input1.mean(dim=-1).reshape(5, 3, -1)
    # 标准差(5, 3, 1)
    std = input1.std(dim=-1, unbiased=False).reshape(5, 3, -1)
    output = (input1-mu) / (std.pow(2)+1e-05).pow(1/2)
    output = output.reshape(5, 6, 16, 16)
    return output

err = GN(input) - GN_custom(input)
print(err.abs().sum())

输出:tensor(0.0003)。
误差的一范数为0.0003可以认为方法正确。
3).InstanceNorm:

import torch
import torch.nn as nn

input = torch.randn(5, 3, 16, 16)
IN = nn.InstanceNorm2d(num_features=3, eps=1e-05, momentum=0, affine=False, track_running_stats=False)
def IN_custom(input):
    # 变形(5*3, 256)
    input1 = input.view(15, -1)
    # 均值
    mu = input1.mean(dim=1).view(5, 3, 1, 1)
    # 标准差
    std = input1.std(dim=1, unbiased=False).view(5, 3, 1, 1)
    output = (input - mu)/(std.pow(2) + 1e-05).pow(1/2)
    return output

err = IN(input) - IN_custom(input)
print(err.abs().sum())

输出:tensor(0.0002)。
误差的一范数为0.0002可以认为方法正确。
4). LayerNorm:

import torch
import torch.nn as nn

input = torch.randn(5, 3, 16, 16)
LN = nn.LayerNorm(normalized_shape=[3,16,16], eps=1e-05, elementwise_affine=False)
def LN_custom(input):
    # 变形(5, 3*16*16)
    input1 = input.view(5, -1)
    # 均值
    mu = input1.mean(dim=1).view(5, 1, 1, 1)
    # 标准差
    std = input1.std(dim=1, unbiased=False).view(5, 1, 1, 1)
    output = (input-mu)/(std.pow(2) + 1e-05).pow(1/2)
    return output

err = LN(input) - LN_custom(input)
print(err.abs().sum())

输出:tensor(0.0001)。
误差的一范数为0.0001可以认为方法正确。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值