深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

一、前言


通过前面的学习我们了解到神经网络的优化和改变会涉及到许多不同的超参数,例如:与神经网络结构相关的层数、每层节点数,与优化算法相关的学习效率以及Momentum、RMSprop、Adam中的指数权重项,学习效率衰减中的衰减系数,Mini-batch中的batch size等等。那么对于超参数而言,我们要如何找到一套好的设定了,下面来介绍一些关于如何系统组织超参数调试过程的技巧。

二、调试处理


值得注意的是,这些所列举的超参数优先级别却是不一样的,学习效率一般是需要调试的最重要的超参数,有时也会调试mini-batch的大小、隐层节点数以及Momentum优化算法中的指数权重,这三个是比较重要的超参数,神经网络层数和学习率衰减系数则是其次比较重要的超参数。另外,在Adam优化算法中一般很少去调试两个指数权重和分母校正项,总是选定为0.9,0.999和10e-8。
接下来我们介绍具体的调试方法,在早一代的机器学习算法中,如果有两个超参数,这里我们称之为超参一,超参二,常见的做法是在网格中取样点,然后系统的研究这些数值。如下例中的左图所示,可以尝试这所有的25个点,然后选择效果最好的参数。当参数的数量相对较少时,这个方法很实用。而在我们的深度学习领域,我们通常随机选择点,对于下面的例子(右图)我们随机选择25个点,用这些随机取得点试验超参数的效果,这样做的原因在于对于要解决的问题而言,我们很难知道哪个超参数最重要。我们假设超参一为学习率,假设超参二为Adam算法中分母校正项,这种情况下学习率的取值很重要,而分母校正项的取值则无关紧要。我们首先基于传统网格方法,在左图中给超参一取五个值,我们会发现无论分母校正项无论取何值结果基本上都是一样的。对比而言,如果随机取值,我们会尝试25个独立的学习率值,所以我们会更容易发现最好的那个。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

实践中,我们可能搜索的超参数不止两个,如果有三个超参数,那么我们搜索空间就不再是一个方格,而是一个立方体。随机取值相对网格取值而言,能够让我们探究更多重要超参数的潜在值。当我们给超参数取值时,另一个惯例是采用粗糙到精细的策略,例如在上面二维的例子中,我们进行了取值并发现效果最好的某个点,也许这个点周围的其他一些点效果也很好,那么接下来要做的就是放大这块小区域(蓝色小方块所示),然后在其中更密集的取值。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


三、为超参数选择合适的范围

上面已经介绍了网格取值和随机取值,但随机取值并不是在有效值范围内的随机均匀取值,而是选择合适的标尺用于探究这些超参数。例如我们要选取隐藏单元的数量n[l],对于给定层 l 而言,假设我们选择的取值范围是从50到100中某点,我们可以在这个范围内随机取点,这是一个搜索特定超参数很直观的方式。又或者我们呢要选取神经网络的层数L,也许我们会选择层数2-4中的某个值,顺着2,3,4随机均匀取样会比较合理,你还可以应用网格搜索。这是几个在我们的考虑范围内随机均匀取值的例子,这些取值似乎还挺合理。但对于某些超参数而言则不适用,假设我们在搜索超参数-学习率alpha,我们怀疑其值最小是0.0001,最大是1,如果画一条从0.0001到1的数轴,延其随机均匀取值,那么90%的值都会落在0.1到1之间,结果就是在0.1到1之间应用了90%的资源,显然这是极不均匀的。反而我们用对数标尺搜索超参数的方式会更合理,因此这里的线性数轴也就变成了对数数轴,在0.0001到0.001之间就会有更多的搜索资源可用。我们所要做的就是在[-4,0]的区间随机均匀的给r取值,最终的学习率alpha值也就为10^r。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


最后,另一个棘手的例子就是给指数权重beta取值,用于计算指数的加权平均值。假设我们认为beta是0.9到0.999之间的某个值,和上个例子类似,我们不能用线性轴取值,也就是不能直接在该范围内随机均匀取值。这里我们不妨转换一下,将探索的对象由beta转换为1-beta,此值在0.1到0.001区间内,应用上个例子中的方法将数值对数化。另外一不选择线性轴的原因在于,当beta取值离1较远时,其值细微变化对最终的加权平均值影响很小;当beta取值接近1时,其细微的变化会值会对我们的加权平均值产生很大的影响(回忆一下指数加权平均的基本原理),因此我们需要在接近1的区间更加密集的取值。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


四、超参数选择的实践

