0 前言

本文对深度神经网络超参数优化进行概要总结,适合有一定基础的人员查阅。

1 训练基础

深度神经网络选择超参数是一个迭代过程,即使经验丰富的工程师,在面对新的任务时也需要在不断尝试中找到好的网络参数。

1.1 训练集、验证集、测试集

比例:

在机器在学习时代,数据集往往不大,一般几百条到几万条,这种小规模数据集被分为:70%训练集、30%测试集(或着说60%训练集、20%验证集、20%测试集)是合理的。但如今大数据时代的数据集,动辄几百万、上千万条数据,再用大规模验证集、测试集就不太合适了,这时候一般的训练集可以达到98%以上,如98%训练集、1%验证集、1%测试集,甚至99.5%训练集,验证和测试集各0.25%,或者0.4%验证集,0.1%测试集。因为100万条数据0.1%也有1000条,足以评估分类器。

分布:

数据集有可能来源不同,数据可能差异明显,这时需要训练集、验证集、测试集满足同分布,这样可以提高网络性能,加快调优。

最后:

测试集是为了确定神经网络的估计是 无偏估计 

1.2 偏差、方差

上图显示方差与偏差的概念。

左图表示高偏差,中图表示刚刚好,右图表示高方差。

从训练结果来看:

假设误差基准为0% - 1%。

如果训练集误差0.5%,验证集误差1%,这时候的算法是合适的。

如果训练集误差1%,验证集误差11%,这时候就发生了高方差,也就是过拟合,泛化能力差。

如果训练集误差15%,验证集误差16%,这时候就发生了高偏差,也就是欠拟合,算法训练的差。

如果训练集误差15%,验证集误差30%,这时候就发生了高偏差、高方差。如下图:

1.3 机器学习基础

训练的首先是要降低偏差,使数据能很好的被拟合。如果训练偏差过高:

这时候应该做的是换一个神经网络模型;
增加更多的隐藏层,隐藏的神经网络单元;
或增加训练时间,或者尝试更先进的算法;
重复上述做法直到降低偏差,拟合数据。
     更深的网络往往或奏效,有时候增加训练时间不见得有用,但也没什么坏处。

偏差降下来后看方差。方差高了就是过拟合。解决过拟合:

增加数据量(有时候无法办到);
正则化;
找到更合适的神经网络模型(有时会一箭双雕解决过拟合、欠拟合问题);
重复上述做法直到降低方差。
在机器学习早期阶段存在权衡偏差与方差的讨论。因为那时候偏差降下来方差就会上去,反过来也一样,人们往往找不到方差、偏差都很低的模型。但在大数据、深度学习时代,只要持续训练一个更大的网络、持续的增大数据集、正则适度,往往会解决这个问题。这也是深度学习相对于传统监督式机器学习的一大优势(不影响偏差或方差的情况下,优化另一方)。

1.4 正则化

逻辑回归中添加正则项:

就是在cost函数中添加正则项:

为什么不加上b的正则项,因为W是比b维度高的参数(参数数量多),足以表达高方差问题。

如果使用L1正则化W矩阵将是稀疏的,但人们往往趋向于使用L2正则化,L1正则化不是全局可微的。

是正则化参数,需要尝试(看验证集方差,检查是否存在过拟合)确定下来的参数。

在深度神经网络中添加正则项(L2):

正则项的F范数实际上是:

再看反向传播:

更新量:

变为:

从上式看出,正则项试图减小w,正因如此,人们也称L2正则化为“权重衰减”。

1.5 正则化可以防止过拟合原因解析

正如上面所述,正则化被称为“权重衰减”,那么设置的足够大,隐藏单元的权重就将训练为趋于0,这相当于原神经网络退化为简单网络(大而深的网络变为小而深的网络)。假设原网络是一个高方差(过拟合)网络,那么调大将使网络变为高偏差网络(欠拟合-有偏的)。正则化任务就是找到一个合适大小的。

更直观的,假设激活函数是双曲正切函数,如果正则化使w很小,会导致z很小,这就会将激活函数限制在0附近的线性区间,如果激活函数失去非线性功能,那再大的网络也只会输出线性结果,更谈不到过拟合了。

1.6 Dropout正则化

