Batch Normalization推理验证

Batch Normalization

使数据分布为均值为0方差为1
批量归一化、批量标准化『https://baike.baidu.com/item/%E6%89%B9%E6%A0%87%E5%87%86%E5%8C%96/22778547』
Standardization(标准化) ???这里不确定

ref

Batch Normalization原理

提出前提

Batch Normalization原理

随着网络深度的加深,在参数更新的时候,每层的输入值的数据分布会发生变化,导致ICS(Internal Covariate Shift)问题。

ICS问题会:

  • 上层网络需要不停调整来适应输入数据分布的变化,导致网络学习速度的降低
  • 网络的训练过程容易陷入梯度饱和区,减缓网络收敛速度

反正,网络的训练过程容易陷入梯度饱和区,减缓网络收敛速度

解决上面的问题

一、白化(whitening)

主要是PCA白化与ZCA白化。白化是对输入数据分布进行变换,进而达到以下两个目的:

  • 使得输入特征分布具有相同的均值与方差。

    其中PCA白化保证了所有特征分布均值为0,方差为1;而ZCA白化则保证了所有特征分布均值为0,方差相同;

  • 去除特征之间的相关性。

白化带来的问题:不理解

  • 计算成本大
  • 改变了网络每一层的分布,丢失了数据的表达能力。就是学到的参数信息会被白话操作丢失。

提出Batch Normalization

Batch Normalization原理

整体解释
n o r m a l i z a i t o n = x − μ σ 2 + ϵ normalizaiton = {x - \mu \over \sqrt{\sigma^2+\epsilon}} normalizaiton=σ2+ϵ xμ
( ϵ \epsilon ϵ防止方差是0而计算出错)

每个batch下,单独对该批量样本的每种特征进行normalizaiton,控制每种特征的特征值分布是均值为0,方差为1的分布

Batch就是mini-batch,因为有时候内存不能一次全装下

计算步骤

  • 假设batch的值为 m m m,即每次输入 m m m个样本参与训练

  • 计算这个batch的第 j j j个特征(即对应当前关注层的第 j j j个神经元)的均值 μ j \mu_j μj
    μ j = 1 m ∑ i = 1 m Z j ( i ) \mu_j={1\over m}\sum^m_{i=1}Z_j^{(i)} μj=m1i=1mZj(i)

  • 计算这个batch的第 j j j个特征(即对应当前关注层的第 j j j个神经元)的方差 σ j 2 \sigma^2_j σj2
    σ j 2 = 1 m ∑ i = 1 m ( Z j ( i ) − μ j ) 2 \sigma^2_j = {1\over m}\sum^m_{i=1}(Z^{(i)}_j-\mu_j)^2 σj2=m1i=1m(Zj(i)μj)2

  • Z j ( i ) Z_j^{(i)} Zj(i)是该batch的第 i i i个样本在当前关注层的第 j − 1 j-1 j1个神经元的输出值,也即当前关注层的第 j j j个神经元的输入值

  • 更新
    Z ^ j = Z j − μ j σ j 2 + ϵ \hat{Z}_j={Z_j-\mu_j \over \sqrt{\sigma^2_j+\epsilon}} Z^j=σj2+ϵ Zjμj

以上只是解决了分布的问题还有数据表达能力的缺失的问题

引入可学习机制(做线性变换)

增加参数 γ \gamma γ β \beta β
Z ~ j = γ j Z ^ j + β j \tilde{Z}_j = \gamma_j\hat{Z}_j+\beta_j Z~j=γjZ^j+βj
γ \gamma γ β \beta β对应方差 σ 2 \sigma^2 σ2和均值 μ \mu μ时,得到最初的原始特征 Z j Z_j Zj

测试阶段如何使用BN

Batch Normalization原理

以训练数据的整体方差和均值来作为测试阶段中BN的均值和方差,具体说:

训练时,记录每个batch的方差和均值,使用**均值和方差的无偏估计**:
μ t e s t = E ( μ b a t c h ) \mu_{test}=E(\mu_{batch}) μtest=E(μbatch)

σ t e s t 2 = m m − 1 E ( σ b a t c h 2 ) \sigma^2_{test}={m \over m-1}E(\sigma^2_{batch}) σtest2=m1mE(σbatch2)

这个最后的结果,对应的应该就是running_meanrunning_var

