3.3 神经网络训练
上一节介绍了神经网络的基本组成单元(神经元)的数学模型和神经网络中参数的定义,这一节将介绍神经网络训练过程和其中涉及的优化细节。
3.3.1 权重初始化
神经网络的参数包括神经网络权重和神经网络偏置。首先可以考虑一下如果不进行参数初始化会怎样?如果在训练开始时将所有权重和偏置都设置为0,那么神经网络中所有神经元都是一样的,在反向传播中它们的运算方式相同。因为所有神经元完全对称,进行相同的计算,它们在反向传播中计算的梯度相同,会进行相同的更新,神经网络将不会学到任何有用的东西。
权重初始化应该使各层的激活值既不饱和,也不为0。为了打破神经元之间的对称性,在神经网络训练之前,应该初始化权重。正确的权重初始化是使神经网络快速收敛的关键,它可以降低反向传播过程中梯度爆炸和梯度消失的风险。
最常见的权重初始化方法是小随机数初始化,它将每个神经元的权重向量初始化为一个随机向量,而这些随机向量又服从一个多变量高斯分布或者多变量均匀分布,这样在输入空间中,所有神经元的指向都是随机的。
一个不合适的初始化会让训练过程变慢,神经网络难以收敛。但这个问题很容易被诊断出来,一个有效的方法是,观察神经网络中所有层的激活值和梯度分布的柱状图。例如,如果某个神经元使用Tanh激活函数,应该看到激活值在整个[-1,1]区间中都有分布。如果看到神经元的激活值全部是0,或者全都饱和了,就可以初步诊断可能是权重初始化出现了问题。此外还可以检查每一层的激活值和梯度的方差。
前面给出了权重初始化的两个必要条件,即各层的激活值不能饱和,且不为0。但是这两个条件只保证了训练过程中神经网络可以学到有用的信息,即参数梯度不为0。而2010年Xavier Glorot[7]等人提出了一个观点:优秀的初始化应该使得各层的激活值和梯度的方差在传播过程中保持一致。他们建议,神经元的权重初始化区间应该与每个神经元的输入数据数量二次方根的倒数成正比,如果输入数据很多,那么最终初始化权值便较小。Xavier初始化在实践中运行良好,获得了更好的收敛速度。但因为Xavier的推导过程是基于激活函数线性且关于0对称的假设,所以Xavier初始化并不适用于ReLU函数和Sigmoid函数。2015年He[8]等人提出了一种针对ReLU神经元的特殊初始化方法ReLU-He,这里不再详细描述。
3.3.2 偏置初始化
因为随机小数值权重矩阵打破了神经元的对称性,因此通常直接将偏置初始化为0,当然这不是固定要求。对于包含ReLU函数的神经网络,有些研究人员喜欢将所有偏置初始化为0.01这样的小数值常量,他们认为这样做能让所有的ReLU神经元一开始就激活,在反向传播过程中不会死亡,但这样做是不是总能提高神经网络性能并没有明确的科学依据,有时候实验结果反而更差,所以通常还是使用0来初始化偏置。
3.3.3 前向传播
3.2.2节已经介绍了神经网络中参数定义以及前馈神经网络的传播方式,通过逐层运算就可以完成前向传播过程。
3.3.4 损失函数
研究人员通常用损失函数来定量估测预测值和目标值的偏差,损失函数定量评价了当前神经网络的健壮性,同时它指导了神经网络的学习过程,数据集的平均损失函数公式如式(3-11)所示。
定义数据集为,其中xi是输入图像,yi是标签,即目标值,W表示神经网络参数矩阵。损失函数Li有很多种类型,但没有任何一种损失函数可以适用于所有的神经网络模型。损失函数的选择取决于神经网络结构、寻优方法和解决问题类型等若干方面,下面介绍比较重要的两种。
1.均方误差
均方误差损失通常用来解决回归问题,回归问题的神经网络一般只有一个输出节点,即预测值,因此均方误差是对具体数值进行预测。均方误差损失函数公式如式(3-12)所示。
其中yi是目标值,si是神经网络输出预测值。
2.交叉熵损失
交叉熵损失用于解决分类问题,它刻画了两个概率分布之间的差异程度,交叉熵损失越小表示两个概率分布越相近,损失越大表示两个概率分布差异越大。要理解交叉熵损失,必须先理解熵和交叉熵的概念。熵可以理解为信息量,是对不确定性的一种对数形式的测量,而交叉熵表示两个分布之间的互信息,反映了它们的相关程度。假设有两个概率分布p(x)和q(x),交叉熵定义如式(3-13)所示。
其中p(x)是目标分布,q(x)是预测分布。从公式可以看出p(x)与q(x)之间的交叉熵和q(x)与p(x)之间的交叉熵是不等价的。交叉熵的物理意义是使用概率分布q(x)来表示概率分布p(x)的困难程度。交叉熵损失公式如式(3-14)所示。
其中yi是目标分布,在分类任务中是0-1分布,目标类别是1,其余类别都是0。f(xi,W)是神经网络输入样本xi的输出分布,W表示神经网络参数矩阵。
前面提到过Softmax函数可以作为激活函数,但更常见的是将它放在神经网络最后一层作为损失函数,即用Softmax函数计算神经网络的预测概率分布,这样交叉熵损失就是我们熟悉的形式,如式(3-16)所示。
其中si表示输入样本xi时Softmax层之前的神经网络输出得分。
3.3.5 反向传播
在得到神经网络损失具体数值之后,我们要做的是逐层反向求损失函数对神经网络参数矩阵的梯度,这个梯度将用于参数更新。下面介绍感知器法则和delta法则。
1.感知器法则
为了获得使感知器分类效果最佳的参数,从随机参数开始,用感知器对每一个训练数据进行训练,在当前感知器错误分类时,则修改感知器的参数。如此重复训练过程,直到感知器正确分类所有的训练数据。修改参数的法则就是感知器法则[1],如式(3-17)和式(3-18)[1]所示。
其中xi是感知器第i个输入,wi是每次训练时xi对应的参数,Δwi是wi的修正值,t是当前训练数据的目标标签,o是感知器的输出,η是学习速率。学习速率的作用是缓和每次训练调整参数的程度,它通常被设置为一个小的数值,例如0.1、0.01或0.001,有时会使其随着参数调整次数的增加而衰减。
事实证明,经过有限次地使用感知器法则后,上述训练过程可以得到一组感知器参数,使所有训练数据分类正确,这个过程称作感知器收敛,但前提是训练数据集线性可分,并且使用了充分小的η。如果训练数据集不是线性可分的,那么不能保证训练过程收敛。
2.delta法则
当训练数据集线性可分时,通过感知器法则,可以简单地找到一组参数让神经网络收敛。但如果数据集线性不可分,感知器法则就无法正常工作了。为了解决这个问题,人们设计了另一个训练法则,称为delta法则[9],其关键思想是使用梯度下降来逐步逼近最佳参数。将神经网络输出O表示如式(3-19)[9]所示。
其中W表示参数矩阵,X表示神经网络输入向量。为了推导神经网络的参数学习法则,先指定一个损失函数,这里使用均方误差损失,如式(3-20)所示。
其中E表示均方误差损失,D表示训练数据集,td表示输入d的目标输出,od表示神经网络对输入d的输出。目标是确定一个参数矩阵W使损失函数E最小。梯度下降法从任意的初始参数开始,以很小的步伐每一步都沿误差曲面下降最陡峭的方向修改参数,反复执行这个过程直到得到全局的最小误差点。
在这个过程中,通过计算E关于参数矩阵W的偏导数来确定误差曲面下降最陡峭的方向,实际上这个下降最陡峭的方向就是使E上升最快的反方向。梯度下降的训练法则如式(3-21)和式(3-22)[9]所示。
这里η是学习率,它是梯度下降中的步长。公式中的负号代表参数向损失函数E下降的方向移动。这个训练法则也可以写成它的分量形式,如式(3-23)和式(3-24)[9]所示。
其中wi是参数矩阵W的分量,按照改变W中的每一个分量,则wi可以找到最陡峭的误差曲面下降。均方误差损失的梯度下降权值更新公式为式(3-25)[9]。
其中xid是神经网络输入的分量。
delta法则构成了深度学习的核心,它也被称为BP[9](反向传播,Backpropagation)算法。BP算法就是根据输出对最终损失的影响,求解最终损失对每个输入的全局梯度。如果是一个正的梯度,那么意味着损失将会随着输入的增大而增大;如果是一个负的梯度,那么损失将会随着输入的增大而减少,BP算法需要将链路中所有的局部梯度相乘。
在运算链路中,每一个中间变量都会对最终的损失函数产生影响,其中运算链路的递推过程也被称为链式法则,如图3-9所示。链式法则指出,门单元应该将回传到其输出端的梯度乘以它对其输入的局部梯度,从而得到整个神经网络的输出对该门单元的每个输入值的梯度,然后继续往后传。
图3-9 链式法则
3.3.6 参数更新
1.寻优
寻优是寻找能使得损失函数值最小的参数矩阵W的过程。一次性找到最优参数是很困难的,因此寻优的主要思路是迭代优化。从随机参数开始,迭代取优,从而获得更低的损失值,最终得到最优参数。目前比较常见的寻优方法主要有梯度下降、SGD、Momentum[10]、NAG[11](Nesterov Accelerated Gradient)、AdaGrad[12]、RMSProp、Adam[13]等。
根据寻优算法在优化过程中使用的导数阶数,可以将寻优算法分为两大类,分别是一阶优化算法和二阶优化算法。一阶优化算法是指使用参数梯度值来最小化或者最大化损失函数的优化算法,同理二阶优化算法就是采用二阶导数进行参数优化的算法。下面介绍常见的几种。
SGD的优化思想是用当前位置的负梯度方向作为搜索方向。它是当前使用非常广泛和相对稳定的神经网络寻优方法,后续的寻优方法都是在它的基础上加以改进的。SGD更新参数的思想如式(3-36)所示。
其中W是神经网络参数矩阵,ΔW表示参数矩阵的梯度,η表示学习率。因为这种寻优方法的梯度来自小批量,所以它们可能是嘈杂的,这会导致参数更新速度很慢,而且容易受到局部最优点或者鞍点的干扰,因为在零梯度时它的梯度下降会被卡住。
为了克服局部最优点和鞍点的干扰,人们考虑为随机梯度下降增加了一个动量项。主要思想是相信之前的速度,将梯度估计值加到原来的速度上,沿着速度的方向走,而不是沿梯度的方向。这种寻优算法叫作Momentum,描述公式见式(3-27)和式(3-28)[10]。
其中vt和vt-1分别表示本次和上次参数更新的速度,E表示损失函数,ρ为摩擦常数,通过摩擦常数ρ会使当前的速度衰减,通常ρ设为0.9。因此现在神经网络的参数将沿着速度的方向优化,而不是沿着原始梯度的方向,这可以理解为一个球滚动着接近最低点时,它的速度会逐渐变快,能逃出局部最优点和鞍点。
另一种改进的寻优算法是NAG动量,它计算的是前瞻梯度,描述公式见式(3-29)和式(3-30)[11]。
NAG和Momentum的唯一区别是NAG计算前瞻点的梯度,并将其与速度混合,以获得实际的更新方向,可以减少无用的迭代。
再介绍另一种很常见的更新方法,叫作AdaGrad。AdaGrad是由Duchi[12]等提出的适应性学习率算法,中心思想是不同参数需要的学习率不同。这种方法的好处是,高梯度值的参数的有效学习率降低了,更新效果将会减弱;同时低梯度值的参数在迭代过程中学习率提升了,更新效果将会增强。但是AdaGrad算法也有缺点,在深度学习中单调递减的学习率会使参数更新步伐越来越小,容易过早停止学习。
因为上述缺点,Hinton对AdaGrad做了改进,改进算法是RMSProp。这个算法没有公开发表的论文,其主要思想是不在每一维度计算平方和,而是变成一个泄漏变量。RMSProp仍然是基于梯度的大小来对每个参数的学习率进行修改,这同样效果不错,但是和AdaGrad不同,其更新不会让学习率单调变小。
Adam是Momentum和RMSProp的结合。
2.学习率
决定了寻优方法就确定了每次参数更新的方向,随后还需要选择调整参数的步长,即学习率。学习率是所有参数中最重要的参数之一,如果设置得太大,参数能很快地从远离最优值的地方回到最优值附近,只是它很容易就在最优值附加徘徊,无法继续优化。但如果设置的太小,收敛速度会非常慢,所以需要一个合适的学习率。目前比较简单但是效果很好的方法是先使用一个大的学习率,等损失不在下降后再减小学习率,重复这个过程。还可以为每个参数选择不同的学习率,或者使用二阶导数,这样一般可以加快神经网络收敛速度。
3.小批量
在大规模的神经网络训练中,训练数据可以达到百万级量级,如果计算整个训练集来获得仅仅一次参数更新就太浪费了。一个常用的方法是计算训练集中的小批量数据。具体是:
① 选择n个训练样本(n<N,N为总训练集样本数);
② 分别训练n个样本得到n个梯度;
③ 对这n个梯度加权平均求和,作为这一次小批量下降梯度;
④ 不断在训练集中重复以上步骤,直到收敛为止。
因为训练集中的数据都是相关的,小批量的训练方法可以起到很好的效果。小批量数据的梯度可以近似整个数据集的梯度,因此小批量训练方法可以让神经网络快速收敛,有利于更频繁地更新参数。小批量大小(Batch Size)是一个超级参数,但是一般并不需要通过交叉验证来调参。一般而言,储存器大小限制了小批量大小,或者也可以直接将小批量大小设置为存储器大小,例如32、64或128。因为在进行很多向量化实际操作时,输入数据量是2的倍数会使运算速度更快,所以一般将小批量大小设置为2的指数。需要注意的是,小批量数据太少会在梯度中引入噪声。论文[14]提示我们:短期来看,增加小批量大小对加速神经网络训练有利,但它会到达阈值。
当一个完整的数据集都输入神经网络并且完成反向传播,这个过程称为一个周期(Epoch)。一般需要训练多个周期,但到底需要训练多少个周期如今还没有定论,每个数据集情况不一样。训练周期过少会导致欠拟合,而太多又会导致过拟合。另外迭代(Step)是指一个周期中小批量的数目,小批量大小是指一个小批量中的样本总数。
3.3.7 批归一化
批归一化是Google[15]在2015年提出的,其基本宗旨是,使神经网络的每一部分都有粗略的单位高斯激活,以保证神经网络训练能够使用更高的学习率并能更少关注数据初始化。它是一个深度神经网络训练常用的技巧,不仅可以加快神经网络的收敛速度,而且可以缓解深层神经网络中梯度弥散的问题。目前批归一化几乎已经成为所有CNN的标配技巧。
从字面意思就可以看出批归一化就是对每一批数据进行归一化处理,这个操作可以放在神经网络中的任意一层,但通常将它放在激活函数之前。其做法是让数据通过一个模块进行预处理,使其服从标准高斯分布,现在的神经网络寻优通常在小批量数据上进行。在实现层面,应用这个技巧通常意味着在全连接层或者卷积层与激活函数之间添加一个批归一化层,也叫BN(批归一化,Batch Normalization)层。BN层的具体计算过程如图3-10所示。
图3-10 BN层计算过程
其中ε是为了避免除数为0使用的微小正数。γ是尺度因子,β是平移因子,γ和β是神经网络训练时自己学习得到的。
简单地归一化各层的输入,可能会改变各层代表的东西。例如,归一化后Sigmoid激活将把下层输入限制在非线性函数的线性区域,神经网络的表达能力会下降。定义BN层中的尺度变换和偏移是为了调整归一化的程度,使得新的分布更接近数据的真实分布,保证神经网络的非线性表达能力,使神经网络可以通过反向传播算法决定是否要取消BN层的作用。如果神经网络发现它有用,就采用BN层,以利用其优势;如果发现效果不佳,就可以利用尺度变换和偏移取消。当γ=σ且β=μ时,BN层将无效。
在训练每一批数据时,会求同一批数据的均值和方差,然后进行归一化处理。但在测试时,BN层的均值和方差不再基于批量数据进行计算,而是使用训练期间激活数据的单一固定的经验均值。例如,基于整个训练集一次性计算出均值和标准差,或者可以用训练期间的移动均值来估计。即在测试过程中,BN变成了一个线性运算符,可与前面的全连接或卷积层相融合。
BN层可以理解为在神经网络的每一层之前都做预处理,它有很多有用的性质。它增强了整个神经网络的梯度流;支持更高的学习率,可以更快地训练神经网络;减少了算法对合理的初始化的依赖性;BN层实际上还起到了一些正则化的作用,将独立的样本捆绑到一起,减少了对随机失活的需要。
3.3.8 正则化
在线性代数理论中,不适定问题是指解不一定存在、解的条件多或解不唯一,而条件多意味着误差会严重地影响问题的结果。求解不适定问题的普遍方法是,用一组与原不适定问题相“邻近”的适定问题的解去逼近原问题的解,这种方法称为正则化。神经网络中的参数矩阵W往往有很多种最优解,即W并不是唯一的,这是一个不适定问题,需要通过正则化来解决。
从数学上讲,正则化就是最小化添加约束条件的损失函数。约束条件就是先验知识,正则化就是引入先验分布。先验知识有引导作用,会使神经网络参数矩阵在最小化损失函数的同时倾向于选择满足约束的梯度下降的方向,从而使最终参数倾向于符合先验知识。同时正则化产生的神经网络参数矩阵是唯一的且依赖于数据,它解决了逆问题的不适定性,让神经网络训练不会过拟合。神经网络中常用的正则化手段就是,为损失函数增加正则化惩罚项R(W),正则化之后的损失函数公式如式(3-31)所示。
其中X和Y分别是神经网络输入和目标标签,W是神经网络参数矩阵,f(X,W)是神经网络输出,L是损失函数,λ是正则化强度。由上式可知,正则化惩罚项R(W)和输入数据X无关(不是输入数据的函数),它仅仅与神经网络参数矩阵W有关。
除了可以减少神经网络参数矩阵W的不确定性,引入正则化惩罚项还有许多其他的好处,例如可以提升神经网络泛化能力,因为正则化意味着没有哪个维度的参数能够独自对整个神经网络的效果产生过大的影响。另外,正则化还可以有效地防止神经网络过拟合。过拟合是指神经网络过于完美地拟合了训练集数据,反而不能有效地预测新样本。造成过拟合的原因可能是,特征量太多或者神经网络模型过于复杂。对此有两种解决思路:保留所有的特征但是减少参数数目或者丢弃无用的特征。
常用的正则化方法是增加惩罚项R(W),来限制神经网络参数矩阵W的绝对值大小,来避免神经网络过拟合。最常用的正则化惩罚项是L2正则化,L2正则化通过对所有参数平方来抑制大数值的参数,即对幅度很大的参数给予很高的惩罚。L2正则化会使参数矩阵矩阵W的取值更加平均,获得更相近的参数值,使得每个输入都可以发挥作用,而不是仅让某些输入起主导作用。L2正则化的数学公式如式(3-32)所示。
其中Wk,l表示神经网络中第l层的第k个参数。L1正则化的应用也很多,L1正则化会使学到的神经网络更加稀疏(W中一些参数为0)。这个特性使L1正则化成为一种很好的特征选择方法,减少了神经网络的复杂度,可以有效地防止神经网络过拟合。L1正则化如式(3-33)所示。
除了这两种,弹性正则化、数据增强、随机失活、随机失连、批归一化、模型集成、最大范数约束正则化等也是常用的正则化手段,下面简要介绍其中三种。
1.数据增强
现在常用的神经网络通常包含大量参数,为了让这些参数都能发挥作用,需要大量的数据对它们进行训练。但实际情况中训练数据往往没有那么多,这时候就需要进行数据增强。
有效的数据增强应该可以改变图像的每一个像素值,但标签的属性不变。数据增强增加了训练集数据,使用变换后的数据进行训练,可以有效地防止过拟合。比较常见的数据增强方法有水平翻转、随机选择图像截图、颜色抖动、随机旋转、伸缩变换等。
2.随机失活
随机失活也可以防止神经网络过拟合,随机失活使神经网络每次训练只有一部分能发挥作用,这样做减少了每次训练过程中涉及的参数数目,降低了训练时的神经网络的表达能力,因此可以减少神经网络过拟合的概率。
下面用图片分类问题来说明随机失活的作用。在随机失活的过程中,不能控制神经网络中哪些神经元会失活,而被失活的神经元目前获得的图片特征对于图片的表示不能起作用,所以如果想让图片分类更准确,就需要让图片分类依赖于更多的特征,而不是完全依赖于某一个特征。这样就能在任何一个决定性特征被失活的情况下也可以进行精确的分类。
从另一个角度看,设置随机失活的神经网络可以视为,由很多子神经网络集成大神经网络,每个子神经网络都是大神经网络的一部分。大神经网络与子神经网络可以共享参数,每次只会用一个小批量数据来训练一个子神经网络,因为每次迭代时失活的神经元不同,会形成新的子神经网络,在多个周期中会用相同的数据来训练不同的有共同参数的神经网络。当一个神经元被失活时,这个神经元的输出值会乘以0,它对损失函数没有影响,那么在反向传播过程中该神经元的梯度为0,相关参数不更新。需要注意的是,随机失活只发生在神经网络训练过程中,在测试时所有的神经元都应被激活,这时必须对激活值进行缩放,以便每个神经元测试时的输出等于训练时期望的输出。
从上面的描述可以看出,随机失活是基于这样一种思想,即在训练过程中,向神经网络添加了一些随机性,以防止它完美地适应训练数据;而在测试过程中,平均所有随机性,希望能改善神经网络泛化能力,这也是正则化的一般策略。
3.模型集成
神经网络模型集成简称模型集成,深度学习中的神经网络模型常常也叫作神经网络,因此模型集成也叫作神经网络集成。分别训练几个独立的神经网络,然后在测试时平均所有神经网络的预测结果,可以将神经网络的准确率提升几个百分点。训练时集成的神经网络数量越多,算法的性能也单调提升,但提升的效果会越来越少。训练时神经网络之间的差异度越大,提升效果可能越好。
模型集成的方法有很多,常见几种包括在训练过程中保持神经网络的多个快照集成、不同的初始化集成、训练过程中不同时间点的神经网络集成等。