赞
踩
机器学习中,进行模型训练之前,需对数据做归一化处理,使其分布一致。在深度神经网络训练过程中,通常一次训练是一个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
上⾯的讲解还不够形象,我们具体通过如下的代码进⾏讲解:
代码:
- import torch
- import torch.nn as nn
- m=nn.BatchNorm2d(3,affine=True) #affine参数设为True表⽰weight和bias将被使⽤
- input=torch.randn(1,3,3,4)
- output=m(input)
- print(input)
- print("m.weight",m.weight)
- print("m.bias",m.bias)
- print(output)
- print("size",output.size())
-
- #输出:
- tensor([[[[ 0.2025, 0.2782, 0.1977, 2.7474],
- [-0.9498, -0.4337, -0.9095, -1.7508],
- [ 0.2636, -0.6627, 0.2154, 0.3723]],
-
- [[ 0.9560, 0.8259, 0.7154, -1.1959],
- [-0.2097, 0.3248, 0.2017, -0.9686],
- [-0.9710, -1.0670, 1.2054, -0.7528]],
-
- [[-0.5529, -1.6171, -0.1723, -2.3286],
- [-0.7136, 0.6029, 0.0084, 1.8002],
- [ 0.5835, -1.5875, 0.9875, 1.8628]]]])
- m.weight Parameter containing:
- tensor([1., 1., 1.], requires_grad=True)
- m.bias Parameter containing:
- tensor([0., 0., 0.], requires_grad=True)
- tensor([[[[ 0.2257, 0.2975, 0.2213, 2.6370],
- [-0.8660, -0.3770, -0.8279, -1.6250],
- [ 0.2836, -0.5940, 0.2380, 0.3867]],
-
- [[ 1.2148, 1.0619, 0.9321, -1.3133],
- [-0.1547, 0.4732, 0.3285, -1.0463],
- [-1.0491, -1.1619, 1.5078, -0.7927]],
-
- [[-0.3583, -1.1892, -0.0612, -1.7447],
- [-0.4839, 0.5440, 0.0799, 1.4788],
- [ 0.5288, -1.1661, 0.8443, 1.5277]]]],
- grad_fn=<NativeBatchNormBackward0>)
- 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]中的数据输出,并计算其中的均值和⽅差。
- print("输⼊的第⼀个维度:")
- first = input[0][0]
- print(first) #这个数据是第⼀个3*4的⼆维数据
- #求第⼀个维度的均值和⽅差
- firstDimenMean=torch.Tensor.mean(first)
- firstDimenVar=torch.Tensor.var(first,False) #false表⽰贝塞尔校正不会被使⽤
- print("m:",m)
- print('m.eps=',m.eps)
- print("firstDimenMean",firstDimenMean)
- print("firstDimenVar",firstDimenVar)
-
- 输出:
- 输⼊的第⼀个维度:
- tensor([[ 0.2025, 0.2782, 0.1977, 2.7474],
- [-0.9498, -0.4337, -0.9095, -1.7508],
- [ 0.2636, -0.6627, 0.2154, 0.3723]])
- m: BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
- m.eps= 1e-05
- firstDimenMean tensor(-0.0358)
- firstDimenVar tensor(1.1139)
我们可以通过计算器计算出均值和⽅差均正确计算。最后通过公式计算input[0][0][0][0]的值,代码如下:
- print("torch.pow(firstDimenVar,0.5)",torch.pow(firstDimenVar,0.5))
- batchnormone=((input[0][0][0][0]-firstDimenMean)/(torch.pow(firstDimenVar,0.5)+m.eps))*m.weight[0]+m.bias[0]
-
- print(batchnormone)
-
- 输出:
- torch.pow(firstDimenVar,0.5) tensor(1.0554)
- tensor(0.2257, grad_fn=<AddBackward0>)
结果值等于output[0][0][0][0]。ok,代码和公式完美的对应起来了。
从公式上理解即在计算⽅差时⼀般的计算⽅式如下:
通过贝塞尔校正的样本⽅差如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。