然后对测试数据做归一化:
B N ( X t e s t ) = γ X t e s t − μ t e s t σ t e s t 2 + ϵ + β BN(X_{test}) = \gamma{X_{test}-\mu_{test}\over\sqrt{\sigma^2_{test}+\epsilon}}+\beta BN(Xtest)=γσtest2+ϵ Xtestμtest+β
另外,除了采用整体样本的无偏估计外。吴恩达在Coursera上的Deep Learning课程指出可以对train阶段每个batch计算的mean/variance采用指数加权平均来得到test阶段mean/variance的估计。指数加权

计算实例

Batch Normalization原理

BN公式总结

x u p d a t e = x − E ( x ) V a r ( x ) + e p s ∗ γ + β x_{update} = {x-E(x)\over\sqrt{Var(x)+eps}}*\gamma+\beta xupdate=Var(x)+eps xE(x)γ+β

拉平成一维来计算均值和方差

pytorch BN

ref

pytorch中BatchNorm1d、BatchNorm2d、BatchNorm3d

【PyTorch】详解pytorch中nn模块的BatchNorm2d()函数

使用说明

pytorch中BatchNorm1d、BatchNorm2d、BatchNorm3d

  • BN的参数num_features都是和输入数据的C相对应
  • BN不改变数据维度
BN输入维度num_features
(等于E、Var个数)
1d(N, C)或者(N, C, L)C
2d(N, C, H, W)C
3d(N, C, D, H, W)C

计算和验证实例

PyTorch基础——torch.nn.BatchNorm2d

  • batch大于1的情况

  • E ( x ) E(x) E(x)就是把 H × W H\times W H×W维的特征==拉直成一维==再计算

  • V a r ( x ) Var(x) Var(x)也是一样

  • t = torch.tensor([[[1,2,3.0],[2,3,5]],[[1,2,3.0],[1,4,5]]])
    q = t.view(-1)
    print(t)
    print(q)
    print(torch.mean(t),torch.mean(q))
    print(torch.var(t, unbiased=False),torch.var(q, unbiased=False))# unbiased参数需要设置为False,否则
                                                  # 计算出方差为无偏估计,与当前结果不同
                                                  # 第二、第三通道相同设置
    
    

pytorch之BatchNorm2d

  • 有图示说明,图上的feature1,2应该是sample1,2

【PyTorch】详解pytorch中nn模块的BatchNorm2d()函数

  • 一个计算和验证BN2d的例子,batch=1的情况

  • C后面的被认定为特征,输出BN的权重就可以发现

    • 在2d中, ( H × W ) (H\times W) (H×W)代表特征,拥有 H W HW HW个数值来表征这个特征

      解释:(1)对于第 j j j个特征 C j C_j Cj来说,假设在该batch中包含 m m m个样本,所以需要统计 m m m份的维度为 ( H × W ) (H\times W) (H×W)的数据的均值和方差。(2)怎么算这个方差和均值?就是对 ( H × W ) (H\times W) (H×W)维度的数据拉成一维的,再像BN1d那样作计算。因此,求得的均值和方差的个数,分别等于C的值。

详细过程

Pytorch BN(BatchNormal)计算过程与源码分析和train与eval的区别

  • BN层的输出将作为下一层激活层的输入

  • PyTorch 源码解读之 BN,『四种Norm的图示

  • running_var = running_var * (1 - eaf) + eaf * inputs_var * n / (n - 1)
    running_mean = running_mean * (1 - eaf) + eaf * inputs_mean
    
  • 方差的计算,做的是有偏估计

BN2d验证代码

import torch.nn as nn
import torch

torch.random.manual_seed(0)
input = torch.randn(2, 3, 3, 4)
# With Learnable Parameters
m = nn.BatchNorm2d(3)
# Without Learnable Parameters
# m = nn.BatchNorm1d(100, affine=False)
output = m(input)
print(input)
print(m.weight)
print(m.bias)
print(m.running_mean)
print(output)
##########################################################################################################
## wrong
##########################################################################################################
print('=' * 100)
"""
使用先在`C`上求和再求均值和方差,均值是对的,但是方差是错误的
"""
input_c = (input[0][0] + input[1][0]) / 2
# input_c = input[0][0]
print(input_c)
firstDimenMean = torch.Tensor.mean(input_c)
firstDimenVar = torch.Tensor.var(input_c, False)  # false表示贝塞尔校正不会被使用
print(firstDimenMean)
print(firstDimenVar)
batchnormone = ((input_c[0][0] - firstDimenMean) / (torch.pow(firstDimenVar, 0.5) + m.eps)) \
               * m.weight[0] + m.bias[0]
