赞
踩
假设我们的数据是(3,2,8)的一维序列格式的数据,表示3个Batch、每个Batch有2个Channel、每个Channel的Sequence为8。这是一维数据处理中十分常见的数据格式(B,C,N)。如下图所示:
上图中不同颜色区域标识不同的Batch,每个Batch均是(2,8)的格式。以下代码举例的维度均是(2,2,4)
torch.nn.BatchNorm1d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
参数:
-> num_features(int)– 特征或通道C的数量.
-> ϵ \epsilon ϵ - eps(float)– 为数值稳定性添加到分母上的值。默认值:1e-5.
-> momentum(float)– 用于running_mean和running_var计算的值。对于累积移动平均线,可以设置为“无”。默认值:0.1
-> affine(bool)– 一个布尔值,当设置为True时,该模块具有可学习的仿射参数。默认值:True (对应于公式中的 γ 、 β \gamma 、 \beta γ、β)
-> track_running_stats(bool)–一个布尔值,当设置为True时,此模块跟踪运行平均值和方差;当设置为False时,该模块不跟踪此类统计信息,并将统计信息缓冲区running_mean和running_var初始化为None。当这些缓冲区为None时,此模块始终使用批处理统计信息。无论是训练模式还是评估模式。默认值:True
y
=
x
−
E
[
x
]
V
a
r
[
x
]
+
ϵ
∗
γ
+
β
y = \frac{ x - E[x] }{ \sqrt{Var[x] + \epsilon} } * \gamma + \beta
y=Var[x]+ϵ
x−E[x]∗γ+β
上面公式中,
x
x
x是我们输入的数据,
E
[
x
]
E[x]
E[x]则是我们需要计算的期望,
V
a
r
[
x
]
Var[x]
Var[x]是计算的方差,
ϵ
\epsilon
ϵ是分母的稳定因子,
γ
、
β
\gamma 、\beta
γ、β 是放射参数(可参考y=ax+b形式的变换)。
现在我们有个问题就是,我们不知道公式中的期望和方差怎么计算的?
在这部分结束后相信大家都能清楚这来个torch的函数的计算方式!!!
在我们查阅pytorch的官方文档后,我们会发现torch.mean的用法有两种,如下所示:
torch.mean(input, *, dtype=None) → Tensor
torch.mean(input, dim, keepdim=False, *, dtype=None, out=None) → Tensor
对于第一种用法,我们则是直接计算所有值的平均值,如下:
>>>a = torch.randn((2,2,4))
>>>a
tensor([[[ 1.1548, 0.5501, -0.5606, 0.8808],
[-1.6358, -1.2661, 1.0681, -1.7350]],
[[-0.1020, -1.1071, -1.9635, 0.2054],
[-1.5953, 1.0970, 0.7805, -0.2438]]])
>>>torch.mean(a)
tensor(-0.2795)
对于第二种用法则添加了很多的参数,包括keepdim、dim等参数:
–> dim(int或int元组)– 要消减的一个或多个维度。
–> keepdim(bool)– 输出张量是否保留了dim,是否和原始的x的维度相同,要和dim参数一起使用。
>>>a = torch.randn((2,2,4))
>>>a
tensor([[[ 1.1548, 0.5501, -0.5606, 0.8808],
[-1.6358, -1.2661, 1.0681, -1.7350]],
[[-0.1020, -1.1071, -1.9635, 0.2054],
[-1.5953, 1.0970, 0.7805, -0.2438]]])
>>>torch.mean(a, dim=0, keepdim=True)
tensor([[[ 0.5264, -0.2785, -1.2621, 0.5431],
[-1.6155, -0.0846, 0.9243, -0.9894]]])
>>>torch.mean(a, dim=0)
tensor([[ 0.5264, -0.2785, -1.2621, 0.5431],
[-1.6155, -0.0846, 0.9243, -0.9894]])
在上面我们说过dim的作用是选择我们需要消减的那个维度,在上面的计算中我们将dim=0传入函数执行,意思就是我们不要维度0了,就是不要batchsize这个维度。
注意上面添加了keepdim和没有添加keepdim的两个计算结果,我么得到的结果是一样的,但是两者结果的维度却不相同,上面的结果任然是是哪个维度,但是下面的结果却是两个维度。(如果看不出来几个维度的,可以使用shape打印出来看看)。
我们可以简单看一下数值,可以发现,是每个batch的对应位置上数值的和的平均。这么说可能很迷糊,或许我们这次记住了,下次又忘了,那怎么办呢?请回忆一下再文章开头展示的图片,就是下面那张图片。下面我将用图形的方式介绍的给大家更清晰的认识。
我们假定在一个空间中,数据的分布方式就是上面的那种方式。那为啥是上面那种方式呢?我也不知道。
如何通俗理解这个消减维度呢,dim=0表示消减第0个维度,那我们应该尽可能的让这个图形看到尽可能少的Batch,对吧!当我们只看到1个batch的时候,是不是可以用squeeze将这个维度消灭掉,因为维度维值为1的不影响数据的分布。
再次看向上面的这张图,我们给这张图加上各个方向的一个方向标识,以便我们后续的进一步理解。
>>>a = torch.randn((2,2,4))
>>>a
tensor([[[ 1.1548, 0.5501, -0.5606, 0.8808],
[-1.6358, -1.2661, 1.0681, -1.7350]],
[[-0.1020, -1.1071, -1.9635, 0.2054],
[-1.5953, 1.0970, 0.7805, -0.2438]]])
>>>torch.mean(a, dim=0, keepdim=True)
tensor([[[ 0.5264, -0.2785, -1.2621, 0.5431],
[-1.6155, -0.0846, 0.9243, -0.9894]]])
>>>torch.mean(a, dim=0)
tensor([[ 0.5264, -0.2785, -1.2621, 0.5431],
[-1.6155, -0.0846, 0.9243, -0.9894]])
>>>a
tensor([[[ 1.1548, 0.5501, -0.5606, 0.8808],
[-1.6358, -1.2661, 1.0681, -1.7350]],
[[-0.1020, -1.1071, -1.9635, 0.2054],
[-1.5953, 1.0970, 0.7805, -0.2438]]])
>>>torch.mean(a, dim=1)
tensor([[-0.2405, -0.3580, 0.2538, -0.4271],
[-0.8486, -0.0050, -0.5915, -0.0192]])
>>>torch.mean(a, dim=1, keepdim=True)
tensor([[[-0.2405, -0.3580, 0.2538, -0.4271]],
[[-0.8486, -0.0050, -0.5915, -0.0192]]])
>>>a tensor([[[ 1.1548, 0.5501, -0.5606, 0.8808], [-1.6358, -1.2661, 1.0681, -1.7350]], [[-0.1020, -1.1071, -1.9635, 0.2054], [-1.5953, 1.0970, 0.7805, -0.2438]]]) >>>torch.mean(a, dim=2, keepdim=True) tensor([[[ 0.5063], [-0.8922]], [[-0.7418], [ 0.0096]]]) >>>torch.mean(a, dim=2) tensor([[ 0.5063, -0.8922], [-0.7418, 0.0096]])
我们第一反应是消减维度0和1,但是我们该如何一次性将这两个维度消灭?
实际上,这个方式可以分解成先消减维度0,在消减维度1。 看代码:
>>>a tensor([[[ 1.1548, 0.5501, -0.5606, 0.8808], [-1.6358, -1.2661, 1.0681, -1.7350]], [[-0.1020, -1.1071, -1.9635, 0.2054], [-1.5953, 1.0970, 0.7805, -0.2438]]]) >>>torch.mean(a, dim=(0,1), keepdim=True) tensor([[[-0.5446, -0.1815, -0.1689, -0.2231]]]) >>>b = torch.mean(a, dim=0, keepdim=True) >>>torch.mean(b, dim=1, keepdim=True) tensor([[[-0.5446, -0.1815, -0.1689, -0.2232]]]) # dim=(1,0)与dim=(0,1)结果相同 >>>torch.mean(a, dim=(1,0), keepdim=True) tensor([[[-0.5446, -0.1815, -0.1689, -0.2231]]])
可以发现我们可以通过先将维度0消减,在对维度1消减,记得带上keepdim=True去验证。
看图理解,从下图我们可以知道,最后得到的就是最右边地下灰色的数据,是经过两次计算均值得到的,但是想象里好的话,我们也可以经过一次计算的到;此外我们也可以先消减维度1,再消减维度0,得到的结果是一样的。看图理解应该不难。
同理dim=(1,2)、dim=(0,3)等等,相信大家也能用同样的方法计算出来了。
想必经过上面图形的解释,大家应该能够非常清楚各种方式的均值计算。对于var的计算方式,也是同理。
torch.var(input, dim=None, *, correction=1, keepdim=False, out=None) → Tensor
参数:
-> input(张量)– 输入张量。
-> dim(int或int元组,可选)– 要消减的一个或多个维度。如果“无”,则所有尺寸都将消减。
关键字参数:
-> correction(int)- 样本大小和样本自由度之间的差异。默认为贝塞尔校正,correction=1。
在2.0版本中更改:以前此参数被称为unbiased,是布尔值,True对应correction=1,False对应correction=0。这里表示是否采用无偏估计。
-> keepdim(bool)– 输出张量是否保留了dim。
-> out(张量,可选)– 输出张量。
>>>a
tensor([[[ 1.1548*, 0.5501, -0.5606, 0.8808],
[-1.6358, -1.2661, 1.0681, -1.7350]],
[[-0.1020*, -1.1071, -1.9635, 0.2054],
[-1.5953, 1.0970, 0.7805, -0.2438]]])
>>>torch.mean(a, dim=0, keepdim=True)
tensor([[[ 0.5264*, -0.2785, -1.2621, 0.5431],
[-1.6155, -0.0846, 0.9243, -0.9894]]])
# 用笔验算一下,发现是和下面一样的
>>>torch.var(a, dim=0, keepdim=True)
tensor([[[7.8977e-01*, 1.3732e+00, 9.8406e-01, 2.2808e-01],
[8.2013e-04, 2.7921e+00, 4.1357e-02, 1.1118e+00]]])
这里默认correction=1,是无偏估计,求样本方差。参加运算的用*表示。计算公式:
S
2
=
1
n
−
1
∑
i
=
1
n
(
X
i
−
X
‾
)
2
S^2 = \frac{1}{n-1} \sum_{i=1}^{n} {(X_i - \overline{X})^2}
S2=n−11i=1∑n(Xi−X)2
举例:
7.8977
e
−
01
=
(
1.1548
−
0.5264
)
2
+
(
−
0.1020
−
0.5264
)
2
2
−
1
7.8977e-01 = \frac {(1.1548 - 0.5264)^2 + (-0.1020 - 0.5264)^2} {2-1}
7.8977e−01=2−1(1.1548−0.5264)2+(−0.1020−0.5264)2
其他的就不一一举例了,请自行参悟。
y
=
x
−
E
[
x
]
V
a
r
[
x
]
+
ϵ
∗
γ
+
β
y = \frac{ x - E[x] }{ \sqrt{Var[x] + \epsilon} } * \gamma + \beta
y=Var[x]+ϵ
x−E[x]∗γ+β
这个公式里面,
V
a
r
[
x
]
Var[x]
Var[x]默认的是有偏估计。有偏估计(总体方差)的计算公式如下:
σ
2
=
1
N
∑
i
=
1
N
(
X
i
−
μ
)
\sigma^2 = \frac{1}{N} \sum_{i=1}^{N} {(X_i - \mu)}
σ2=N1i=1∑N(Xi−μ)
>>>a tensor([[[ 1.1548*, 0.5501, -0.5606, 0.8808], [-1.6358, -1.2661, 1.0681, -1.7350]], [[-0.1020*, -1.1071, -1.9635, 0.2054], [-1.5953, 1.0970, 0.7805, -0.2438]]]) >>>mean = torch.mean(a, dim=(0,2), keepdim=True) >>>mean tensor([[[-0.1178], [-0.4413]]]) >>>var = torch.var(a, dim=(0,2), keepdim=True, unbiased=False) >>>var tensor([[[0.9686], [1.4111]]]) # 自己计算的结果 >>>(a-mean)*(var+1e-5).rsqrt() tensor([[[ 1.2930, 0.6786, -0.4500, 1.0146], [-1.0055, -0.6943, 1.2706, -1.0891]], [[ 0.0160, -1.0052, -1.8754, 0.3284], [-0.9715, 1.2950, 1.0285, 0.1663]]]) # 定义一个BatchNorm1d >>>bn = torch.nn.BatchNorm1d(num_features=2, momentum=0,affine=False, track_running_stats=False) >>>bn(a) tensor([[[ 1.2930, 0.6786, -0.4500, 1.0146], [-1.0055, -0.6943, 1.2706, -1.0891]], [[ 0.0160, -1.0052, -1.8754, 0.3284], [-0.9715, 1.2950, 1.0285, 0.1663]]])
可以发现两者的结果一样。希望可以通过这种方式帮助你理解BatchNorm1d的原理,理解BatchNorm1d作用在哪些特征上面。
上图最右边的图中,只有最后面的灰色是得到的最终结果。或许换个方向,从图形的角度,我们可以更加清楚BatchNorm1d是在干什么,理解BatchNorm1d的归一化的目的是什么,有什么作用,能对神经网络起到什么作用。很明显的作用就是,在所有数据的分布基本一致时,这样做是可以加快神经网络收敛的,似乎可以更好的提取大部分数据共有的特征。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。