Batch Normalization

一、算法

1.算法步骤

编辑

添加图片注释,不超过 140 字(可选)

2.参数解释

假设有如下特征Tensor=[B,C,W,H]=[4,3,2,2],也就是有4个batch,每个batch有3个特征图,也可以称为3个channel。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

首先计算channel为0维度上的均值和方差,如下图中的黄色部分,得到 \mu_0 和

\sigma_0 ,然后对channel是0 维度的每个值都进行如下计算,最终经过BN之后,对应的值变为 \hat{y_i}

$\hat{x_i}=\frac{(x_i-\mu_0)}{\sigma_0} \qquad \hat{y_i}=\hat{x_i}*\gamma +\beta$

编辑切换为居中

添加图片注释,不超过 140 字(可选)

同理处理channel为1的绿色部分和channel为2的橙色部分,处理方法和channel为0是的一样。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

编辑切换为居中

添加图片注释,不超过 140 字(可选)

• x \in \mathbb{R} ^{N\times C\times W \times H} ,其中, N 是batch_size,亦即N个样本;每个样本通道数为 C,对应图片是3,红绿蓝三个通道;高为 H,宽为 W。其中\epsilon是为了防止方差为0产生无效计算。

•在通道的维度上求均值和方差时,将在 N、H、W上操作,具体来说,就是把第1个样本的第1个通道,加上第2个样本第1个通道 ...... 加上第 N 个样本第1个通道,求平均,得到通道 1 的均值。方差同理。

  • 将第一个通道上的每一个值都减去第一通道的均值除以第一通道的方差,其他通道类似。

• \beta 是再平移参数(re-shift parameter),\gamma是再缩放参数(re-scale parameter)。最终的得到的数据符合均值为\beta,方差为 \gamma 得分布,这两个参数的维度相等于channel,亦即每个通道都学习一个权重和位移。

3.再分布的作用

问题一:通过第一步都已经得到了标准分布,为什么还需要第二步再改变分布?

是为了保证模型的表达能力不因为归一化而下降。另一方面,通过让每一层的输入分布均值为0,方差为1,会使得输入在经过sigmoid或tanh激活函数时,容易陷入激活函数的线性区域。

问题二:经过这么的变回来再变过去,会不会跟没变一样?

不会。再变换引入的两个新参数 \beta 和 \gamma,可以表示旧参数作为输入的同一族函数,但是新参数有不同的学习动态。在旧参数中, x 的均值取决于底层的神经网络;但在新参数中, y=\gamma(\frac{x-\mu(x)}{\sigma(x)})+\beta 仅由 \beta 和 \gamma来确定,去除了与底层计算的密切耦合。新参数很容易通过梯度下降来学习,简化了神经网络的训练。

二、Internal Covariate Shift

Google发表论文Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift,提出“Internal Covariate Shift”。在训练过程中,因为各层参数不停在变化,所以每个隐层都会面临covariate shift的问题,也就是在训练过程中,隐层的输入分布老是变来变去,这就是所谓的“Internal Covariate Shift”,Internal指的是深层网络的隐层,是发生在网络内部的事情,而不是covariate shift问题只发生在输入层。

如果输入数据经常变换,那么网络模型很难学到泛化的特征。所以,BatchNorm的基本思想:让每个隐层节点的激活输入分布固定下来呢?这样就避免了“Internal Covariate Shift”问题了。

三、加速收敛

在没有进行BN之前,如果两个输入数据 x_1,x_2 的分布的量级差别很大的话,导致 x_2 对计算结果的影响比较大(图左),所以训练的时候,横纵方向上需要给与不同的training rate,在 x_1 方向需要一个更大的learning rate,使参数快速的变大,才能平衡影响的 x_2 结果,不过这样做的办法却不见得很简单,因为学习率不好控制。如果做了normalization之后,输入数据是同一个量级,使得error surface看起来比较接近正圆的话(图右),就可以使训练容易得多,从而加速收敛。

编辑

添加图片注释,不超过 140 字(可选)

四、解决梯度消失和梯度爆炸

因为深层神经网络在做非线性变换前的激活输入值(就是那个 y=wx+b , x 是输入)随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于Sigmoid函数来说,意味着激活输入值 wx+b 是大的负值或正值),所以这导致反向传播时低层神经网络的梯度消失.

