Dropout和BN(Batch Normalization)分析
文章目录
简介:无论是机器学习,还是深度学习,模型过拟合是很常见的问题,解决手段无非是两个层面,一个是算法层面,一个是数据层面。数据层面一般是使用 数据增强手段,算法层面不外乎是: 正则化、模型集成、earlystopping、 dropout、 BN等,本文重点详细讲解一下dropout和BN。
Dropout
参考:[深度学习中Dropout原理解析 - 知乎 (zhihu.com)](https://blog.csdn.net/qq_40176087/article/details/105904379)
1.背景
在2012年,Hinton在其论文《Improving neural networks by preventing co-adaptation of feature detectors》中提出Dropout。当一个复杂的前馈神经网络被训练在小的数据集时,容易造成过拟合。Dropout可以作为训练深度神经网络的一种trick供选择,在每次训练批次中,通过忽略一部分的特征检测器(让一部分隐藏节点值为0),可以明显减少过拟合现象。
简单来说:在(训练阶段)前向传播过程中,让某些神经元的激活值以一定的概率p停止工作,这样可以使模型泛化能力增强,并且减少训练时间。
2.具体工作流程
假设我们需要训练以下神经网络:
输入是x,输出是y,正常的流程是:首先把x通过网络前向传播,然后把误差反向传播以更新参数。
在使用Dropout之后,过程变成如下:
(1) 首先随机(临时)删掉网络中一半的隐藏神经元,输入输出神经元保持不变
(2) 然后把输入x通过修改后的网络前向传播,然后把得到的损失结果通过修改的网络反向传播,当前批训练样本执行完这个过程后,在没有被删除的神经元上按照随机梯度下降法更新对应参数 ( w , b ) (w,b) (w,b)
(3) 重复下述过程
- 恢复被删除的神经元
- 从隐藏层神经元中随机选择一个一般大小的子集临时删除掉(备份被删除的神经元参数)
- 对下一批训练样本进行训练(先前向传播后后向传播损失并根据随机梯度下降法更新参数 ( w , b ) (w,b) (w,b))
不断重复上述过程。
3.Dropout在神经网络中的使用
本部分将从代码层面的公式推导进行讲解
(1) 训练阶段
对应的公式变化如下:
- Standard network
z i l + 1 = w i l + 1 y l + b i l + 1 , y i l + 1 = f ( z i l + 1 ) z_i^{l+1}=w_i^{l+1}y^l+b_i^{l+1}, \\ y_i^{l+1}=f(z_i^{l+1}) zil+1=wil+1yl+bil+1,yil+1=f(zil+1)
- Dropout network
r j ( l ) ∼ B e r n o u l l i ( p ) y ^ l = r ( l ) ∗ y ( l ) z i l + 1 = w i l + 1 y ^ l + b i l + 1 , y i l + 1 = f ( z i l + 1 ) r^{(l)}_j \sim Bernoulli(p) \\ \hat{y}^l=r^{(l)}*y^{(l)} \\ z_i^{l+1}=w_i^{l+1}\hat{y}^l+b_i^{l+1}, \\ y_i^{l+1}=f(z_i^{l+1}) rj(l)∼Bernoulli(p)y^l=r(l)∗y(l)zil+1=wil+1y^l+bil+1,yil+1=f(zil+1)
上面公式中Bernoulli函数是为了生成概率r向量,也就是随机生成一个0、1的向量。
代码层面实现让某个神经元以概率p停止工作,其实就是让它的激活函数值以概率p变为0。比如我们某一层网络神经元的个数为1000个,其激活函数输出值为 y 1 、 y 2 、 y 3 、 . . . . . . 、 y 1 000 y_1、y_2、y_3、......、y_1000 y1、y2、y3、......、y1000,我们dropout比率选择0.4,那么这一层神经元经过dropout后,1000个神经元中会有大约400个的值被置为0。
**注意:**屏蔽神经元后,还需要对向量 y 1 、 y 2 、 y 3 、 . . . . . . 、 y 1 000 y_1、y_2、y_3、......、y_1000 y1、y2、y3、......、y1000进行缩放,乘以 1 1 − p \frac{1}{1-p} 1−p1,如果在训练的时候,经过置0后,没有对向量进行缩放,那么在测试时就需要对权重进行缩放,如下:
(2) 测试阶段
预测模型的时候,每一个神经单元的权重参数要乘以概率p。
测试阶段
w
t
e
s
t
(
l
)
=
p
W
(
l
)
w_{test}^{(l)}=pW^{(l)}
wtest(l)=pW(l)
4.dropout防止过拟合的原因
- 随机删掉一半隐藏神经元导致网络结构已经不同,整个dropout过程就相当于对很多个不同的神经网络取平均。而不同的网络产生不同的过拟合,在某种程度上相当于模型融合。
- 随机删掉一半隐藏神经元使得需要更新的参数减少,有利于减小过拟合
归一化处理(BN、LN、IN、GN)
参考:Batch Normalization(BN层)详解 - 简书 (jianshu.com)、(28条消息) Dropout和BN(层归一化)详解_谈笑风生…的博客-CSDN博客_层归一化
1.背景
Batch Normalization 出自《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》。
神经网络训练前都需要对输入数据进行归一化处理,原因在于神经网络学习过程本质是为了学习数据分布,一旦训练数据与测试数据的分布不同,那么网络的泛化能力也大大降低;另外一方面,一旦每批训练数据的分布各不相同(batch 梯度下降),那么网络就要在每次迭代都去学习适应不同的分布,这样将会大大降低网络的训练速度。
2.四种归一化
在深度学习中,有多种归一化,接下来,我们先用一个示意图来形象的表现BN、LN、IN和GN的区别,在输入图片的维度为(NCHW)中,HW是被合成一个维度,这个是方便画出示意图,C和N各占一个维度。
Batch Normalization
1.BN的计算就是把每个通道的NHW单独拿出来归一化处理
2.针对每个channel我们都有一组γ,β,所以可学习的参数为2*C
3.当batch size越小,BN的表现效果也越不好,因为计算过程中所得到的均值和方差不能代表全局
Layer Normalizaiton
1.LN的计算就是把每个CHW单独拿出来归一化处理,不受batchsize 的影响
2.常用在RNN网络,但如果输入的特征区别很大,那么就不建议使用它做归一化处理
Instance Normalization
1.IN的计算就是把每个HW单独拿出来归一化处理,不受通道和batchsize 的影响
2.常用在风格化迁移,但如果特征图可以用到通道之间的相关性,那么就不建议使用它做归一化处理
Group Normalizatio
1.GN的计算就是把先把通道C分成G组,然后把每个gHW单独拿出来归一化处理,最后把G组归一化之后的数据合并成CHW
2.GN介于LN和IN之间,当然可以说LN和IN就是GN的特列,比如G的大小为1或者为C
BN、LN、IN和GN这四个归一化的计算流程几乎是一样的,可以分为四步:
1.计算出均值
2.计算出方差
3.归一化处理到均值为0,方差为1
4.变化重构,恢复出这一层网络所要学到的分布
μ
B
←
1
m
∑
i
=
1
m
x
i
σ
B
2
←
1
m
∑
i
=
1
m
(
x
i
−
μ
B
)
2
x
^
i
←
x
i
−
μ
B
σ
B
2
+
ϵ
y
i
←
γ
x
^
i
+
β
≡
B
N
γ
,
β
(
x
i
)
\begin{aligned} \mu_{\mathcal{B}} & \leftarrow \frac{1}{m} \sum_{i=1}^{m} x_{i} \\ \sigma_{\mathcal{B}}^{2} & \leftarrow \frac{1}{m} \sum_{i=1}^{m}\left(x_{i}-\mu_{\mathcal{B}}\right)^{2} \\ \widehat{x}_{i} & \leftarrow \frac{x_{i}-\mu_{\mathcal{B}}}{\sqrt{\sigma_{\mathcal{B}}^{2}+\epsilon}} \\ y_{i} & \leftarrow \gamma \widehat{x}_{i}+\beta \equiv \mathrm{BN}_{\gamma, \beta}\left(x_{i}\right) \end{aligned}
μBσB2x
iyi←m1i=1∑mxi←m1i=1∑m(xi−μB)2←σB2+ϵxi−μB←γx
i+β≡BNγ,β(xi)
源码实现
m = K.mean(X, axis=-1, keepdims=True)#计算均值
std = K.std(X, axis=-1, keepdims=True)#计算标准差
X_normed = (X - m) / (std + self.epsilon)#归一化
out = self.gamma * X_normed + self.beta#重构变换
3.训练时BN
训练的时候,是根据输入的每一批数据来计算均值和方差
那么测试的时候,其实网络一旦训练完毕,参数都是固定的。对于均值来说直接计算所有训练时batch均值的平均值;然后对于标准偏差采用每个batch方差的无偏估计。
E
[
x
]
←
E
B
[
μ
B
]
V
a
r
[
x
]
←
m
m
−
1
E
B
[
σ
B
2
]
E[x] \leftarrow E_{\mathcal{B}}[\mu_{\mathcal{B}}] \\ Var[x] \leftarrow \frac{m}{m-1}E_{\mathcal{B}}[\sigma_{\mathcal{B}}^{2}]
E[x]←EB[μB]Var[x]←m−1mEB[σB2]
最终测试阶段,BN的使用公式是
y
=
γ
Var
[
x
]
+
ϵ
⋅
x
+
(
β
−
γ
E
[
x
]
Var
[
x
]
+
ϵ
)
y=\frac{\gamma}{\sqrt{\operatorname{Var}[x]+\epsilon}} \cdot x+\left(\beta-\frac{\gamma \mathrm{E}[x]}{\sqrt{\operatorname{Var}[x]+\epsilon}}\right)
y=Var[x]+ϵγ⋅x+(β−Var[x]+ϵγE[x])
4.BN在CNN中的使用
卷积神经网络经过卷积后得到的是一系列的特征图,如果min-batch sizes为m,那么网络某一层输入数据可以表示为四维矩阵(m,f,p,q),m为min-batch sizes,f为特征图个数,p、q分别为特征图的宽高。在CNN中,可以把每个特征图看成是一个特征处理(一个神经元),因此在使用Batch Normalization,mini-batch size的大小就是 m × p × q m \times p \times q m×p×q,于是对于每个特征图都只有一对可学习参数:γ、β.
相当于求取所有样本所对应的一个特征图的所有神经元的平均值、方差,将每个特征图神经元做归一化。
以下是keras卷积层的BN实现一部分源码
input_shape = self.input_shape
reduction_axes = list(range(len(input_shape)))
del reduction_axes[self.axis]
broadcast_shape = [1] * len(input_shape)
broadcast_shape[self.axis] = input_shape[self.axis]
if train:
m = K.mean(X, axis=reduction_axes)
brodcast_m = K.reshape(m, broadcast_shape)
std = K.mean(K.square(X - brodcast_m) + self.epsilon, axis=reduction_axes)
std = K.sqrt(std)
brodcast_std = K.reshape(std, broadcast_shape)
mean_update = self.momentum * self.running_mean + (1-self.momentum) * m
std_update = self.momentum * self.running_std + (1-self.momentum) * std
self.updates = [(self.running_mean, mean_update),
(self.running_std, std_update)]
X_normed = (X - brodcast_m) / (brodcast_std + self.epsilon)
else:
brodcast_m = K.reshape(self.running_mean, broadcast_shape)
brodcast_std = K.reshape(self.running_std, broadcast_shape)
X_normed = ((X - brodcast_m) /
(brodcast_std + self.epsilon))
out = K.reshape(self.gamma, broadcast_shape) * X_normed + K.reshape(self.beta, broadcast_shape)