PyTorch踩坑指南(1)nn.BatchNorm2d()函数

PyTorch踩坑指南(1)nn.BatchNorm2d()函数前言最近在研究深度学习中图像数据处理的细节,基于的平台是PyTorch。心血来潮,总结一下,好记性不如烂笔头。BatchNormalization对于2015年出现的BatchNormalization1,2018年的文章GroupNormalization2在Abstract中总结得言简意赅,我直接copy过来。BatchNormalization(BN)isamile…

大家好,又见面了,我是你们的朋友全栈君。

前言

最近在研究深度学习中图像数据处理的细节,基于的平台是PyTorch。心血来潮,总结一下,好记性不如烂笔头。

Batch Normalization

对于2015年出现的Batch Normalization1,2018年的文章Group Normalization2在Abstract中总结得言简意赅,我直接copy过来。

Batch Normalization (BN) is a milestone technique in the development of deep learning, enabling various networks to train. However, normalizing along the batch dimension introduces problems — BN’s error increases rapidly when the batch size becomes smaller, caused by inaccurate batch statistics estimation. This limits BN’s usage for training larger models and transferring features to computer vision tasks including detection, segmentation, and video, which require small batches constrained by memory consumption.

机器学习中,进行模型训练之前,需对数据做归一化处理,使其分布一致。在深度神经网络训练过程中,通常一次训练是一个batch,而非全体数据。每个batch具有不同的分布产生了internal covarivate shift问题——在训练过程中,数据分布会发生变化,对下一层网络的学习带来困难。Batch Normalization强行将数据拉回到均值为0,方差为1的正太分布上,一方面使得数据分布一致,另一方面避免梯度消失。

结合图1,说明Batch Normalization的原理。假设在网络中间经过某些卷积操作之后的输出的feature maps的尺寸为N×C×W×H,5为batch size(N),3为channel(C),W×H为feature map的宽高,则Batch Normalization的计算过程如下。
在这里插入图片描述


图 1

  • 1.每个batch计算同一通道的均值 μ \mu μ,如图取channel 0,即 c = 0 c=0 c=0(红色表示)
    μ = ∑ n = 0 N − 1 ∑ w = 0 W − 1 ∑ h = 0 H − 1 X [ n , c , w , h ] N × W × H \mu = \frac{\sum\limits_{n=0}^{N-1}\sum\limits_{w=0}^{W-1} \sum\limits_{h=0}^{H-1} X[n, c, w, h]}{N×W×H} μ=N×W×Hn=0N1w=0W1h=0H1X[n,c,w,h]
  • 2.每个batch计算同一通道的方差 σ 2 σ^2 σ2
    σ 2 = ∑ n = 0 N − 1 ∑ w = 0 W − 1 ∑ h = 0 H − 1 ( X [ n , c , w , h ] − μ ) 2 N × W × H σ^2 = \frac{\sum\limits_{n=0}^{N-1}\sum\limits_{w=0}^{W-1} \sum\limits_{h=0}^{H-1} (X[n, c, w, h]-\mu)^2}{N×W×H} σ2=N×W×Hn=0N1w=0W1h=0H1(X[n,c,w,h]μ)2
  • 3.对当前channel下feature map中每个点 x x x,索引形式 X [ n , c , w , h ] X[n, c, w, h] X[n,c,w,h],做归一化
    x ′ = ( x − μ ) σ 2 + ϵ x^{‘}=\frac{(x-\mu)}{\sqrt{σ^2+\epsilon}} x=σ2+ϵ
    (xμ)
  • 4.增加缩放和平移变量 γ \gamma γ β \beta β(可学习的仿射变换参数),归一化后的值
    y = γ x ′ + β y=\gamma x^{‘}+\beta y=γx+β
    简化公式:
    y = x − μ σ 2 + ϵ γ + β y=\frac{x-\mu}{\sqrt{\sigma^2+\epsilon}}\gamma +\beta y=σ2+ϵ
    xμ
    γ+
    β

    原文中的算法描述如下,
    在这里插入图片描述
    注:上图1所示 m m m就是 N ∗ W ∗ H N*W*H NWH

PyTorch的nn.BatchNorm2d()函数

理解了Batch Normalization的过程,PyTorch里面的函数就参考其文档3用就好。
BatchNorm2d()内部的参数如下:

  • num_features:一般情况下输入的数据格式为batch_size * num_features * height * width,即为特征数,channel数
  • eps:分母中添加的一个值,目的是为了计算的稳定性,默认:1e-5
  • momentum:一个用于运行过程中均值和方差的一个估计参数,默认值为 0.1 0.1 0.1 x ^ n e w = ( 1 − m o m e n t u m ) × x ^ + m o m e n t u m × x t \hat{x}_{new} =(1−momentum) × \hat{x} +momentum×x_t x^new=(1momentum)×x^+momentum×xt,其中 x ^ \hat{x} x^是估计值, x t x_t xt是新的观测值
  • affine:当设为true时,给定可以学习的系数矩阵 γ \gamma γ β \beta β

Show me the codes

import torch
import torch.nn as nn

