深度学习——批量归一化处理

1.为什么要进行归一化处理

1.对于我们输入而言,标准化输入是一项重要的步骤,例如预测房间时,我们让特征值方差为1,均值为0,可以使我们的参数量级做到统一

2.对于典型的多层感知机而言,有些层输出的范围可能与输入的范围存在过大的区别,导致我们的模型收敛速度过慢

3.越深的模型,越容易过拟合·,就越需要正则化

2.归一化操作

具体流程:在每次训练迭代中,我们首先规范化输入,即通过减去其均值并除以其标准差,其中两者均基于当前小批量处理。接下来,我们应用比例系数和比 例偏移。
简单来说就是先将数据每个批次对应的特征归一化到均值为0,方差为1的区间,然后乘以一个可学习的y和加上一个偏执b

特别的当批量大小为1时,我们学习不到任何东西,因为减去均值后,每个特征都为0 ,所以需要使用足够大的批量,批量规范化才是稳定的

我们的均值和方差是通过以下方法求出的

 对于多层感知机而言,均值和方差是对一个批次中相同特征求(64,32)->(1,32),而对于卷积而言,是对于通道数去求,就相当于(3,3,224,224)批量为3的数据,变为(1,3,1,1)求每个通道的均值

特:我们在方差上加入了一个小的噪音,可以有效解决计算时除以0的问题,并且加入噪音也有利于我们去正则化

批量规范化层在”训练模式“和“预测模式”中的功能不同。在训练过程中,我们无法得知使用整个数据集来估计平均值和方差,所以只能根据每个小批 次的平均值和方差不断训练模型。而在预测模式下,可以根据整个数据集精确计算批量规范化所需的平均值 和方差。

 从零实现

引入

import torch
from torch import nn
from d2l import torch as d2l

对于归一化块的实现

def batch_norm(X,gamma,beta,moving_mean,moving_var,eps,momentum):#eps防止除以0
    #通过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:
            #计算二维卷积层的情况
            mean=X.mean(dim=(0,2,3),keepdim=True)#对通道做做平均  相当于一个一个取平均0 2 3维
            var=((X-mean)**2).mean(dim=(0,2,3),keepdim=True)#触发广播机制
        #训练模式下,采用当前均值和方差做标准化
        X_hat=(X-mean)/torch.sqrt(var+eps)
        #更新移动的均值方差
        moving_mean=momentum*moving_mean+(1-momentum)*mean
        moving_var=momentum*moving_var+(1-momentum)*var
    Y=gamma*X_hat+beta#注意这里用的是点乘
    return Y,moving_mean.data,moving_var.data

 注意:我们在理想情况下希望的均值和方差是整个样本的,而不是批次,但在训练过程中我们是用批次的的均值和方差估算整体的,同时通过移动平均估算整个训练数据集的样 本均值和方差

所以在训练时用的是批次的均值和方差,而预测时用的是估算整个训练数据集的样 本均值和方差

归一化层的实现

class BatchNorm(nn.Module):
    def __init__(self,num_features,num_dims):
        super().__init__()
        if num_dims==2:
            shape=(1,num_features)
        else:
            shape=(1,num_features,1,1)
        #申请可学习的参数
        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):
            # 如果X不在内存上,将moving_mean和moving_var
            # 复制到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

num_features是特征的数量,num_dims是输入的维度,通过这两个去计算我们参数的形状

训练参数设置及训练

lr, num_epochs, batch_size = 1.0, 10, 256
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())
d2l.plt.show()
torch.save(net.state_dict(),"规范化")

结果

 批量归一化简介实现

其余的不变

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))

nn.batchnorm2d只接受特征数量,自动识别维度

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值