一、Batch Norm归一化激活函数
首先回顾一下归一化输入是怎样的?
μ
=
1
m
∑
i
=
1
x
(
i
)
\mu=\frac{1}{m}\sum_{i=1} x^{(i)}
μ=m1i=1∑x(i)
x = x − μ x=x-\mu x=x−μ
σ 2 = 1 m ∑ i = 1 x 2 \sigma^2=\frac{1}{m}\sum_{i=1} x^2 σ2=m1i=1∑x2
x / = σ x/=\sigma x/=σ
现在考虑归一化激活函数,通常做法是归一化计算得到的
z
(
i
)
z^{(i)}
z(i)而不是
a
(
i
)
a^{(i)}
a(i)。
μ
=
1
m
∑
i
=
1
z
(
i
)
\mu=\frac{1}{m}\sum_{i=1}z^{(i)}
μ=m1i=1∑z(i)
σ 2 = 1 m ∑ i = 1 ( z ( i ) − μ ) 2 \sigma^2=\frac{1}{m}\sum_{i=1} (z^{(i)}-\mu)^2 σ2=m1i=1∑(z(i)−μ)2
z n o r m ( i ) = z ( i ) − μ σ 2 + ε z_{norm}^{(i)}=\frac{z^{(i)}-\mu}{\sqrt{\sigma^2+\varepsilon}} znorm(i)=σ2+εz(i)−μ
z
~
(
i
)
=
γ
z
n
o
r
m
(
i
)
+
β
\tilde z^{(i)}=\gamma z_{norm}^{(i)}+\beta
z~(i)=γznorm(i)+β
通过参数
γ
\gamma
γ控制了
σ
2
+
ε
\sqrt{\sigma^2+\varepsilon}
σ2+ε
通过参数
β
\beta
β控制了
μ
\mu
μ
所以
z
~
(
i
)
=
z
(
i
)
\tilde z^{(i)}=z^{(i)}
z~(i)=z(i)
通过调整
γ
β
\gamma \beta
γβ,调整了方差和均值,可以使得
z
z
z在自己希望赋予的范围内
二、将Batch Norm拟合进神经网络
X
→
Z
[
1
]
→
Z
~
[
1
]
→
A
[
1
]
=
g
[
1
]
(
Z
~
[
1
]
)
→
Z
[
2
]
→
Z
~
[
2
]
→
A
[
2
]
→
.
.
.
X\to Z^{[1]}\to \tilde{Z}^{[1]}\to A^{[1]}=g^{[1]}(\tilde{Z}^{[1]})\to Z^{[2]}\to \tilde{Z}^{[2]}\to A^{[2]}\to...
X→Z[1]→Z~[1]→A[1]=g[1](Z~[1])→Z[2]→Z~[2]→A[2]→...
在TensorFlow框架中,不需要自己实现Batch Norm过程,只需要调用:
tf.nn.batch_normalization
结合Mini-batch使用Batch Norm
Batch Norm的做法是相同的,但是注意z是需要均值处理的,所以这里的b不起效,应从参数中去除。
Batch Norm实施梯度下降
三、为什么Batch Norm奏效?
Covariate shift
左图中训练的结果不一定在右图中生效,右图的输入出现了偏移
考虑在深层神经网络中,遮住前面几层
遮挡住前2层后,这组a作为第3层的输入值,同时这组值由前两层运算而来,每一轮训练会有不同的值,即有不同的这组a值,那么就出现了上述提及的输入值偏移问题。
正是因为有这样的问题,所以用Batch Norm可以尽可能使每一层保持相对独立,神经网络的之后层就有更高的稳定性,也有助于神经网络的加速学习。
还有一点值得关注:Batch Norm处理后,数据方差和均值实际上是被控制住的。
Batch Norm有轻微的正则化作用,但是不要当作正则化来使用。应该把Batch Norm当作归一化隐藏单元激活值来使用,从而加速学习进程。
四、测试中的Batch Norm
- 训练时, μ 、 σ \mu、\sigma μ、σ是在Mini-batch上计算得到的
- 测试时,需要可能需要逐一处理样本,这里的 μ 、 σ \mu、\sigma μ、σ需要估算,估算的方法可以是在整个网络训练运行得到 μ 、 σ \mu、\sigma μ、σ。实际操作中,采用 指数加权平均(流动平均) 跟踪训练中的 μ 、 σ \mu、\sigma μ、σ,得到粗略的 μ 、 σ \mu、\sigma μ、σ
如果用深度学习框架编程,通常有默认的估算
μ
、
σ
\mu、\sigma
μ、σ的方法。