文章目录
- 0 前言
- 1 全连接神经网络
- 2 激活函数
- 2.1 Sigmoid
- 2.2 Tanh
- 2.3 ReLU
- 2.4 Leaky ReLU
- 3 交叉熵损失
- 4 计算图与反向传播
- 4.1 计算图
- 4.2 梯度消失与梯度爆炸
- 4.3 动量法
- 5 权重初始化
- 5.1 全零初始化
- 5.2 标准随机初始化
- 5.3 Xavier初始化
- 5.4 Kaming初始化
- 6 批归一化
- 7 参考资料
0 前言
本文是公司组内分享的课程笔记,主要参考了北邮鲁鹏老师的《计算机视觉与深度学习》课程,课程视频链接在这里。
上一讲:深度学习基础-1
本讲在上一讲的基础上,更近一步,将分类器替换为了全连接分类器,并围绕全连接分类器介绍了实际训练模型时,常用的知识点。
1 全连接神经网络
首先来回顾一下上一讲的线性分类器f(x)=Wx+bf(x) = Wx + bf(x)=Wx+b,每个类别有一个单独的线性分类器,它只适用于下图1-1所示的线性可分的情况。
线性可分指的是至少存在一个线性分界面 能把两类样本没有错误的分开。
如果我们面临的是线性不可分的问题,该怎么办呢?为了简化问题,我们令xxx只有一维,如图1-2所示,此时无论www和bbb如何变化,都只能变成蓝色分界线所示的情况,永远无法拟合出红色分界面的情况。
为了能够变成红色分界面所示的情况,我们就需要在线性分类器外包一个非线性函数ggg。
f(x)=g(Wx+b)(1-1)f(x) = g(Wx + b) \tag{1-1} f(x)=g(Wx+b)(1-1)
ggg是一个我们可以任意设置的非线性函数,我们可以将其设计成红色分界面的样子,但是,换一个任务,这个ggg就不适用了,根据特定任务来设计ggg是没有通用性的,这不是深度学习的目的。深度学习的目的是模型在数据和任务变更后,只需要根据数据重新训练即可,不需要重新设计模型。也就是我们希望设计的模型可以通过学习拟合任意的函数。
这其实很简单,只需要在非线性函数外,再包一层线性组合即可。
f(x)=W2g(W1x+b1)+b2(1-2)f(x) = W_2 g(W_1 x + b_1) + b_2 \tag{1-2} f(x)=W2g(W1x+b1)+b2(1-2)
也就是说,非线性函数的线性组合可以有更强的非线性表达能力。这种级联了多个变换来实现输入到输出的映射的模型,称为全连接神经网络。式(1−2)(1-2)(1−2)所示的就是两层的神经网络。
两层的神经网络可以表示成下图1-4所示的网络图。麻雀虽小,五脏俱全,图1-4里包含了N层的全连接神经网络中的所有结构。输入层,隐藏层和输出层。输入层和输出层一般只有一层,隐藏层可以有很多层。
只要隐藏层的神经元个数足够多,两层的全连接神经网络理论上可以拟合任意的非线性连续函数。这里的原因,有兴趣的读者可以自行研究一下,这里不展开讲了。
两层的全连接神经网络相比于一层的,出了非线性表达能力更强之外,还有一点单层的全连接神经网络是没法做到的。一层全连接受到输出个数的限制,W1W_1W1权重的维度需要和类别个数保持一致,而二层全连接只需要W2W_2W2和类别个数一致即可, W1W_1W1可以自由控制维度。回想上一讲的内容,调整W1W_1W1等于增加了模板个数,分类器有机会学习到两个方向不同的马的模板,所以二层全连接网络比一层全连接网络表述能力更强。
不难举一反三,三层的全连接神经网络可以画成下图1-5所示的样子,N层的相信读者也就明白是怎么回事了。
同一个隐藏层的非线性函数一般是一样的,不同层的非线性函数可以是不一样的。
既然两层的全连接网络可以拟合任意的函数,我们为什么要N层的全连接网络呢?
因为如果只用两层网络就想表示出所有的函数,那么每一层就需要非常多的神经元,参数和计算量会多到在目前设备上不实用,而且在同样训练数据下,深层网络比两层网络更容易学出效果,因为网络层数每增加一层就会引入一次非线性变换,网络整体的非线性表达就更强,同时相同的节点深层网络对理想预测函数提供了更大的解空间,比如图1-6,经过第一层的6个神经元,第二层的4个神经元,相当于组合了24次非线性变换,如果使用一层,则需要24个神经元。当然,网络层数也不是越多越好,网络最终设计的层数,与设备性能,耗时,数据量都有关。
2 激活函数
每个隐藏层都会有一个非线性函数,这个非线性函数在深度学习中的术语叫做激活函数。激活函数是一种添加到人工神经网络中的函数,它决定了最终要发射给下一个神经元的内容。在人工神经网络中,一个节点的激活函数定义了该节点在给定的输入或输入的集合下的输出。因此,激活函数是确定神经网络输出的数学方程式。
如果不用激活函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合,相当于时多个矩阵相乘的结果。如果使用的话,激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中。
一般输出层可能会使用线性激活函数,但在隐含层(除输入输出外的层)都使用非线性激活函数。
下面介绍几种常用的激活函数:
2.1 Sigmoid
Sigmoid的表达式为
g(x)=11+e−x(2-1)g(x) = \frac{1}{1 + e^{-x}} \tag{2-1} g(x)=1+e−x1(2-1)
其函数图像可以表示为
优点:
- Sigmoid函数的输出在(0,1)之间,输出范围有限,优化稳定,可以用作输出层。
- 连续函数,便于求导。
缺点:
- sigmoid函数在变量取绝对值非常大的正值或负值时会出现饱和现象,意味着函数会变得很平,并且对输入的微小改变会变得不敏感。在反向传播时,当梯度接近于0,权重基本不会更新,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。
- sigmoid函数的输出不是0均值的,会导致后层的神经元的输入是非0均值的信号,这会对梯度产生影响(可以结合图像看下梯度,0附近的梯度是最明显的)。
- 计算复杂度高,因为sigmoid函数是指数形式
2.2 Tanh
Tanh是对Sigmoid输出非0均值的改进,其表达式为
g(x)=ex−e−xex+e−x(2-2)g(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} \tag{2-2} g(x)=ex+e−xex−e−x(2-2)
其函数图像可以表示为
优点:
- Tanh函数是 0 均值的,因此实际应用中 Tanh 会比 sigmoid 更好。
缺点:
- 仍然存在梯度饱和与exp计算复杂度高的问题。
2.3 ReLU
ReLU的表达式为
g(x)=max(0,x)(2-3)g(x) = max(0, x) \tag{2-3} g(x)=max(0,x)(2-3)
其函数图像可以表示为
优点:
- 使用ReLU的SGD算法的收敛速度比 sigmoid 和 tanh 快。
- 在x>0区域上,不会出现梯度饱和、梯度消失的问题。
- 计算复杂度低,不需要进行指数运算,只要一个阈值就可以得到激活值。
缺点:
- ReLU的输出不是0均值的。
- Dead ReLU Problem(神经元坏死现象):ReLU在负数区域被kill的现象叫做dead relu。ReLU在训练的时很“脆弱”。在x<0时,梯度为0。这个神经元及之后的神经元梯度永远为0,不再对任何数据有所响应,导致相应参数永远不会被更新。
2.4 Leaky ReLU
Leaky ReLU是为了解决ReLU负半轴输出为0的问题,其表达式为
g(x)=max(0.1x,x)(2-4)g(x) = max(0.1x, x) \tag{2-4} g(x)=max(0.1x,x)(2-4)
其函数图像可以表示为
优点:
- 使得ReLU在负数区域更偏向于激活而不是死掉。这里的斜率都是确定的。
缺点:
- 有些近似线性,导致在复杂分类中效果不好。
- 输出不是0均值。
3 交叉熵损失
上一讲讲了多类支持向量机损失,这个损失在实际的分类任务中不常使用,这一讲讲一下交叉熵,这才是用的最多的一种分类损失。
先来讲一下什么是Softmax。Softmax将输出的每一个分数都过了指数函数,然后做了归一化,相当于每一个类别输出了模型预测该类别的概率。经过Softmax之后,所有类别的输出求和等于1。
softmax(fi)=efi∑c=1Cefc(3-1)softmax(f_i) = \frac{e^{f_i}}{\sum_{c=1}^{C}e^{f_c}} \tag{3-1} softmax(fi)=∑c=1Cefcefi(3-1)
其示意图如下图3-1所示。
为了便于理解,举一个实际的例子,如下图3-2所示。
那为什么要选择使用指数函数呢?指数函数的优势可以总结为一下几点
(1)指数函数曲线呈现递增趋势,最重要的是斜率逐渐增大,也就是说在x轴上一个很小的变化,可以导致y轴上很大的变化。这种函数曲线能够将输出的数值拉开距离。
(2)直接相加会有负数,Softmax可以处理负数。
(3)指数求导比较方便,(ex)′=ex(e^x)' = e^x(ex)′=ex。
不过指数函数也有缺点,就是容易数值溢出。实际情况下会减去输出值中的最大值。
softmax(fi)=efi−D∑c=1Cefc−D,D=max(f)(3-2)softmax(f_i) = \frac{e^{f_i - D}}{\sum_{c=1}^C e^{f_c - D}}, D = max(f) \tag{3-2} softmax(fi)=∑c=1Cefc−Defi−D,D=max(f)(3-2)
有了Softmax之后,我们相当于有了一个分类器预测的概率分布q(x)q(x)q(x),交叉熵损失要做的事情就是计算预测分布q(x)q(x)q(x)与真实分布p(x)p(x)p(x)之间的距离。对于单标签的问题,真实分布通常是指有一个类别为1,其他类别为0的分布,这也是一种one-hot的表示形式。
下面来解释为什么交叉熵可以度量两个分布之间的距离。
首先来说一下什么是熵。这是信息论当中的一个概念,熵表示了一个事件所包含的信息量。我们时常听到“这句话信息量好大”,其实这么说,都是因为“这句话”所描述的内容发生的概率很小,比如“我不会死”这几个字,包含了巨大的信息量。
信息量用下式(3−3)(3-3)(3−3)来表示,这也叫做自信息
I(x)=−log(p(x))(3-3)I(x) = -log(p(x)) \tag{3-3} I(x)=−log(p(x))(3-3)
信息量满足以下两个性质:
(1)越不可能发生的事件信息量越大
(2)独立事件的信息量可叠加
熵则是自信息在分布ppp熵的期望,如下式(3−4)(3-4)(3−4)所示。
H(p)=Ex−p(I(x))=−∑xp(x)log(p(x))(3-4)H(p) = E_{x - p}(I(x)) = -\sum_x p(x)log(p(x)) \tag{3-4} H(p)=Ex−p(I(x))=−x∑p(x)log(p(x))(3-4)
熵有两个特点:
(1)那些接近确定性的分布(输出几乎可以确定)具有较低的熵。
(2)那些接近均匀分布的概率分布具有较高的熵。
熵只是一个分布的自嗨,并不能度量两个分布之间的距离。KL散度在熵的基础上,更进一步,衡量了两个分布的距离
KL(p∣∣q)=∑ip(xi)log(p(xi)q(xi))=∑ip(xi)(log(p(xi))−log(q(xi)))(3-5)KL(p||q) = \sum_i p(x_i)log(\frac{p(x_i)}{q(x_i)})=\sum_ip(x_i)(log(p(x_i))−log(q(x_i))) \tag{3-5} KL(p∣∣q)=i∑p(xi)log(q(xi)p(xi))=i∑p(xi)(log(p(xi))−log(q(xi)))(3-5)
KL(p∣∣q)KL(p||q)KL(p∣∣q)也就是p与q之间的对数差在p上的期望值。
KL散度有三个特点:
(1)KL散度是非负的
(2)KL散度为0,当且仅当A和B在离散型变量的情况下是相同的分布
(3)KL 散度不是真的距离,它不是对称的,即KL(p∣∣q)≠KL(q∣∣p)KL(p||q) ≠ KL(q||p)KL(p∣∣q)=KL(q∣∣p)
其实有了KL散度就可以计算损失了,但是为了简化计算,还是引入了交叉熵。再回忆一下,ppp是真实分布,qqq是预测分布,回看式(3−5)(3-5)(3−5),既然p(xi)p(x_i)p(xi)是常量,那p(xi)log(p(xi))p(x_i)log(p(x_i))p(xi)log(p(xi))也就是常量了,前面是真实分布的熵,是可以省略的,省略之后就是交叉熵了
H(p,q)=−∑xp(x)log(q(x))(3-6)H(p, q) = -\sum_x p(x)log(q(x)) \tag{3-6} H(p,q)=−x∑p(x)log(q(x))(3-6)
交叉熵和熵与KL散度的关系为
H(p,q)=H(p)+KL(p∣∣q)(3-7)H(p, q) = H(p) + KL(p||q) \tag{3-7} H(p,q)=H(p)+KL(p∣∣q)(3-7)
交叉熵具有三个特点:
(1)交叉熵是非负的
(2)和KL散度相同,交叉熵也不具备对称性,即H(p,q)≠H(q,p)H(p, q)≠H(q, p)H(p,q)=H(q,p)
(3)对同一个分布求交叉熵等于对其求熵
说完了交叉熵损失,来对比一下交叉熵损失与上一讲中的多类支持向量机损失。为了方便回忆,下图3-4给出了两者的计算示例。
不过,交叉熵损失到底比多类支持向量机损失好在哪里?如下图3-5所示,多类支持向量机损失只要满足真实标签的预测分数比其他标签预测分数大1就行了,但是当分数值比较大的时候,1并不能拉开真实类别与其他类别的预测分数,预测的分布接近于均匀分布,这个时候,使用交叉熵就可以有比较大的损失了,交叉熵会迫使真实标签的预测分数远大于其他标签的预测分数。
4 计算图与反向传播
4.1 计算图
当网络变成两层甚至N层的时候,复合函数的求导就会变得异常复杂。不同的损失或网络,每次都要重新手动编写导数解析式的话,容易出错,也太麻烦,因此,就有了计算图。
计算图是一种有向图,它用来表达输入、输出以及中间变量之间的计算关系,图中的每个节点对应着一种数学运算。目的是将复合函数拆成多个简单的基本单元。下图是f(x)=(x+y)2f(x)=(x+y)^2f(x)=(x+y)2的计算图示例。
每一个圆圈表示一种门运算,只要定义好了基础的门运算,就可以表示任意的复合函数。
有了计算图之后,求导也是只需要每个门单独求导就可以了,最终的导数就是每个门运算导数的连乘,这要得益于链式法则。下图4-2是当x=1x=1x=1且y=2y=2y=2时的计算图求导。链式法则是反向传播的基本传递方式。
再来看一个更加复杂的例子,如图4-3,sigmoid函数也可以很轻松地用计算图来表示。
整个正向计算和反向求导的过程,读者可以看着图试试看。
实际情况下,常用的门运算有如下图4-4所示的四种。
4.2 梯度消失与梯度爆炸
由于反向传播当中会有多个导数的累乘,非常容易产生梯度消失或者梯度爆炸的问题。如果网络层之间的梯度值小于1.0,那么重复相乘会导致梯度呈指数级增长,梯度变的非常小,可能接近于0,导致训练极度缓慢(权重变化很小),这种现象叫梯度消失;如果网络层之间的梯度值大于 1.0,那么重复相乘会导致梯度呈指数级增长,梯度变的非常大,然后导致网络权重的大幅更新,并因此使网络变得不稳定甚至出现Nan,这种现象叫梯度爆炸。
深层神经网络隐层数很多,可达几十或一百多隐层,这就是“深”带来的问题。
更直观一点来说,假设我们有如下图4-5所示的神经网络。
对于每一个神经元都有
yi=σ(zi)=σ(wi×xi+bi)(4-1)y_i = \sigma(z_i) = \sigma(w_i \times x_i + b_i) \tag{4-1} yi=σ(zi)=σ(wi×xi+bi)(4-1)
其中,σ(⋅)\sigma(\cdot)σ(⋅)表示sigmoid激活函数。根据链式法则,可以推导出
∂C∂w1=∂C∂y4∂y4∂z4∂z4∂y3∂y3∂z2∂z2∂y1∂y1∂z1∂z1∂w1=∂C∂y4σ′(z4)w4σ′(z3)w3σ′(z2)w2σ′(z1)x1(4-2)\begin{aligned} \frac{\partial C}{\partial w1} &= \frac{\partial C}{\partial y4} \frac{\partial y4}{\partial z4} \frac{\partial z4}{\partial y3} \frac{\partial y3}{\partial z2} \frac{\partial z2}{\partial y1} \frac{\partial y1}{\partial z1} \frac{\partial z1}{\partial w1} \\ &= \frac{\partial C}{\partial y4} \sigma'(z_4) w_4 \sigma'(z_3) w_3 \sigma'(z_2) w_2 \sigma'(z_1) x_1 \end{aligned} \tag{4-2} ∂w1∂C=∂y4∂C∂z4∂y4∂y3∂z4∂z2∂y3∂y1∂z2∂z1∂y1∂w1∂z1=∂y4∂Cσ′(z4)w4σ′(z3)w3σ′(z2)w2σ′(z1)x1(4-2)
sigmoid激活函数的导数如下图4-6所示,可见其最大值也就是0.25。
当初始时wσ(z)<1w\sigma(z)<1wσ(z)<1,经过很多个小于1的数的连乘,最终得到的偏导数远远小于1,甚至接近于零,就产生梯度消失的现象。一般初始化www都是小于1,xxx归一化到[0,1][0,1][0,1]之间,而sigmoid的导数的最大值是0.25,因此很容易出现梯度消失。
当初始时wσ(z)>1w\sigma(z)>1wσ(z)>1,经过很多个大于1的数的连乘,最终得到的偏导数远远大于1,甚至出现Nan,就产生梯度爆炸的现象。输入数值xxx比较大或出现异常值时,会导致权重在更新几次后就变得很大,连乘因子大于1,此时比较容易出现梯度爆炸。
这里提一下在实际情况下,梯度消失的解决方案有
(1)将sigmoid激活函数替换为ReLU等可以避免梯度衰减的激活函数
(2)采用batch normalization层
(3)残差网络捷径(shortcut)
(4)LSTM的“门(gate)”结构
梯度爆炸的解决方案有
(1)选择relu等梯度大部分落在常数上的激活函数
(2)通过梯度截断,避免梯度爆炸
(3)添加正则项,避免梯度爆炸
(4)采用batch normalization层
这里有很多名词和概念还没有讲过,读者只需要有个了解即可。
4.3 动量法
关于梯度,这里再讲一个相对于普通梯度下降的优化——动量法。
先回顾一下上一讲的梯度下降。梯度下降法沿着梯度的反方向以步长λλλ迭代更新权重θθθ。
Δθ=−λ×(∂loss∂θ)θ+=Δθ(4-3)\begin{aligned} &\Delta \theta = -\lambda \times (\frac{\partial loss}{\partial \theta}) \\ &\theta += \Delta \theta \end{aligned}\tag{4-3} Δθ=−λ×(∂θ∂loss)θ+=Δθ(4-3)
如果学习率过大,在loss快速下降后,会在最优值附近摆动,导致最终误差较大;如果学习率过小,又会使得迭代次数增加,学习时间会很长。普通梯度下降难以找到一个合适的步长λλλ加快收敛并使最终误差小。
普通梯度下降(图中红色线段),函数会在纵轴上不停的波动,但实际上纵轴上的这些波动的平均值是接近于0的,我们更希望其波动较小,在横轴上能快速前进。动量梯度就是通过计算其加权平均值,把这些在纵轴上多余的波动去除,从而让函数尽可能快的朝着横轴移动,因此其收敛的速度也会很快。
动量法相比于普通的梯度下降有如下图4-9所示的区别。
本质上就是有一个记录历史梯度加权和的动量vvv,用这个动量来代替梯度。
举一个具体的例子,假设初始的动量为v0=0v_0 = 0v0=0,动量系数μ=0.9\mu=0.9μ=0.9。经过几次梯度下降后的动量如下图4-10所示。
前面的每个梯度值都赋予了一个权重,这个权重距离当前迭代次数越近,权重越大,反之也越小。
除了可以在开始阶段使得震荡更稳定之外,还可以让算法冲出局部最小点以及鞍点,找到更优的解。由于局部最小点和鞍点的导数为0,普通梯度下降是会停留在这些点的,但是动量法有历史的动量在,可以冲过这些点。
5 权重初始化
5.1 全零初始化
当使用梯度下降法来进行优化网络参数时,参数初始值的选取十分关键,不正确初始化的权重会导致梯度消失或爆炸问题,从而对训练过程产生负面影响。
全零初始化,顾名思义就是网络中所有的权重和偏置都初始化为零。
这是最简单也是最省力的一种初始化方式,读者可以思考一下,全零初始化有什么缺点?
不难想象,全零初始化会使得所有的神经元没有区别,会导致“对称性”问题。对于同一层隐含层来说,不同神经元有着相同的输入和输出,进行同样的参数更新,因此这些神经元学到的参数都是一样的,等价于一个神经元。
同理,固定值的初始化,都会导致对称性问题。
5.2 标准随机初始化
标准随机初始化即对网络中的权重和偏置都采样于标准化高斯分布。采用标准随机初始化,保证权重都不同从而保证不同神经元的输入和输出。避免固定值初始化。
但是标准随机初始化会导致梯度下降或者爆炸的问题。
假设我们的激活函数为如图5-1所示的tanh函数,其中间部分可近似看成线性的,且满足f′(0)=1f^′(0)=1f′(0)=1。
另一个神经元的输入为z1,z2,…zNz_1,z_2,…z_Nz1,z2,…zN,这N个输入是均值为0的独立同分布,其权值为w1,w2,…wNw_1,w_2,…w_Nw1,w2,…wN,也是均值为0的独立同分布,激活函数fff为tanh,最终的表达式为
y=f(w1∗z1+…+wN∗zN)(5-1)y=f(w_1∗z_1+…+w_N∗z_N) \tag{5-1} y=f(w1∗z1+…+wN∗zN)(5-1)
N个均值为0的独立同分布的求和也是均值为0的,由于tanh可以在0附近可以看成线性的,因此可以无视tanh的影响。我们来计算一下方差的变化
Var(y)=Var(∑i=1Nwizi)=∑i=1NVar(wizi)=∑iN([E(wi)]2Var(zi)+[E(zi)]2Var(wi)+Var(wi)Var(zi))=∑iNVar(wi)Var(zi)(5-2)\begin{aligned} Var(y)&=Var(∑_{i=1}^Nw_iz_i)=∑_{i=1}^NVar(w_iz_i) \\ &=∑_i^N([E(w_i)]^2Var(z_i)+[E(z_i)]^2Var(w_i)+Var(w_i)Var(z_i)) \\ &=∑_i^NVar(w_i)Var(z_i) \end{aligned}\tag{5-2} Var(y)=Var(i=1∑Nwizi)=i=1∑NVar(wizi)=i∑N([E(wi)]2Var(zi)+[E(zi)]2Var(wi)+Var(wi)Var(zi))=i∑NVar(wi)Var(zi)(5-2)
根据式(5−2)(5-2)(5−2)不难看出,如果输入的方差为1的话,输出的方差就是权重方差的N倍。
假设我们的网络结构为10个隐层,1个输出层,每个隐层包含500个神经元,使用tanh激活函数,权值采样自N(0,0.012)N(0,0.01^2)N(0,0.012)的高斯分布。
输入层和10个隐层激活值(激活函数的输出值)的均值和方差如下:
可以看到,标准差随着层数的增加不断趋紧于0,除了前两层,后续所有层的激活值为0,此时输入信息传递不到输出层,最终网络得不到训练。
10个隐层激活值直方图如下图5-3所示。第三层开始,基本都是0了。
如果我们令权值采样自N(0,12)N(0,1^2)N(0,12)的高斯分布,就又是另一种情况了。
输入层和10个隐层激活值(激活函数的输出值)的均值和方差如下:
由于随机到的数更大,几乎所有的神经元都饱和了(不是1就是-1),此时神经元局部梯度都是零,网络没有反向梯度流,最终所有的参数得不到更新。
10个隐层激活值直方图如下图5-5所示,每一层都是饱和的。可想而知,N(0,12)N(0,1^2)N(0,12)的话,500个神经元一加就N(0,500)N(0,500)N(0,500)了,方差极大。
5.3 Xavier初始化
Xavier初始化的目的是让输出和输入同分布,这样以来就不会有变化这么大方差了。
观察式(5−2)(5-2)(5−2),不难看出,令Var(w)=1/NVar(w)=1/NVar(w)=1/N即可保证yyy与zzz的方差一致,NNN是当前隐藏层的神经元个数。
权重采样自N(0,(1N)2)N(0,(\sqrt{\frac{1}{N}})^2)N(0,(N1)2)的高斯分布后,每层神经元的激活值分布如下所示
就是这么简单的一点改变,就可以让结果有如此大的变化。
画图代码摘自CS231n。
亲自动手试一下,感受更深刻。
不过这是在激活函数为tanh的情况,当激活函数变成ReLU之后,权值又不稳定了。
5.4 Kaming初始化
为了解决激活函数为ReLU的问题,就有了Kaming初始化。Kaiming初始化,又称之为MSAR初始化,出自何凯明之手。与Xavier初始化相似,初始化策略应该使得各层的激活值和状态梯度的方差在传播过程中的方差保持一致;Kaiming初始化的参数仍然满足均值是0,且更新的过程中权重的均值一直是0。与Xavier初始化不同的是,Kaiming初始化不再要求每层输出均值都是0,当然也不再要求f′(0)=1f^′(0)=1f′(0)=1。
Kaming初始化采自N(0,(2N)2)N(0,(\sqrt{\frac{2}{N}})^2)N(0,(N2)2)的高斯分布,证明过程可以参见https://zhuanlan.zhihu.com/p/305055975。这里不展开讲了。
使用了Kaming初始化后,每层神经元的激活值分布如下所示
因此,激活函数选择双曲正切或者sigmoid时,建议使用Xaizer初始化方法;激活函数选择Relu或者LeakLY Relu时,推荐使用Kaming初始化方法。
6 批归一化
和权值初始化的目的相同,批归一化也是为了使得输入和输出同分布。
其同分布的方式为硬性将输出做归一化。其整体流程如下图6-2所示,每次针对的是一个batch,需要注意的是假设输入为N×C×H×WN \times C \times H \times WN×C×H×W,其均值μB\mu_BμB和方差σB\sigma_BσB都是在N×H×WN \times H \times WN×H×W维度内求的,最终会有CCC个μB\mu_BμB,CCC个σB\sigma_BσB。
有平移缩放参数γ\gammaγ和β\betaβ的原因是0均值1方差的正态分布并不一定是最有利于网络分类的分布,我们希望网络可以自己学习最合适的分布。
另一点要提到的是,预测时,均值和方差是训练时记录下来的。
还有,BN放的位置也有讲究,最开始的时候,是放在激活层之前的,如下图6-3所示。
但有人质疑其设计的位置,将BN放在了激活层之后,发现效果更好了。
原因是ReLU截断了部分bn归一化以后的数据,所以很有可能归一化的数据已经不再完全满足0均值和单位方差。
具体可以参见https://github.com/ducha-aiki/caffenet-benchmark/blob/master/batchnorm.md。
有关BN更进阶的解读可以参见我的另一篇博客论文阅读 - Group Normalization。
7 参考资料
[1] 计算机视觉与深度学习 北京邮电大学 鲁鹏 清晰版合集(完整版)
[2] CS321n
[3] KL散度与交叉熵区别与联系