7.5 详解批量规范化 对某个维度取平均值代码解读

news2024/11/23 11:25:36

一.举例计算均值、方差

假设我们有以下一组数据:[10, 15, 20, 25, 30]

首先,我们计算均值,即将所有数据相加后除以数据的数量:
均值 = (10 + 15 + 20 + 25 + 30) / 5 = 100 / 5 = 20

1.1标准差

接下来,我们计算标准差,用来衡量数据的离散程度。标准差的计算公式如下:
标准差 = sqrt( ( (x1 - 平均值)^2 + (x2 - 平均值)^2 + … + (xn - 平均值)^2 ) / n )

标准差 = sqrt( ( (10 - 20)^2 + (15 - 20)^2 + (20 - 20)^2 + (25 - 20)^2 + (30 - 20)^2 ) / 5 )
= sqrt( (100 + 25 + 0 + 25 + 100) / 5 )
= sqrt( 250 / 5 )
= sqrt( 50 )
≈ 7.071

二.对例子中的数据标准化

现在,让我们对数据进行标准化。标准化是将数据转换为均值为0,标准差为1的标准正态分布。
对于每个数据点,我们可以使用以下公式进行标准化:

2.1公式

标准化数据 = (原始数据 - 均值) / 标准差

对于我们的数据集,标准化后的结果如下:
(10 - 20) / 7.071 ≈ -1.414
(15 - 20) / 7.071 ≈ -0.707
(20 - 20) / 7.071 = 0
(25 - 20) / 7.071 ≈ 0.707
(30 - 20) / 7.071 ≈ 1.414

因此,经过标准化后的数据集为:[-1.414, -0.707, 0, 0.707, 1.414]

2.2 标准化后的数据特点

均值为0,方差为1

2.3 将数据标准化有什么好处?

  1. 消除数据相差太大的影响:标准化后的数据具有相同的量纲,消除了原始数据中不同变量之间因量纲不同而引起的影响,确保各个变量对分析结果的贡献相对均等。

  2. 提高模型性能:在许多机器学习算法中,输入数据的标准化可以提高模型的训练效果和预测准确性。标准化后的数据分布更接近于标准正态分布,可以降低模型对异常值的敏感性,使模型更加稳定和可靠。

  3. 加速优化过程:某些优化算法(如梯度下降法)在处理标准化后的数据时更加高效。标准化可以使优化算法收敛更快,并且更容易找到全局最优解或更接近最优解的解。

  4. 减少计算开销:标准化后的数据具有较小的数值范围,可以减少计算时的数据溢出或欠溢问题,提高计算的稳定性和准确性。

2.4 为什么数据可以标准化?可视化标准化效果

** BatchNorm(归一化/标准化)**

归一化/标准化实质是一种线性变换,线性变换有很多良好的性质,这些性质决定了对数据改变后不会造成“失效”,反而能提高数据的表现,这些性质是归一化/标准化的前提。比如有一个很重要的性质:线性变换不会改变原始数据的数值排序。

标准化前:
在这里插入图片描述
标准化后:
在这里插入图片描述
看到变化了吗,虽然各个点的相对位置看上去还是没变,但是坐标轴变了。均值是0,标准差为1。

参考文献:
数据预处理:标准化和归一化
https://zhuanlan.zhihu.com/p/63911364

三. 在模型中对小批次数据进行批量标准化

3.1 批量标准化公式

在这里插入图片描述

3.2 在模型的什么地方应用批量标准化?

  1. 在全连接层的激活函数之前
    在这里插入图片描述

  2. 卷积层之后的非线性的激活函数之前

  3. 预测过程中的批量标准化
    我们需要对逐个样本预测,我们需要移动估算整个训练数据集的样
    本均值和⽅差。

四.代码

import torch
from torch import nn
from d2l import torch as d2l
import time
# eps是上面公式由于标准差在分母的位置,所以加入一个常量eps,防止分母为0
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:
            # 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持X的形状以便后面可以做广播运算
            mean = X.mean(axis=(0, 2, 3), keepdims=True)
            var = ((X - mean) ** 2).mean(axis=(0, 2, 3), keepdims=True)
        # 训练模式下用当前的均值和方差做标准化
        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