Dropout正则化就是使隐藏层单元随机失活,来防止过拟合,相当于每次训练一个不同的、较小的网络。实施Dropout需要设置keep-prob (0,1],也就是隐藏层单元随机失活的概率,同时也要在该层的激活值上除以keep-prob,以弥补失活的但单元的损失,否则测试阶段的平均值会变得异常复杂。

单元数量越多的隐藏层可能需要更小的keep-prob(更多的失活概率),因为这样的隐藏层可能会有更大的概率过拟合,有些小规模的隐藏层可能会将keep-prob设置为1,即不进行随机失活,保留所有单元。输入层也可以设置一个小于1的keep-prob,但通常不会这样做。

在测试时,不使用Dropout,因为我们不希望预测结果是随机的。理论上如果在预测阶段使用Dropout,只要多次运行预测,结果几乎相同,就像是不同的网络产生相同的结果,但这样势必会降低计算效率。

在计算机视觉中,这种正则化几乎成了默认的选择。

但是需要注意的是,正则化是一种防止过拟合的方法,在模型没有出现过拟合的情况下,不建议使用正则化等手段。

计算机视觉任务中,往往没有足够多的图片来防止过拟合,所以正则化通常是必要的。

Dropout的缺点就是不再有明确的定义,调试时可以先关闭Dropout,确保每次优化都会下降,再打开Dropout。

1.7 直观理解Dropout作用机理

每一个神经元代表一个特征,这种特征随着正向传播,成为下一层神经元提取特征的数据。Dropout这种随机失活的方法使得神经元不依赖于任何一个输入特征,因为它之前的任何神经元都有可能被随机的清除,并为其它神经元增加一点权重,通过传播所有权重,将产生收缩权重平方范数的效果,和之前的L2正则化类似。

1.8 其它正则化方法

数据增强:

数据增强是利用原数据集增加训练集的方法,获取数据成本低,虽然不如直接获取更多数据好,但也会起到防止过拟合的作用。这种方法可作为正则化方法使用,实际功能与正则化相似。

以图片为例,主要有这几种处理方式:翻转图片、剪裁图片、旋转图片、小幅度扭曲(轻微波形)图片、改变颜色等。

Early Stopping:

Early Stoppoing方法是在优化过程中找到验证集误差的最小值时停止训练。

优化过程中,训练误差会逐渐减小,而验证集误差会先减小后增大,在验证集误差最小时停止训练,就得到比较好的参数。

机理分析:

当刚开始训练时,参数W很小,接近随机初始化的值(随机初始化往往为0附近随机值),随着训练次数增加,W会变得越来越大。Early Stoppoing就是在合适的时候停止训练,防止W过大,这与L2正则化相似。

Early Stoppoing的缺点:

缺点是这种方法不能独立的处理偏差与方差,过早的停止训练,意味着J不能足够小,同时你又不期望出现过拟合,这时问题就变得复杂。

Early Stoppoing只使用一次优化就能找到合适的W,而使用L2正则化则需要更多的时间来训练,需要尝试很多值。

1.9 归一化输入

从上图可以看出归一化输入后的Cost Function 趋于各项同性的梯度,这样就不至于初始化陷入某一方向使导致训练时间过长。

1.10 梯度消失与梯度爆炸

梯度消失指的是当神经网很深时,减小的梯度会逐层累积,以至于趋于0;相反,梯度爆炸时逐层累积增大的梯度使之趋于无穷大。

举例来说,对于一个线性(激活函数为线性)深层网络,假设b = 0,则输出为:

若系数矩阵均小于1,则会趋于0(消失),相反,若系数矩阵均大于1,则会变得非常大(爆炸式增长),且变化是指数级的。我们关注的导数或者说梯度也是一样的。

在训练过程中,梯度极大或极小,都将导致训练难度增大,尤其是梯度消失时,梯度下降法的步长会变得非常小,需要花大量的时间优化。

1.11 初始化权值参数

有技巧的权值初始化可以一定程度的改善梯度消失与梯度爆炸问题。

以一个神经元为例,假设 b = 0,为了使输出 z 不至于过大,需要减小W:

合理的方法是设置,表示神经元输入特征数量,例如,在Python中可以设置权值矩阵:

W_l = np.random.randn(shape)*np.sqrt(1/n_l-1)
Relu激活函数使用效果更好。

这也是一个超参数,但相对其它超参数来讲,这个超参数的重要程度低,所以调优时它的优先级可以放的比较低。

1.12 数值微分

数值微分,对于做计算的人员再熟悉不过了。首先看导数定义:

在数值计算中,极限被定义为离散量,也就是用一个小值代替,也就是著名的差分法:

上面是一阶精度的,再来看二阶精度的中心差分格式:

还有各种其他形式的差分格式,以及各阶导数的差分格式,这里不一一列举。

1.13 梯度检验

梯度检验是一种调试程序或寻找反向传播算法Bug的方法,可以很大程度上节省神经网络开发时间。主要做法就是比对数值梯度,与程序自动求导得到的梯度误差,误差变大,说明有Bug。

使用TensoFlow框架基本不需要使用这种方法。

注意事项:

这种方法旨在检验神经网络是否搭建正确,所以检验无误后需要关闭调试,不再计算数值梯度,因为这部分很耗时;
包含L2正则项的Cost Function一定要包含正则项来做梯度检验;
包含Dropout正则化时需要去掉它,再执行梯度检验。

2 优化方法

机器学习的应用是一个高度依赖经验的过程,工程师需要经过训练大量模型才能找到合适的那个,使用好用的优化算法会大大提高开发效率。

2.1 Mini-batch梯度下降

使用向量化后的梯度下降法(Batch)可以同时计算整个训练集的样本,再训练集规模很大时,进行一次参数更新需要计算全部训练集。而Mini-batch梯度下降法的做法是将训练集等分成若干的mini-batch,例如将500万条训练数据及其标签等分为5000分mini-batch,每个mini-batch有1000个样本,一个mini-batch运行一次梯度下降法与整个训练集运行一次梯度下降法原理是一样的,训练集全部跑1遍称为“1 epoch”,当跑完整个训练集时已经进行5000次梯度下降了,这将比常规的梯度下降法快多了,因为每个mini-batch执行梯度下降法时将使用前面更新过的参数。

Batch梯度下降法的图是随着迭代持续下降的,Mini-batch梯度下降法的图并不是持续下降的,而是波动下降的,原因在于前者每次梯度下降训练的数据是一样的,后者每次训练的数据是不同batch的,有些batch容易训练,有些batch难驯练。

当Batch大小为整个训练集时的梯度下降法就是Batch梯度下降法,每次训练整个数据集;

当Batch大小为 1 时的梯度下降法就是随机梯度下降法,每次训练1条数据,需要调小学习率,而且这将失去向量化带来的优势;

介于两者之间的就是Mini-batch梯度下降法。

上图表现的就是各种梯度下降法的收敛趋势,随机梯度下降法最终会在极值点附近波动,而不会停在极值点。

在小数据集时(例如2000以内)时使用Batch梯度下降法,而在大数据集情况下推荐使用Mini-batch梯度下降法,一般会选择64-1024大小的Batch,也就是2的n次幂。

2.2 指数加权移动平均数

指数加权平均数是一种求样本均值的方法。直接看定义:

其中代表样本在位置时的均值,是样本值,是参数。

其意义就在于代表了位置前个样本算术平均值。

理解指数加权移动平均数:

假设:

这时我们就可以看出实际上就是前面样本的加权平均,且权值呈指数级衰减,这就是指数加权移动平均数。

所有指数相加的极限值是1,向前取项时,权值降为第一个权值的。

为什么使用指数加权移动平均数:节省内存

要求之前10个样本的均值,直接做算术平均会获得更好的估值,但你必须保存10个样本在内存中,如果使用指数加权移动平均数,你只需保存1个样本就可以,意思就是用前一个值更新当前值。

修正:

在求指数加权移动平均数时,迭代的初项 (并不是第一个样本,是为了求第一项均值设置的一个初始值) 为0,这就造成了指数加权移动平均数的前几项的权值很小(),这个偏差是成指数级衰减的。解决方案是使用求前几项,这个修正项实际上是在原基础上加了一个因子,在前几项中可以修正均值,但随着增大,这个修正因子也是呈指数级衰减。

