手撕/手写/自己实现 BN层/batch norm/BatchNormalization python torch pytorch

2023-10-29

计算过程

在卷积神经网络中,BN 层输入的特征图维度是 (N,C,H,W), 输出的特征图维度也是 (N,C,H,W)
N 代表 batch size
C 代表 通道数
H 代表 特征图的高
W 代表 特征图的宽

我们需要在通道维度上做 batch normalization,
在一个 batch 中,
使用 所有特征图 相同位置上的 channel 的 所有元素,计算 均值和方差,
然后用计算出来的 均值和 方差,更新对应特征图上的 channel , 生成新的特征图

如下图所示:
对于4个橘色的特征图,计算所有元素的均值和方差,然后在用于更新4个特征图中的元素(原来元素减去均值,除以方差)
![[attachments/BN示意图.png]]

代码

def my_batch_norm_2d_detail(features, eps=1e-5):
    '''
        这个函数的写法是为了帮助理解 BatchNormalization 具体运算过程
        实际使用时这样写会比较慢
    '''
    
    n,c,h,w = features.shape
    features_copy = features.clone()
    running_var = torch.randn(c)
    running_mean = torch.randn(c)
    for ci in range(c):# 分别 处理每一个通道
        mean = 0 # 均值
        var = 0 # 方差
        
        _sum = 0 
        # 对一个 batch 中,特征图相同位置 channel 的每一个元素求和
        for ni in range(n):            
            for hi in range(h):
                for wi in range(w):
                    _sum += features[ni,ci, hi, wi]
        mean = _sum / (n * h * w) 
        running_mean[ci] = mean
        

        _sum = 0
        # 对一个 batch 中,特征图相同位置 channel 的每一个元素求平方和,用于计算方差 
        for ni in range(n):            
            for hi in range(h):
                for wi in range(w):
                    _sum += (features[ni,ci, hi, wi] - mean) ** 2
        var = _sum / (n * h * w )
        running_var[ci] = _sum / (n * h * w - 1)

        # 更新元素
        for ni in range(n):            
            for hi in range(h):
                for wi in range(w):
                    features_copy[ni,ci, hi, wi] = (features_copy[ni,ci, hi, wi] - mean) / torch.sqrt(var + eps) 
        
    return features_copy, running_mean, running_var

if __name__ == "__main__":


    torch.set_printoptions(precision=7)

    torch_bn = nn.BatchNorm2d(4)  # 设置 channel 数
    torch_bn.momentum = None
    features = torch.randn(4, 4, 2, 2) # (N,C,H,W)
        
    torch_bn_output = torch_bn(features)    
    my_bn_output, running_mean, running_var = my_batch_norm_2d_detail(features)        
            
    print(torch.allclose(torch_bn_output, my_bn_output))
    print(torch.allclose(torch_bn.running_mean, running_mean))
    print(torch.allclose(torch_bn.running_var, running_var))

注意事项

方差计算

需要注意的是,在训练的过程中,方差有两种不同的计算方式,

在训练时,用于更新特征图的是 有偏方差
而 running_var 的计算,使用的是 无偏方差
在这里插入图片描述

相关链接

官方人员手写BN

"""
Comparison of manual BatchNorm2d layer implementation in Python and
nn.BatchNorm2d

@author: ptrblck
"""

import torch
import torch.nn as nn


def compare_bn(bn1, bn2):
    err = False
    if not torch.allclose(bn1.running_mean, bn2.running_mean):
        print('Diff in running_mean: {} vs {}'.format(
            bn1.running_mean, bn2.running_mean))
        err = True

    if not torch.allclose(bn1.running_var, bn2.running_var):
        print('Diff in running_var: {} vs {}'.format(
            bn1.running_var, bn2.running_var))
        err = True

    if bn1.affine and bn2.affine:
        if not torch.allclose(bn1.weight, bn2.weight):
            print('Diff in weight: {} vs {}'.format(
                bn1.weight, bn2.weight))
            err = True

        if not torch.allclose(bn1.bias, bn2.bias):
            print('Diff in bias: {} vs {}'.format(
                bn1.bias, bn2.bias))
            err = True

    if not err:
        print('All parameters are equal!')