class BatchNorm(nn.Module):
# num_features:完全连接层的输出数量或卷积层的输出通道数。
# num_dims:2表示完全连接层,4表示卷积层
    def __init__(self, num_features, num_dims):
        super().__init__()
        if num_dims == 2:
            shape = (1, num_features)
        else:
            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):
        # 如果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)
        # 保存更新过的moving_mean和moving_var
        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

sigmoid激活函数版本模型

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

库中的训练函数 train_ch6 没有取最优的准确率,自己实现一个

def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    """Train a model with a GPU (defined in Chapter 6).

    Defined in :numref:`sec_lenet`"""
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
            nn.init.xavier_uniform_(m.weight)
    net.apply(init_weights)
    print('training on', device)
    net.to(device)
    optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    loss = nn.CrossEntropyLoss()
    animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
                            legend=['train loss', 'train acc', 'test acc'])
    timer, num_batches = d2l.Timer(), len(train_iter)
    best_test_acc = 0
    for epoch in range(num_epochs):
        # Sum of training loss, sum of training accuracy, no. of examples
        metric = d2l.Accumulator(3)
        net.train()
        for i, (X, y) in enumerate(train_iter):
            timer.start()
            optimizer.zero_grad()
            X, y = X.to(device), y.to(device)
            y_hat = net(X)
            l = loss(y_hat, y)
            l.backward()
            optimizer.step()
            with torch.no_grad():
                metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
            timer.stop()
            train_l = metric[0] / metric[2]
            train_acc = metric[1] / metric[2]
            if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
                animator.add(epoch + (i + 1) / num_batches,
                             (train_l, train_acc, None))
        test_acc = d2l.evaluate_accuracy_gpu(net, test_iter)
        if test_acc>best_test_acc:
            best_test_acc = test_acc
        animator.add(epoch + 1, (None, None, test_acc))
    print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
          f'test acc {test_acc:.3f}, best test acc {best_test_acc:.3f}')
    # 取的好像是平均准备率
    print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
          f'on {str(device)}')

开始训练

'''开始计时'''
start_time = time.time()

# 配置参数
lr, num_epochs, batch_size = 1.0, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

'''计时结束'''
end_time = time.time()
run_time = end_time - start_time
# 将输出的秒数保留两位小数
if int(run_time)<60:
    print(f'{round(run_time,2)}s')
else:
    print(f'{round(run_time/60,2)}minutes')

sigmoid激活函数版本结果

在这里插入图片描述

将sigmoid换成relu的版本结果

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

在这里插入图片描述

将sigmoid激活函数换成relu和把平均池化AvgPool2d换成最大值池化MaxPool2d版本结果

# 换成Relu()+最大值池化
net = nn.Sequential(
    nn.Conv2d(1, 6, kernel_size=5), BatchNorm(6, num_dims=4), nn.ReLU(),
    nn.MaxPool2d(kernel_size=2, stride=2),
    nn.Conv2d(6, 16, kernel_size=5), BatchNorm(16, num_dims=4), nn.ReLU(),
    nn.MaxPool2d(kernel_size=2, stride=2), nn.Flatten(),
    nn.Linear(16*4*4, 120), BatchNorm(120, num_dims=2), nn.ReLU(),
    nn.Linear(120, 84), BatchNorm(84, num_dims=2), nn.Sigmoid(),
    nn.Linear(84, 10)

)在这里插入图片描述

五.补充

5.1 方差和标准差公式

在这里插入图片描述

5.2 对某个维度取平均值

X.mean(dim=0),表示对每个列取平均值,保留行

import torch
# X = torch.rand(size=(2,2))
X = torch.tensor([[1.0, 1.0],
                  [-1.0, -1.0]])
mean = X.mean(dim=0)
mean,mean.shape

输出结果:

(tensor([0., 0.]), torch.Size([2]))

X.mean(dim=1),表示对每个行取平均值,保留列

mean = X.mean(dim=1)
mean,mean.shape
(tensor([ 1., -1.]), torch.Size([2]))

