栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【李沐深度学习】59.BN层实线 代码示例

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【李沐深度学习】59.BN层实线 代码示例

具体有关Batch Normlization的解释 可阅读blog

代码示例
import torch
from torch import nn

'''
bn操作训练和推理时用的均值方差是不同的:
    - 训练时,是当前小批量中图片的均值方差,不同批次是不一样的;
    - 推理时,是全局样本的均值方差,固定的;
     
gamma, beta : bn层可学习的参数;
moving_mean, moving_var : 推理时用到的 全局均值和方差;
eps: 方差必须要加的极小值,防止归一化时除以的分母为0 导致出错;
momentum : 更新moving_mean,moving_var的参数,通常取0.9或其他固定值;
'''
def batch_norm(x, gamma, beta, moving_mean, moving_var, eps, momentum):
    if not torch.is_grad_enabled(): # 若是推理时(梯度记录未开启)
        x_hat = (x - moving_mean) / torch.sqrt(moving_var + eps)
    else: # 训练时
        assert len(x.shape) in (2, 4) # 输入特征图x的shape 为2,则是全连接层输出; 为4,则是2D卷积层输出;
        if len(x.shape) == 2:
            mean = x.mean(dim=0) # n*c dim=0 指 按行压缩,保留列---> 1*c; shape(5,3)--->(1,3)
            var = ((x - mean)**2).mean(dim=0)
        else:
            mean = x.mean(dim=(0,2,3), keepdim=True) # nchw,保留通道数,其他都算均值---> 因为keepdim所以还是4维 1*c*1*1
            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.0 - momentum) * mean
        moving_var = momentum * moving_mean + (1.0 - momentum) * var

    y = gamma * x_hat + beta
    return y, moving_mean.data, moving_var.data # 如果moving_mean/var是tensor的话,返回.data即可。梯度diff没用

# ------定义一个bn层------
class BatchNorm(nn.Module):
    def __init__(self, num_features, num_dims):
        super().__init__()
        if num_dims == 2: # 根据输入特征图形状,确定参数的形状
            shape = (1, num_dims)
        else:
            shape = (1, num_dims, 1, 1)
        self.gamma = nn.Parameter(torch.ones(shape)) # 注意是可学习参数,用nn.Parameter()包着
        self.beta = nn.Parameter(torch.zeros(shape))
        self.moving_mean = torch.zeros(shape)
        self.moving_var = torch.ones(shape)

    def forward(self, x):
        # 因为nn.Parameter()管理的可学习参数,在训练时xx.to(device)会自动转移到device对应的设备上,如GPU。此处moving_mean/var要自己管理
        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),
    nn.BatchNorm2d(6), # 上层输出的通道数
    nn.ReLU(),
    nn.MaxPool2d(kernel_size=2, stride=2),

    nn.Conv2d(6, 16, kernel_size=5),
    nn.BatchNorm2d(16),
    nn.LeakyReLU(),
    nn.MaxPool2d(kernel_size=2, stride=2),

    nn.Flatten(),
    nn.Linear(256, 120)
    nn.BatchNorm2d(120),

    nn.ReLU()
    nn.Linear(120, 10)
)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1012048.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号