文章目录
深度神经网络训练过程中,各网络层参数在不断变化,每层网络的输入分布不断变化 ,不同的输入分布可能需重新训练,此外,我们也不得不使用 较小的参数初始化、较小的学习率 训练模型,避免网络输出陷入饱和区,造成BP算法的梯度消失,深度模型一般难以训练。
作者称这种内部网络层输入分布变化的现象为“Internal Covariate Shift”,作者提出Batch Normalization, BN算法解决Internal Covariate Shift和输出饱和问题 ,使训练速度加快,算法的特点是:
- 允许使用较大的学习率训练模型,允许使用较大的参数初始化模型,经过BN处理后的输入,基本不会处于激活函数饱和区
- 自带正则化,与dropout类似,它为每个隐藏层的输入增加了噪声,这意味着我们可使用更少的dropout
- 模型收敛速度显著加快,ImageNet数据集分类任务使用BN,以7%的训练步数达到相同的表现
为什么要使用BN?
使用mini-batch SGD训练模型的好处?在batch使用SGD是深度网络模型训练的主流方法,如Adagrad等,这种方法是模型在每个step在batch上的损失更新模型参数,随着batch size增加,训练效果也会增加,此外,通过batch方式训练,也可以利用到现代的计算平台实现并行计算,如GPU的核心数为2的n次方,将batch size设置为2的n次方,往往可以获得更快的训练速度。
使用SGD训练模型存在的问题?由于每层网络的输入受前面所有层网络的参数影响,这可能导致前层网络参数较小变化,多数神经元位于非饱和区(梯度爆炸),后层网络变化很大,又或者前层网络较大变化,某些神经元陷入饱和区(梯度消失),后层网络变化很小(前面波涛汹涌,后面波澜不惊)。
为什么要规范化网络层输入分布?当每层网络输入分布变化,意味着每层网络要不断地适应新的分布,这是一种“covariate shift”现象,其实这个协变量移位的概念可以扩展至整个学习系统之外,如子网络或者神经网络中的一层:
ℓ
=
F
2
(
F
1
(
u
,
Θ
1
)
,
Θ
2
)
\ell=F_2(F_1(u, \Theta_1), \Theta_2)
ℓ=F2(F1(u,Θ1),Θ2)
式中
F
1
,
F
2
F_1,F_2
F1,F2可以是任意变换,参数
Θ
1
,
Θ
2
\Theta_1,\Theta_2
Θ1,Θ2通过最小化损失
ℓ
\ell
ℓ学习得到。
如果将
x
=
F
1
(
u
,
Θ
1
)
x=F_1(u,\Theta_1)
x=F1(u,Θ1)看作为子网络的输入,则参数
Θ
2
\Theta_2
Θ2的过程可看作为(batch size=
m
m
m,learning rate=
α
\alpha
α)
ℓ
=
F
2
(
x
,
Θ
2
)
,
Θ
2
←
Θ
2
−
α
m
∑
i
=
1
m
∂
F
2
(
x
i
,
Θ
2
)
∂
Θ
2
\ell = F_2(x, \Theta_2),\quad \Theta_2 \leftarrow \Theta_2 - \frac{\alpha}{m}\sum_{i=1}^m \frac{\partial F_2(x_i,\Theta_2)}{\partial \Theta_2}
ℓ=F2(x,Θ2),Θ2←Θ2−mαi=1∑m∂Θ2∂F2(xi,Θ2)
这完全等价于以
x
x
x作为输入训练独立的网络
F
2
F_2
F2,我们都知道 训练集和测试集具有相同分布是模型可有效训练的前提,其实这也适用于训练子网络或子层,如果能保持每次训练时,输入
x
x
x的分布相同,则在学习参数
Θ
2
\Theta_2
Θ2时,就不必补偿因
x
x
x分布变化带来的影响。
如何解决深层网络训练的梯度消失问题?考虑sigmoid激活函数
z
=
g
(
W
u
+
b
)
,
g
(
x
)
=
1
1
+
e
−
x
z=g(Wu+b),\quad g(x)=\frac{1}{1+e^{-x}}
z=g(Wu+b),g(x)=1+e−x1
随着输入绝对值
∣
x
∣
|x|
∣x∣的增大,梯度
g
′
(
x
)
g'(x)
g′(x)趋于0,意味着
x
=
W
u
+
b
x=Wu+b
x=Wu+b的所有维度,除非该维度绝度值较小,否则该维度流向
u
u
u的梯度将消失,模型训练减缓。由于输入
x
x
x受前面所有层参数的影响,改变前面层参数,很小可能将
x
x
x的许多维度推向饱和区,这种现象在深层网络中尤其明显,在实践过程中,使用 ReLU激活函数并小心地初始化参数,可以较好的避免饱和问题。
如何使得网络层的每次输入分布一致且避免输出饱和,从而加速训练?基于此,提出 Batch Normalization 方法,将输入分布规范化为标准正太分布,解决以上问题。
怎样使用BN?
参照图像处理领域以 白化(whitening, 像素值线性变化至0均值、1方差) 加速训练的方式,Batch Normalization对神经网络的每一层或一些层的输入执行 “白化” 操作,固定输入分布,从而降低Internal Covariate Shift的影响。
白化在数据预处理过程中的目的:
- 去除特征间相关性,使得特征独立;
- 使得所有特征具有相同的均值和方差,特征同分布;
对包含规范化的网络层使用SGD训练会出现什么问题?对于包含Batch Norm的优化过程,优化器在使用SGD更新模型参数时,可能会以一种要求规范化更新(去规范化) 的形式更新参数,从而尽可能地加快训练过程!
举例来说,对于一个简单的网络层,输入为
u
u
u,偏差为
b
b
b,以下列方式得到规范化后输入
x
^
\hat x
x^:
x
^
=
x
−
E
[
x
]
,
x
=
u
+
b
,
E
[
x
]
=
1
N
∑
i
=
1
N
x
i
,
X
=
{
x
1...
N
}
\hat x=x -\Bbb E[x], \quad x=u+b, \quad \Bbb E[x]=\frac{1}{N}\sum_{i=1}^N x_i,\quad \mathcal X=\{x_{1...N}\}
x^=x−E[x],x=u+b,E[x]=N1i=1∑Nxi,X={x1...N}
假如期望
E
[
x
]
\Bbb E[x]
E[x]和偏差
b
b
b无依赖关系,则偏差
b
b
b的更新公式为
b
←
b
+
Δ
b
=
b
−
∂
ℓ
∂
x
^
∂
x
^
∂
b
=
b
−
∂
ℓ
∂
x
^
b\leftarrow b +\Delta b = b - \frac{\partial\ell}{\partial\hat x}\frac{\partial\hat x}{\partial b}=b-\frac{\partial\ell}{\partial\hat x}
b←b+Δb=b−∂x^∂ℓ∂b∂x^=b−∂x^∂ℓ
因此,
u
+
(
b
+
Δ
b
)
−
E
[
u
+
(
b
+
Δ
b
)
]
=
u
+
b
−
E
[
u
+
b
]
u+(b+\Delta b)-\Bbb E[u+(b+\Delta b)]=u+b-\Bbb E[u+b]
u+(b+Δb)−E[u+(b+Δb)]=u+b−E[u+b]
从更新前后结果可以看到,
b
b
b值的更新不会影响网络输出,当然也不会降低总体损失! 当我们在梯度下降过程之外进行参数规范化时,
b
b
b值可能无限制增长,导致模型blows up! 发生这一问题的原因在于,优化器未考虑到某些参数进行了规范化,也就是说损失函数中不包含某些参数的规范化项。
如何让优化器考虑到所有参数的规范化?如果对于任意参数,网络总是能以期望的分布产生激活值,也就是说 损失函数对模型参数的梯度应考虑模型参数的规范化,或者说模型参数的规范化依赖于模型参数。
令向量
x
x
x表示网络层输入,
X
\mathcal X
X是训练样本集,规范化输入
x
x
x可表示为
x
^
=
Norm
(
x
,
X
)
\hat x =\text{Norm}(x,\mathcal X)
x^=Norm(x,X)
如果
x
x
x是其它网络层的输出,则规划范项
x
^
\hat x
x^不仅依赖于
x
x
x,而且依赖于
X
\mathcal X
X中的每一个训练样本,因为经过多次迭代,每个训练样本都对
x
x
x产生过作用!在使用BP算法优化参数时,需分别计算
Norm
\text{Norm}
Norm关于
x
x
x和
X
\mathcal X
X的雅可比矩阵,如果忽略后项,很可能造成上述 模型爆炸 的现象。计算规范化项对训练集的雅可比矩阵计算量太大,Batch Norm算法基于整个训练集的统计信息,对一个训练样本进行规范化。
如何有效地实现BN?
第一种简单化处理:对输入向量
x
x
x的每一维独立地进行标准化(0均值、1方差规范化)
x
^
(
k
)
=
x
(
k
)
−
E
[
x
(
k
)
]
V
a
r
[
x
(
k
)
]
\hat x^{(k)}=\frac{x^{(k)}-\Bbb E[x^{(k)}]}{\sqrt{Var [x^{(k)}]}}
x^(k)=Var[x(k)]x(k)−E[x(k)]
其中,期望和方差是在整个训练集中计算得到的。
此外,对每层网络都进行简单的标准化,可能会降低模型的非线性表达能力,如对sigmoid的输入标准化,目的是把一些绝对值较大的非线性区值拉回到线性区,增大导数值,因此最终大多数点被约束在[-2, 2]区间,相当于仅利用与sigmoid函数的近似线性部分:
Batch Normlization对规范化后的值在进行缩放和平移解决这个问题:
y
(
k
)
=
γ
(
k
)
x
^
(
k
)
+
β
(
k
)
y^{(k)}=\gamma^{(k)}\hat x^{(k)}+\beta^{(k)}
y(k)=γ(k)x^(k)+β(k)
模型可以学习变量
γ
\gamma
γ和
β
\beta
β,以恢复模型的非线性表达能力,每个神经元都有自己独特的伸缩、平移参数。特别地,当
γ
\gamma
γ等于标准差、
β
\beta
β等于期望时,模型等价于没有进行规范化,这赋予了模型自我控制规范化的自由度! 换一种角度来看,引入这两个变量之后,使得优化器仅通过修改这两个参数 去规范化,而不是调整可能会降低网络稳定性的网络权重参数。
第二种简单化处理:在每个mini-batch内部估计每次激活的均值和方差。 y i y_i yi 可看作为 x i x_i xi规范化后的值,易证整个Norm过程可微,因此可以使用BP更新网络参数。
BN的实现见算法1。
如何训练和推理使用BN的网络?
在训练过程中,若mini-batch的样本数大于1,我们都可以使用batch norm有效地训练网络,但在推理过程中,mini-batch可能仅有一个样本,因此,使用以下公式规范化输入
x
^
=
x
−
E
[
x
]
Var
[
x
]
+
ϵ
\hat x = \frac{x-\Bbb E[x]}{\sqrt{\text{Var}[x]+\epsilon}}
x^=Var[x]+ϵx−E[x]
与训练过程不同的是,上式中期望和方差都是训练集总体的统计量,若迭代次数为
m
m
m,则 无偏统计量
E
[
x
]
=
E
B
[
μ
B
]
,
Var
[
x
]
=
m
m
−
1
⋅
E
B
[
σ
B
2
]
\Bbb E[x]=\Bbb E_{\mathcal B}[\mu_{\mathcal B}],\quad \text{Var}[x]=\frac{m}{m-1}\cdot \Bbb E_{\mathcal B}[\sigma^2_{\mathcal B}]
E[x]=EB[μB],Var[x]=m−1m⋅EB[σB2]
推理和训练过程见算法2。
BN作用在神经元的输入侧还是输出侧?
Batch Normalization 可以应用于网络的任一组激活 ,我们考虑element-wise非线性变化
z
=
g
(
W
u
+
b
)
z=g(Wu+b)
z=g(Wu+b)
g
(
⋅
)
g(·)
g(⋅)为非线性映射,如ReLU或者sigmiod。
我们可以将BN作用于非线性变换之前,即规范化 x = W u + b x=Wu+b x=Wu+b,同样 可以将BN作用于 u u u,但是 u u u很可能是另一非线性函数的输出,在训练过程中其分布形状可能会发生改变,而且约束其一、二阶矩并不能消除协变量转移???
相比较,
W
u
+
b
Wu+b
Wu+b更有可能具有对称性、非稀疏分布性,即更加具有“高斯特性”,因此规范化此部分,很可能获得我们想要的稳定分布。如果我们规范化
W
u
+
b
Wu+b
Wu+b,则 可以忽略偏差项
b
b
b,因为它的作用会在均值相减时被抵消,因此网络层的规范化可表示为
z
=
g
(
BN
(
W
u
)
)
z=g(\text{BN}(Wu))
z=g(BN(Wu))
为什么BN网络可以使用更高的学习率?
传统深层网络使用较大的学习率训练模型,可能 造成梯度消失、梯度爆炸或陷入局部极小点,而BN可阻止输入进入激活函数的饱和区,从而避免这些问题。
从另一个角度来看,伸缩变化网络权重参数,不影响BN输出,对于确定的标量
a
a
a:
BN
(
W
u
)
=
BN
(
(
a
W
)
u
)
\text{BN}(Wu)=\text{BN}((aW)u)
BN(Wu)=BN((aW)u)
梯度为
∂
BN
(
(
a
W
)
u
)
∂
u
=
∂
BN
(
W
u
)
∂
u
∂
BN
(
(
a
W
)
u
)
∂
a
W
=
1
a
⋅
∂
BN
(
W
u
)
∂
W
\begin{aligned} \frac{\partial \text{BN}((aW)u)}{\partial u} & =\frac{\partial \text{BN}(Wu)}{\partial u}\\[2ex] \frac{\partial \text{BN}((aW)u)}{\partial aW} & =\frac{1}{a}·\frac{\partial \text{BN}(Wu)}{\partial W} \end{aligned}
∂u∂BN((aW)u)∂aW∂BN((aW)u)=∂u∂BN(Wu)=a1⋅∂W∂BN(Wu)
为什么BN网络自带正则化效果?
BM相当于对神经元的输入进行平移和缩放,而平移和缩放的大小仅在当前mini-batch中计算得到,等价于对神经元的输入增加了噪音,dropout也有增加噪音的作用。
The stochasticity from the batch statistics serves as a regularizer during training. (From Layer Normalization)
换一种角度来看,神经元的输入值是经过在mini-batch中标准化后得到的,具有样本结合性,神经网络不再需要为单一训练样本生成一个特定值,这种效应有利于模型的泛化,在 BN网络中Dropout似乎可以减少强度或者移除。
BN在Tensorflow中的实现
主要与原论文的区别在于,每次迭代以滑动平均的方式将mini-batch的均值和方差更新到总体!
以下仅展示BN的实际过程,batch_size=8,hidden_size=3:
import tensorflow as tf
x = tf.reshape(tf.range(24, dtype=tf.float32), shape=(8, 3))
"""
<tf.Tensor: id=1269, shape=(8, 3), dtype=float32, numpy=
array([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.],
[12., 13., 14.],
[15., 16., 17.],
[18., 19., 20.],
[21., 22., 23.]], dtype=float32)>
"""
"""
axis: Integer, the axis that should be normalized (typically the features axis).
For instance, after a `Conv2D` layer with `data_format="channels_first"`, set `axis=1` in `BatchNormalization`.
"""
bn = tf.keras.layers.BatchNormalization(axis=1)
# training
bn(x, training=True)
"""
<tf.Tensor: id=1397, shape=(8, 3), dtype=float32, numpy=
array([[-1.5275091 , -1.5275091 , -1.5275091 ],
[-1.0910779 , -1.0910779 , -1.0910779 ],
[-0.65464675, -0.65464675, -0.65464675],
[-0.21821558, -0.21821558, -0.21821558],
[ 0.21821558, 0.21821558, 0.21821558],
[ 0.65464675, 0.65464675, 0.65464675],
[ 1.0910779 , 1.0910779 , 1.0910779 ],
[ 1.5275091 , 1.5275091 , 1.5275091 ]], dtype=float32)>
"""
# inference
bn(x)
"""
<tf.Tensor: id=1433, shape=(8, 3), dtype=float32, numpy=
array([[-0.08679464, 0.73155487, 1.5499043 ],
[ 2.3930523 , 3.2114017 , 4.0297513 ],
[ 4.872899 , 5.6912484 , 6.5095983 ],
[ 7.352746 , 8.171096 , 8.989445 ],
[ 9.832593 , 10.650943 , 11.469292 ],
[12.31244 , 13.13079 , 13.949139 ],
[14.792287 , 15.610637 , 16.428986 ],
[17.272135 , 18.090483 , 18.908833 ]], dtype=float32)>
"""
Reference
1. Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
2. 详解深度学习中的Normalization,BN/LN/WN
3.【深度学习】深入理解Batch Normalization批标准化