X.mean(dim=(0,2,3),keepdim=True),表示对维度0(样本),维度2(行数),维度3(列数)求平均。保留维度1(通道)
keepdim=True,表示保留维度

X = torch.tensor([[[[1.0, 2.0],
                  [0.0, 4.0]]]])
X.shape
# 按通道数求均值就是 把二维矩阵求和/矩阵大小。 如上方 1+2+0+4=7,7/4=1.75
mean = X.mean(dim=(0,2,3),keepdim=True)
mean,mean.shape
(tensor([[[[1.7500]]]]), torch.Size([1, 1, 1, 1]))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/856586.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

_declspec(naked) 初试(裸函数)

最近在写驱动时候初次使用裸函数&#xff0c;做一些记录 _declspec(naked)修饰可以生成一个“裸”函数&#xff0c; 使用后C编译器将生成不含函数框架的纯汇编代码&#xff0c;裸函数中什么都没有&#xff0c;所以也不能使用局部变量&#xff0c;只能全部用内嵌汇编实现。 可…

使用Presto、Trino数据库时提示“The datetime zone id ‘GMT+08:00‘ is not recognised”

出现这个问题的原因是&#xff1a;Presto、Trino的驱动使用了joda这个库来处理时区的问题。但这个库的编写人似乎对java zone的格式没有太多经验。先看一下出错的代码&#xff1a; com.facebook.presto.jdbc.internal.joda.time.DateTimeZone#forID 根据String类型的zoneId转成…

java日期常用操作