print(batchnormone)
#######################################################################################################
## the computation is correct!!!
#######################################################################################################
print('=' * 100)
input_c1 = input[:, 0, :, :]
print(input_c1)
"""
注意: `torch.Tensor.var(input_c1, Ture)`和`torch.var(input_c1)`
本质是展平后作计算
"""
firstDimenMean = torch.Tensor.mean(input_c1)
firstDimenVar = torch.Tensor.var(input_c1, False)  # false表示贝塞尔校正不会被使用

print(firstDimenMean)
print(firstDimenVar)
batchnormone = ((input_c1 - firstDimenMean) / (torch.pow(firstDimenVar, 0.5) + m.eps)) \
               * m.weight[0] + m.bias[0]
print(batchnormone)

########################################################################################################
"""
验证均值和方差的计算,是否是通过展平后计算的
"""
print('=' * 100)
print(input_c1.flatten())
print(torch.mean(input_c1.flatten()))
print(torch.var(input_c1.flatten()))
print(torch.mean(input_c1))
print(torch.var(input_c1))

torch.Tensor.var(input_c1, Ture)torch.var(input_c1)的区别

# t = torch.tensor([[[1,2,3.0],[2,3,5]],[[1,2,3.0],[1,4,5]]])
t = torch.tensor([[[-1.1258, -1.1524, -0.2506, -0.4339],
                   [0.8487, 0.6920, -0.3160, -2.1152],
                   [0.3223, -1.2633, 0.3500, 0.3081]],
                  [[0.4397, 0.1124, 0.6408, 0.4412],
                   [-0.1023, 0.7924, -0.2897, 0.0525],
                   [0.5229, 2.3022, -1.4689, -1.5867]]])
q = t.view(-1)
print(t)
print(q)
print(torch.mean(t), torch.mean(q))
print(torch.var(t), torch.var(q))
print(torch.Tensor.mean(t),torch.Tensor.mean(q))
print(torch.Tensor.var(t, False),torch.Tensor.var(q, False)) # BN的方式
print(torch.Tensor.var(t, True),torch.Tensor.var(q, True))

分析torch.Tensor.var(input_c1, Ture)==torch.var(input_c1)

# 运行结果
tensor([[[-1.1258, -1.1524, -0.2506, -0.4339],
         [ 0.8487,  0.6920, -0.3160, -2.1152],
         [ 0.3223, -1.2633,  0.3500,  0.3081]],

        [[ 0.4397,  0.1124,  0.6408,  0.4412],
         [-0.1023,  0.7924, -0.2897,  0.0525],
         [ 0.5229,  2.3022, -1.4689, -1.5867]]])
tensor([-1.1258, -1.1524, -0.2506, -0.4339,  0.8487,  0.6920, -0.3160, -2.1152,
         0.3223, -1.2633,  0.3500,  0.3081,  0.4397,  0.1124,  0.6408,  0.4412,
        -0.1023,  0.7924, -0.2897,  0.0525,  0.5229,  2.3022, -1.4689, -1.5867])
tensor(-0.0950) tensor(-0.0950)
tensor(0.9611) tensor(0.9611)
tensor(-0.0950) tensor(-0.0950)
tensor(0.9211) tensor(0.9211)
tensor(0.9611) tensor(0.9611)

解释

关键在与var()unbiased这个参数,在Batch Normalization原理中有提到。

总结

训练阶段,用的是有偏估计,unbiased设置为True

测试阶段,用的有偏估计,在『测试阶段如何使用BN』有写,这部分不想验证了,搞了两天,累了

有偏估计、无偏估计

在数学上,方差的有偏估计和无偏估计

样本总体方差有偏估计和无偏估计的理解

[机器学习] 无偏估计和有偏估计及公式证明

通俗的说,就是我们拿不到所有的样本来做统计,所以只是用手上现有的数据的分布来替代整体数据分布,当手上数据无限多时,等价于整体数据。

从现有数据分布做统计,就是有偏的。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值