这是你所有看到的有关神经网络参数的理解中最通俗易懂的一个了,公式也减到了最少,神经网络的专业人士绕道哦。
在上一篇《理解深度学习的钥匙 –启蒙篇》,我们提到定义⼀个二次代价函数,也叫损失函数或目标函数:
这⾥ w 表⽰所有的⽹络中权重的集合,b 是所有的偏置,n 是训练输⼊数据的个数,a 是表⽰当输⼊为 x 时输出的向量,y(x)是实际输出的向量,求和则是在总的训练输⼊ x 上进⾏的。
参考《理解深度学习的钥匙 –启蒙篇》文章C(v)中v的计算过程,∇C 来表示梯度向量:
现在有两个分量组成w 和b,⽽梯度向量∇C 则有相应的分量∂C/∂w 和 ∂C/∂b,⽤这些分量来写梯度下降的更新规则,我们得到:
通过重复应⽤这⼀更新规则我们就能“让球体滚下⼭”,并且有望能找到代价函数的最⼩值,换句话说,这是⼀个能让神经⽹络学习的规则。
注意这个代价函数是遍及每个训练样本的,x表示某一个样本:
在实践中,为了计算梯度∇C,我们需要为每个训练输⼊x 单独地计算梯度值∇Cx,然后求平均值:
不幸的是,当训练输⼊的数量过⼤时会花费很⻓时间,这样会使学习变得相当缓慢。
1、随机梯度下降
这一节你将了解具体的一个训练过程,了解什么叫作⼩批量数据(mini-batch),什么叫作训练迭代期(epoch)。
有种叫做随机梯度下降的算法能够加速学习,其思想就是通过随机选取⼩量训练输⼊样本来计算∇Cx,进⽽估算梯度∇C,通过计算少量样本的平均值我们可以快速得到⼀个对于实际梯度∇C 的很好的估算,这有助于加速梯度下降,进⽽加速学习过程。
更准确地说,随机梯度下降通过随机选取⼩量的m 个训练输⼊来⼯作,我们将这些随机的训练输⼊标记为X1;X2… Xm,并把它们称为⼀个⼩批量数据(mini-batch)。假设样本数量m ⾜够⼤,我们期望∇Cxj 的平均值⼤致相等于整个∇Cx 的平均值,即:
可以推导得到:
然后我们再挑选另⼀随机选定的⼩批量数据去训练,直到我们⽤完了所有的训练输⼊,这被称为完成了⼀个训练迭代期(epoch)。然后我们就会开始⼀个新的训练迭代期。
我们可以把随机梯度下降想象成⼀次⺠意调查:在⼀个⼩批量数据上采样⽐对⼀个完整数据集进⾏梯度下降分析要容易得多,正如进⾏⼀次⺠意调查⽐举⾏⼀次全⺠选举要更容易。例如,如果我们有⼀个规模为n = 60000 的训练集,就像MNIST,并选取⼩批量数据⼤⼩为m=10,这意味着在估算梯度过程中加速了6000 倍。
现在让我们写⼀个学习如何识别⼿写数字的程序,使⽤随机梯度下降算法和MNIST
训练数据,除了MNIST 数据,我们还需要⼀个叫做Numpy 的Python 库,⽤来做快速线性代数,不要怕,笔者不会贴代码,只是示意一下,大家理解函数调用的方式即可:
在加载完MNIST 数据之后,我们将设置⼀个有784个像素输入、30 个隐藏层神经元、10个输出的Network:
我们将使⽤随机梯度下降来从MNIST training_data 学习超过30 次迭代期,⼩批量数据⼤⼩为10,学习速率η=3.0:
打印内容显⽰了在每轮训练期后神经⽹络能正确识别测试图像的数量。正如你所⻅到,在仅仅⼀次迭代期后,达到了10,000 中选中的9,129 个,⽽且数⽬还在持续增⻓,经过训练的⽹络给出的识别率约为95%:
让我们重新运⾏上⾯的实验,将隐藏神经元数量改到100:
果然,它将结果提升⾄96.59%,⾄少在这种情况下,使⽤更多的隐藏神经元帮助我们得到了更好的结果。
当然,为了获得这些准确性,我不得不对训练的迭代期数量(epoch),⼩批量数据⼤⼩(minbatch)和学习速率η做特别的选择,正如我上⾯所提到的,这些在我们的神经⽹络中被称为超参数,以区别于通过我们的学习算法所学到的参数(权重和偏置),如果我们选择了糟糕的超参数,我们会得到较差的结果。
假如我们选定学习速率为η= 0.001:
结果则不太令人鼓舞了:
然⽽,你可以看到⽹络的性能随着时间的推移慢慢地变好了,这表明应该增⼤学习速率,例如η= 0.01,如果我们那样做了,我们会得到更好的结果,这表明我们应该再次增加学习速率。(如果改变能够改善⼀些事情,试着做更多!)如果我们这样做⼏次,我们最终会得到⼀个像η=1.0 的学习速率(或者调整到3.0),这跟我们之前的实验很接近。因此即使我们最初选择了糟糕的超参数,我们⾄少获得了⾜够的信息来帮助我们改善对于超参数的选择。
通常,调试⼀个神经⽹络是具有挑战性的,尤其是当初始的超参数的选择产⽣的结果还不如随机噪点的时候。假如我们试⽤之前成功的具有30 个隐藏神经元的⽹络结构,但是学习速率改为η= 100,在这点上,我们实际⾛的太远,学习速率太⾼了:
我们可能不仅关⼼学习速率,还要关⼼我们的神经⽹络中的其它每⼀个部分,我们可能想知道是否⽤了让⽹络很难学习的初始权重和偏置?或者可能我们没有⾜够的训练数据来获得有意义的学习?或者我们没有进⾏⾜够的迭代期?或者可能对于具有这种结构的神经⽹络,学习识别⼿写数字是不可能的?可能学习速率太低?或者可能学习速率太⾼?当你第⼀次遇到问题,你不总是能有把握。
就像常规编程那样,它是⼀⻔艺术,你需要学习调试的艺术来获得神经⽹络更好的结果,更普通的是,我们需要启发式⽅法来选择好的超参数和好的结构,后面将讨论怎么样选择超参数。
2、迈向深度学习
这一节你将了解神经网络是如何过渡到深度学习的。
虽然我们的神经网络给出了令⼈印象深刻的表现,但这样的表现带有⼏分神秘,⽹络中的权重和偏置是被⾃动发现的,这意味着我们不能⽴即解释⽹络怎么做的、做了什么,我们能否找到⼀些方法来理解我们的⽹络通过什么原理分类⼿写数字?并且,在知道了这些原理后,我们能做得更好吗?
为了让这些问题更具体,我们假设数⼗年后神经⽹络引发了⼈工智能(AI)。到那个时候,我们能明⽩这种智能⽹络的⼯作机制吗?或许,因为有着⾃动学习得到的权重和偏置,这些是我们⽆法理解的,这样的神经⽹络对我们来说是不透明的。在⼈⼯智能的早期研究阶段,⼈们希望在构建⼈⼯智能的努⼒过程中,也同时能够帮助我们理解智能背后的机制,以及⼈类⼤脑的运转⽅式,但结果可能是我们既不能够理解⼤脑的机制,也不能够理解⼈⼯智能的机制。
为解决这些问题,让我们重新思考⼀下我在本章开始时所给的⼈⼯神经元的解释,作为⼀种衡量证据的方法,假设我们要确定⼀幅图像是否显⽰有⼈脸 :
我们可以用解决⼿写识别问题的相同⽅式来攻克这个问题 —— ⽹络的输⼊是图像中的像素,⽹络的输出是⼀个单个的神经元⽤于表明“是的,这是⼀张脸”或“不,这不是⼀张脸”,假设我们就采取了这个⽅法,但接下来我们先不去使⽤⼀个学习算法,⽽是去尝试亲⼿设计⼀个⽹络,并为它选择合适的权重和偏置。我们要怎样做呢?暂时先忘掉神经⽹络,我们受到启发的⼀个想法是将这个问题分解成⼦问题:图像的左上⻆有⼀个眼睛吗?右上⻆有⼀个眼睛吗?中间有⼀个⿐⼦吗?下⾯中央有⼀个嘴吗?上⾯有头发吗?诸如此类,如果⼀些问题的回答是“是”,或者甚⾄仅仅是“可能是”,那么我们可以作出结论这个图像可能是⼀张脸,相反地,如果⼤多数这些问题的答案是“不是”,那么这张图像可能不是⼀张脸。
这个想法表明了如果我们能够使用神经⽹络来解决这些⼦问题,那么我们也许可以通过将这些解决⼦问题的⽹络结合起来,构成⼀个⼈脸检测的神经⽹络,下图是⼀个可能的结构,其中的⽅框表⽰⼦⽹络,注意,这不是⼀个⼈脸检测问题的现实的解决⽅法,⽽是为了帮助我们构建起⽹络如何运转的直观感受。
子网络也可以被继续分解,这看上去很合理,假设我们考虑这个问题:“左上⻆有⼀个眼睛吗?”这个问题可以被分解成这些⼦问题:“有⼀个眉⽑吗?”,“有睫⽑吗?”,“有虹膜吗?”等等,当然这些问题也应该包含关于位置的信息 —— 诸如“在左上⻆有眉⽑,上⾯有虹膜吗?”——但是让我们先保持简单,回答问题“左上⻆有⼀个眼睛吗?”的⽹络能够被分解成:
这些子问题也同样可以继续被分解,并通过多个⽹络层传递得越来越远,最终,我们的⼦⽹络可以回答那些只包含若⼲个像素点的简单问题。举例来说,这些简单的问题可能是询问图像中的⼏个像素是否构成⾮常简单的形状,这些问题就可以被那些与图像中原始像素点相连的单个神经元所回答,最终的结果是,我们设计出了⼀个⽹络,它将⼀个⾮常复杂的问题 —— 这张图像是否有⼀张⼈脸 —— 分解成在单像素层⾯上就可回答的⾮常简单的问题,它通过⼀系列多层结构来完成,在前⾯的⽹络层,它回答关于输⼊图像⾮常简单明确的问题,在后⾯的⽹络层,它建⽴了⼀个更加复杂和抽象的层级结构,包含这种多层结构 —— 两层或更多隐藏层 —— 的⽹络被称为深度神经网络。
⾃ 2006 年以来,⼈们已经开发了⼀系列技术使深度神经网络能够学习,这些深度学习技术基于随机梯度下降和反向传播,并引进了新的想法,这些技术已经使更深(更⼤)的⽹络能够被训练 —— 现在训练⼀个有 5 到 10 层隐藏层的⽹络都是很常⻅的,⽽且事实证明,在许多问题上,它们⽐那些浅层神经⽹络,例如仅有⼀个隐藏层的⽹络,表现的更加出⾊,当然,原因是深度⽹络能够构建起⼀个复杂的概念的层次结构。
3、交叉熵代价函数
这一节你将了解神经网络训练速度太慢的原因,为什么要用交叉熵代价函数替代MSE或二次代价函数。
我们希望和期待神经网络可以从错误中快速地学习,在实践中,这种情况经常出现吗?为了回答这个问题,让我们看看⼀个⼩例⼦,这个例⼦包含⼀个只有⼀个输入的神经元:
我们会训练这个神经元来做⼀件非常简单的事:让输⼊ 1 转化为 0。当然,这很简单了,⼿⼯找到合适的权重和偏置就可以了,然⽽,看起来使⽤梯度下降的⽅式来学习权重和偏置是很有启发的,所以,我们来看看神经元如何学习。
为了让这个例⼦更明确,我会⾸先将权重和偏置初始化为 0.6 和 0.9。这些就是⼀般的开始学习的选择,并没有任何刻意的想法。⼀开始的神经元的输出是 0.82,所以这离我们的⽬标输出0.0 还差得很远,从下图来看看神经元如何学习到让输出接近 0.0 的,注意这些图像实际上是正在进⾏梯度的计算,然后使⽤梯度更新来对权重和偏置进⾏更新,并且展⽰结果,设置学习速率 η = 0.15 进行学习⼀⽅⾯⾜够慢的让我们跟随学习的过程,另⼀⽅⾯也保证了学习的时间不会太久,⼏秒钟应该就⾜够了,代价函数就是MSE,C。
随着迭代期的增加,神经元的输出、权重、偏置和代价的变化如下⾯⼀系列图形所⽰:
正如你所⻅,神经元快速地学到了使得代价函数下降的权重和偏置,给出了最终的输出为0.09,这虽然不是我们的目标输出 0.0,但是已经挺好了。
假设我们现在将初始权重和偏置都设置为 2.0,此时初始输出为 0.98,这是和目标值的差距相当⼤的,现在看看神经元学习的过程。
你将看到如下的⼀系列变化:
虽然这个例⼦使用了同样的学习速率(η = 0.15),我们可以看到刚开始的学习速度是⽐较缓慢的,对前 150 左右的学习次数,权重和偏置并没有发⽣太⼤的变化,随后学习速度加快,与上⼀个例⼦中类似了,神经⽹络的输出也迅速接近 0.0。
这种行为看起来和⼈类学习⾏为差异很,我们通常是在犯错⽐较明显的时候学习的速度最快,但是我们已经看到了⼈⼯神经元在其犯错较⼤的情况下其实学习很有难度,⽽且,这种现象不仅仅是在这个⼩例⼦中出现,也会在更加⼀般的神经⽹络中出现,为何学习如此缓慢?我们能够找到避免这种情况的方法吗?
为了理解这个问题的源头,想想我们的神经元是通过改变权重和偏置,并以⼀个代价函数的偏导数(∂C/∂w 和 ∂C/∂b)决定的速度学习,所以,我们在说“学习缓慢”时,实际上就是说这些偏导数很⼩,理解他们为何这么⼩就是我们⾯临的挑战,为了理解这些,让我们计算偏导数看看,我们⼀直在⽤的是⼆次代价函数,定义如下:
其中 a 是神经元的输出,训练输⼊为 x = 1,y = 0 则是⽬标输出,显式地使⽤权重和偏置来表达这个,我们有 a = σ(z),其中 z = wx + b,使用链式法则来求权重和偏置的偏导数就有:
其中我已经将 x = 1 和 y = 0 代⼊了。为了理解这些表达式的行为,让我们仔细看 σ ′ (z) 这⼀项,⾸先回忆⼀下 σ 函数图像:
我们可以从这幅图看出,当神经元的输出接近 1 的时候,曲线变得相当平,所以 σ ′ (z) 就很⼩了,也即∂C/∂w 和 ∂C/∂b 会⾮常⼩,这其实就是学习缓慢的原因所在,⽽且,我们后面也会提到,这种学习速度下降的原因实际上也是更加⼀般的神经⽹络学习缓慢的原因,并不仅仅是在这个特例中特有的。
研究表明,我们可以通过使用交叉熵代价函数来替换⼆次代价函数,为了理解什么是交叉熵,我们稍微改变⼀下之前的简单例⼦,假设,我们现在要训练⼀个包含若⼲输⼊变量的的神经元,x1 ,x2 ,... 对应的权重为 w1 ,w2 ,... 和偏置 b:
神经元的输出就是 a = σ(z),其中 z =∑j W j X j+ b 是输⼊的带权和,我们如下定义这个神经元的交叉熵代价函数:
其中 n 是训练数据的总数,求和是在所有的训练输⼊ x 上进⾏的,y 是对应的⽬标输出,在解决学习缓慢前,我们来看看交叉熵为何能够解释成⼀个代价函数。
如果对于所有的训练输⼊ x,神经元实际的输出接近⽬标值,那么交叉熵将接近 0,假设在这个例⼦中,y = 0 ⽽ a ≈ 0,交叉熵接近于0,反之,y = 1 ⽽ a ≈ 1,交叉熵也接近于0,综上所述,交叉熵是⾮负的,在神经元达到很好的正确率的时候会接近 0,这些其实就是我们想要的代价函数的特性,其实这些特性也是⼆次代价函数具备的,所以,交叉熵就是很好的选择了。
但是交叉熵代价函数有⼀个⽐二次代价函数更好的特性就是它避免了学习速度下降的问题,为了弄清楚这个情况,我们来算算交叉熵函数关于权重的偏导数,只列出结果:
这是⼀个优美的公式,它告诉我们权重学习的速度受到 σ(z) − y,也就是输出中的误差的控制,更大的误差,更快的学习速度,这是我们直觉上期待的结果。特别地,这个代价函数还避免了像在⼆次代价函数中类似⽅程中 σ ′ (z) 导致的学习缓慢。
让我们重回最原初的例⼦,来看看换成了交叉熵之后的学习过程,现在仍然按照前⾯的参数配置来初始化⽹络,开始权重为 0.6,而偏置为 0.9。
看看在换成交叉熵之后⽹络的学习情况,你将看到如下变化的曲线:
毫不奇怪,在这个例子中,神经元学习得相当出⾊,跟之前差不多,现在我们再看看之前出问题的那个例⼦(链接),权重和偏置都初始化为 2.0:
你将看到如下变化的曲线:
成功了!这次神经元的学习速度相当快,跟我们预期的那样,如果你观测的⾜够仔细,你可以发现代价函数曲线要⽐二次代价函数训练前⾯部分要陡很多,那个交叉熵导致的陡度让我们⾼兴,这正是我们期待的当神经元开始出现严重错误时能以最快速度学习。
4、过度拟合
这一节你将了解过度拟合的一般原因和解决策略。
诺贝尔奖获得者,物理学家恩⾥科·费⽶有⼀次被问到他对⼀些同僚提出的⼀个数学模型的意⻅,这个数学模型尝试解决⼀个重要的未解决的物理难题。模型和实验⾮常匹配,但是费⽶却对其产⽣了怀疑。他问模型中需要设置的⾃由参数有多少个。答案是“4”。费⽶回答道 6 :“我记得我的朋友约翰·冯·诺伊曼过去常说,有四个参数,我可以模拟⼀头⼤象,⽽有五个参数,我还能让他卷鼻⼦。”
这⾥,其实是说拥有大量的⾃由参数的模型能够描述特别神奇的现象。即使这样的模型能够很好的拟合已有的数据,但并不表⽰是⼀个好模型。因为这可能只是因为模型中⾜够的⾃由度使得它可以描述⼏乎所有给定⼤⼩的数据集,⽽不需要真正洞察现象的本质。所以发⽣这种情形时,模型对已有的数据会表现的很好,但是对新的数据很难泛化,对⼀个模型真正的测验就是它对没有⻅过的场景的预测能⼒。
费米和冯·诺伊曼对有四个参数的模型就开始怀疑了,我们⽤来对 MNIST 数字分类的 30 个隐藏神经元神经⽹络拥有将近 24,000 个参数!当然很多,我们有 100 个隐藏元的⽹络拥有将近80,000 个参数,⽽⽬前最先进的深度神经⽹络包含百万级或者⼗亿级的参数。我们应当信赖这些结果么?
让我们通过构造⼀个网络泛华能⼒很差的例⼦使这个问题更清晰。我们的⽹络有 30 个隐藏神经元,共 23,860 个参数,但是我们不会使⽤所有 50,000 幅 MNIST 训练图像,相反,我们只使⽤前 1,000 幅图像。使⽤这个受限的集合,会让泛化的问题突显。我们按照之前同样的⽅式,使⽤交叉熵代价函数,学习速率设置为 η = 0.5 ⽽⼩批量数据⼤⼩设置为 10,不过这⾥我们要训练 400 个迭代期,⽐前⾯的要多⼀些,因为我们只⽤了少量的训练样本。
使⽤上面的结果,我们可以画出当⽹络学习时代价变化的情况:
这看起来令人振奋,因为代价函数有⼀个光滑的下降,跟我们预期⼀致。注意,我只是展⽰了 200 到 399 迭代期的情况。
让我们看看分类准确率在测试集上的表现:
这里我还是聚焦到了后⾯的过程。在前 200 迭代期(图中没有显⽰)中准确率提升到了 82%。然后学习逐渐变缓,最终,在 280 迭代期左右分类准确率就停⽌了增⻓,后⾯的迭代期,仅仅看到了在 280 迭代期准确率周围随机的⼩波动,将这幅图和前⾯的图进⾏对⽐,前⾯的图中和训练数据相关的代价持续平滑下降,如果我们只看那个代价,会发现我们模型的表现变得“更好”,但是测试准确率展⽰了提升只是⼀种假象,就像费⽶不⼤喜欢的那个模型⼀样,我们的⽹络在 280 迭代期后就不在能够推⼴到测试数据上,所以这不是有⽤的学习,我们说⽹络在 280迭代期后就过度拟合(overfitting)或者过度训练(overtraining)了。
所以我们的网络实际上在学习训练数据集的特例,⽽不是能够⼀般地进⾏识别,我们的⽹络⼏乎是在单纯记忆训练集合,⽽没有对数字本质进⾏理解能够泛化到测试数据集上。
过度拟合是神经网络的⼀个主要问题。这在现代⽹络中特别正常,因为⽹络权重和偏置数量巨⼤,为了⾼效地训练,我们需要⼀种检测过度拟合是不是发⽣的技术,这样我们不会过度训练,并且我们也想要找到⼀些技术来降低过度拟合的影响。
检测过度拟合的明显方法是使⽤上⾯的⽅法 —— 跟踪测试数据集合上的准确率随训练变化情况,如果我们看到测试数据上的准确率不再提升,那么我们就停⽌训练。当然,严格地说,这其实并⾮是过度拟合的⼀个必要现象,因为测试集和训练集上的准确率可能会同时停⽌提升,当然,采⽤这样的策略是可以阻⽌过度拟合的。
我们已经研究了只使⽤ 1,000 幅训练图像时的过度拟合问题。那么如果我们使⽤所有的50,000 幅图像的训练数据会发⽣什么?我们会保留所有其它的参数都⼀样(30 个隐藏元,学习速率 0.5,小批量数据规模为 10),但是迭代期为 30 次,下图展⽰了分类准确率在训练和测试集上的变化情况。
如你所⻅,测试集和训练集上的准确率相⽐我们使⽤ 1,000 个训练数据时相差更小。特别地,在训练数据上的最佳的分类准确率 97.86% 只⽐测试集上的 95.33% 准确率⾼了 1.53%。⽽之前的例⼦中,这个差距是 17.73%!过度拟合仍然发⽣了,但是已经减轻了不少,我们的⽹络从训练数据上更好地泛化到了测试数据上,⼀般来说,最好的降低过度拟合的⽅式之⼀就是增加训练样本的量,有了⾜够的训练数据,就算是⼀个规模⾮常⼤的⽹络也不⼤容易过度拟合,不幸的是,训练数据其实是很难或者很昂贵的资源,所以这不是⼀种太切实际的选择。
5、规范化
这一节你将了解用规范化方法来防止过度拟合的方法,但无法给出科学的解释。
增加训练样本的数量是⼀种减轻过度拟合的方法,还有其他的⼀下⽅法能够减轻过度拟合的程度吗?⼀种可⾏的⽅式就是降低⽹络的规模。然⽽,⼤的⽹络拥有⼀种⽐⼩⽹络更强的潜⼒,所以这⾥存在⼀种应⽤冗余性的选项,幸运的是,还有其他的技术能够缓解过度拟合,即使我们只有⼀个固定的⽹络和固定的训练集合,这种技术就是规范化。
本节,我会给出⼀种最为常⽤的规范化手段 —— 有时候被称为权重衰减(weight decay)或者 L2 规范化,L2 规范化的想法是增加⼀个额外的项到代价函数上,这个项叫做规范化项,下⾯是规范化的交叉熵:
其中第⼀个项就是常规的交叉熵的表达式。第⼆个现在加⼊的就是所有权重的平⽅的和,然后使⽤⼀个因⼦ λ/2n 进⾏量化调整,其中 λ > 0 可以称为规范化参数,⽽ n 就是训练集合的⼤⼩,我们会在后⾯讨论 λ 的选择策略。
直觉地看,规范化的效果是让网络倾向于学习⼩⼀点的权重,其他的东西都⼀样的。⼤的权重只有能够给出代价函数第⼀项⾜够的提升时才被允许,换⾔之,规范化可以当做⼀种寻找⼩的权重和最⼩化原始的代价函数之间的折中,这两部分之前相对的重要性就由 λ 的值来控制了:λ 越⼩,就偏向于最⼩化原始代价函数,反之,倾向于⼩的权重。
现在,对于这样的折中为何能够减轻过度拟合还不是很清楚!但是,实际表现表明了这点。
为了构造这个例⼦,我们⾸先需要弄清楚如何将随机梯度下降算法应⽤在⼀个规范化的神经网络上。
这正和通常的梯度下降学习规则相同,除了通过⼀个因⼦ 1−ηλ/n重新调整了权重 w,这种调整有时被称为权重衰减,因为它使得权重变⼩,粗看,这样会导致权重会不断下降到 0,但是实际不是这样的,因为如果在原始代价函数中造成下降的话其他的项可能会让权重增加。
让我们看看规范化给网络带来的性能提升吧。这⾥还会使⽤有 30 个隐藏神经元、⼩批量数据⼤⼩为 10,学习速率为 0.5,使⽤交叉熵的神经⽹络,然⽽,这次我们会使⽤规范化参数为λ = 0.1,注意在代码中,我们使⽤的变量名字为 lmbda。
训练集上的代价函数持续下降,和前⾯无规范化的情况⼀样的规律:
但是这次测试集上的准确率在整个 400 迭代期内持续增加:
显然,规范化的使用能够解决过度拟合的问题,⽽且,准确率相当⾼了,最⾼处达到了 87.1%,相较于之前的 82.27%,因此,我们⼏乎可以确信在 400 迭代期之后持续训练会有更加好的结果,看起来,经实践检验,规范化让⽹络具有更好的泛化能⼒,显著地减轻了过度拟合的影响。
我们已经看到了规范化在实践中能够减少过度拟合了,这是令⼈振奋的,不过,这背后的原因还不得而知!通常的说法是:⼩的权重在某种程度上,意味着更低的复杂性,也就对数据给出了⼀种更简单却更强⼤解释,因此应该优先选择,这虽然很简短,不过暗藏了⼀些可能看起来会令⼈困惑的因素。
假设神经网络⼤多数有很⼩的权重,这最可能出现在规范化的⽹络中,更⼩的权重意味着⽹络的⾏为不会因为我们随便改变了⼀个输⼊⽽改变太⼤,这会让规范化⽹络学习局部噪声的影响更加困难,将它看做是⼀种让单个的证据不会影响⽹络输出太多的⽅式。相对的,规范化⽹络学习去对整个训练集中经常出现的证据进⾏反应。对⽐看,⼤权重的⽹络可能会因为输⼊的微⼩改变⽽产⽣⽐较⼤的⾏为改变。所以⼀个⽆规范化的⽹络可以使⽤⼤的权重来学习包含训练数据中的噪声的⼤量信息的复杂模型。简⾔之,规范化⽹络受限于根据训练数据中常⻅的模式来构造相对简单的模型,⽽能够抵抗训练数据中的噪声的特性影响,我们的想法就是这可以让我们的⽹络对看到的现象进⾏真实的学习,并能够根据已经学到的知识更好地进⾏泛化。
所以,倾向于更简单的解释的想法其实会让我们觉得紧张。人们有时候将这个想法称为“奥卡姆剃⼑原则”,然后就会热情地将其当成某种科学原理来应⽤这个法则。但是,这就不是⼀个⼀般的科学原理,也没有任何先验的逻辑原因来说明简单的解释就⽐更为负责的解释要好。
我们应当时时记住这⼀点,规范化的神经网络常常能够⽐⾮规范化的泛化能⼒更强,这只是⼀种实验事实(empirical fact)。
6、弃权
这一节你将了解用相当激进的弃权(Dropout)防止过度拟合的技术。
弃权(Dropout)是⼀种相当激进的技术,和规范化不同,弃权技术并不依赖对代价函数的修改,⽽是,在弃权中,我们改变了⽹络本⾝。
假设我们尝试训练⼀个网络:
特别地,假设我们有⼀个训练数据 x 和对应的目标输出 y,通常我们会通过在⽹络中前向传播 x ,然后进⾏反向传播来确定对梯度的贡献,使⽤弃权技术,这个过程就改了。我们会从随机(临时)地删除⽹络中的⼀半的隐藏神经元开始,同时让输⼊层和输出层的神经元保持不变。在此之后,我们会得到最终如下线条所⽰的⽹络。注意那些被弃权的神经元,即那些临时被删除的神经元,⽤虚圈表⽰在图中:
我们前向传播输⼊ x,通过修改后的⽹络,然后反向传播结果,同样通过这个修改后的⽹络,在⼀个小批量数据⼩批量的若⼲样本上进⾏这些步骤后,我们对有关的权重和偏置进⾏更新。然后重复这个过程,⾸先重置弃权的神经元,然后选择⼀个新的随机的隐藏神经元的⼦集进⾏删除,估计对⼀个不同的⼩批量数据的梯度,然后更新权重和偏置。
通过不断地重复,我们的网络会学到⼀个权重和偏置的集合。当然,这些权重和偏置也是在⼀半的隐藏神经元被弃权的情形下学到的,当我们实际运⾏整个⽹络时,是指两倍的隐藏神经元将会被激活,为了补偿这个,我们将从隐藏神经元元出去的权重减半。
为什么我们会指望这样的⽅法能够进⾏规范化呢?为了解释所发⽣的事,我希望你停下来想⼀下没有标准(没有弃权)的训练⽅式。特别地,想象⼀下我们训练⼏个不同的神经⽹络,都使⽤同⼀个训练数据,当然,⽹络可能不是从同⼀初始状态开始的,最终的结果也会有⼀些差异。出现这种情况时,我们可以使⽤⼀些平均或者投票的⽅式来确定接受哪个输出。例如,如果我们训练了五个⽹络,其中三个把⼀个数字分类成“3”,那很可能它是“3”,另外两个可能就犯了错误。这种平均的方式通常是⼀种强⼤(尽管代价昂贵)的⽅式来减轻过度拟合,原因在于不同的⽹络可能会以不同的⽅式过度拟合,平均法可能会帮助我们消除那样的过度拟合。
那么这和弃权有什么关系呢?启发式地看,当我们弃权掉不同的神经元集合时,有点像我们在训练不同的神经网络。所以,弃权过程就如同⼤量不同⽹络的效果的平均那样,不同的⽹络会以不同的⽅式过度拟合了,所以,弃权过的⽹络的效果会减轻过度拟合。
弃权技术的真正衡量是它已经在提升神经⽹络性能上应用得相当成功,在训练⼤规模深度⽹络时尤其有⽤,这样的⽹络中过度拟合问题经常特别突出。
7、人为扩展训练数据
我们前面看到了 MNIST 分类准确率在我们使⽤ 1,000 幅训练图像时候下降到了 80% 中间的准确率。这种情况并不奇怪,因为更少的训练数据意味着我们的⽹络接触更少的⼈类⼿写的数字中的变化。让我们训练 30 个隐藏神经元的⽹络,使⽤不同的训练数据集,来看看性能的变化情况。我们使⽤⼩批量数据⼤⼩为 10,学习速率为 η = 0.5,规范化参数是λ = 5.0,交叉熵代价函数,我们在全部训练数据集合上训练 30 个迭代期,然后会随着训练数据量的下降⽽成⽐例增加迭代期的数量。
分类准确率在使⽤更多的训练数据时提升了很⼤。根据这个趋势的话,提升会随着更多的数据⽽不断增加。
获取更多的训练样本其实是很好的想法。不幸的是,这个⽅法代价很⼤,在实践中常常是很难达到的,不过,还有⼀种⽅法能够获得类似的效果,那就是⼈为扩展训练数据,假设我们使⽤⼀个 5 的 MNIST 训练图像:
将其进⾏旋转,比如说 15 度:
这还是会被设别为同样的数字的,但是在像素层级这和任何⼀幅在 MNIST 训练数据中的图像都不相同,所以将这样的样本加⼊到训练数据中是很可能帮助我们的⽹络学会更多如何分类数字,⽽且,显然我们不限于只增加这幅图像,我们可以在所有的 MNIST 训练样本上通过很多小的旋转扩展训练数据,然后使⽤扩展后的训练数据来提升我们⽹络的性能。
这个想法非常强⼤并且已经被⼴发应⽤了。让我们从⼀篇论⽂看看⼀些结果,这⽚论⽂中,作者在 MNIST 上使⽤了⼏个的这种想法的变化⽅式。其中⼀种他们考虑的⽹络结构其实和我们已经使⽤过的类似 —— ⼀个拥有 800 个隐藏元的前馈神经⽹络,使⽤了交叉熵代价函数。在标准的 MNIST 训练数据上运⾏这个⽹络,得到了 98.4% 的分类准确率,他们不只旋转,还转换和扭曲图像来扩展训练数据,通过在这个扩展后的数据集上的训练,他们提升到了 98.9% 的准确率,然后还在“弹性扭曲”的数据上进⾏了实验,这是⼀种特殊的为了模仿⼿部肌⾁的随机抖动的图像扭曲⽅法,通过使⽤弹性扭曲扩展的数据,他们最终达到了 99.3% 的分类准确率,他们通过展⽰训练数据的所有类型的变化形式来扩展⽹络的经验。
8、权重初始化
创建了神经网络后,我们需要进⾏权重和偏置的初始化,之前的⽅式就是根据独⽴⾼斯随机变量来选择权重和偏置,其被归⼀化为均值为 0,标准差 1。这个⽅法⼯作的还不错,但是⾮常特别,所以值得去重新探讨它,看看是否能寻找⼀些更好的⽅式来设置初始的权重和偏置,这也许能帮助我们的⽹络学习得更快。
结果表明,我们可以比使⽤归⼀化的⾼斯分布做得更好,为什么?假设我们使⽤⼀个有⼤量输⼊神经元的⽹络,⽐如说 1,000 个,假设,我们已经使⽤归⼀化的⾼斯分布初始化了连接第⼀个隐藏层的权重,现在我将注意⼒集中在这⼀层的连接权重上,忽略⽹络其他部分:
为了简化,假设我们使用训练输⼊ x,其中⼀半的输⼊神经元值为 1,另⼀半为 0,以下的论点更普遍适⽤,但你可以从这种特殊情况得到要点。让我们考虑隐藏神经元输⼊的带权和z =∑j W j X j+ b。其中 500 个项消去了,因为对应的输⼊ X j 为 0。所以 z 是遍历总共 501 个归⼀化的⾼斯随机变量的和,包含 500 个权重项和额外的 1 个偏置项,因此 z 本⾝是⼀个均值为 0标准差为√ 501 ≈ 22.4 的⾼斯分布。z 其实有⼀个⾮常宽的⾼斯分布,完全不是⾮常尖的形状:
尤其是,我们可以从这幅图中看出 |z| 会变得非常的⼤,即 z ≫ 1 或者 z ≪−1。如果是这样,隐藏神经元的输出 σ(z) 就会接近 1 或者 0。也就表⽰我们的隐藏神经元会饱和。所以当出现这样的情况时,在权重中进⾏微⼩的调整仅仅会给隐藏神经元的激活值带来极其微弱的改变。⽽这种微弱的改变也会影响⽹络中剩下的神经元,然后会带来相应的代价函数的改变。结果就是,这些权重在我们进⾏梯度下降算法时会学习得⾮常缓慢。
假设我们有⼀个有 n 个输入权重的神经元。我们会使⽤均值为 0 标准差为 1/ √ n 的⾼斯随机分布初始化这些权重。也就是说,我们会向下挤压⾼斯分布,让我们的神经元更不可能饱和,我们会继续使⽤均值为 0 标准差为 1 的⾼斯分布来对偏置进⾏初始化,后⾯会告诉你原因。有了这些设定,带权和 z =∑jW jX j+ b 仍然是⼀个均值为 0,不过有尖锐峰值的⾼斯分布。假设,我们有 500 个值为 0 的输⼊和 500 个值为 1 的输⼊。那么很容易证明 z 是服从均值为 0 标准差为√ 3/2 = 1.22... 的⾼斯分布。
这样的⼀个神经元更不可能饱和,因此也不大可能遇到学习速度下降的问题,让我们在 MNIST 数字分类任务上⽐较⼀下新旧两种权重初始化⽅式,同样,还是使⽤ 30 个隐藏元,⼩批量数据的⼤⼩为 10,规范化参数 λ = 5.0,然后是交叉熵代价函数。我们将学习速率从 η = 0.5 降到 0.1,因为这样会让结果在图像中表现得更加明显。
两种情形下,我们在 96% 的准确率上重合了。最终的分类准确率⼏乎完全⼀样。但是新的初始化技术带来了速度的提升,在第⼀种初始化⽅式的分类准确率在 87% 以下,⽽新的⽅法已经⼏乎达到了 93%。看起来的情况就是我们新的关于权重初始化的⽅式将训练带到了⼀个新的境界,让我们能够更加快速地得到好的结果。
9、宽泛策略
直到现在,我们还没有解释对诸如学习速率 η,规范化参数 λ 等等超参数选择的⽅法,我只是给出那些效果很好的值⽽已,实践中,当你使⽤神经网络解决问题时,寻找好的超参数其实是很困难的⼀件事。例如,我们要解决 MNIST 问题,开始时对于选择什么样的超参数⼀⽆所知。假设,刚开始的实验中选择前⾯章节的参数都是运⽓较好,但在使⽤学习速率 η=10.0 ⽽规范化参数 λ = 1000.0,下⾯是我们的⼀个尝试:
我们分类准确率并不比随机选择更好,⽹络就像随机噪声产⽣器⼀样,你可能会说,“这好办,降低学习速率和规范化参数就好了。”不幸的是,你并不先验地知道这些就是需要调整的超参数。可能真正的问题出在 30 个隐藏元中,本身就不能很有效,不管我们如何调整其他的超参数都没有作⽤的?可能我们真的需要⾄少 100 个隐藏神经元?或者是 300个隐藏神经元?或者更多层的⽹络?或者不同输出编码⽅式?可能我们的⽹络⼀直在学习,只是学习的回合还不够?可能 minibatch 的太⼩了?可能我们需要切换成⼆次代价函数?可能我们需要尝试不同的权重初始化⽅法?等等。很容易就在超参数的选择中迷失了⽅向。如果你的⽹络规模很⼤,或者使⽤了很多的训练数据,这种情况就很令⼈失望了,因为⼀次训练可能就要⼏个⼩时甚⾄⼏天乃⾄⼏周,最终什么都没有获得。如果这种情况⼀直发⽣,就会打击你的⾃信⼼。可能你会怀疑神经⽹络是不是适合你所遇到的问题?可能就应该放弃这种尝试了?
假设,我们第⼀次遇到 MNIST 分类问题。刚开始,你很有激情,但是当第⼀个神经⽹络完全失效时,你会就得有些沮丧,此时就可以将问题简化,丢开训练和验证集合中的那些除了 0 和 1的那些图像,然后试着训练⼀个⽹络来区分 0 和 1,不仅仅问题⽐ 10 个分类的情况简化了,同样也会减少 80% 的训练数据,这样就给出了 5 倍的加速。这样可以保证更快的实验,也能给予你关于如何构建好的网络更快的洞察。
你通过简化网络来加速实验进⾏更有意义的学习,如果你相信 [784,10] 的⽹络更可能⽐随机更加好的分类效果,那么就从这个⽹络开始实验,这会⽐训练⼀个 [784,30,10] 的⽹络更快,你可以进⼀步尝试后⼀个。
你可以通过提⾼监控的频率来在试验中获得另⼀个加速了,比如我们将训练数据减少到前 1,000 幅 MNIST 训练图像。让我们尝试⼀下,看看结果:
在上⾯的例⼦中,我设置 λ=1000.0,跟我们之前⼀样。但是因为这⾥改变了训练样本的个数,我们必须对 λ 进⾏调整以保证权重下降的同步性,这意味着改变 λ =20.0,如果我们这样设置,则有:
哦也!现在有了信号了,不是非常糟糕的信号,却真是⼀个信号。我们可以基于这点,来改变超参数从⽽获得更多的提升,可能我们猜测学习速率需要增加(你可以能会发现,这只是⼀个不⼤好的猜测,原因后⾯会讲,但是相信我)所以为了测试我们的猜测就将 η 调整⾄ 100.0:
这并不好!告诉我们之前的猜测是错误的,问题并不是学习速率太低了,所以,我们试着将η 将⾄ η = 1.0:
这样好点了!所以我们可以继续,逐个调整每个超参数,慢慢提升性能。⼀旦我们找到⼀种提升性能的 η 值,我们就可以尝试寻找好的值。然后按照⼀个更加复杂的⽹络架构进⾏实验,假设是⼀个有 10 个隐藏元的⽹络。然后继续调整 η 和 λ。接着调整成 20 个隐藏元。然后将其他的超参数调整再调整。如此进⾏,在每⼀步使用我们 hold out 验证数据集来评价性能,使⽤这些度量来找到越来越好的超参数,当我们这么做的时候,⼀般都需要花费更多时间来发现由于超参数改变带来的影响,这样就可以⼀步步减少监控的频率。
所有这些作为⼀种宽泛的策略看起来很有前途。
10、学习速率
假设我们运⾏了三个不同学习速率(η = 0.025、η = 0.25、η = 2.5)的 MNIST 网络,我们会像前⾯介绍的实验那样设置其他的超参数,进⾏30 回合,minibatch ⼤⼩为 10,然后λ = 5.0,我们同样会使⽤整个 50,000 幅训练图像,下⾯是⼀副展⽰了训练代价的变化情况的图:
使⽤ η = 0.025,代价函数平滑下降到最后的回合,使⽤ η = 0.25,代价刚开始下降,在⼤约20 回合后接近饱和状态,后⾯就是微小的震荡和随机抖动,最终使⽤ η = 2.5 代价从始⾄终都震荡得⾮常明显,为了理解震荡的原因,回想⼀下随机梯度下降其实是期望我们能够逐渐地抵达代价函数的⾕底的:
然⽽,如果 η 太大的话,步⻓也会变⼤可能会使得算法在接近最⼩值时候⼜越过了⾕底,这在η = 2.5 时⾮常可能发⽣。当我们选择 η = 0.25 时,初始⼏步将我们带到了⾕底附近,但⼀旦到达了⾕底,⼜很容易跨越过去,⽽在我们选择 η = 0.025 时,在前 30 回合的训练中不再受到这个情况的影响。当然,选择太⼩的学习速率,也会带来另⼀个问题 —— 随机梯度下降算法变慢了,⼀种更加好的策略其实是,在开始时使⽤ η = 0.25,随着越来越接近⾕底,就换成 η = 0.025,现在,我们就聚焦在找出⼀个单独的好的学习速率的选择η。
所以,有了这样的想法,我们可以如下设置 η。⾸先,我们选择在训练数据上的代价⽴即开始下降⽽非震荡或者增加时作为 η 的阈值的估计,这个估计并不需要太过精确,你可以估计这个值的量级,⽐如说从 η = 0.01 开始,如果代价在训练的前⾯若⼲回合开始下降,你就可以逐步地尝试 η = 0.1,1.0,...,直到你找到⼀个 η 的值使得在开始若⼲回合代价就开始震荡或者增加,相反,如果代价在 η = 0.01 时就开始震荡或者增加,那就尝试 η = 0.001,0.0001,... 直到你找到代价在开始回合就下降的设定,按照这样的⽅法,我们可以掌握学习速率的阈值的量级的估计,你可以选择性地优化估计,选择那些最⼤的 η,⽐⽅说 η = 0.5 或者 η = 0.2。
11、小批量数据大小
我们应该如何设置小批量数据的⼤⼩?为了回答这个问题,让我们先假设正在进⾏在线学习,也就是说使⽤⼤⼩为 1 的⼩批量数据。
我们使用100 的小批量数据的学习规则如下:
这⾥是对小批量数据中所有训练样本求和,而在线学习是:
即使它仅仅是 50 倍的时间,结果仍然⽐直接在线学习更好,因为我们在线学习更新得太过频繁了。
所以,选择最好的小批量数据⼤⼩也是⼀种折衷,太⼩了,你不会⽤上很好的矩阵库的快速计算,太⼤,你是不能够⾜够频繁地更新权重的,你所需要的是选择⼀个折衷的值,可以最⼤化学习的速度,幸运的是,⼩批量数据⼤⼩的选择其实是相对独⽴的⼀个超参数(⽹络整体架构外的参数),所以你不需要优化那些参数来寻找好的⼩批量数据⼤⼩,因此,可以选择的⽅式就是使⽤某些可以接受的值(不需要是最优的)作为其他参数的选择,然后进⾏不同⼩批量数据⼤⼩的尝试,像上⾯那样调整 η。画出验证准确率的值随时间(⾮回合)变化的图,选择哪个得到最快性能的提升的⼩批量数据⼤⼩。得到了 ⼩批量数据⼤⼩,也就可以对其他的超参数进⾏优化了。
跟随上面看的经验并不能帮助你的⽹络给出绝对最优的结果,但是很可能给你⼀个好的开始和⼀个改进的基础,特别地,我已经非常独⽴地讨论了超参数的选择。实践中,超参数之间存在着很多关系,你可能使⽤ η 进⾏试验,发现效果不错,然后去优化 λ,发现这⾥⼜对 η 混在⼀起了,在实践中,⼀般是来回往复进⾏的,最终逐步地选择到好的值。总之,启发式规则其实都是经验,不是⾦规⽟律。你应该注意那些没有效果的尝试的信号,然后乐于尝试更多试验,特别地,这意味着需要更加细致地监控神经⽹络⾏为,特别是验证集上的准确率。
设定超参数的挑战让⼀些人抱怨神经⽹络相⽐较其他的机器学习算法需要⼤量的⼯作进⾏参数选择。我也听到很多不同的版本:“的确,参数完美的神经⽹络可能会在这问题上获得最优的性能。但是,我可以尝试⼀下随机森林(或者 SVM 或者……这⾥脑补⾃⼰偏爱的技术)也能够⼯作的。我没有时间搞清楚那个最好的神经⽹络。”当然,从⼀个实践者角度,肯定是应⽤更加容易的技术,这在你刚开始处理某个问题时尤其如此,因为那时候,你都不确定⼀个机器学习算法能够解决那个问题。但是,如果获得最优的性能是最重要的⽬标的话,你就可能需要尝试更加复杂精妙的知识的⽅法了,如果机器学习总是简单的话那是太好不过了,但也没有⼀个应当的理由说机器学习⾮得这么简单。
洋洋洒洒这么多,其实也只是接触了些皮毛,但相对于很多书本关于公式和代码的堆砌,这写内容的确给人以不少启迪,让你知道为什么这么做,而让笔者吃惊的是,神经网络的参数调整很多竟然是没有明确科学依据的,更多的还要依赖经验。