最后要指出的是,在机器学习中,人们往往不关注前几项,所以不用加修正,但如果你关心初始时期的偏差,那就加上修正。

2.3 动量梯度下降法(Momentum)

动量梯度下降法就是使用上面提到的指数加权移动平均数来平均梯度,再使用平均后的梯度更新参数W、b,下面图可以看到蓝色是Mini-batch梯度下降法,红色是动量梯度下降法,动量梯度下降法很好的平均了波动方向移动,趋势方向并没有改变,动量梯度下降法往往比Mini-batch梯度下降法快。

更新参数公式如下:

超参数一般取0.9(平均之前十次的梯度),误差修正往往是不必要的,因为迭代几次之后误差基本消失,况且W、b初始值往往接近 0。

有些文献会使用下面的公式更新梯度,这差不多相当于多了个因子,一般不推使用这种形式更新梯度:

2.4 加速梯度下降法(RMSprop)

和动量梯度下降法类似,RMSprop也同样是一种减小波动加速运算的优化方法,更新梯度如下:

(为保证不与动量梯度下降法的超参数混淆,这里使用)

为保证更新参数时分母不趋近于 0,可以在分母上加一个小常量 一般取。

2.5 Adam优化法 [Adaptive Moment Estimation]

在深度学习历史上出现过一系列优化方法,大部分的方法都只是用于某种特定结构的深度神经网络模型,Momentum、RMSprop以及即将要讲解的Adam优化算法是少有的几个经得住人们考验的通用优化方法。

Adam算法可以说是Momentum与RMSprop的融合,直接看更新公式:

这里面包含了修正()。

训练时一般只需要调节超参数(学习率),其它的取默认值、以及(一般情况下是不用设置这一项的),也可以调整、以及的值,但一般不这么做。

2.6 学习率衰减

在进行Mini-batch梯度下降法时,学习率固定会使得参数在最小值点附近跳动,而使用随着迭代衰减的学习率可以缩小跳动步伐,增加精度。

衰减公式:

其中,是衰减率,也是需要调节的超参数,比如取 1;是当前的“epoch”,“1 epoch”就是整个训练集训练一次;也是需要调节的超参数,即初始学习率。

其它的衰减公式:

另外还有离散衰减、手动衰减等。离散衰减就是在某个epoch设定特定值,手动衰减就是,在训练过程中手动调节学习率,以加快训练。

以上提到了很多超参数,有可能会让人无从下手,后面还将进一步阐述如何系统的选择超参数。

2.7 局部最优问题

早期人们理解局部最优问题时脑海里通常会出现下面的图形,J有很多局部最优解(极小值):

但随着理论发展,人们的理解发生了改变。

在高维情形中,梯度为 0 的点往往是鞍点,因为极小值要求所有维度有一致的凹凸性,保证高维中每一维都为凸(或凹)为小概率事件,现实中基本不会发生。

这样一来,局部最优问题就转变为平缓段(梯度为 0 附近)学习效率低的问题,前提是你训练的神经网络足够大(维度足够高)。Momentum、RMSprop或Adam算法会加速平缓段的学习。

最后,附上两张动图:

3 超参数调试、Batch Normalization以及Softmax多分类    

3.1 调试过程

深度神经网络有很多超参数,这一节介绍选择超参数的方法。(方法没有统一的标准,每个人的理解不同,方法也不同,这里介绍的方法是比较好用的,可以作为指导原则的方法)

超参数列表:

1.αα;
2.ββ;
3.beta1、β2、ϵbeta1、β2、ϵ;
4.layerslayers;
5.hidenunitshidenunits;
6.decay_ratedecay_rate;
7.Mini−batchsizeMini−batchsize等。

哪个超参数重要没有定论,但一般认为学习率(1)最重要,其次是(2)、(5)、(7),这里面有一些超参数尽量使用默认值(前文提到过的,这里不赘述)。

调试过程:

早期机器学习使用过超参数网络来调试,比如说有两个超参数,我们可以将两个超参数形成两两配对的矩阵网格。逐点选取超参数,评估哪些模型结果优秀。对于超参数少的情况下,这个方法很实用。

