当前位置:   article > 正文

torch nn.BatchNorm2d实现原理_torch.nn.batchnorm2d

torch.nn.batchnorm2d

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

Batch Noramlization 是想让输入满足同一个分布, 那么是让输入的什么特征满足同一分布呢?就是让每张图片的相同通道的所有像素值的均值和方差相同。比如我们有两张图片(都为3通道),我们现在只说R通道,我们希望第一张图片的R通道的均值 和 第二张图片R通道的均值相同,方差同理。

那么在实际运行过程中均值是如何计算的呢?可以有两种方法:

  • 把所有图片的相同通道的值相加,然后求平均数,

  • 也可以先求出每一个图片此通道的均值,然后再求所有图片此通道均值的均值。

在卷积神经⽹络的卷积层之后总会添加BatchNorm2d进⾏数据的归⼀化处理,这使得数据在进⾏Relu之前不会因为数据过⼤⽽导致⽹络性
能的不稳定,BatchNorm2d()函数数学原理如下:
 

BatchNorm2d()内部的参数如下:
1.num_features:一般输入参数为batch_size*num_features*height*width,即为其中特征的数量,channel数
2.eps:分母中添加的⼀个值,⽬的是为了计算的稳定性,默认为:1e-5
3.momentum:⼀个⽤于运⾏过程中均值和⽅差的⼀个估计参数(我的理解是⼀个稳定系数,类似于SGD中的momentum的系数)
4.affine:当设为true时,会给定可以学习的系数矩阵gamma和beta
上⾯的讲解还不够形象,我们具体通过如下的代码进⾏讲解:

代码:

  1. import torch
  2. import torch.nn as nn
  3. m=nn.BatchNorm2d(3,affine=True) #affine参数设为True表⽰weight和bias将被使⽤
  4. input=torch.randn(1,3,3,4)
  5. output=m(input)
  6. print(input)
  7. print("m.weight",m.weight)
  8. print("m.bias",m.bias)
  9. print(output)
  10. print("size",output.size())
  11. #输出:
  12. tensor([[[[ 0.2025, 0.2782, 0.1977, 2.7474],
  13. [-0.9498, -0.4337, -0.9095, -1.7508],
  14. [ 0.2636, -0.6627, 0.2154, 0.3723]],
  15. [[ 0.9560, 0.8259, 0.7154, -1.1959],
  16. [-0.2097, 0.3248, 0.2017, -0.9686],
  17. [-0.9710, -1.0670, 1.2054, -0.7528]],
  18. [[-0.5529, -1.6171, -0.1723, -2.3286],
  19. [-0.7136, 0.6029, 0.0084, 1.8002],
  20. [ 0.5835, -1.5875, 0.9875, 1.8628]]]])
  21. m.weight Parameter containing:
  22. tensor([1., 1., 1.], requires_grad=True)
  23. m.bias Parameter containing:
  24. tensor([0., 0., 0.], requires_grad=True)
  25. tensor([[[[ 0.2257, 0.2975, 0.2213, 2.6370],
  26. [-0.8660, -0.3770, -0.8279, -1.6250],
  27. [ 0.2836, -0.5940, 0.2380, 0.3867]],
  28. [[ 1.2148, 1.0619, 0.9321, -1.3133],
  29. [-0.1547, 0.4732, 0.3285, -1.0463],
  30. [-1.0491, -1.1619, 1.5078, -0.7927]],
  31. [[-0.3583, -1.1892, -0.0612, -1.7447],
  32. [-0.4839, 0.5440, 0.0799, 1.4788],
  33. [ 0.5288, -1.1661, 0.8443, 1.5277]]]],
  34. grad_fn=<NativeBatchNormBackward0>)
  35. size torch.Size([1, 3, 3, 4])

分析:输⼊是⼀个1*3*3*4 四维矩阵,gamma和beta为⼀维数组,是针对input[0][0],input[0][1]两个3*4的⼆维矩阵分别进⾏处理的,我们不妨将input[0][0]的按照上⾯介绍的基本公式来运算,看是否能对的上output[0][0]中的数据。⾸先我们将input[0][0]中的数据输出,并计算其中的均值和⽅差。
 

  1. print("输⼊的第⼀个维度:")
  2. first = input[0][0]
  3. print(first) #这个数据是第⼀个3*4的⼆维数据
  4. #求第⼀个维度的均值和⽅差
  5. firstDimenMean=torch.Tensor.mean(first)
  6. firstDimenVar=torch.Tensor.var(first,False) #false表⽰贝塞尔校正不会被使⽤
  7. print("m:",m)
  8. print('m.eps=',m.eps)
  9. print("firstDimenMean",firstDimenMean)
  10. print("firstDimenVar",firstDimenVar)
  11. 输出:
  12. 输⼊的第⼀个维度:
  13. tensor([[ 0.2025, 0.2782, 0.1977, 2.7474],
  14. [-0.9498, -0.4337, -0.9095, -1.7508],
  15. [ 0.2636, -0.6627, 0.2154, 0.3723]])
  16. m: BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  17. m.eps= 1e-05
  18. firstDimenMean tensor(-0.0358)
  19. firstDimenVar tensor(1.1139)

我们可以通过计算器计算出均值和⽅差均正确计算。最后通过公式计算input[0][0][0][0]的值,代码如下:
 

  1. print("torch.pow(firstDimenVar,0.5)",torch.pow(firstDimenVar,0.5))
  2. batchnormone=((input[0][0][0][0]-firstDimenMean)/(torch.pow(firstDimenVar,0.5)+m.eps))*m.weight[0]+m.bias[0]
  3. print(batchnormone)
  4. 输出:
  5. torch.pow(firstDimenVar,0.5) tensor(1.0554)
  6. tensor(0.2257, grad_fn=<AddBackward0>)

结果值等于output[0][0][0][0]。ok,代码和公式完美的对应起来了。
从公式上理解即在计算⽅差时⼀般的计算⽅式如下:


通过贝塞尔校正的样本⽅差如下:


参考:Pytorch:nn.BatchNorm2d()函数 - 灰信网(软件开发博客聚合)

Batch Normalization详解 - 知乎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/606360
推荐阅读
相关标签
  

闽ICP备14008679号