【学习笔记】Pytorch深度学习—Batch Normalization

本节内容主要分为2大部分:(1)Batch Normalization概念;(2)Pytorch的Batch Normalization 1d/2d/3d 实现

Batch Normalization概念

Batch Normalization
Batch Normalization 定义:“ 批标准化 ”

1、批:指的是一批数据,通常为mini-batch:假设训练集有10万个样本,通常选择64、128、256这样的小批量数据;
2、标准化:指将数据特征的分布进行标准化,处理到“0均值、1方差”的分布;

Batch Normalization 优点

Batch Normalization批标准化定义简单,但却具有很大“能量”,其优点从论文《Batch Normalization:Accelerating Deep Network Training by Reducing Internal Covariate Shfit》(2015)如下,分别是“1用4不用”:

(1)可以用更大学习率,加速模型收敛
优化器(二)学习率 学习过,采用较大的学习率易导致梯度激增而使得模型无法训练,但采用的Batch Normalization以后可以采用较大学习率加速模型训练。

(2)可以不用精心设计权值初始化
权值初始化 一节学习过,不恰当的权值初始化明明采用梯度下降法但仍不能减小Loss,反而引发梯度激增或消失,出现nan现象,为解决问题设计出了Xavier和Kaiming方法对权值进行初始化。但有了BN层后,BN可以对数据尺度进行规范和约束,不用再精心设计权值初始化。

(3)可以不用dropout或较小的dropout
(4)可以不用L2或较小的weight decay
(5)可以不用LRN(Local response normalization)
LRN局部响应值的标准化,这一方法在AlexNet中有使用到,功能与Batch Normalization一样,对数据尺度进行规范。

Batch Normalization 算法分析

在这里插入图片描述

BN计算概念是:在mini_batch形式上减去均值,除以标准差,即得到1个0均值、1标准差的数据分布形式,完成数据的normalize;
但BN还具有1个Affine transform,Affine给BN层提供了可逆的操作,可以改变、或不改变batch的数据分布,至于到底改不改变就交给模型,具体则看 γ \gamma γ β \beta β 的学习结果。

Batch Normalization 优点分析

这样1个简单的操作是如何实现那么多的优点的?
在论文《Batch Normalization:Accelerating Deep Network Training by Reducing Internal Covariate Shfit》(2015),提出BN是为了解决Internal Covariate Shfit这一问题的。

Internal Covariate Shfit

ICS这一概念可以简单理解为“数据尺度、数据分布的变化”,在学习权值初始化时,我们分析过网络层数据方差的变化。

在全连接网络中,第一个网络层 H 1 H_{1} H1层中的神经元 H 11 H_{11} H11, D ( H 1 ) = n × D ( X ) × D ( W ) D(H_1)=n\times D(X)\times D(W) D(H1)=n×D(X)×D(W),方差是连乘形式;如果尺度上稍有减小趋势,随着网络的加深,减小趋势会越来越明显,从而导致梯度消失;抑或是尺度上有增大趋势,随着网络的加深,从而导致梯度爆炸,造成模型难以训练。所以BN的提出是为了解决ICS问题的,同时发现BN带来的一系列的好处(即上面提到的5大优点)。

在这里插入图片描述

实验一:bn层对于权值初始化不敏感

class MLP(nn.Module):
    def __init__(self, neural_num, layers=100):
        super(MLP, self).__init__()
        self.linears = nn.ModuleList([nn.Linear(neural_num, neural_num, bias=False) for i in range(layers)])
        self.bns = nn.ModuleList([nn.BatchNorm1d(neural_num) for i in range(layers)])
        self.neural_num = neural_num

    def forward(self, x):

        for (i, linear), bn in zip(enumerate(self.linears), self.bns):
            x = linear(x)
            x = bn(x) # (1)如果加入bn,数据尺度则控制在了0.5;或者(2)直接去掉权值初始化,只加入bn层,也能更好的控制数据尺度。
            x = torch.relu(x)

            if torch.isnan(x.std()):
                print("output is nan in {} layers".format(i))
                break

            print("layers:{}, std:{}".format(i, x.std().item()))

        return x

    def initialize(self):
        for m in self.modules():
            if isinstance(m, nn.Linear):

                # method 1,虽然设置了0均值、1方差,但仍属于不恰当的权值初始化,数据的尺度在100层达到了-40的数量级,明显出现了“梯度消失”的现象。
                # nn.init.normal_(m.weight.data, std=1)    # normal: mean=0, std=1

                # method 2 kaiming 是精心设计的权值初始化,数据的尺度从一开始0.8逐渐控制在了0.6,克服了梯度消失的问题
                nn.init.kaiming_normal_(m.weight.data)


neural_nums = 256
layer_nums = 100
batch_size = 16

net = MLP(neural_nums, layer_nums)
# net.initialize()

inputs = torch.randn((batch_size, neural_nums))  # normal: mean=0, std=1

output = net(inputs)
print(output)

方法一:设置权值尺度属于0均值、1标准差的范围,但输出数据尺度在第100层网络层达到-40次数量级,出现了梯度消失;
方法二:精心设计kaiming初始化方法,数据尺度得以控制;
方法三:针对在有无权值初始化基础上使用bn层,
(一)case1:在初始化基础上使用bn层;在forward当中,一定要在激活函数ReLu之前使用bn层,对输入的数据进行batch_normalization,数据的尺度保持的更好了,维持在0.5左右。
(二)case2:在无权值初始化基础上使用bn层;加了bn层后,都使得数据的尺度保持的更好了,在本例中维持在0.5左右浮动。
有了bn层,可以不用精心设计权值初始化,甚至不用权值初始化。