如今的深度学习已经应用到许多不同的领域,某个领域的超参数设定可能通用于另一领域。对于我们所研究的一个特定领域,我们可能已经找到一组好的超参数设置并继续发展算法。或许在几个月的过程中,我们会观察到所收集的数据会逐渐改变,或许只是数据中心更新了服务器,我们原来所设定的超参数不再好用。最好的做法是每隔几个月重新测试或评估你的超参数,以确保你对数值依然很满意。
搜索超参数主要有两种重要的思想流派,第一种是照看一个模型(Babysitting one model),这种情况一般是拥有庞大的数据资源但没有很多计算资源(CPU和GPU),因此每次只能负担起试验一个模型或一批小模型。这种情况下,即使当它在试验时,你也可以逐渐改良,根据训练的成本函数变化趋势,随时去调整超参数。第二种方法则是同时试验多种模型,通过比较多个模型的成本函数变化曲线,然后选择工作效果最好的那个。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


五、Batch归一化(Batch Normalization)

Batch归一化由Sergey loffe和Christian Szegedy两位研究者创造,该方法的提出一方面使得参数搜索问题变得很容易,另一方面使得神经网络对超参数的选择更加稳定。让我们来看看Batch归一化是如何起作用的。当训练一个Logistic Regressition模型时,我们知道归一化输入特征可加速学习过程,但当我们训练一个比较深的神经网络时,不仅输入了特征值x,而且每个隐层都会有**值a[l],也是下一层的输入值。如下图所示,那么我们为了训练这些参数,比如w[3]和b[3],那归一化a[2]的平均值和方差岂不是很好,以便使得w[3]和b[3]的训练更高效。那么最主要的问题来了,对于每个隐层而言,我们能否归一化a值,以便更快速的训练每层的权值w和b,答案是肯定的。简单来说,这就是Batch归一化的作用。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

其实在实践中,我们真正归一化的并不是每层的**值a而是z(关于归一化a还是z目前还存在争议,吴恩达老师推荐归一化z值)。假设我们有一些隐藏单元值,从z(1)到在z(m),m为训练样本个数,下面是Batch归一化的使用方法:

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

首先通过减均值和除标准差(分母中加了一项是为了数值稳定,一般取值很小10e-8)我们得到标准化之后的z值(含有平均值0和方差1),但实际我们并不想让隐藏单元总是含有平均值0和方差1,也许让隐藏单元有了不同的分布会有意义,因此我们还需进行最后面的计算进而得到能最好适应训练样本的z值,最后一个式子中的两个参数是模型的学习参数,可以通过优化算法来进行更新。这两个参数的作用是可以随意设置标准化后z的平均值和方差值,这也是和Logistic Regression归一化输入特征所不同的。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


六、将Batch归一化拟合进神经网络

下面让我们来看看将Battch归一化拟合进神经网络的具体计算过程,如下图所示:

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


我们可以看到,算法所需要计算的参数不仅包括模型参数w和b,另外还包括Batch归一化中的两个参数,我们需要通过优化算法(梯度下降法、Momentum、RMSprop以及Adam等)反复迭代来更新这些参数。实际中,我们在训练深度神经网络时一般是通过Mini-batch方法,因此Batch归一化所处理的就不再是整个训练样本集,而是一小块子训练集。另外值得注意的是,由于在Batch归一化中本身就包含了z与其均值相减的操作,因此无论b[l]的值是多少,最终都是要被均值减法所抵消,所以在应用Batch归一化时其实可以消除参数b[l]。


深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


最终的迭代求解形式也就如下图所示:

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

七、Batch归一化为何奏效

第一个原因,你已经看到前面通过归一化输入特征x,使其均值为0,方差为1。因为与其有一些从0到1、从1到1000的特征值,通过归一化所有的输入特征值x,以获得类似范围的值,进而加速我们的学习过程,而Batch归一化其实也是在做类似的工作,只不过均值不再固定为0方差不再固定为1。第二个原因,Batch归一化可以使权重参数比你的网络更滞后或更深层,比如第10层的权重相比于神经网络中前层的权重(层1)更能经受得住变化。这可能有点难理解,让我们来看看下面的例子,基于下面中的神经网络模型来进行猫脸识别。假设你已经在所有黑猫的图像上训练了数据集,如果现在你要把此网络应用于有色猫,那么你的模型可能就不会太适用。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

那么为什么训练好的模型会不适用新数据了,原因在于训练集与测试集数据的分布是不一样的。对于下面的数据分布,最理想的情况是找到下图所示的绿色分界面,无论是训练集还是测试集都能很好的拟合。但实际上,基于该数据分布的训练集并不可能训练得到该分界面,极有可能训练得到的是一个线性分界面,能够将训练集拟合得很好,但并不适用于测试集。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架
深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

为了使我们的模型不仅能够很好地拟合训练数据还能适用于测试数据,必须该改变数据的分布,包括训练集和测试集,其专业术语为covariate shift。其想法大致为:如果我们已经学习了 x 到 y 的映射,如果 x 的分布改变了,那么可能需要重新训练我们的学习算法,为了避免重新训练,我们尝试去改变输入数据的分布,进而增强我们模型对数据分布改变的适应能力。下面将这种想法引入到下面的深度神经网络中:

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架
对于该神经网络中的第三个隐藏层,神经网络已经学习了参数 w[3],b[3],第三隐藏层也从前层中取得一些输入值,并希望使得最终的输出值 y^ 尽可能接近真实值 y。让我们先遮住第三层左边的部分,从第三层的角度来看,它得到了前层的输出值作为输入,a^[2]_1,a^[2]_2,a^[2]_3,a^[2]_4,第三层的工作就是找到一种方式使这些值映射到 y^。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

