手推BN、IN、LN、GN

发布于:2023-01-02 ⋅ 阅读:(968) ⋅ 点赞:(0)

手推BN、IN、LN、GN

手推BN、IN、LN、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]+ϵ xE[x]γ+β

本篇文章通过实例说明BN、IN、LN、GN是取哪些维度上的均值和方差来进行标准化的。

当处理图片时,输入数据维度为(N, C, H, W),代表(batch,channel,height,width)

假设batch=2,channel=4,height=1,width=2,可通过下图直观感受,图中的1和2为高和宽。

import numpy as np
a = np.array([[[[ 1.,  5.]],
			                [[ 2.,  6.]],
			                [[ 3.,  7.]],
			                [[ 4.,  8.]]],
			               [[[ 9., 13.]],
			                [[10., 14.]],
			                [[11., 15.]],
			                [[12., 16.]]]], dtype=np.float32)

print('a.shape:', a.shape)
# output:a.shape:(2, 4, 1, 2)

在这里插入图片描述

简要介绍

标准化:通过一部分数据得到均值和方差,经过下面的公式得到标准化后的值。各种不同的标准化方法差异主要在于选取哪些数据做均值和方差。

ϵ \epsilon ϵ 是防止分母为零而取的一个极小的数, γ \gamma γ β \beta β是为了将归一化的数成比例放缩和平移,可自动学习。本文重点观察不同归一化方法对均值和方差的处理。
在这里插入图片描述

BN

取①各批次、②单个通道、③所有值做均值和方差,得到的均值和方差维度为(C,),(以均值举例,方差也是取这些值,IN、LN、GN同),可通过上图直观感受如何取值的。

u = (1 + 5 + 9 + 13) / 4 = 7

用程序说明,手动处理的归一化结果与pytorch函数作用结果相同,并以第一个数字举例,其他数值可自行测试。

# BatchNorm2d
import torch
import torch.nn as nn
import numpy as np
import math
a = np.array([[[[ 1.,  5.]],
			                [[ 2.,  6.]],
			                [[ 3.,  7.]],
			                [[ 4.,  8.]]],
			               [[[ 9., 13.]],
			                [[10., 14.]],
			                [[11., 15.]],
			                [[12., 16.]]]], dtype=np.float32)

print('a.shape:', a.shape)
u = np.mean(a, axis=(0,2,3))
var = np.var(a, axis=(0,2,3))
print('均值为:', u)
print('方差为:', var)

# nn.BatchNorm2d第一个参数为通道数
batch_norm = nn.BatchNorm2d(4, eps=1e-6, affine=False) 
b = torch.from_numpy(a)
c = batch_norm(b) # BatchNorm输入维度需[N,C,H,W]
print('变换后:', c)

# 验证第一个元素
print('1变换后为:', (1 - u[0]) / math.sqrt(var[0] + 1e-6))

在这里插入图片描述

IN

取①单个批次,②单个通道,③所有值做均值和方差,得到的均值和方差维度为(N, C)

u = (1 + 5) / 2 = 3

程序说明

# InstanceNorm2d
import torch
import torch.nn as nn
import numpy as np
import math
a = np.array([[[[ 1.,  5.]],
			                [[ 2.,  6.]],
			                [[ 3.,  7.]],
			                [[ 4.,  8.]]],
			               [[[ 9., 13.]],
			                [[10., 14.]],
			                [[11., 15.]],
			                [[12., 16.]]]], dtype=np.float32)

print('a.shape:', a.shape)
u = np.mean(a, axis=(2, 3))
var = np.var(a, axis=(2, 3))
print('均值为:', u)
print('方差为:', var)

# nn.InstanceNorm2d第一个参数为通道数
instance_norm = nn.InstanceNorm2d(4, eps=1e-6, affine=False) 
b = torch.from_numpy(a)
c = instance_norm(b)
print('变换后:', c)

# 验证第一个元素
print('1变换后为:', (1 - u[0][0]) / math.sqrt(var[0][0] + 1e-6))

在这里插入图片描述

LN

LN较为特殊,nn.LayerNorm要求的输入维度为(N, *),与其他标准化所需要的(N, C, H, W)不同,并且第一个参数要求输入需要归一化的维度。通常图像数据为(N, C, H, W),而文本数据为(批次大小,序列长度,词嵌入大小)。

层归一化大多数的解释为①单个批次、②所有通道、③所有值做均值和方差,而实际上是可以自定义的。LN在文本领域通常对最后一个维度做标准化,即对每个词内部进行标准化。本实验以文本数据输入为例,即将最后两个维度合并,介绍LN处理方法,此时与实例归一化结果相同。

在这里插入图片描述

u = (1 + 5) / 2 = 3

程序说明

# LayerNorm
import torch
import torch.nn as nn
import numpy as np
import math
a = np.array([[[[ 1.,  5.]],
			                [[ 2.,  6.]],
			                [[ 3.,  7.]],
			                [[ 4.,  8.]]],
			               [[[ 9., 13.]],
			                [[10., 14.]],
			                [[11., 15.]],
			                [[12., 16.]]]], dtype=np.float32)

a = a.reshape((2, 4, 2))
print('a.shape:', a.shape)
u = np.mean(a, axis=(2))
var = np.var(a, axis=(2))
print('均值为:', u)
print('方差为:', var)

# nn.LayerNorm第一个参数为归一化的维度,通常图像为(H,W),文本为最后一维
layer_norm = nn.LayerNorm(a.shape[-1], eps=1e-6, elementwise_affine=False) 
b = torch.from_numpy(a)
c = layer_norm(b)
print('变换后:', c)

# 验证第一个元素
print('1变换后为:', (1 - u[0][0]) / math.sqrt(var[0][0] + 1e-6))

在这里插入图片描述

GN

①单个批次、②在通道上分n组、③该组的所有值做均值和方差(以两组为例)

u = (1 + 5 + 2 + 6) / 4 = 3.5

程序说明

# GroupNorm
import torch
import torch.nn as nn
import numpy as np
import math
a = np.array([[[[ 1.,  5.]],
			                [[ 2.,  6.]],
			                [[ 3.,  7.]],
			                [[ 4.,  8.]]],
			               [[[ 9., 13.]],
			                [[10., 14.]],
			                [[11., 15.]],
			                [[12., 16.]]]], dtype=np.float32)

print('a.shape:', a.shape)
u = np.concatenate((np.mean(a[:,:2,:,:], axis=(1, 2, 3)), np.mean(a[:,2:,:,:], axis=(1, 2, 3)))) 
var = np.concatenate((np.var(a[:,:2,:,:], axis=(1, 2, 3)), np.var(a[:,2:,:,:], axis=(1, 2, 3)))) 
print('均值为:', u)
print('方差为:', var)

# nn.GroupNorm前两个参数代表分组数和通道数,用 通道数/分组数 得到每组对几个通道进行归一化
group_norm = nn.GroupNorm(2, 4, eps=1e-6, affine=False) 
b = torch.from_numpy(a)
c = group_norm(b) # GroupNorm输入维度需[N,C,H,W]
print('变换后:', c)

# 验证第一个元素
print('1变换后为:', (1 - u[0]) / math.sqrt(var[0] + 1e-6))

在这里插入图片描述

本文含有隐藏内容,请 开通VIP 后查看