Testpublic void validateDateUtils(){// 1 字符串转换日期Date result DateUtil.parse("2023-08-01", com.alibaba.excel.util.DateUtils.DATE_FORMAT_10);log.info("result : [{}]" , result);// 2 日期转换字符串final Date date new Date();String f…

网络防御之SSL VPN

1. SSL工作过程是什么&#xff1f; 第一阶段&#xff1a; 客户端发送client hello消息到服务端&#xff0c;服务端收到client hello消息后&#xff0c;再发送server hello消息到客户端。 第二阶段&#xff1a; 服务器的证书&#xff0c;用于客户端给客户端发送信息时加密 serv…

韩顺平Linux基础篇

一、课程内容 二、Linux应用领域 一、Linux使用在哪些地方 Linux最强应用&#xff1a;服务器 三、Linux概述 三、Linux和Unix的关系 五、VM和Linux的安装 基本说明 学习Linux需要一个环境&#xff0c;我们需要创建一个虚拟机&#xff0c;然后再虚拟机上安装一个Centos系统来学…

将 Kwargs 传递给 Python 中的另一个函数

文章目录 Python 中的关键字参数在 Python 中使用**kwargs 调用函数使用 Python 将 kwargs 传递给另一个函数总结 Python 列出了可以传递给程序中的函数的两种类型的参数。 非关键字参数 (**args) 和关键字参数 (**kwargs)。 通常&#xff0c;python 函数必须使用正确数量的参…

春秋云镜 CVE-2022-24124

春秋云镜 CVE-2022-24124 Casdoor api 获取组织 SQL注入 靶标介绍 Casdoor是开源的一个身份和访问管理&#xff08;IAM&#xff09;/单点登录&#xff08;SSO&#xff09;平台&#xff0c;标记支持OAuth 2.0 / OIDC和SAML身份验证的Web UI。 Casdoor 1.13.1之前存在安全漏洞&…

Unity导入图片时,通过设置属性快速实现资源的压缩

是在学习tilemap绘制世界地图的时候发现的这个功能。 之前一直只是粗略的知道这部分是对应图片资源的压缩的。比如Compression是指的压缩质量&#xff0c;想要完全不压缩就设置None&#xff0c;会导致图片资源会大一些。 在我的例子工程中&#xff0c;其他图片资源的尺寸都是6…

服务器数据恢复-RAID5上层Hyper-V虚拟机数据恢复案例

服务器数据恢复环境&#xff1a; 一台Windows Server服务器&#xff0c;部署Hyper-V虚拟化环境&#xff0c;虚拟机的硬盘文件和配置文件存放在一台DELL存储中。该存储中有一组由4块硬盘组建的RAID5阵列&#xff0c;用来存放虚拟机的数据文件&#xff0c;另外还有一块大容量硬盘…

Centos7.6 安装mysql过程全记录

在centos 7.6上 离线安装mysql 的步骤&#xff0c;可参考下文&#xff1a; 一、查看当前MySQL的安装情况并卸载 1. 查看当前MySQL的安装情况 查找之前是否安装了MySQL rpm -qa|grep -i mysql 2.卸载mysql 如果已经安装mysql&#xff0c;则需要先停止MySQL&#xff0c;再删除…

基于springboot+vue的幼儿园管理系统的设计与实现_5umt6

随着世界经济信息化、全球网络化的到来推动信息线上管理的飞速发展&#xff0c;为幼儿园行业的改革起到关键作用。若想达到安全&#xff0c;快捷的目的&#xff0c;就需要拥有信息化的组织和管理模式&#xff0c;建立一套合理、畅通、高效的幼儿园管理系统。当前的幼儿园管理系…

【JAVA】继承

作者主页&#xff1a;paper jie的博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JAVASE语法系列》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精…

vue3官网文档学习、复习笔记(快速上手)

目录 2.Attribute 绑定&#xff08;v-bind&#xff09; 3.事件监听&#xff08;v-on&#xff09; 4.表单绑定&#xff08;v-model&#xff09; 5.条件渲染&#xff08;v-if&#xff09; 6.列表渲染&#xff08;v-for&#xff09; all.value all.value.filter&#xff08;…

[C++]类与对象(下) -- 初始化列表 -- static成员 -- 友元 -- 内部类,一篇带你深度了解。

目录 1、再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.2.1 初始化列表的意义 1.3 explicit关键字 2、static成员 2.1 问题引入 2.2 特性 3、友元 3.1 友元函数 3.2 友元类 4、内部类 1、再谈构造函数 1.1 构造函数体赋值 在创建对象时&#xff0c;编译器通…

改进的麻雀算法优化最大相关峭度解卷积(SCSSA-MCKD),实现早期微弱故障诊断,MATLAB代码实现

01 引言 由于一些设备的早期故障产生的冲击十分微弱&#xff0c;易被系统噪声干扰&#xff0c;如何有效地对设备的原始故障信号进行降噪并增强信号中微弱冲击成分&#xff0c;是进行该类部件早期故障诊断的关键。 最大相关峭度解卷积&#xff08;MCKD&#xff09;通过解卷积运算…

干翻Dubbo系列第九篇:Dubbo体系中序列化详解

文章目录 文章说明 一&#xff1a;序列化概念 1&#xff1a;概念 2&#xff1a;Dubbo中序列化方式 二&#xff1a;Kyro序列化方案 1&#xff1a;引入依赖 2&#xff1a;XML的配置方式 3&#xff1a;Boot的方式 4&#xff1a;Consumer端调用 三&#xff1a;FST序列化方…

JVM 调优实例

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ JVM提供了多种垃圾回收器&#xff0c;可以根据应用程序的需求选择最适合的垃圾回收器。例如&#xff0c;如果应用程序需要更快的响应时间&#xff0c;可以选择并行垃圾回收…

GIS在地质灾害危险性评估与灾后重建中的应用教程

详情点击链接&#xff1a;GIS在地质灾害危险性评估与灾后重建中的实践技术应用 前言 地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质…

【JavaSE】接口的语法知识和使用方法总结

目录 1. 接口的概念 2. 语法规则 3. 接口特性 4. 接口使用 5. 实现多个接口 6. 接口间的继承 1. 接口的概念 在现实生活中&#xff0c;接口的例子比比皆是&#xff0c;比如&#xff1a;笔记本上的USB口&#xff0c;电源插座等。 电脑的USB口上&#xff0c;可以插&#x…

Unity游戏源码分享-仿开心消消乐Match3Jewel

Unity游戏源码分享-仿开心消消乐Match3Jewel 工程地址&#xff1a; https://download.csdn.net/download/Highning0007/88198762