批量规范化+代码+Q&A

1.批量归一化

在作者的论文中,还解释了其原理:通过减少内部协变量偏移(internal covariate shift)。 据推测,作者所说的“内部协变量转移”类似于上述的投机直觉,即变量值的分布在训练过程中会发生变化。 然而,这种解释有两个问题: 1、这种偏移与严格定义的协变量偏移(covariate shift)非常不同,所以这个名字用词不当。 2、这种解释只提供了一种不明确的直觉,但留下了一个有待后续挖掘的问题:为什么这项技术如此有效?

但事实上我们不需要纠结这么多,因为学术界现在没有得出到底他为什么这么有效。事实上我们现在普遍认为是一个正则项。让中间输出的值变得稳定。

需要记住的是BN再全连接和卷积使用方式不同。

批量规范化层和暂退层一样,在训练模式和预测模式下计算不同。

批量规范化有许多有益的副作用,主要是正则化。另一方面,”减少内部协变量偏移“的原始动机似乎不是一个有效的解释。

2.代码部分

import torch
from torch import nn
from d2l import torch as d2l
# 输入,两个学习的参数,moving_mean全局的均值,moving_var全局的方差,在推理的时候用
#也就是所有批次的方差和均值、eps为了避免除0的东西,momentum更新全局的方差和均值的
def batch_norm(X, gamma, beta, moving_mean, moving_var, eps, momentum):
    #is_grad_enabled判断当前是训练还是预测模式
    if not torch.is_grad_enabled():
        #如果是预测模式 ,直接传入平均的均值和方差
        X_hat = (X-moving_mean) / torch.sqrt(moving_var + eps)
    else:#这里就是要么是全连接层 要么是卷积层
        assert len(X.shape) in (2, 4)
        if len(X.shape) == 2 :
            #按行求均值
            mean = X.mean(dim=0)
            var = ((X - mean)**2).mean(dim=0)
        else:
            #2d卷积的情况  0是批量大小,1是通道数,2,3,是高和宽
            #1*n*1*1的
            mean = X.mean(dim=(0, 2, 3), keepdim=True)
            var = ((X - mean)**2).mean(dim=(0 , 2, 3), keepdim=True)
        #训练中的小批量的mean和var
        X_hat = (X - mean) / torch.sqrt(var + eps)
        #全局的更新
        moving_mean = momentum * moving_mean + (1.0 - momentum) * mean
        moving_var = momentum * moving_var + (1.0 - momentum) * var
    Y = gamma * X_hat + beta
    return Y,moving_mean.data, moving_var.data      

#创建一个batchNorm的层 
#层中需要的是你的输入的数。和你是什么层 2?4? 全连接或卷积
class BatchNorm(nn.Module):
    # num_features:完全连接层的输出数量或卷积层的输出通道数。
    # num_dims:2表示完全连接层,4表示卷积层
    def __init__(self, num_features, num_dims):
        super().__init__()
        if num_dims == 2:
            #1*n的
            shape = (1, num_features)
        else:
            #1*n*1*1的
            shape = (1, num_features, 1, 1)
         # 参与求梯度和迭代的拉伸和偏移参数,分别初始化成1和0
        self.gamma = nn.Parameter(torch.ones(shape))
        self.beta = nn.Parameter(torch.zeros(shape))
        # 非模型参数的变量初始化为0和1
        self.moving_mean = torch.zeros(shape)
        self.moving_var = torch.ones(shape)
        
    def forward(self, X):
        if self.moving_mean.device != X.device:
            self.moving_mean = self.moving_mean.to(X.device)
            self.moving_var = self.moving_var.to(X.device)
        Y, self.moving_mean, self.moving_var = batch_norm(
        X, self.gamma, self.beta, self.moving_mean, self.moving_var,
        eps=1e-5, momentum=0.9)
        return Y

net = nn.Sequential(
    nn.Conv2d(1, 6, kernel_size=5), BatchNorm(6, num_dims=4), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Conv2d(6, 16, kernel_size=5), BatchNorm(16, num_dims=4), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),
    nn.Linear(16*4*4, 120), BatchNorm(120, num_dims=2), nn.Sigmoid(),
    nn.Linear(120, 84), BatchNorm(84, num_dims=2), nn.Sigmoid(),
    nn.Linear(84, 10))

lr, num_epochs, batch_size = 1.0, 10, 1
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

简明实现: 

#我们可以使用深度学习框架中定义的BN
net = nn.Sequential(
    nn.Conv2d(1, 6, kernel_size=5), nn.BatchNorm2d(6), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Conv2d(6, 16, kernel_size=5), nn.BatchNorm2d(16), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),
    nn.Linear(256, 120), nn.BatchNorm1d(120), nn.Sigmoid(),
    nn.Linear(120, 84), nn.BatchNorm1d(84), nn.Sigmoid(),
    nn.Linear(84, 10))


d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

3.练习

  1. 在使用批量规范化之前,我们是否可以从全连接层或卷积层中删除偏置参数?为什么?
    可以,因为不改变方差和均值。

  2. 比较LeNet在使用和不使用批量规范化情况下的学习率。
    自己动手与试验一下

    1. 绘制训练和测试准确度的提高。

    2. 你的学习率有多高?

       用1.3好一点

       

  3. 我们是否需要在每个层中进行批量规范化?尝试一下?
    全连接没必要

  4. 你可以通过批量规范化来替换暂退法吗?行为会如何改变?
    都相当于正则化 应该是可以的。但是深度的神经网络,BN效果应该好一点

  5. 确定参数betagamma,并观察和分析结果。

  6. 查看高级API中有关BatchNorm的在线文档,以查看其他批量规范化的应用。

  7. 研究思路:想想你可以应用的其他“规范化”转换?你可以应用概率积分变换吗?全秩协方差估计可以么?

4.Q&A

有一个评论很有意思

       1.请注意,如果我们尝试使用大小为 1 的小批量应用批量归一化,我们将无法学到任何东西。 这是因为在减去均值之后,每个隐藏单元将为 0。 所以,只有使用足够大的小批量,批量归一化这种方法才是有效且稳定的。 请注意,在应用批量归一化时,批量大小的选择可能比没有批量归一化时更重要”,请问怎么理解呢?这里的批量请问是网络训练的batch吗?

 

 指batch_size,notebook上设置为256。如果batch_size为1,那么这个小批量的均值就是这个样本值本身,则样本值减去均值就为0了,也即文中所说的”每个隐藏单元将为 0“,所以batch_size要足够大,但也不要太大

 1.BN到底干嘛?

防止极端数据出现,在整个模型中,强行的让你保持到几乎一样的层次。对深度的网络比较好哦,

2.为什么加了BN后,收敛时间变短了?

BN本身会让梯度变大一点,每个层的梯度都差不多,这样就可以使用更大的Lr。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值