文章内容皆为个人理解,如有不足欢迎指正。
1、输入归一化
在机器学习里使用线性分类器的时候,比如
y
=
w
0
+
w
1
∗
x
1
+
w
2
∗
x
2....
y=w0+w1*x1+w2*x2....
y=w0+w1∗x1+w2∗x2....
我们需要先将特征
x
1
x1
x1、
x
2
x2
x2…进行归一化,因为如果
x
1
x1
x1取值范围[100,1000],而
x
2
x2
x2取值范围只有[0.1,1],会使得
w
1
w1
w1在分类过程中起主导作用,这样往往并符合实际情况。虽然神经网络可以通过参数的调整来适应不同特征的取值范围,但是会导致训练效率比较低。
不同输入特征的取值范围差异比较大时,会影响到梯度下降法的效率。以2维特征为例,特征取值不同会导致大多数位置的梯度方向并不是最优的搜索方向,当使用梯度下降法寻求最优解时,会导致需要很多次迭代才能收敛,如图(a);当特征归一化后,梯度方向会近似为最优的搜索方向,如图(b)。
介绍两种最简单常用的归一化方法。
缩放归一化: 将特征缩放到[0,1]或者[-1,1]的区间里。假设有
N
N
N个训练样本
{
x
1
,
x
2
,
…
…
x
N
}
\{x1,x2,……xN\}
{x1,x2,……xN},则对任一维特征
ω
\omega
ω的缩放为
ω
^
=
ω
−
m
i
n
(
ω
)
m
a
x
(
ω
)
−
m
i
n
(
ω
)
,
% \f is defined as f(#1) using the macro \hat\omega =\frac{\omega-min(\omega)}{max(\omega)-min(\omega)} ,
ω^=max(ω)−min(ω)ω−min(ω),
其中
ω
^
\hat\omega
ω^为变换后特征向量,
ω
\omega
ω为原始特征,他们都是一维向量,长度为N。
m
a
x
(
ω
)
max(\omega)
max(ω)和
m
i
n
(
ω
)
min(\omega)
min(ω)分别表示该维度上特征的最大值和最小值。
标准归一化: 将每一个维特征都调整为均值为0,方差为1。继续假设有N个训练样本{x1,x2,……xN},若要对某一维度的特征进行标准归一化,需要先求出该维特征在这N个数据上的均值
μ
\mu
μ和方差
σ
2
\sigma^2
σ2。则缩放的特征为
ω
^
=
ω
−
μ
σ
\hat\omega=\frac{\omega-\mu}{\sigma}
ω^=σω−μ这里σ不能为0。如果方差为0,说明这一维特征没有任务区分性,可以直接删掉这个特征。
2、批量归一化&层归一化
神经网络都是多层结构,上一层 的输出即为下一层的输入,所以即使输入数据做了归一化,由于经过了线性变换以及激活函数,下一层的输入在取值范围可能又会有比较大的差别。从机器学习角度来看,如果某个神经层的输入分布发生了改变,那么其参数需要重新学习,这种现象叫做内部协变量偏移(Internal Covariate Shift)。
在传统机器学习中, 一个常见的问题是协变量偏移(Covariate Shift)。协变量是一个统计学概念,是可能影响预测结果的统计变量。在机器学习中,协变量可以看作是输入。一般的机器学习算法都要求输入在训练集和测试集上的分布是相似的。如果不满足这个假设,在训练集上学习到的模型在测试集上的表现会比较差。
为了解决内部协变量偏移问题,就要使得每一个神经层的输入的分布在训练过程中保持一致,最简单有效的方法就是逐层归一化。
批量归一化: 批量归一化(Batch Normalization)是对神经层中单个神经元进行归一化。
我们单从第
l
l
l层第
i
i
i个神经元来看,其输入为
z
i
l
=
W
,
i
a
l
−
1
z^l_i=W_{,i}a^{l-1}
zil=W,ial−1,输出为
a
i
l
a^l_i
ail;要避免协变量偏移,就得对
z
i
l
z^l_i
zil进行归一化,即归一化进行在线性变化之后,激活函数之前,一般都用标准正态分布。
理想的情况是知道所有训练数据的
z
i
l
z^l_i
zil,但是我们现在用的最多的是小批量梯度下降法,没法再迭代过程中知道所有的
z
i
l
z^l_i
zil,所以只能用batch size个数据来估计近似。假设有batch size=N,则N个训练数据的输入
z
i
l
z^l_i
zil分别为
{
z
i
l
(
1
)
,
z
i
l
(
2
)
…
…
z
i
l
(
N
)
}
\{z^l_i(1),z^l_i(2)……z^l_i(N)\}
{zil(1),zil(2)……zil(N)}先求出均值
μ
\mu
μ和方差
σ
2
\sigma^2
σ2
μ
=
1
N
∑
n
=
1
N
z
i
l
(
n
)
\mu={\frac{1}{N}}{\sum_{n=1}^{N}z^l_i(n)}
μ=N1n=1∑Nzil(n)
σ
2
=
1
N
∑
n
=
1
N
[
z
i
l
(
n
)
−
μ
]
2
\sigma^2={\frac{1}{N}}{\sum_{n=1}^{N}[z^l_i(n)-\mu]^2}
σ2=N1n=1∑N[zil(n)−μ]2再求得归一化的输入为
z
^
i
l
=
z
i
l
−
μ
σ
\hat z^l_i=\frac{z^l_i-\mu}{\sigma}
z^il=σzil−μ对净输入
z
i
l
z^l_i
zil的标准归一化会使得其取值集中到0附近,如果使用sigmoid型激活函数时,这个取值区间刚好是接近线性变换的区间,减弱了神经网络的非线性性质。因此,为了使得归一化不对网络的表示能力造成负面影响,可以通过一个附加的缩放和平移变换改变取值区间。
z
^
i
l
=
z
i
l
−
μ
σ
2
+
ϵ
∗
γ
+
β
\hat z^l_i=\frac{z^l_i-\mu}{\sqrt{\sigma^2+\epsilon}}*\gamma+\beta
z^il=σ2+ϵzil−μ∗γ+β其中
γ
\gamma
γ 和
l
β
l\beta
lβ分别代表缩放和平移的参数向量,是需要学习的。
层归一化: 批量归一化是对一个中间层的单个神经元进行归一化操作,因此要求小批量样本的数量不能太小,否则难以计算单个神经元的统计信息。层归一化(Layer Normalization)是和批量归一化非常类似的方法。和批量归一化不同的是,层归一化是对某一层的所有神经元进行归一化。
假设某一层有M个神经元,那么该层的输入
z
l
z^l
zl为
{
z
1
l
,
z
2
l
,
…
…
,
z
M
l
}
\{z^l_1,z^l_2,……,z^l_M \}
{z1l,z2l,……,zMl}其均值为
μ
=
1
M
∑
m
=
1
M
z
m
l
\mu={\frac{1}{M}}{\sum_{m=1}^{M}z^l_m}
μ=M1m=1∑Mzml其方差为
σ
2
=
1
M
∑
m
=
1
M
(
z
m
l
−
μ
)
2
\sigma^2={\frac{1}{M}}{\sum_{m=1}^{M}(z^l_m-\mu)^2}
σ2=M1m=1∑M(zml−μ)2与批量归一化类似,层归一化也得附加一个缩放和平移变换的取值区间,操作方法与批量归一化一样,不再赘述。
注意与批量归一化的区别:批量归一化是不同训练数据之间对单个神经元的归一化,层归一化是单个训练数据对某一层所有神经元之间的归一化。 所以,应当注意这两个“之间”,搞清楚到底是谁与谁进行求平均、方差,乃至归一化。
BN和LN最大的好处就是使得网络中每层输入数据的分布相对稳定,加速模型学习速度。
欢迎留言讨论~
[1]https://nndl.github.io/
[2]https://zhuanlan.zhihu.com/p/55852062