40_pytorch Batch Norm

1.37.Batch Normalization,批规范化
1.37.1.Batch Norm介绍
1.37.2.Intuitive explanation
1.37.3.Intuitive explanation
1.37.4.Feature scaling
1.37.5.BatchNorm1d、BatchNorm2d、BatchNorm3d
1.37.5.1.nn.BatchNorm1d(num_features)
1.37.5.2.nn.BatchNorm2d(num_features)
1.37.5.3.nn.BatchNorm3d(num_features)
1.37.6.Batch Norm
1.37.7.Pipeline
1.37.8.参考博文

1.37.Batch Normalization,批规范化

1.37.1.Batch Norm介绍

Batch Normalization(简称为BN)[2],中文翻译成批规范化,是在深度学习中普遍使用的一种技术,通常用于解决多层神经网络中间层的协方差偏移(Internal Covariate Shift)问题,类似于网络输入进行零均值化和方差归一化的操作,不过是在中间层的输入中操作而已。

1.37.2.Intuitive explanation

在这里插入图片描述

1.37.3.Intuitive explanation

使用sigmoid会出现梯度消失的情况,在实际训练中,引入了BatchNorm操作,可以将输入值限定在(γ = 1 , β)之间
在这里插入图片描述
如下图,如果不进行Batch Norm,如果输入weight差别过大,在两个方向进行梯度下降,会出现梯度下降不平衡,在训练过程中不能稳定的收敛,在实际应用过程中也不能稳定的输出label结果,因此Normalization是很重要的
在这里插入图片描述

1.37.4.Feature scaling

Image Normalization

normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

Batch Normalization

1.37.5.BatchNorm1d、BatchNorm2d、BatchNorm3d