而BN就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,其实就是把越来越偏的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,也能加快训练速度。

BN之后,因为大权重有小梯度,这就不怕bp导致梯度放大,引起梯度爆炸。

五、BN其他优点

1.允许使用较大的学习率

  分布较为一致,较大的学习率也不会导致不稳定的学习,较大的学习率可以避免进入局部最优,也能够加速收敛。

2.可以不需要小心翼翼地设置权重初始化

  初始化对学习的影响减小了,可以不那么小心地设置初始权重。举例来说,对于一个单元的输入值,不管权重w,还是放缩后的权重kw,BN过后的值都是一样的,这个k被消掉了,对于学习来说,激活值是一样的。$\frac{kw-k\bar{w}}{k\sqrt{\sigma }}$ ,可以看到k被消掉。

3.减小对正则的需要

  而导致overfitting往往是数据很大导致,而BN就使数据变小,overfitting现象就可以得到一定的缓解。所以可以减小或者不用dropout。

六、BN的BP计算

借由论文中的给定的链式推导公式

编辑

添加图片注释,不超过 140 字(可选)

其中 \sigma^2=\sum_{i=1}^{m}\frac{(x_i-\mu_B)^2}{m} ,所以 \frac{\partial l}{\partial \mu_B} 后面会又加了一项;而 对于导数\frac{\partial l}{\partial x_i} , \hat{x}、\mu、\sigma 均包含 x_i ,所以有三项相加。

七、代码验证

如下代码为给定一个tensor,通过手动实现和调用系统方法实现BN。

import torch
import torch.nn as nn


def check_batchNorm():
    # [N,C,W,H];batch size,channel,width of feature map,height of feature map
    size = [4, 3, 2, 2]
    # batch normalization layer
    BN = nn.BatchNorm2d(size[1], affine=True)  # gamma和beta, 其维度与channel数相同,就是每一个channel共享gamma和beta
    BN.weight.data.copy_(torch.Tensor([1.1, 1.2, 1.3]))
    print("gamma ",BN.weight)  # 这个值是gamma
    print("beta ",BN.bias)  # 这个值是beta
    feature = torch.randn(size)
    output = BN(feature)
    data = []
    # 按照channel的维度挨个计算最后的值
    for i in range(size[1]):
        one_channel = feature[:, i, :, :]
        Mean = torch.Tensor.mean(one_channel)
        Var = torch.Tensor.var(one_channel, False)  # Bessel's Correction贝塞尔校正不被使用
        one_channel = ((feature[:, i, :, :] - Mean) / (torch.pow(Var + BN.eps, 0.5))) * BN.weight[i] + BN.bias[i]
        data.append(one_channel)
    data = torch.cat(data, dim=1).reshape(size)
    #取第一个数据进行验证
    print('+++' * 15, '\n', 'manually operation: ',data[0, 0, 0, 0])
    print('+++' * 15, '\n', 'pytorch result:',output[0, 0, 0, 0])
    #如下两个Tensor是相等的,可以打印验证
    # print('+++' * 15, '\n', 'manually operation: ', data)
    # print('+++' * 15, '\n', 'pytorch result: ', output)

结果如下:

 
 

gamma Parameter containing: tensor([1.1000, 1.2000, 1.3000], requires_grad=True) beta Parameter containing: tensor([0., 0., 0.], requires_grad=True) +++++++++++++++++++++++++++++++++++++++++++++ manually operation: tensor(1.0823, grad_fn=<SelectBackward>) +++++++++++++++++++++++++++++++++++++++++++++ pytorch result: tensor(1.0823, grad_fn=<SelectBackward>)

八、在测试阶段如何使用BN?

在测试阶段,不合适去计算测试时的batch的mean和var,比如测试仅对单样本输入进行测试时,这时去计算单样本输入的mean和var是完全没有意义的。因此会直接拿训练过程中对整个样本空间估算的mean和var直接来用。

编辑

添加图片注释,不超过 140 字(可选)

参考:

【深度学习】深入理解Batch Normalization批标准化 - 郭耀华 - 博客园

12. 批标准化(Batch Normalization )

详解深度学习中的Normalization,BN/LN/WN - 知乎

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值