def checkBN(debug = False):
    # parameters
    N = 5 # batch size
    C = 3 # channel
    W = 2 # width of feature map
    H = 2 # height of feature map
    # batch normalization layer
    BN = nn.BatchNorm2d(C,affine=True) #gamma和beta, 其维度与channel数相同
    # input and output
    featuremaps = torch.randn(N,C,W,H)
    output = BN(featuremaps)
    # checkout
    ###########################################
    if debug:
        print("input feature maps:\n",featuremaps)
        print("normalized feature maps: \n",output)
    ###########################################
    
    # manually operation, the first channel
    X = featuremaps[:,0,:,:]
    firstDimenMean = torch.Tensor.mean(X)
    firstDimenVar = torch.Tensor.var(X,False) #Bessel's Correction贝塞尔校正不被使用
    
    BN_one = ((input[0,0,0,0] - firstDimenMean)/(torch.pow(firstDimenVar+BN.eps,0.5) )) * BN.weight[0] + BN.bias[0]
    print('+++'*15,'\n','manually operation: ', BN_one)
    print('==='*15,'\n','pytorch result: ', output[0,0,0,0])
    
if __name__=="__main__":
    checkBN()

可以看出手算的结果和PyTorch的nn.BatchNorm2d的计算结果一致。

+++++++++++++++++++++++++++++++++++++++++++++
 manually operation:  tensor(-0.0327, grad_fn=<AddBackward0>)
=============================================
 pytorch result:  tensor(-0.0327, grad_fn=<SelectBackward>)

贝塞尔校正

代码中出现,求方差时是否需要贝塞尔校正,即从样本方差到总体方差的校正。
方差公式从,
σ 2 = ∑ i = 0 N − 1 ( x i − m e a n ( x ) ) 2 N \sigma^2 = \frac{\sum\limits_{i=0}^{N-1} (x_i-mean(x))^2}{N} σ2=Ni=0N1(ximean(x))2
变成(基于样本的总体方差的无偏估计),
σ 2 = ∑ i = 0 N − 1 ( x i − m e a n ( x ) ) 2 N − 1 \sigma^2 = \frac{\sum\limits_{i=0}^{N-1} (x_i-mean(x))^2}{N-1} σ2=N1i=0N1(ximean(x))2

Reference


  1. Ioffe, Sergey, and Christian Szegedy. “Batch normalization: Accelerating deep network training by reducing internal covariate shift.” arXiv preprint arXiv:1502.03167 (2015). ↩︎ ↩︎

  2. Wu, Yuxin, and Kaiming He. “Group normalization.” Proceedings of the European Conference on Computer Vision (ECCV). 2018. ↩︎

  3. BatchNorm2d ↩︎

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/134016.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月7日 下午3:16
下一篇 2022年6月7日 下午3:16


相关推荐

  • 是在传统pc的路上走呢,还是跟潮流走移动互联网「建议收藏」

    这些天在准备期末考试,复习c++,可是总是对手机应用的开发感兴趣,往java方向发展可能前途更好么?以我目前接触的信息来看,貌似java语言更受欢迎,而且照现在的趋势发展,手机这种移动终端的发展应该是以后一段时间的趋势,前几天看到一个关于c++的帖子,说以后c++的程序员会两极分化,学得很好的会找到很好的工作,高新,而学的一般的,全都找不到工作。大意是这样,看了很没有信心,现在全校有一半的专业都在

    2022年3月8日
    53
  • Selenium中implicitly_wait等待失效

    Selenium中implicitly_wait等待失效

    2021年5月23日
    223
  • Android制作字符串表格String.xml转EXCEL工具

    Android制作字符串表格String.xml转EXCEL工具publicstaticListgetAllExternalSdcardPath(){ListPathList=newArrayList();StringfirstPath=Environment.getExternalStorageDirectory().getPath();Log.d(TAG,”getAllExter

    2022年8月22日
    13
  • QSettings用法介绍

    QSettings用法介绍简介 QSettings 类提供了持久的跨平台应用程序设置 用户通常期望应用程序记住它的设置 窗口大小 位置等 所有会话 这些信息通常存储在 Windows 系统注册表 OSX 和 iOS 的属性列表文件中 在 Unix 系统中 在缺乏标准的情况下 许多应用程序 包括 KDE 应用程序 使用 INI 文本文件 QSettings 围绕这些抽象技术 使我们能够以便携的方式保存和恢复应用程序设置 它还支持自定义存储

    2026年3月18日
    3
  • Java 并发:volatile 关键字解析「建议收藏」

    Java 并发:volatile 关键字解析「建议收藏」在Java并发编程中,要想使并发程序能够正确地执行必须要保证三条原则:原子性、可见性和有序性。只要有一条原则没有被保证,就有可能导致线程安全性问题。volatile关键字被用来保证可见性,即保证共享变量的内存可见性以解决缓存一致性问题,同时其还会禁止进行指令重排序。volatile关键字主要用于使其他线程及时感知共享变量的修改并保证使用变量最新值,例如,用于修饰状态标记量和Double-Check(双重检查)中。

    2022年7月11日
    22
  • 为什么hashmap线程不安全我们还要用_arraylist线程不安全体现在哪里

    为什么hashmap线程不安全我们还要用_arraylist线程不安全体现在哪里一、Map概述我们都知道HashMap是线程不安全的,但是HashMap的使用频率在所有map中确实属于比较高的。因为它可以满足我们大多数的场景了。Map类继承图上面展示了java中Map的继承图,Map是一个接口,我们常用的实现类有HashMap、LinkedHashMap、TreeMap,HashTable。HashMap根据key的hashCode值来保存value,需要注意的是,HashMap不保证遍历的顺序和插入的顺序是一致的。HashMap允许有一条记录的key为null,但

    2022年10月11日
    12

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号