实验二:bn层在人民币二分类实验中的使用情况,对Lenet改进
人民币二分类实验中主体函数部分——模型发生了变化,使用的是加入了bn层的lenet模型。

# ============================ step 2/5 模型 ============================

net = LeNet_bn(classes=2)
# net = LeNet(classes=2)
# net.initialize_weights()

关于加入了bn层的lenet模型结构是:

    class LeNet_bn(nn.Module):
def __init__(self, classes):
    super(LeNet_bn, self).__init__()
    在输出特征时加入bn层,对特征数据的尺度进行规范化。
    self.conv1 = nn.Conv2d(3, 6, 5)
    在_init_中定义一系列的bn层,采用BatchNorm2d()形式,设置重要参数num_features(因为卷积层输出有几个特征,这里第1个卷积层有6个特征图)
    self.bn1 = nn.BatchNorm2d(num_features=6)
    self.conv2 = nn.Conv2d(6, 16, 5)
    self.bn2 = nn.BatchNorm2d(num_features=16)

    self.fc1 = nn.Linear(16 * 5 * 5, 120)
    这里采用BatchNorm1d()形式
    self.bn3 = nn.BatchNorm1d(num_features=120)

    self.fc2 = nn.Linear(120, 84)
    self.fc3 = nn.Linear(84, classes)


def forward(self, x):    #bn层在forward中的使用
    out = self.conv1(x)
    out = self.bn1(out)
    bn层一定要在激活函数relu前使用
    out = F.relu(out)

    out = F.max_pool2d(out, 2)

    out = self.conv2(out)
    out = self.bn2(out)
    out = F.relu(out)

    out = F.max_pool2d(out, 2)

    out = out.view(out.size(0), -1)

    out = self.fc1(out)
    out = self.bn3(out)
    out = F.relu(out)

    out = F.relu(self.fc2(out))
    out = self.fc3(out)
    return out

def initialize_weights(self):
    for m in self.modules():
        if isinstance(m, nn.Conv2d):
            nn.init.xavier_normal_(m.weight.data)
            if m.bias is not None:
                m.bias.data.zero_()
        elif isinstance(m, nn.BatchNorm2d):
            m.weight.data.fill_(1)
            m.bias.data.zero_()
        elif isinstance(m, nn.Linear):
            nn.init.normal_(m.weight.data, 0, 1)
            m.bias.data.zero_()

对比:
(1)使用原始的Lenet模型,不进行权值初始化,观察Loss曲线;
(2)使用权值初始化后的lenet模型:如果加上1个精心设计的权值初始化,观察Loss曲线;
(3)使用加入bn层后的lenet模型:采用加入了bn的lenet,观察Loss曲线;
在这里插入图片描述

Pytorch的Batch Normalization 1d/2d/3d 实现

一、Batch Normalization 1d/2d/3d 基本属性

Pytorch中提供了Batch Normalization的1d、2d、3d,在pytorch中所有batch normalization的实现都继承于_BatchNorm这一基类:

_BatchNorm
nn.BatchNorm1d
nn.BatchNorm2d
nn.BatchNrom3d
_init(self,num_features,eps=1e-5,momentum=0.1,
affine=True,track_running_stats=True)

主要参数

num_features:一个样本特征数量(最重要)

eps:分母修正项(通常会设置1个比较小的数字,10的-5次方,为了防止分
母为0而造成计算错误)

momentum:指数加权平均估计当前mean/var(通常设置为0.1)

affine:是否需要affine transform(布尔变量,控制是否需要进行Affine,默认为打开)

track_running_stats:是训练状态,还是测试状态(指示状态)
如果在训练状态,均值、方差需要重新估计;如果在测试状态,会采用当前
的统计信息,均值、方差固定的,但训练时这两个数据是会根据batch发生改
变。

主要属性

running_mean:均值
running_var:方差
weight:affine transform中的gamma
bias:affine transform中的beta

通过上面bn——“batch normalization算法分析”的运算过程就可以知道,运算过程中有4个主要参数,在pytorch中就对应下述名称:
在这里插入图片描述

-----------进行normalize标准化时-----------
running_mean:均值
running_var:方差
不仅考虑mini_batch均值和方差,还需考虑之前mini_batch数据的均值和方差
图片名称
------------进行affine transform-------------
weight:affine transform中的gamma
bias:affine transform中的beta
其中,weight和bias是由模型自主可学习的。
二、Batch Normalization 1d/2d/3d 对数据的要求
_BatchNorm
nn.BatchNorm1d input=B*特征数*1d特征
nn.BatchNorm2d input=B*特征数*2d特征
nn.BatchNrom3d input=B*特征数*3d特征

(1)Batch Normalization 1d形式

  batch_size = 3
  num_features = 5
  momentum = 0.3

  features_shape = (1)

在这里插入图片描述

(2)Batch Normalization 2d形式
通常,卷积神经网络输出的特征图就是2d形式。
在这里插入图片描述
2d形式:

   batch_size = 3
   num_features = 6
   momentum = 0.3
   
   features_shape = (2, 2)

3d形式

   batch_size = 3
   num_features = 4
   momentum = 0.3

   features_shape = (2, 2, 3)
三、Batch Normalization 1d/2d/3d 4个主要参数的计算

在这里插入图片描述

总结:
在bn中,有减均值、除标准差、乘以gamma、加beta这4个参数,该4个参数在特征这一维度,每1个特征维度都可以算的4个参数,计算均值、标准差时需要使用指数加权法,gamma、beta则不需要关心,可以自主学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

又青。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值