通过梯度下降法学习参数
我们已经设计出了一个神经网络结构,现在面临的问题是,它应该如何学习识别数字呢?首先,我们需要一个待学习的数据集——即所谓的训练数据集。我们下面会使用MNIST数据集,其中包含了大量扫描得到的手写数字图像以及它们对应的数字。MNIST 数据集是由NIST(the United States' National Institute of Standards and Technology,美国国家标准与技术研究院)根据收集得到的两个数据集经修改后得到的子数据集构成,所以取名叫 MNIST。下面是 MNIST 中的一些图像:
正如你所见,这些数字实际上就是我们在本章开始所提到的图像。当我们测试我们的神经网络时,我们需要让它去识别训练集之外的数据。
MNIST 数据集可以分为两个部分。第一个部分包含了 60,000 个用于训练的图像。这些图像是扫描了 250 个人的手写数字得到的,他们之中一半是来自美国人口普查局的员工,另一半是高中生。这些图像是 28 乘 28 个像素点灰度图像。MNIST 的第二个部分是 10,000 个用于测试的图像,它们同样也是 28 乘 28 的灰度图像。我们将会用这些测试数据去评估我们的神经网络的识别效果。为了保证测试结果的准确性,这些测试数据是采样于另一个_不同的_250人的样本(尽管这些人也是美国人口普查局的员工和高中生)。这保证了我们的系统能够识别训练集之外的手写数字图像。
我们用去定义训练输入。为了方便起见,我们将每一个训练输入视为一个维的向量。向量中的一个元素代表图像的一个像素点的灰度值。我们定义输出为,每一个是一个维的向量。举例来说,对于一个数字的训练图像,我们期待的输出是。这里的是转置符号,它能将一个行向量变为列向量。
现在我们需要一个算法能让我们找到合适的权重和偏置,从而对所有的训练输入为的输出都近似于。为了衡量我们当前取得的结果距离目标结果的好坏程度,我们定义一个代价函数:
公式里面的表示所有的权重的集合,表示所有的偏置,是训练数据的个数,代表作为输入时输出层的向量,求和针对所有的训练输入。显而易见,输出取决于, 和,但是为了保持公式的简洁性,我们没有明确指出这种依赖性。符号是指求向量的范数。这时,我们称为二次代价函数;有时我们也称它为平方误差或者MSE。通过代价函数的形式我们可以得知是非负的,因为加和的每一项都是非负的。另外,当所有的训练输入的输出基本都等于时,代价函数的值会变小,可能有。因此如果我们的学习算法可以找到合适的权重和偏置使得,那么这就是一个好的学习算法。反过来来说,如果很大,那么就说明学习算法的效果很差——这意味着对于大量的输入,我们的结果与正确结果相差很大。因此,我们的训练算法的目标就是通过调整函数的权重和偏置来最小化代价函数。换句话说,我们想寻找合适的权重和偏置让代价函数尽可能地小。我们将使用一个叫做梯度下降法(gradient descent)的算法来达到这个目的。
为什么要介绍平方损失(quadratic cost)呢?毕竟我们最初所感兴趣的内容不是对图像正确地分类吗?为什么不增大正确输出的得分,而是去最小化一个像平方损失类似的间接评估呢?这么做是因为在神经网络中,被正确分类的图像的数量关于权重、偏置的函数并不是一个平滑的函数。大多数情况下,对权重和偏置做出的微小变动并不会影响被正确分类的图像的数量。这会导致我们很难去刻画如何去优化权重和偏置才能得到更好的结果。一个类似平方损失的平滑代价函数能够更好地指导我们如何去改变权重和偏置来达到更好的效果。这就是为何我们集中精力去最小化平方损失,只有通过这种方式我们才能让分类器更精确。
即使知道了我们需要选择一个平滑的代价函数,你可能仍然会好奇为什么我们选择方程(6)中的二次函数。这是一个拍脑袋的决定吗?是不是我们选择另一个不同的代价函数将会得到完全不同的权重和偏置呢?这是一个合理的问题,稍后我们会再次提到这个代价函数并做一些修改。尽管如此,方程(6)中的平方代价函数能让我们更好地理解神经网络的基本原理,因此我们目前先用它。
再次回顾一下,我们训练神经网络的目的是寻找合适的权重和偏置来最小化平方代价函数。这个问题已经明确定义好了。但是现在还存在很多让我们分散精力的问题——对权重和偏置合理的解释,隐藏在背后的函数,神经网络结构的选择,MNIST 等等。实际上我们可以先忽略这些问题,把精力集中在最小化的问题上。现在让我们忘掉代价函数的具体形式,忘掉神经网络的结构,忘掉其它一切。现在想象我们仅仅是要去最小化一个给定的有很多变量的函数。我们即将要介绍一种可以解决最小化问题的技术,称作梯度下降法。然后我们再回到要在神经网络中最小化的函数上来。
假定我们要最小化某些函数,。它可能是任意的多元实值函数,。注意我们将会用去代表和以强调它可能是任意的函数——我们不会把问题局限在神经网络中。假定有两个变量 和 :
我们的目标就是找到在何处取得全局最小值。当然,对于上图的函数,我们能通过肉眼就可以找到最小值。这是因为我所展示的函数太简单了!一个一般的函数,可能是一个复杂的多元函数,通过肉眼通常找不到它的最小值。
一种解决方法就是用数值计算的方法去计算出它的最小值。我们可以计算出偏导,利用偏导去寻找函数的极值点。运气好的话我们的函数只有一个或者少数的几个变量。但是变量过多的话将是一个噩梦。在神经网络中我们通常会需要多得多得多的变量——最大的神经网络的代价函数包含了数亿个权重和偏置。根本没法使用数值计算的方法!
(我们只讨论了只有两个变量的情况,如果我说「嗨,如果函数有多于两个变量怎么办?」。对于这种情况我只能说很抱歉。请相信我把看成一个二元函数是有助于我们的理解的。善于思考数学通常也包含善于利用多种直观的图片,学习什么时候用什么图片合适。)
所以,数值计算的方法没法完成这个任务了。幸运的是,有一个漂亮的类比预示着有一种算法能得到很好的效果。首先把我们的函数想象成一个山谷。我们想象有一个小球从山谷的斜坡滚落下来。我们的日常经验告诉我们这个球终会达到谷底。也许我们可以用这种思想来解决函数最小值的问题?我们随机地为小球选取一个起点,然后开始模拟小球滚落到谷底的运动过程。我们可以简单的通过计算的导数(或者二阶导数)来模拟这个过程——这些导数将会告诉我们关于山谷「地形」的一切信息,从而告诉我们的小球该如何下落。
基于上述的想法,你可能会认为我们会写下牛顿运动定理,考虑摩擦力、重力等等。其实我们不打算真的去实现这个小球的类比——我们只想要一个算法去最小化,而不是真的去模拟它真实的物理定律。小球的视角能激发我们的想象而不是束缚我们的思维。因此与其去考虑麻烦的物理定律,不如我们这样问自己:如果我们扮演一天的上帝,能够构造自己的物理定律,能够支配小球的下落方式,那么我们将会采取什么样的物理定律来让小球能够始终滑落到谷底呢?
为了更精确地描述这个问题,让我们想象一下如果我们在方向移动一个很小的量并在方向移动一个很小的量将会发生什么呢。通过计算可以告诉我们将会产生如下改变:
我们将要寻找一种方式去选择和使得为负,因为负值能够让小球下落。为了搞清楚如何选择,我们有必要定义,它是描述变化的向量,,是转置符号。我们也定义用来表示偏导的向量,。我们用来表示梯度向量:
待会我们将用和来重写。在这之前我想先说明一些令人困惑的关于梯度的事情。当第一次碰到梯度的符号时,人们常会好奇为什么符号是这样。究竟代表什么?事实上你可以把梯度仅仅看做一个简单的数学记号——一个方便用来表示偏导的向量——这样我们就不必写两个符号了。这样来看,仅仅是一面旗帜,它告诉你:「嘿,是一个梯度向量」。也有很多其他的关于的解释(比如,作为一种微分符号),但我们不需要这种观点。
定义好上述符号之后,关于的表达式(7)能被重写成如下形式
这个表达式能很好地解释为什么被称作梯度向量:和中的变化密切相关,只是我们把它称为梯度罢了。但是这个式子真正让我们兴奋的是,它让我们看到了如何选取才能让为负数。假设我们选取
这里的是个很小的正数(就是我们熟知的学习率(learning rate))。等式(9)告诉我们。由于,这保证了,例如,如果我们以等式(10)的方式去改变,那么将一直会降低,不会增加。(当然,要在(9)式的近似约束下)。这就是我们想要的特性!因此我们把(10)式看做梯度下降算法的「运动定律」。也就是说,我们用(10)式计算,把小球位置移动:
然后我们可以迭代地去更新。如果我们反复那么做,那么会一直降低到我们想要寻找的全局最小值。
总结一下,梯度下降算法工作的方式就是重复计算梯度,然后沿着梯度的反方向运动,即沿着山谷的斜坡下降。就像下图一样:
需要注意这种梯度下降的规则不代表真实的物理运动。在真实世界里,小球有势能,势能让小球可以在山谷斜坡上滚动,甚至顷刻间滚向山顶。只有加上摩擦力的影响才能保证小球会下落到谷底。我们选择的规则不一样,我们就好像在命令「立马下降!」。这仍然是一个寻找最小值的好办法!
为了使我们的梯度下降法能够正确地工作,我们需要选择足够小的学习速率使得等式(9)能得到很好的近似。如果不那么做,我们将会以结束,这显然不是一个很好的结果。与此同时,我们也不能把设得过小,因为如果过小,那么梯度下降算法就会变得异常缓慢。在真正的实现中,通常是变化的,从而方程(9)能保持很好地近似度同时保证算法不会太慢。我们稍后会看这是如何工作的。
我已经解释了具有两个变量的函数的梯度下降法。但事实上当是其他多元函数时也能很好地运行。我们假设是一个有个变量的多元函数。我们对自变量做如下改变,那么将会变为
这里的是
正如两个变量的例子一样,我们可以选取 并且我们也会保证公式(12)中是负数。这使得我们能够随着梯度得到函数的最小值,即使是任意的多元函数,我们也能重复运用下面的规则 你可以把这个更新规则看作梯度下降算法的定义。这给我们提供了一种方式去通过重复改变来找到函数的最小值。然而这种方式并不总是有效的——有几种情况能导致错误的发生,使得我们无法从梯度得到函数的全局最小值,这种情况我们会在后面的章节中讨论。但在实践中,梯度下降法通常效果非常好,在神经网络中这是一种非常有效的方式去求代价函数的最小值,从而帮助神经网络学习。
事实上,有一种观念认为梯度下降法是求最小值的最优策略。我们假设努力去改变来让尽可能地减小,减小量为。我们首先限制步长为固定值,即 ,。当步长固定时,我们要找到使得减小最大的下降方向。可以证明,使得取得最小值的为,这里是由步长限制所决定的。因此,梯度下降法可以被视为一种通过在下降最快的方向上做微小变化来使得立即下降的方法。
练习
证明最后一段的断言。提示:利用柯西-斯瓦茨不等式。
我已经解释了当是二元及其多元函数的情况。那如果是一个单变量的函数呢?你能给出梯度下降法在一元函数的几何解释么?
人们已经研究出很多梯度下降法的变种,其中还包括一些去真正模拟真实物理运动的做法。这些模拟小球的变种有很多优点,但是也有一个主要的缺点:这些方法必须去计算的二阶偏导,这可能代价非常大。为了理解为什么这种做法代价高,假设我们想求所有的二阶偏导。如果我们有上百万的变量,那我们必须要计算数万亿级别的二阶偏导!这的确会造成很大的计算代价。不过也有一些避免这些问题的技巧,寻找梯度下降方法的替代品也是个很活跃的研究领域。但在这本书中我们将主要用梯度下降法(包括变种)去训练我们的神经网络。
我们在神经网络中应用梯度下降法呢?方式就是利用梯度下降法去寻找权重和偏置 能减小(6)式中的代价函数。为了弄清楚具体是如何工作的,我们将用权重和偏置代替变量来重新描述梯度下降算法的更新规则。我们描述「位置」的元素是和,梯度向量对应和。申明了梯度下降中成分之后,我们得到 通过重复更新我们能「滚到山底」,从而有望能找到代价函数的最小值。换句话说,这个规则能用在神经网络的学习中。
应用梯度下降规则有很多挑战。我们将在下一章深入讨论。但是现在我想提及一个问题。为了理解问题是什么,我们先回顾(6)中的二次代价函数。注意这个代价函数有着如下的形式,也就是说,它是每个样本损失的平均值。事实上,为了计算梯度,我们需要为每个训练样本单独地计算梯度值,然后求平均值,。不幸的是,当训练输入过大时会花费很长时间,这样会使学习变得相当缓慢。
有种叫做随机梯度下降(SGD)的算法能够用来加速学习过程。想法就是通过随机选取小量输入样本来计算,进而可以计算。采取少量样本的平均值可以快速地得到梯度,这会加速梯度下降过程,进而加速学习过程。
更准确地说,SGD是随机地选取小量的个训练数据。我们将选取的这些训练数据标号,并把它们称为一个mini-batch。我们选取的要足够大才能保证的平均值才能接近所有样本的平均值,也就是说, 其中,第二个求和是针对整个训练数据集的。交换两边我们可以得到 证实了我们可以通过计算随机选取的mini-batch的梯度来估计整体的梯度。
为了将这种想法更明确地联系到神经网络的学习中来,假设用和分别代表权重和偏置。SGD就是随机地选取大小为一个mini-batch的训练数据,然后去训练这些数据,
这个和就是当前 mini-batch 中每个的梯度值。然后我们再随机选取另一个mini-batch去训练,直到我们用完了所有的训练数据,这就完成了一轮(epoch)迭代训练。这样我们就会重新开始下一轮迭代。
值得一提的是,关于调节代价函数和 mini-batch 去更新权重和偏置有很多不同的约定。在(6)式中,我们通过因子来缩放全部的代价函数。人们通常忽略,直接计算单独训练样本损失之和,而不是求平均值。这对我们不能提前知道训练数据集大小的情况下特别有效。这可能发生在有更多的训练数据是实时加入的情况下。同样,mini-batch 的更新规则(20)和(21)有时也会舍弃。从概念上这也会有一点区别,因为它等价于重新调节学习速率。但在对不同工作进行详细比较时,它是值得关注的。
我们能把 SGD 想象成一场民主选举:使用小规模的 mini-batch 计算梯度,比使用整个训练集计算梯度容易得多,就如开展一次民意调查比举行一次完整的选举容易得多。举个例子,在 MNIST 中有个测试数据,我们选取 mini-batch 的大小为,这样,计算梯度的过程就加速了倍!当然,这个估计可能并不准确——仍然会存在统计波动——但也没必要准确:我们只关心在某个方向上移动可以减少,这意味着我们没必要准确去计算梯度的精确值。事实上,SGD 十分有效,广泛应用在神经网络的学习中,它也是本书中展开的大多数学习技术的基础。
练习
- 梯度下降一个比较极端的版本就是让 mini-batch 的大小为1。这就是说,给定一个输入,我们通过规则 和 更新权重和偏置。当我们选取另一个训练数据时也做同样的处理。其它的训练数据也做相同的处理。这种处理方式就是在线学习(online learning)或增量学习(incremental learning)。在在线学习中,神经网络在一个时刻只学习一个训练数据(正如人类的做法)。说出 online learning 相比 mini-batch 为 20 的 SGD 的一个缺点和一个优点。
作为总结,让我们讨论一个可能会让刚刚接触梯度下降的人困惑的问题。在神经网络中,代价函数是一个关于所有权重和偏置的多元函数,因此在某种意义上来说,就是在一个高维空间定义了一个平面。有些人可能会那么想:「嗨,我必须要看见其它多出的维度」。他们会开始疑惑:「我不能想象出四维空间,更不用说五维(或者五百万维)」。是不是他们缺少某种只有超级数学家才有的超能力?当然不是。即便是专业的数学家,大多数也不能想象出四维空间的样子。他们会用一些其它的方式来思考。正如我们上面所做的那样,我们可以用代数(而不是几何)来表示如何变化才能让减少。善于思考高维的人会在脑中做一些思想实验;我们采用的代数技巧是其中一个方法。这些方法可能不如观察三维那么直观,但我们熟悉这些方法之后会帮助我们思考更高维度。我不想在这里详细展开,如果你感兴趣,你可以读一下这篇关于数学家如何思考高维空间的讨论。我们讲的一些原理可能会有点复杂,但大多数内容还是比较直观的,任何人都能熟练掌握。