深度学习领域中,可以使用随机选点的方法。举个例子,有两个超参数需要确定,假设第一个参数重要(在现实条件下,很多时候是无法确定哪个参数是重要的、那个参数是不那么重要的,这个需要尝试),第二个参数不重要(极端情况:对结果没有影响),那么如果使用矩阵网格策略,需要训练次,但实际上,只有次是有效的,这时,使用随机选点方式会用同样的训练次数尝更多的超参数。

另外一种方法是先粗略搜索优秀的超参数的范围,再从缩小的范围进行精细搜索更加优秀的超参数。见图:

3.2 确定超参数合适的尺度范围

上一节讲述了随机搜索提升搜索效率,但是随机取值并不意味着在有效范围随机均匀取值,而是设定合适的标尺。

某些超参数随机均匀取值是合理的,例如,你选取的隐藏神经元数量范围是50~100,那你可以随机均匀的取50、51、52...100,但是,在选取某些超参数时就不适用了,具体往下看。

假设你在搜索学习率,你怀疑的范围是0.0001~1,如果你画一条0.0001~1的均匀数轴,随机均匀选取,那90%的数值会落在0.1~1之间,再0.0001~0.1内你只用了10%的资源,这看上去不太对。

这时候使用对数标尺会更合理。

再来看看,一般使用默认值就好,如果你非要调节这个超参数,那它一般会在0.9~0.999间取值,你可以看,这个的取值是0.001~0.1,再使用对数标尺选取。

直观理解对数标尺:对数标尺体现了非线性的敏感度,有些超参数在越趋近于0或1时会变得敏感,所以不能用线性标尺,使用非线性标尺。

3.3 训练模式

训练模式大概可分为两类,一类是当你不具备足够的算力(硬件条件)时,使用照看模式,另一类是当你具备足够强大的硬件资源,你可以并行训练多个模型。

照看模式顾名思义,就是在你有限的硬件资源上,只训练一个模型或小批量模型,在训练过程中精心调教超参数改良模型,比如第一天,随机初始化参数,然后开始训练,并观察学习曲线,第二天,你调了调学习率,效果变好了,第三天,你调了其它超参数... 就像照顾小孩子一样精心调试你的模型,观察它的表现。

并行模式是,当你有足够强大的硬件资源时,你可以同时跑多个不同超参数的模型,几天后,你就能获得多条学习曲线,从中选择优秀的那个模型,这种模式不用去管某个模型是否优秀,你要做的就是从众多模型中选出一个最优秀的。

3.4 归一化(标准化)隐藏层[Batch Normalization]

前面1.9节讲过归一化输入,可以使训练更加容易,这一节要讲的是归一化隐藏层,这个方法可以使隐藏层训练更加容易。

就像归一化输入一样,我们可以归一化(激活后的输出),但严格说我们并不归一化它,而是归一化(输入到激活函数的线性值)。其实在文献中有一些争论,关于是否在激活函数之前归一化,但这里讲的是实践中常用的做法。

和归一化输入类似,先将均值归零,在将方差置为1:

其中的是用来防止分母为 0 的一个小值。

归一化之后还需要对做进一步处理:

这一步,把已经归一化的又加上了均值与方差,这两个参数也是需要训练的,也就是说原有的均值与方差被归一化掉了,因为原有的方差与偏差(均值)是随机的、不确定的,之后又加上了训练的出来的均值与方差,这时候的均值与方差是固定的,训练出来的,这就避免了数据在传播过程中的摇摆(每一个Mini-batch都不一样)。

上图中表现得很明显,如果不进行BN,那么每一批数据在隐藏层间传播都会产生摇摆,给训练带来巨大的困难。

另外需要注意的是,BN处理之后的没模型,参数 b 就没有意义了,可以不设置 bias

测试时的BN:

测试时对单个样本求方差与均值是没有意义的,这时候就需要指数加权移动平均值了。对每一批以及测试时的样本可以使用指数加权平均值。

3.5 Softmax分类器

Softmax多分类器输出的是概率向量,这里不多解释,直接看公式:

Softmax就像一个激活函数作用在前一层,前一层输出的是长度为C的向量。

不包含隐藏层的Softmax分类器的决策边界是线性的。

损失函数: