1.5 使用梯度下降算法进行学习
现在我们有了神经网络的设计,它怎样可以学习识别数字呢?我们需要的第一样东西是一个 用来学习的数据集 —— 称为训练数据集。我们将使用 MNIST 数据集,其包含有数以万计的连 带着正确分类器的手写数字的扫描图像。MNIST 的名字来源于 NIST ——美国国家标准与技术研究所 —— 收集的两个数据集改进后的子集。这是取自 MNIST 的一些图像:
正如你看到的,这些数字其实是和本章开始提到的一样。当然,当测试我们的网络时我们将要求它识别不在训练集中的图像。
MNIST 数据分为两个部分。第一部分包含 60,000 幅用于训练数据的图像。这些图像扫描自250 人的手写样本,他们中一半人是美国人口普查局的员工,一半人是高校学生。这些图像是28 × 28 大小的灰度图像。第二部分是 10,000 幅用于测试数据的图像,同样是 28 × 28 的灰度图像。我们将用这些测试数据来评估我们的神经网络学会识别数字有多好。为了让其有好的测试表现,测试数据取自和原始训练数据不同的另外一组 250 人(尽管仍然分别是美国人口普查局和高校学生)。这有助于确保我们的系统能识别那些没有看到训练数据的人写的数字。
我们将用符号 x 来表示一个训练输入。为了方便,把每个训练输入 x 看作一个 28 × 28 = 784维的向量。每个向量中的项目代表图像中单个像素的灰度值。我们用 y = y(x) 表示对应的期 望输出,这里 y 是一个 10 维的向量。例如,如果有一个特定的画成 6 的训练图像,x,那么y(x) = (0, 0, 0, 0, 0, 0, 1, 0, 0, 0)T 则是网络的期望输出。注意这里 T 是转置操作,把一个行向量 转换成一个列向量。
我们希望有一个算法,能让我们找到权重和偏置,以至于网络的输出 y(x) 能够拟合所有的训练输入 x。为了量化我们如何实现这个目标,我们定义一个代价函数(也称为损失函数):
这里 w 表示所有的网络中权重的集合,b 是所有的偏置,n 是训练输入数据的个数,a 是表 示当输入为 x 时输出的向量,求和则是在总的训练输入 x 上进行的。当然,输出 a 取决于 x,w 和 b,但是为了保持符号的简洁性,我没有明确地指出这种依赖关系。符号 ||v|| 是指向量 v的模。我们把 C 称为二次代价函数;有时也被称为均方误差或者 MSE。观察二次代价函数的 形式我们可以看到 C(w, b) 是非负的,因为求和公式中的每一项都是非负的。此外,代价函数C(w,b) 的值相当小,即 C(w,b) ≈ 0,精确地说,是当对于所有的训练输入 x,y(x) 接近于输出a 时。因此如果我们的学习算法能找到合适的权重和偏置,使得 C(w, b) ≈ 0,它就能很好地工 作。相反,当 C(w, b) 很大时就不怎么好了,那意味着对于大量地输入,y(x) 与输出 a 相差很大。 因此我们的训练算法的目的,是最小化权重和偏置的代价函数 C(w, b)。换句话说,我们想要找到一系列能让代价尽可能小的权重和偏置。我们将采用称为梯度下降的算法来达到这个目的。
为什么要介绍二次代价呢?毕竟我们最初感兴趣的内容不是能正确分类的图像数量吗?为什么不试着直接最大化这个数量,而是去最小化一个类似二次代价的间接评量呢?这么做是因为在神经网络中,被正确分类的图像数量所关于权重和偏置的函数并不是一个平滑的函数。大多数情况下,对权重和偏置做出的微小变动完全不会影响被正确分类的图像的数量。这会导致我 们很难去解决如何改变权重和偏置来取得改进的性能。而用一个类似二次代价的平滑代价函数则能更好地去解决如何用权重和偏置中的微小的改变来取得更好的效果。这就是为什么我们首先专注于最小化二次代价,只有这样,我们之后才能测试分类精度。
即使已经知道我们需要使用一个平滑的代价函数,你可能仍然想知道为什么我们在方程 (6)中选择二次函数。这是临时想出来的吗?是不是我们选择另一个不同的代价函数将会得到完全 不同的最小化的权重和偏置呢?这种顾虑是合理的,我们后面会再次回到这个代价函数,并做 一些修改。尽管如此,方程 (6) 中的二次代价函数让我们更好地理解神经网络中学习算法的基 础,所以目前我们会一直使用它。
重复一下,我们训练神经网络的目的是找到能最小化二次代价函数 C(w,b) 的权重和偏置。 这是一个适定问题,但是现在它有很多让我们分散精力的结构 —— 对权重 w 和偏置 b 的解释, 晦涩不清的 σ 函数,神经网络结构的选择,MNIST 等等。事实证明我们可以忽略结构中大部分, 把精力集中在最小化方面来理解它。现在我们打算忘掉所有关于代价函数的具体形式、神经网络的连接等等。现在让我们想象只要最小化一个给定的多元函数。我们打算使用一种被称为梯 度下降的技术来解决这样的最小化问题。然后我们回到在神经网络中要最小化的特定函数上来。
好了,假设我们要最小化某个函数,C(v)。它可以是任意的多元实值函数,v = v1, v2, . . .。注 意我们用 v 代替了 w 和 b 以强调它可能是任意的函数 —— 我们现在先不局限于神经网络的环境。为了最小化 C(v),想象 C 是一个只有两个变量 v1 和 v2 的函数:
我们想要的是找到 C 的全局最小值。当然,对于上图的函数,我们一眼就能找到最小值。那 只意味着,也许我展示的函数过于简单了!通常函数 C 可能是一个复杂的多元函数,看一下就 能找到最小值是不可能的。
一种解决这个问题的方式是用微积分来解析最小值。我们可以计算导数去寻找 C 的极值点。 运气好的话,C 是一个只有一个或少数几个变量的函数。但是变量过多的话那就是噩梦。而且神经网络中我们经常需要大量的变量——最大的神经网络有依赖数亿权重和偏置的代价函数,极 其复杂。用微积分来计算最小值已经不可行了。
(确定我们将可以通过有两个变量的函数 C 来理解神经网络后,我已经两次提到:“嘿,如果 函数有远多于两个变量怎么办?”。对此我只能说很抱歉。请相信我把 C 想象成一个二元函数是 有助于我们的理解的。有时候这种想象的画面会遇到障碍,这正是上面两个段落在帮助你克服 的。善于思考数学通常也涉及到有效地利用多种直觉上的想象画面,学会什么时候用什么画面 合适。)
好吧,微积分是不能用了。幸运的是,有一个漂亮的推导法暗示有一种算法能得到很好的效 果。首先把我们的函数想象成一个山谷。只要瞄一眼上面的绘图就不难理解。我们想象有一个 小球从山谷的斜坡滚落下来。我们的日常经验告诉我们这个球最终会滚到谷底。也许我们可以 用这一想法来找到函数的最小值?我们会为一个(假想的)球体随机选择一个起始位置,然后 模拟球体滚落到谷底的运动。我们可以通过计算 C 的导数(或者二阶导数)来简单模拟——这 些导数会告诉我们山谷中局部“形状”的一切,由此知道我们的球将怎样滚动。
看到这里你可能会以为我们会写下球体的牛顿运动定理,考虑摩擦力、重力等影响。实际上, 我们不打算真的去实现这个球体滚落的推导 —— 我们是在设计一个最小化 C 的算法,而不是 在用物理定律做精确的仿真。对球体的肉眼观察是为了激发我们的想象而不是束缚我们的思维。 因此与其陷进物理学里凌乱的细节,不如我们就这样问自己:如果我们扮演一天的上帝,能够 构造自己的物理定律,能够支配球体可以如何滚动,那么我们将会采取什么样的运动学定律来 让球体能够总是滚落到谷底呢?
为了更精确地描述这个问题,让我们思考一下,当我们在 v1 和 v2 方向分别将球体移动一个 很小的量,即 ∆v1 和 ∆v2 时,球体将会发生什么情况。微积分告诉我们 C 将会有如下变化:
我们要寻找一种选择 ∆v1 和 ∆v2 的方法使得 ∆C 为负;即,我们选择它们是为了让球体滚 落。为了弄明白如何选择,需要定义 ∆v 为 v 变化的向量,∆v ≡ (∆v1, ∆v2)T ,T 是转置符号。
我们也定义 C 的梯度为偏导数的向量,
。我们用 ∇C 来表示梯度向量,即:
我们⻢上会用 ∆v 和梯度 ∇C 来重写 ∆C 的变化。在这之前我想先澄清一些令人困惑的关 于梯度的事情。当第一次碰到 ∇C 这个符号,人们有时会想知道怎么去理解 ∇ 符号。∇ 究竟 是什么意思?事实上你可以把 ∇C 仅仅看做一个简单的数学记号 —— 上面定义的向量 —— 这 样就不必写两个符号了。这样来看,∇ 仅仅是一个符号,犹如⻛中摆动的旗帜,告诉你:“嘿,∇C 是一个梯度向量”。也有很多其它的数学上不同视⻆对于 ∇ 的专业解释(比如,作为一个微 分操作),但我们不需要这些观点。
有了这些定义,∆C 的表达式 (7) 可以被重写为:
这个表达式解释了为什么 ∇C 被称为梯度向量:∇C 把 v 的变化关联为 C 的变化,正如我 们期望的用梯度来表示。但是这个方程真正让我们兴奋的是它让我们看到了如何选取 ∆v 才能让 ∆C 为负数。假设我们选取:
这里的 η 是个很小的正数(称为学习速率)。方程 (9) 告诉我们 ∆C ≈ −η∇C·∇C = −η ||∇C||2。 由于 ||∇C||2 ≥ 0,这保证了 ∆C ≤ 0,即,如果我们按照方程 (10) 的规则去改变 v,那么 C 会 一直减小,不会增加。(当然,要在方程 (9) 的近似约束下)。这正是我们想要的特性!因此我 们把方程 (10) 用于定义球体在梯度下降算法下的“运动定律”。也就是说,我们用方程 (10) 计算 ∆v,来移动球体的位置 v:
然后我们用它再次更新规则来计算下一次移动。如果我们反复持续这样做,我们将持续减小C 直到 —— 正如我们希望的 —— 获得一个全局的最小值。
总结一下,梯度下降算法工作的方式就是重复计算梯度 ∇C,然后沿着相反的方向移动,沿着山谷“滚落”。我们可以想象它像这样:
注意具有这一规则的梯度下降并不是模仿实际的物理运动。在现实中一个球体有动量,使得 它岔开斜坡滚动,甚至(短暂地)往山上滚。只有在克服摩擦力的影响,球体才能保证滚到山谷。 相比之下,我们选择 ∆v 规则只是说:“往下,现在”。这仍然是一个寻找最小值的非常好的规则!
为了使梯度下降能够正确地运行,我们需要选择足够小的学习速率 η 使得方程 (9) 能得到很 好的近似。如果不这样,我们会以 ∆C > 0 结束,这显然不好。同时,我们也不想 η 太小,因为 这会使 ∆v 的变化极小,梯度下降算法就会运行得非常缓慢。在真正的实现中,η 通常是变化 的,以至方程 (9) 能保持很好的近似度,但算法又不会太慢。我们后面会看这是如何工作的。
我已经解释了具有两个变量的函数 C 的梯度下降。但事实上,即使 C 是一个具有更多变量 的函数也能很好地工作。我们假设 C 是一个有 m 个变量 v1, . . . , vm 的多元函数。那么对 C 中自变量的变化 ∆v = (∆v1, . . . , ∆vm)T ,∆C 将会变为:
这里的梯度 ∇C 是向量
正如两个变量的情况,我们可以选取
而且 ∆C 的(近似)表达式 (12) 保证是负数。这给了我们一种方式从梯度中去取得最小值,即使 C 是任意的多元函数,我们也能重复运用更新规则
你可以把这个更新规则看做定义梯度下降算法。这给我们提供了一种方式去通过重复改变 v来找到函数 C 的最小值。这个规则并不总是有效的 —— 有几件事能导致错误,让我们无法从梯 度下降来求得函数 C 的全局最小值,这个观点我们会在后面的章节中去探讨。但在实践中,梯度下降算法通常工作地非常好,在神经网络中这是一种非常有效的方式去求代价函数的最小值, 进而促进网络自身的学习。
事实上,甚至有一种观点认为梯度下降法是求最小值的最优策略。假设我们正在努力去改变∆v 来让 C 尽可能地减小。这相当于最小化 ∆C ≈ ∇C · ∆v。我们首先限制步⻓为小的固定值, 即 ||∆v|| = ε,ε > 0。当步⻓固定时,我们要找到使得 C 减小最大的下降方向。可以证明,使得∇C ·∆v 取得最小值的 ∆v 为 ∆v = −η∇C,这里 η = ε/||∇C|| 是由步⻓限制 ||∆v|| = ε 所决定 的。因此,梯度下降法可以被视为一种在 C 下降最快的方向上做微小变化的方法。
练习
• 证明上一段落的推断。提示:可以利用柯西-施瓦茨不等式。 • 我已经解释了当 C 是二元及其多元函数的情况。那如果 C 是一个一元函数呢?你能给出梯度下降法在一元函数的几何解释么?
人们已经研究出很多梯度下降的变化形式,包括一些更接近真实模拟球体物理运动的变化形 式。这些模拟球体的变化形式有很多优点,但是也有一个主要的缺点:它最终必需去计算 C 的 二阶偏导,这代价可是非常大的。为了理解为什么这种做法代价高,假设我们想求所有的二阶偏导 ∂2C/∂vj∂vk。如果我们有上百万的变量 vj,那我们必须要计算数万亿(即百万次的平方) 级别的二阶偏导!这会造成很大的计算代价。不过也有一些避免这类问题的技巧,寻找梯度下 降算法的替代品也是个很活跃的研究领域。但在这本书中我们将主要用梯度下降算法(包括变化形式)使神经网络学习。
我们怎么在神经网络中用梯度下降算法去学习呢?其思想就是利用梯度下降算法去寻找能使 得方程 (6) 的代价取得最小值的权重 wk 和偏置 bl。为了清楚这是如何工作的,我们将用权重 和偏置代替变量 vj。也就是说,现在“位置”变量有两个分量组成:wk 和 bl,而梯度向量 ∇C则有相应的分量 ∂C/∂wk 和 ∂C/∂bl。用这些分量来写梯度下降的更新规则,我们得到:
通过重复应用这一更新规则我们就能“让球体滚下山”,并且有望能找到代价函数的最小值。 换句话说,这是一个能让神经网络学习的规则。
应用梯度下降规则有很多挑战。我们将在下一章深入讨论。但是现在只提及一个问题。为了理解问题是什么,我们先回顾(6) 中的二次代价。注意这个代价函数有着这样的形式
即,它是遍及每个训练样本代价
的平均值。在实践中,为了计算梯度 ∇C,我们需要为每个训练输入 x 单独地计算梯度值 ∇Cx,然后求平均值,
。不幸的是,当训练输入的数量过大时会花费很⻓时间,这样会使学习变得相当缓慢。 有种叫做随机梯度下降的算法能够加速学习。其思想就是通过随机选取小量训练输入样本来 计算 ∇Cx,进而估算梯度 ∇C。通过计算少量样本的平均值我们可以快速得到一个对于实际梯度 ∇C 的很好的估算,这有助于加速梯度下降,进而加速学习过程。 更准确地说,随机梯度下降通过随机选取小量的 m 个训练输入来工作。我们将这些随机的训练输入标记为 X1, X2, . . . , Xm,并把它们称为一个小批量数据。假设样本数量 m 足够大,我 们期望 ∇CXj 的平均值大致相等于整个 ∇Cx 的平均值,即,
这里的第二个求和符号是在整个训练数据上进行的。交换两边我们得到
证实了我们可以通过仅仅计算随机选取的小批量数据的梯度来估算整体的梯度。 为了将其明确地和神经网络的学习联系起来,假设 wk 和 bl 表示我们神经网络中权重和偏置。随机梯度下降通过随机地选取并训练输入的小批量数据来工作,
其中两个求和符号是在当前小批量数据中的所有训练样本 Xj 上进行的。然后我们再挑选另一 随机选定的小批量数据去训练。直到我们用完了所有的训练输入,这被称为完成了一个训练迭代期。然后我们就会开始一个新的训练 迭代期。
另外值得提一下,对于改变代价函数大小的参数,和用于计算权重和偏置的小批量数据的 更新规则,会有不同的约定。在方程 (6) 中,我们通过因子 1/n 来改变整个代价函数的大小。人们有时候忽略,直接取单个训练样本的代价总和,而不是取平均值。这对我们不能提前知道训练数据数量的情况下特别有效。例如,这可能发生在有更多的训练数据是实时产生的情况下。 同样,小批量数据的更新规则 (20)和 (21) 有时也会舍弃前面的 1/m。从概念上这会有一点区别,因为它等价于改变了学习速率 η 的大小。但在对不同工作进行详细对比时,需要对它警惕。
我们可以把随机梯度下降想象成一次⺠意调查:在一个小批量数据上采样比对一个完整数 据集进行梯度下降分析要容易得多,正如进行一次⺠意调查比举行一次全⺠选举要更容易。例 如,如果我们有一个规模为 n = 60, 000 的训练集,就像 MNIST,并选取 小批量数据大小为m = 10,这意味着在估算梯度过程中加速了 6, 000 倍!当然,这个估算并不是完美的 —— 存在 统计波动 —— 但是没必要完美:我们实际关心的是在某个方向上移动来减少 C,而这意味着我 们不需要梯度的精确计算。在实践中,随机梯度下降是在神经网络的学习中被广泛使用、十分有效的技术,它也是本书中展开的大多数学习技术的基础。
练习
• 梯度下降算法一个极端的版本是把小批量数据的大小设为 1。即,假设一个训练输入 x,我 们按照规则 wk → wk′ = wk − η∂Cx/∂wk 和 bl → b′l = bl − η∂Cx/∂bl 更新我们的权重和偏 置。然后我们选取另一个训练输入,再一次更新权重和偏置。如此重复。这个过程被称为在线、online、on-line、或者增量学习。在 online 学习中,神经网络在一个时刻只学习 一个训练输入(正如人类做的)。对比具有一个小批量输入大小为 20 的随机梯度下降,说出增量学习的一个优点和一个缺点。
让我们讨论一个令刚接触梯度下降的人困惑的问题来总结这部分的内容。在神经网络中,代价函数 C 是一个关于所有权重和偏置的多元函数,因此在某种意义上来说,就是在一个高维空间定义了一个平面。有些人可能会担心地想:“嘿,我必须要想象其它多出的维度”。他们会开 始发愁:“我不能想象出四维空间,更不用说五维(或者五百万维)”。是不是他们缺少某种只有“超级”数学家才有的超能力?当然不是。即使大多数专业的数学家也不能想象出四维空间的样子。他们用的技巧,是扩展出其它的方法来描绘发生了什么事。正如我们上面所做的那样,我 们用代数(而不是图像)描绘 ∆C 来计算如何变化才能让 C 减少。那些善于思考高维的人内心 有着包含有许多不同的技术的知识库;我们的代数技巧也是一个例子。这些技术可能没有我们 习惯于思考三维时的那么简单,但一旦你构建起这样的知识库,你能够更从容应对更高的维度。 我不想在这里详细展开,如果你感兴趣,你可以阅读这个关于专业的数学家如何思考高维空间 的讨论。我们讨论的一些技术可能会有点复杂,但很多最好的内容还是比较直观并容易理解的, 任何人都能熟练掌握。