• 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,否则
                                                    # 计算出方差为无偏估计,与当前结果不同
                                                    # 第二、第三通道相同设置
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    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
      
      • 1
      • 2
    • 方差的计算,做的是有偏估计

    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))
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    分析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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    解释

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

    总结

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

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

    有偏估计、无偏估计

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

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

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

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

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

    在这里插入图片描述

  • 相关阅读:
    PHP入门-Window 下利用Nginx+PHP 搭建环境
    实用技术-Restful
    【C语言初阶】 一文详解分支语句 if
    Powershell命令行设置代理
    04-SpringBoot的基础配置及其配置文件分类,解决Yaml文件失效问题
    面向对象与面向过程的区别
    吴恩达深度学习笔记——卷积神经网络(Convolutional Neural Networks)
    [python]basemap后安装后hello world代码
    小学生python游戏编程arcade----坦克大战(1)
    Win安装protobuf和IDEA使用protobuf插件
  • 原文地址:https://blog.csdn.net/qq_37774098/article/details/125424060