当然该神经网络中除了右边的参数 w[3],b[3],w[4],b[4],还有参数w[2],b[2],w[1],b[1],如果这些参数变化,会导致a^[2]_1,a^[2]_2,a^[2]_3,a^[2]_4的值也会发生改变。从第三隐藏层的角度来看,这些隐藏单元的值在不断地发生改变(也就是其分布也在不断改变),所以这里就有了covariate shift的问题。Batch归一化所做的就是减少了这些隐藏值分布变化的数量,因为无论z^[2]_1,z^[2]_2,z^[2]_3,z^[2]_4的值怎么变化,Batch归一化可确保其均值和方差保持不变,这里的具体的均值和方差是由Batch归一化中的两个参数所决定的,因此Batch归一化限制了前层的参数更新影响数据分布的程度。在此基础上,神经网络后面的每层就会有更坚实的基础,即使输入数据的分布改变了,通过Batch归一化也削弱了前层参数的作用,使得神经网络的每层稍稍独立于其他层,能够单独进行学习,这也有助于加速整个神经网络的学习。其实,Batch归一化还有另外一个作用,就是具有轻微的正则化效果,对于应用到每个Mini-batch的Batch归一化,由于只是对一小块训练数据进行求平均和方差,因此计算结果本身是带有噪音的,这也会给后续的每步处理引入噪声,和dropout类似,所以起到了正则化的作用。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

八、测试时的Batch归一化

因为在测试时我们可能需要对样本进行逐一处理,这样一来我们没法求样本的均值和方差,因为一个样本的均值和方差没有意义。具体的做法是:对于每个mini-batch求取每层的 z^[l] 的均值和方差,将每个mini-batch的均值和方差作为指数加权平均中的一项。例如,训练第一个mini-batch X{1},我们得到第 l 层的均值和方差,继续训练第二个mini-batch X{2},得到第二个均值和方差,再训练第一个mini-batch X{3},我们得到第三个的均值和方差,依此类推。正如我们之前用指数加权平均来计算温度值一样,分别计算theta_1,theta_2,theta_3.....的均值,这样我们就能实时得到每个mini-batch均值和方差的加权平均值,将最终的均值和方差作为训练样本和测试样本的均值和方差,进而对单个测试样本进行Batch归一化。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架

在实际当中,无论用什么方式来估算样本整体均值和方差,这套过程都是稳健的。可以通过将整个训练集输入到神经网络来计算其均值和方差,也可以通过上述方式针对单个mini-batch来计算,最后再进行指数加权平均,最后的效果都是很好的,如果是在深度学习开源框架中使用,那么也都会有特定的处理方式来辅助你完成上述处理。

九、Softmax回归

前面我们所接触的分类问题基本都是二分类,这种分类只有两种可能的标记,0或1,对于猫识别问题,要么为猫要么不是猫。如果我们有多种可能的类型呢?我们不得不介绍另一种方法,有一种logistic回归的一般形式,叫做Softmax回归,其能够让我们在识别某一分类时或是多种分类中的一个做出预测,不只是识别两个分类。假设在这里你需要识别的不仅仅是猫,而是要去识别猫,狗,小鸡以及与前面三个都不符合的其他类,其中C为我们的类别个数,数字1代表猫,数字2代表狗,数字3代表小鸡,数字0代表其他类。在这个例子中我们将建立一个神经网络,其输出层有4个单元,我们希望输出层单元的数字告诉我们这4个类别的概率分别为多大,并且4个概率之和为1。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


为了实现上述功能,我们只需在输出层中和Softmax层,Softmax层类似于原先Logistic Regression中的sigmoid**函数。不同的是,Softmax层的输入为一个向量,因为后面需要对每项进行归一化,而sigmoid输入为实数输出也为实数。具体的计算过程如下:

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


Softmax分类器的训练和之前的神经网络训练类似,我们这里直接给出L层也就是输出层的梯度项作为引导,其他前层的梯度项按照之前的方法推导:

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架


十、深度学习框架

前面基于python和numpy的神经网络编程主要是为了理解神经网络的训练过程,但随着神经网络越来越复杂(卷积神经网络、循环神经网络等),我们会发现纯粹基于python和numpy会很困难和复杂,下面是一些常用的深度学习开源框架以及选择框架的指导建议,对于我们构建大型的应用程序会非常有帮助。

深度学习与神经网络-吴恩达(Part2Week3)-超参数调试、Batch正则化和程序框架