1.37.5.1.nn.BatchNorm1d(num_features)
1.对小批量(mini-batch)2d3d输入进行批标准化(Batch Normalization)操作
2.num_features:
  来自期望输入的特征数,该期望输入的大小为'batch_size x num_features [x width]'
  意思即输入大小的形状可以是'batch_size x num_features''batch_size x num_features x width' 都可以。
 (输入输出相同)
  输入Shape:(N, C)或者(N, C, L)
  输出Shape:(N, C)或者(N,C,L)

  eps:为保证数值稳定性(分母不能趋近或取0,给分母加上的值。默认为1e-5。
  momentum:动态均值和动态方差所使用的动量。默认为0.1。
  affine:一个布尔值,当设为true,给该层添加可学习的仿射变换参数。
3.在每一个小批量(mini-batch)数据中,计算输入各个维度的均值和标准差。gamma与beta是可学习的大小为C的参数向量(C为输入大小)
  在训练时,该层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。
  在验证时,训练求得的均值/方差将用于标准化验证数据。 
4.例子
>>> # With Learnable Parameters
>>> m = nn.BatchNorm1d(100) #num_features指的是randn(20, 100)中(N, C)的第二维C
>>> # Without Learnable Parameters
>>> m = nn.BatchNorm1d(100, affine=False)
>>> input = autograd.Variable(torch.randn(20, 100)) #输入Shape:(N, C)
>>> output = m(input)  #输出Shape:(N, C)
1.37.5.2.nn.BatchNorm2d(num_features)
1.对小批量(mini-batch)3d数据组成的4d输入进行批标准化(Batch Normalization)操作
2.num_features: 
  来自期望输入的特征数,该期望输入的大小为'batch_size x num_features x height x width'
 (输入输出相同)
  输入Shape:(N, C,H, W)
  输出Shape:(N, C, H, W)
  eps: 为保证数值稳定性(分母不能趋近或取0,给分母加上的值。默认为1e-5。
  momentum: 动态均值和动态方差所使用的动量。默认为0.1。
  affine: 一个布尔值,当设为true,给该层添加可学习的仿射变换参数。
3.在每一个小批量(mini-batch)数据中,计算输入各个维度的均值和标准差。gamma与beta是可学习的大小为C的参数向量(C为输入大小)
  在训练时,该层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。
  在验证时,训练求得的均值/方差将用于标准化验证数据。
4.例子
>>> # With Learnable Parameters
>>> m = nn.BatchNorm2d(100) #num_features指的是randn(20, 100, 35, 45)中(N, C,H, W)的第二维C
>>> # Without Learnable Parameters
>>> m = nn.BatchNorm2d(100, affine=False)
>>> input = autograd.Variable(torch.randn(20, 100, 35, 45))  #输入Shape:(N, C,H, W)
>>> output = m(input)
1.37.5.3.nn.BatchNorm3d(num_features)
1.对小批量(mini-batch)4d数据组成的5d输入进行批标准化(Batch Normalization)操作
2.num_features: 
来自期望输入的特征数,该期望输入的大小为'batch_size x num_features depth x height x width'
(输入输出相同)
 输入Shape:(N, C,D, H, W)
 输出Shape:(N, C, D, H, W)

  eps: 为保证数值稳定性(分母不能趋近或取0,给分母加上的值。默认为1e-5。
  momentum: 动态均值和动态方差所使用的动量。默认为0.1。
  affine: 一个布尔值,当设为true,给该层添加可学习的仿射变换参数。

3.在每一个小批量(mini-batch)数据中,计算输入各个维度的均值和标准差。gamma与beta是可学习的大小为C的参数向量(C为输入大小)
  在训练时,该层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。
  在验证时,训练求得的均值/方差将用于标准化验证数据。
4.例子
    >>> # With Learnable Parameters
    >>> m = nn.BatchNorm3d(100)  #num_features指的是randn(20, 100, 35, 45, 10)中(N, C, D, H, W)的第二维C
    >>> # Without Learnable Parameters
    >>> m = nn.BatchNorm3d(100, affine=False)  #num_features指的是randn(20, 100, 35, 45, 10)中(N, C, D, H, W)的第二维C
    >>> input = autograd.Variable(torch.randn(20, 100, 35, 45, 10)) #输入Shape:(N, C, D, H, W) 
    >>> output = m(input)

1.37.6.Batch Norm

目前已知的Normalization的方法有4种,对于输入数据为[N,C,(H * W)] (N代表tensor数据,C代表通道,H代表高,W代表宽)
下面图形中表示的就是4种常见的BatchNorm,其中第一种比较常见。
在这里插入图片描述
Batch Norm: Batch Norm:对每一个批次(N个tensor)的每个通道分别计算均值mean和方差var,如[10,4,9] 最终输出是[0,1,2,3]这样的1*4的tensor
Layer Norm: 对于每一个tensor的所有channels进行均值和方差计算
Instance Norm: 对于每个tensor的每个channels分别计算
Group Norm: 引用了group的概念,比如BGR表示一个组----不常见
在这里插入图片描述

pytorch中的实现:

# -*- coding: UTF-8 -*-

import torch
import torch.nn as nn

x = torch.rand(100, 16, 784)
# 这里直接将28*28变为一维的784
layer = nn.BatchNorm1d(16)
# 一维直接使用.BatchNorm1d即可
# 因为Batch Norm的参数直接是由channel数量得来的,
# 因此这里直接给定了channel的数量为16,后续会输出16个channel的统计信息
out = layer(x)
# 进行前向计算
print(layer.running_mean)

"""
输出结果:
tensor([0.0501, 0.0500, 0.0501, 0.0500, 0.0499, 0.0501, 0.0501, 0.0500, 0.0498,
        0.0498, 0.0500, 0.0501, 0.0501, 0.0500, 0.0501, 0.0500])
"""

可以自行对上述结果进行验证,该结果的平均值恰好为0.5

1.37.7.Pipeline

Batch Normalization的规范化写法为:
在这里插入图片描述
首先第一步先统计了当前规范化的均值和方差。接下来进行Normalize的操作,即将x值减去均值再除以根号下方差的平方与一个很小的误差。最后再进行缩放,缩放成一个适宜的分布。

网友的解释,如下:
在这里插入图片描述
注意到这里的最后一步也称之为仿射(affine),引入这一步的目的主要是设计一个通道,使得输出output至少能够回到输入input的状态(当γ = 1 , β = 0时)使得BN的引入至少不至于降低模型的表现,这是深度网络设计的一个套路

整个过程见流程图,BN在输入后插入,BN的输出作为规范后的结果输入的后层网络中。
在这里插入图片描述
代码示例:

# -*- coding: UTF-8 -*-

import torch
import torch.nn as nn

x = torch.rand(1, 16, 28, 28)
# 这里是28 * 28的数据
layer = nn.BatchNorm2d(16)
# 二维直接使用.BatchNorm2d
# 因为Batch Norm的参数直接是由channel数量得来的,
# 因此这里直接给定了channel的数量为16,后续会输出16个channel的统计信息
out = layer(x)
# 进行前向计算
print(layer.running_mean)
"""
输出结果:
tensor([0.0503, 0.0499, 0.0493, 0.0490, 0.0477, 0.0502, 0.0476, 0.0498, 0.0504,
        0.0506, 0.0504, 0.0506, 0.0500, 0.0486, 0.0511, 0.0489])
"""

# 进行权值计算并输出
print(layer.weight)
"""
输出结果:
Parameter containing:
tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
       requires_grad=True)
"""

这里的weight即为σ值
这里还可以设置一些参数,如添加;training=True(表明当前的模式), affine=True(设置参数自动更新学习)。
Batch Norm同样需要手动给予参数

layer.eval()
# 调用不同的模式,以完成参数是否自动更新学习
nn.BatchNorm1d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

Batch Norm具有相当优异的使用效果,如下图所示:
在这里插入图片描述
使用了Batch Norm后,收敛速度加快、精度提高。上右图可看出尖峰的偏差对比左侧变小了很多。

再如案例:

# -*- coding: UTF-8 -*-

import torch
import torch.nn as nn

m = nn.BatchNorm2d(2, affine=True) #权重w和偏重将被使用
input = torch.randn(1, 2, 3, 4)
output = m(input)

print("输入图片:")
print(input)
"""
输出结果:
tensor([[[[-1.7310, -1.5597,  0.8319,  0.9386],
          [ 0.8572,  1.6315, -0.2010,  0.1398],
          [-0.2074,  0.4479, -0.1920, -1.4322]],
          
         [[ 1.1964, -0.4497, -0.0277, -0.2446],
          [-1.0605, -1.1224, -1.1656,  0.2643],
          [ 0.1333,  2.2977, -1.0742,  1.3960]]]])
"""

print("归一化权重:")
print(m.weight)
"""
输出结果:
tensor([1., 1.], requires_grad=True)
"""

print("归一化的偏重:")
print(m.bias)
"""
输出结果:
tensor([0., 0.], requires_grad=True)
"""

print("归一化的输出:")
print(output)
"""
输出结果:
tensor([[[[-1.6394, -1.4734,  0.8449,  0.9483],
          [ 0.8694,  1.6199, -0.1564,  0.1740],
          [-0.1625,  0.4726, -0.1476, -1.3498]],
          
         [[ 1.1003, -0.4288, -0.0368, -0.2383],
          [-0.9962, -1.0537, -1.0939,  0.2345],
          [ 0.1128,  2.1234, -1.0090,  1.2858]]]],
       grad_fn=<NativeBatchNormBackward>)
"""

print("输出的尺度:")
print(output.size())
"""
输出结果:
torch.Size([1, 2, 3, 4])
"""

# i = torch.randn(1,1,2)
print("输入的第一个维度:")
print(input[0][0])
"""
输出结果:
tensor([[-1.7310, -1.5597,  0.8319,  0.9386],
        [ 0.8572,  1.6315, -0.2010,  0.1398],
        [-0.2074,  0.4479, -0.1920, -1.4322]])
"""

firstDimenMean = torch.Tensor.mean(input[0][0])
firstDimenVar = torch.Tensor.var(input[0][0],False) #Bessel's Correction贝塞尔校正不会被使用

print(m.eps)
"""
输出结果:
1e-05
"""

print("输入的第一个维度平均值:")
print(firstDimenMean)
"""
输出结果:
tensor(-0.0397)
"""

print("输入的第一个维度方差:")
print(firstDimenVar)
"""
输出结果:
tensor(1.0643)
"""

bacthnormone = ((input[0][0][0][0] - firstDimenMean)/(torch.pow(firstDimenVar+m.eps,0.5))) * m.weight[0] + m.bias[0]
print(bacthnormone)
"""
输出结果:
tensor(-1.6394, grad_fn=<AddBackward0>)
"""
1.37.8.参考博文

https://blog.csdn.net/loseinvain/article/details/86476010
https://cloud.tencent.com/developer/article/1549349
https://www.pianshen.com/article/4348414318/
https://www.jianshu.com/p/6358d261ade8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涂作权的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值