nn.BatchNorm2d——批量标准化操作解读
nn.BatchNorm2d——批量标准化操作
torch .nn .BatchNorm2d (num_features , eps =1e -05, momentum =0.1, affine =True , track_running_stats =True , device =None , dtype =None )功能:对输⼊的四维数组进⾏批量标准化处理,具体计算公式如下:
对于所有的batch中的同⼀个channel的数据元素进⾏标准化处理,即如果有C个通道,⽆论有多少个batch,都会在通道维度上进⾏标准化处理,⼀共进⾏C次。
训练阶段的均值和⽅差计算⽅法相同,将所有batch相同通道的值取出来,⼀块计算均值和⽅差,即计算当前观测值的均值和⽅差。测试阶段的均值和⽅差有两种计算⽅法:
①估计所有图⽚的均值和⽅差,即做全局计算,具体计算⽅法如下:
模型分别储存各个通道(通道数需要预先定义)的均值和⽅差数据(初始为0和1),在每次训练过程中,每标准化⼀组数据,都利⽤计算得到的局部观测值的均值和⽅差对储存的数据做更新,测试阶段利⽤模型存储的两个数据做标准化处理,更新公式如下:
②采⽤和训练阶段相同的计算⽅法,即只计算当前输⼊数据的均值和⽅差输⼊:
num_features :输⼊图像的通道数量。
eps :稳定系数,防⽌分母出现0。
momentum :模型均值和⽅差更新时的参数,见上述公式。
affine :代表gamma,beta是否可学。如果设为True ,代表两个参数是通过学习得到的;如果设为False ,代表两个参数是固定值,默认情况下,gamma是1,beta是0。track_running_stats :代表训练阶段是否更新模型存储的均值和⽅差,即测试阶段的均值与⽅差的计算⽅法采⽤第⼀种⽅法还是第⼆种⽅法。如果设为True ,则代表训练阶段每次迭代都会更新模型存储的均值和⽅差(计算全局数据),测试过程中利⽤存储的均值和⽅差对各个通道进⾏标准化处理;如果设为False ,则模型不会存储均值和⽅差,训练过程中也不会更新均值和⽅差的数据,测试过程中只计算当前输⼊图像的均值和⽅差数据(局部数据)。具体区别见代码案例。注意:
训练阶段的标准化过程中,均值和⽅差来源途径只有⼀种⽅式,即利⽤当前输⼊的数据进⾏计算。测试阶段的标准化过程中,均值和⽅差来源途径有两种⽅式,⼀是来源于全局的数据,即模型本⾝存储⼀组均值和⽅差数据,在训练过程中,不断更新它们,使其具有描述全局数据的统计特性;⼆是来源于当前的输⼊数据,即和训练阶段计算⽅法⼀样,但这样会在测试过程中带来统计特性偏移的弊端,⼀般track_running_stats 设置为True ,即采⽤第⼀种来源途径。
换句话说,就是训练阶段和测试阶段所承载的任务不同,训练阶段主要是通过已知的数据去优化模型,⽽测试阶段主要是利⽤已知的模型去预测未知的数据。⽤途:训练过程中遇到收敛速度很慢的问题时,可以通过引⼊BN层来加快⽹络模型的收敛速度
遇到梯度消失或者梯度爆炸的问题时,可以考虑引⼊BN层来解决
⼀般情况下,还可以通过引⼊BN层来加快⽹络的训练速度
y =∗V ar [x ]+eps x −mean [x ]gamma +beta
X =new (1−momentum )×X +old momentum ×X t
其中,X 是模型的新参数,X 是模型原来的参数,X 是当前观测值的参数
new old t
批量标准化的具体原理请参考论⽂:
代码案例
⼀般⽤法
import torch
from torch import nn
# 在(0-1)范围内随机⽣成数据
img=torch.rand(2,2,2,3)
bn=nn.BatchNorm2d(2)
img_2=bn(img)
print(img)
print(img_2)
输出
# 标准化前
tensor([[[[0.5330,0.7753,0.6192],
[0.9190,0.1657,0.5841]],
[[0.7766,0.7864,0.2004],
[0.9379,0.3253,0.1964]]],
[[[0.7448,0.9222,0.1860],
[0.3829,0.8812,0.2508]],
[[0.0130,0.0405,0.2205],
[0.8997,0.5143,0.9414]]]])
# 标准化后
tensor([[[[-0.1764,0.7257,0.1446],
[1.2605,-1.5434,0.0140]],
[[0.8332,0.8615,-0.8287],
[1.2987,-0.4685,-0.8403]]],
[[[0.6121,1.2726,-1.4678],
[-0.7350,1.1199,-1.2269]],
[[-1.3693,-1.2899,-0.7707],
[1.1883,0.0769,1.3088]]]], grad_fn=<NativeBatchNormBackward>)
标准化过程是以通道为维度计算的,即所有batch下,相同通道(channel)下的数据合并到⼀块,做标准化处理。若有C个通道,⽆论batch 是多少,都会有C次标准化。
import torch
from torch import nn
img=torch.rand(2,2,2,3)
# 取出两个batch下第⼀个维度的数据
a=torch.cat((img[0,0,:,:],img[1,0,:,:]),dim=0)
# 转化为numpy格式,便于计算均值⽅差
b=a.numpy()
import numpy as np
an(b)
std=np.std(b)+1e-5
# ⼿动标准化
img_2=(b-mean)/std
bn=nn.BatchNorm2d(2)
# 利⽤BatchNorm2d标准化
eval是做什么的img_3=bn(img)
print(img_2)
print(img_3)
输出
⼿动标准化得到的数据,前两⾏代表第⼀个batch下第⼀个通道标准化后的数据,与利⽤BatchNorm2d的前两⾏数据相等;后两⾏代表第⼆个batch下第⼀个通道标准化后的数据,与利⽤BatchNorm2d的前五六⾏数据相等。
# ⼿动标准化
[[-0.8814389-1.35359670.05035681]
[-0.5180839-1.396645 1.8198812]
[0.91518920.9469903-0.7903797]
[0.356902631.135288-0.28446582]]
# 利⽤BatchNorm2d标准化
tensor([[[[-0.8814,-1.3535,0.0504],
[-0.5181,-1.3966,1.8198]],
[[-1.5779,-0.5996,-1.0233],
[-0.3919,-0.6692,0.6693]]],
[[[0.9151,0.9469,-0.7903],
[0.3569,1.1352,-0.2844]],
[[0.5829,-0.7664,1.1329],
[1.4469,-0.4100,1.6063]]]], grad_fn=<NativeBatchNormBackward>)
track_running_stats设为True与Fasle的区别
训练过程
import torch
from torch import nn
img=torch.rand(2,2,2,3)
bn_t=nn.BatchNorm2d(2,track_running_stats=True)
bn_f=nn.BatchNorm2d(2,track_running_stats=False)
# 输出初始的模型存储值
print('bn_t,mean:',bn_t.running_mean,'var:',bn_t.running_var)
print('bn_f,mean:',bn_f.running_mean,'var:',bn_f.running_var)
# 转化为训练阶段
ain()
ain()
img_t=bn_t(img)
img_f=bn_f(img)
print(img_t)
print(img_f)
print('⼀次迭代更新bn_t,mean:',bn_t.running_mean,'var:',bn_t.running_var)
img_t=bn_t(img)
print('两次迭代更新bn_t,mean:',bn_t.running_mean,'var:',bn_t.running_var)
输出
# 初始过程,track_running_stats设为True时,模型存储全局均值与⽅差
# 初始化为0和1,两个值对应两个通道
bn_t,mean: tensor([0.,0.]) var: tensor([1.,1.])
# track_running_stats设为False时,模型不存储均值与⽅差
bn_f,mean:None var:None
# 由下⾯的结果易知,track_running_stats设为True与False,对训练过程的标准化结果⽆影响tensor([[[[-1.0599,0.9532,-0.2647],
[0.8146,0.2971,-1.7099]],
[[1.0554,0.9239,1.9331],
[0.0334,-1.3058,-0.0804]]],
[[[1.0146,0.7528,-0.1986],
[1.3564,-1.6232,-0.3325]],
[[-1.6591,-0.7690,-0.3045],
[0.7691,0.1344,-0.7306]]]], grad_fn=<NativeBatchNormBackward>)
tensor([[[[-1.0599,0.9532,-0.2647],
[0.8146,0.2971,-1.7099]],
[[1.0554,0.9239,1.9331],
[0.0334,-1.3058,-0.0804]]],
[[[1.0146,0.7528,-0.1986],
[1.3564,-1.6232,-0.3325]],
[[-1.6591,-0.7690,-0.3045],
[0.7691,0.1344,-0.7306]]]], grad_fn=<NativeBatchNormBackward>)
# track_running_stats设为Ture时,模型每标准化⼀组数据,都会更新⾃⼰存储的数据⼀次
⼀次迭代更新bn_t,mean: tensor([0.0562,0.0586]) var: tensor([0.9092,0.9043])
两次迭代更新bn_t,mean: tensor([0.1068,0.1114]) var: tensor([0.8275,0.8183])
测试过程
import torch
from torch import nn
# img和上个训练过程的数据⼀样,为了便于做⽐较
bn_t=nn.BatchNorm2d(2,track_running_stats=True)
bn_f=nn.BatchNorm2d(2,track_running_stats=False)
# 输出初始的模型存储值,测试过程中,bn_t利⽤该值进⾏标准化
print('bn_t,mean:',bn_t.running_mean,'var:',bn_t.running_var)
# 转化为测试过程
bn_t.eval()
bn_f.eval()
img_t=bn_t(img)
img_f=bn_f(img)
print(img)
print(img_t)
print(img_f)
ain()
img_t=bn_t(img)
bn_t.eval()
img_t=bn_t(img)
print('更新后bn_t,mean:',bn_t.running_mean,'var:',bn_t.running_var)
print(img_t)
输出
# track_running_stats设为Ture时
# 在测试过程中利⽤running_mean和running_var做标准化计算
bn_t,mean: tensor([0.,0.]) var: tensor([1.,1.])
# 如果不进⾏训练,则默认初始值为0和1,⽤这两个数做标准化时的结果与输⼊相同# 输⼊数据
tensor([[[[0.2542,0.8395,0.4854],
[0.7992,0.6488,0.0652]],
[[0.7970,0.7707,0.9722],
[0.5929,0.3256,0.5702]]],
[[[0.8574,0.7813,0.5046],
[0.9568,0.0904,0.4657]],
[[0.2550,0.4327,0.5255],
[0.7398,0.6131,0.4404]]]])
# track_running_stats设为Ture时,拿初始化数据进⾏标准化计算结果
# 可见与上述结果相同
tensor([[[[0.2542,0.8395,0.4854],
[0.7992,0.6488,0.0652]],
[[0.7970,0.7707,0.9722],
[0.5929,0.3256,0.5702]]],
[[[0.8574,0.7813,0.5046],
[0.9568,0.0904,0.4657]],
[[0.2550,0.4327,0.5255],
[0.7398,0.6131,0.4404]]]], grad_fn=<NativeBatchNormBackward>)
# track_running_stats设为Fasle时,标准化计算结果和训练过程⼀样,因此结果相同# 这⾥的输⼊数据和上⼀个案例⼀样,可以和上个过程的结果做⽐较。
tensor([[[[-1.0599,0.9532,-0.2647],
[0.8146,0.2971,-1.7099]],
[[1.0554,0.9239,1.9331],
[0.0334,-1.3058,-0.0804]]],
[[[1.0146,0.7528,-0.1986],
[1.3564,-1.6232,-0.3325]],
[[-1.6591,-0.7690,-0.3045],
[0.7691,0.1344,-0.7306]]]], grad_fn=<NativeBatchNormBackward>)
# 经过⼀次训练过程,running_mean与running_var都有所改变
更新后bn_t,mean: tensor([0.0562,0.0586]) var: tensor([0.9092,0.9043])
# 再进⾏测试时,⽤新的running_mean和running_var做标准化计算
tensor([[[[0.2076,0.8215,0.4501],
[0.7792,0.6214,0.0094]],
[[0.7764,0.7488,0.9607],
[0.5619,0.2807,0.5380]]],
[[[0.8402,0.7604,0.4702],
[0.9444,0.0358,0.4294]],
[[0.2065,0.3934,0.4909],
[0.7163,0.5831,0.4015]]]], grad_fn=<NativeBatchNormBackward>)
官⽅⽂档
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论