class MyBatchNorm2d(nn.BatchNorm2d):
    def __init__(self, num_features, eps=1e-5, momentum=0.1,
                 affine=True, track_running_stats=True):
        super(MyBatchNorm2d, self).__init__(
            num_features, eps, momentum, affine, track_running_stats)

    def forward(self, input):
        self._check_input_dim(input)

        exponential_average_factor = 0.0

        if self.training and self.track_running_stats:
            if self.num_batches_tracked is not None:
                self.num_batches_tracked += 1
                if self.momentum is None:  # use cumulative moving average
                    exponential_average_factor = 1.0 / float(self.num_batches_tracked)
                else:  # use exponential moving average
                    exponential_average_factor = self.momentum

        # calculate running estimates
        if self.training:
            mean = input.mean([0, 2, 3])
            # use biased var in train
            var = input.var([0, 2, 3], unbiased=False)
            n = input.numel() / input.size(1)
            with torch.no_grad():
                self.running_mean = exponential_average_factor * mean\
                    + (1 - exponential_average_factor) * self.running_mean
                # update running_var with unbiased var
                self.running_var = exponential_average_factor * var * n / (n - 1)\
                    + (1 - exponential_average_factor) * self.running_var
        else:
            mean = self.running_mean
            var = self.running_var

        input = (input - mean[None, :, None, None]) / (torch.sqrt(var[None, :, None, None] + self.eps))
        if self.affine:
            input = input * self.weight[None, :, None, None] + self.bias[None, :, None, None]

        return input


# Init BatchNorm layers
my_bn = MyBatchNorm2d(3, affine=True)
bn = nn.BatchNorm2d(3, affine=True)

compare_bn(my_bn, bn)  # weight and bias should be different
# Load weight and bias
my_bn.load_state_dict(bn.state_dict())
compare_bn(my_bn, bn)

# Run train
for _ in range(10):
    scale = torch.randint(1, 10, (1,)).float()
    bias = torch.randint(-10, 10, (1,)).float()
    x = torch.randn(10, 3, 100, 100) * scale + bias
    out1 = my_bn(x)
    out2 = bn(x)
    compare_bn(my_bn, bn)

    torch.allclose(out1, out2)
    print('Max diff: ', (out1 - out2).abs().max())

# Run eval
my_bn.eval()
bn.eval()
for _ in range(10):
    scale = torch.randint(1, 10, (1,)).float()
    bias = torch.randint(-10, 10, (1,)).float()
    x = torch.randn(10, 3, 100, 100) * scale + bias
    out1 = my_bn(x)
    out2 = bn(x)
    compare_bn(my_bn, bn)

    torch.allclose(out1, out2)
    print('Max diff: ', (out1 - out2).abs().max())
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手撕/手写/自己实现 BN层/batch norm/BatchNormalization python torch pytorch 的相关文章

  • 在 Django 中定义视图和 url。为什么调用函数时不使用括号?

    我已经在经历 Python速成课程 目前正在进行 Django Web应用程序项目 学习日志 阶段 有些东西与我已经学到的相矛盾 views py file from django shortcuts import render def i
  • Python 中的六边形自组织映射

    我在寻找六边形 自组织映射 http en wikipedia org wiki Self organizing map在Python上 准备好模块 如果存在的话 绘制六边形单元格的方法 将六边形单元作为数组或其他方式使用的算法 About
  • 使用 Django 的 post_save() 信号

    我有两张桌子 class Advertisement models Model created at models DateTimeField auto now add True author email models EmailField
  • Dask DataFrame 的逐行处理

    我需要处理一个大文件并更改一些值 我想做这样的事情 for index row in dataFrame iterrows foo doSomeStuffWith row lol doOtherStuffWith row dataFrame
  • 类属性在功能上依赖于其他类属性

    我正在尝试使用静态类属性来定义另一个静态类属性 我认为可以通过以下代码来实现 f lambda s s 1 class A foo foo bar f A foo 然而 这导致NameError name A is not defined
  • 如何自动替换多个文件的文本内容中的字符?

    我有一个文件夹 myfolder包含许多乳胶表 我需要替换其中每个字符 即替换任何minus sign by an en dash 只是为了确定 我们正在替换连字符INSIDE该文件夹中的所有 tex 文件 我不关心 tex 文件名 手动执
  • 使用正则表达式解析 Snort 警报文件

    我正在尝试使用 Python 中的正则表达式从 snort 警报文件中解析出源 目标 IP 和端口 和时间戳 示例如下 03 09 14 10 43 323717 1 2008015 9 ET MALWARE User Agent Win9
  • 将 subprocess.Popen 的输出通过管道传输到文件

    我需要启动一些长时间运行的进程subprocess Popen 并希望拥有stdout and stderr从每个自动管道到单独的日志文件 每个进程将同时运行几分钟 我想要两个日志文件 stdout and stderr 每个进程当进程运行
  • 如何在 Windows 上使用 Python 3.6 来安装 Python 2.7

    我想问一下如何使用pip install对于 Python 2 7 当我之前安装并使用 Python 3 6 时 我现在必须使用 Windows 上的 Python 版本 pip install 继续安装 Python 3 6 我需要使用以
  • Python:随时接受用户输入

    我正在创建一个可以做很多事情的单元 其中之一是计算机器的周期 虽然我将把它转移到梯形逻辑 CoDeSys 但我首先将我的想法放入 Python 中 我将进行计数 只需一个简单的操作 counter 1 print counter 跟踪我处于
  • 使用Python将图像转换为十六进制格式

    我的下面有一个jpg文件tmp folder upload path tmp resized test jpg 我一直在使用下面的代码 Method 1 with open upload path rb as image file enco
  • Python unicode 字符代码?

    有没有办法将 Unicode 字符 插入 Python 3 中的字符串 例如 gt gt gt import unicode gt gt gt string This is a full block s unicode charcode U
  • 使用循环将对象添加到列表(python)

    我正在尝试使用 while 循环将对象添加到列表中 基本上这就是我想做的 class x pass choice raw input pick what you want to do while choice 0 if choice 1 E
  • Python int 太大,无法放入 SQLite

    我收到错误 OverflowError Python int 太大 无法转换为 SQLite INTEGER 来自以下代码块 该文件约25GB 因此必须分部分读取 length 6128765 Works on partitions of
  • python中的sys.stdin.fileno()是什么

    如果这是非常基本的或之前已经问过的 我很抱歉 我用谷歌搜索但找不到简单且令人满意的解释 我想知道什么sys stdin fileno is 我在代码中看到了它 但不明白它的作用 这是实际的代码块 fileno sys stdin filen
  • Python 矩阵每一行的总和

    lista 1 2 3 4 5 6 7 8 9 print lista def filas lista res for elemento in lista x sum lista elemento res append x print re
  • Plotly:如何避免巨大的 html 文件大小

    我有一个 3D 装箱模型 它使用绘图来绘制输出图 我注意到 绘制了 600 个项目 生成 html 文件需要很长时间 文件大小为 89M 这太疯狂了 我怀疑可能存在一些巨大的重复 或者是由单个项目的 add trace 方法引起的 阴谋 为
  • 如何在单独的文件中使用 FastAPI Depends 作为端点/路由?

    我在单独的文件中定义了一个 Websocket 端点 例如 from starlette endpoints import WebSocketEndpoint from connection service import Connectio
  • 使用 Keras 和 fit_generator 绘制 TensorBoard 分布和直方图

    我正在使用 Keras 使用 fit generator 函数训练 CNN 这似乎是一个已知问题 https github com fchollet keras issues 3358TensorBoard 在此设置中不显示直方图和分布 有
  • 从时间序列生成日期特征

    我有一个数据框 其中包含如下列 Date temp data holiday day 01 01 2000 10000 0 1 02 01 2000 0 1 2 03 01 2000 2000 0 3 30 01 2000 200 0 30

随机推荐

  • IDEA导入Eclipse项目步骤详解

    IDEA导入Eclipse项目步骤详解 文章目录 IDEA导入Eclipse项目步骤详解 首先在idea里file gt new gt Project from Existing Sources 选中到要导入的项目 这里我选用创建新的 Cl
  • 情感分析概述

    情感分析主要研究观点挖掘 倾向性分析等 一 为什么需要观点挖掘和倾向性分析 文本信息主要包括两类 客观性事实 主观性观点 但是已有的文本分析方法主要侧重在客观性文本内容的分析和挖掘 二 什么是观点挖掘与倾向性分析 观点挖掘与倾向性分析就是从
  • Java多线程进阶(十九)—— J.U.C之synchronizer框架:CyclicBarrier

    本文首发于一世流云专栏 https segmentfault com blog 一 CyclicBarrier简介 CyclicBarrier是一个辅助同步器类 在JDK1 5时随着J U C一起引入 这个类的功能和我们之前介绍的Count
  • Jmeter录制脚本

    性能关注点 接口响应时间 50毫秒 1000毫秒 吞度量 10000万每天 tPs 每秒处理事务数 压测需求与业务操作步骤 压测对象 http news baidu com 压测页面 首页 国际频道 财经频道 步骤 访问首页 单击 国际频道
  • 测试用例的优先级

    刚接触软件测试 先熟悉一下测试用例的优先级的概念 有时会听到0级别case的说法 其实这是对具有一定优先级的测试用例的说法 在这际测试实践中 测试用例根据重要性分成一定的等级 在不通的公司 可能测试用例的等级划分有所差异 但是基本大同小异
  • 积分计算两条曲线围绕y坐标轴旋转形成的立体体积

    积分计算两条曲线围绕y坐标轴旋转形成的立体体积 和附录文章1类似 计算两条曲线y x 2和y 2x围绕y坐标轴形成的立方体体积 首先要计算积分的上限和下限 根据两者相交的点求出 0 4 外层大圆R y y 1 2 和内层小圆r y y 2的
  • 使用iptables进行入站流量过滤

    iptables是Linux内置的流量过滤工具 同时也是多种防火墙的底层实现 如fw3 在本次应用中 iptables通过丢弃不符合规则的数据包 使得未注册设备在DHCP获取ip阶段失败 无法连接到专用内网 保证系统安全 iptables使
  • 10年软件测试工程师感悟——写给还在迷茫中的朋友

    这两天和朋友谈到软件测试的发展 其实软件测试已经在不知不觉中发生了非常大的改变 前几年的软件测试行业还是一个风口 随着不断地转行人员以及毕业的大学生疯狂地涌入软件测试行业 目前软件测试行业 缺口 已经基本饱和 当然 我说的是最基础的功能测试
  • QT之D指针

    什么是D指针 如果你已经看过到Qt源码 你会发现它经常使用Q D和Q Q 宏 本文介绍了这些宏的用途 该Q D和Q Q宏是一个设计模式的一部分被称为d 指针 也称为 不透明的指针 其中一个库的实现细节可以从它的用户 并转移到执行被隐藏 另外
  • LLVM每日谈之二 LLVM IR

    作者 snsn1984 在介绍LLVM IR之前 我们需要先了解下LLVM的结构 传统的静态编译器分为三个阶段 前端 优化和后端 LLVM的三阶段设计是这样的 这样做的优点是如果需要支持一种新的编程语言 那么我们只需要实现一种新的前端 如果
  • 0基础java入门:第二十五节.面向对象思想理解思路。

    0基础java入门 第二十五节 面向对象思想理解思路 本章需要时间和代码积累才能理解通透 不要着急 先来了解 敲上三年代码再回来看 面向对象是现在大部分编程语言中都会提及和使用到的一种思想方式 有人说很难理解 但个人觉得其实不难 因为面向对
  • element ui tabs 修改成hover触发点击

    Element UI tabs标签页 将点击选择改成鼠标指到就点击 类似hover 1 单个组件 在el tabs里添加个ref 删去el tab pane里的 name绑定 然后在mounted里添加代码 mounted this nex
  • f12获取网页文本_网页上的文字不能复制怎么办?有这5招轻松复制

    有时候我们需要一些辅助资料时 会经常使用搜索工具查坎相关网页文件 但遇到一些需要用到的段落却不能直接复制时 一个字一个字的敲肯定是不现实 有什么方法可以让其直接进行复制呢 方法1 打印网页 这种方式相对比较简单 而且电脑也不需要真的安装打印
  • 串行通信协议---HART协议

    实际应用中 HART协议是仅次于Modbus协议的最接近统一现场总线的标准 主要是在4 20mA电流信号上面叠加数字信号 物理层采用Bell 202标准的FSK技术成功实现模拟信号和数字信号双向同时通信而互不干扰 HART协议规定了传输的物
  • 怎么启用windwos无线网驱动

    重启windwos无线网驱动 说明 进入系统窗口 打开设备管理器 在设备管理器目录中找到网络适配器 找到 Realtek 8822BE Wireless LAN 802 11ac PCI ENIC 左键选中Realtek 8822BE Wi
  • 【QT5】tslib移植

    tslib全称应该是Touch Screen Library 也就是专门针对触摸屏创建的开源库 tslib的最新工程的github地址为 https github com libts tslib 感谢牛人的开源工程 clone下来 进入源码
  • 使用Visual Studio开发Linux程序

    首先我们使用visual studio创建项目 这里我使用的是visual studio 2022 visual studio 2019的也一样 如下创建项目即可 然后我们需要在visual studio中连接我们的Linux服务器 点击
  • 刷脸支付顺应时代各种优惠政策出现

    相比于人工合成的二维码扫码支付 刷脸支付采用的是生物信息识别技术 在安全性上后者要比前者高很多 刷脸支付自从出世以来就受到广大创业者 商家的关注 自从去年支付宝推出刷脸支付并在实体店投入运营 到今年刷脸支付得到快速的发展 微信也加入刷脸支付
  • 后台运行VirtualBox虚拟机

    运行一个VirtualBox虚拟机最常见的方式是 打开VirtualBox 点击对应的虚拟机来运行 使用这种传统方式运行的虚拟机通常都有一个前台界面 可以像操作本地电脑一样进行操作 但是Linuxer有时候更喜欢通过终端远程接入 而不是在虚
  • 手撕/手写/自己实现 BN层/batch norm/BatchNormalization python torch pytorch

    计算过程 在卷积神经网络中 BN 层输入的特征图维度是 N C H W 输出的特征图维度也是 N C H W N 代表 batch size C 代表 通道数 H 代表 特征图的高 W 代表 特征图的宽 我们需要在通道维度上做 batch