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 被称为梯度向量:∇C 把 v 的变化关联为 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 下降最快的⽅向上做微⼩变化的⽅法。

练习1

  • 证明上⼀段落的推断。提⽰:可以利⽤柯西-施⽡茨不等式。
  • 我已经解释了当 C 是⼆元及其多元函数的情况。那如果 C 是⼀个⼀元函数呢?你能给出梯度下降法在⼀元函数的⼏何解释么?

⼈们已经研究出很多梯度下降的变化形式,包括⼀些更接近真实模拟球体物理运动的变化形式。这些模拟球体的变化形式有很多优点,但是也有⼀个主要的缺点:它最终必需去计算 C 的⼆阶偏导,这代价可是⾮常⼤的。为了理解为什么这种做法代价⾼,假设我们想求所有的⼆阶偏导 如果我们有上百万的变量 \( v_j\) ,那我们必须要计算数万亿(即百万次的平⽅)级别的⼆阶偏导4!这会造成很⼤的计算代价。不过也有⼀些避免这类问题的技巧,寻找梯度下降算法的替代品也是个很活跃的研究领域。但在这本书中我们将主要⽤梯度下降算法(包括变化形式)使神经⽹络学习。

我们怎么在神经⽹络中⽤梯度下降算法去学习呢?其思想就是利⽤梯度下降算法去寻找能使得⽅程 (6) 的代价取得最⼩值的权重 \( w_k\) 和偏置 \( b_l\)。为了清楚这是如何⼯作的,我们将⽤权重和偏置代替变量 \( v_j\)。也就是说,现在“位置”变量有两个分量组成:wk 和 bl,⽽梯度向量 ∇C 则有相应的分量。⽤这些分量来写梯度下降的更新规则,我们得到:

通过重复应⽤这⼀更新规则我们就能“让球体滚下⼭”,并且有望能找到代价函数的最⼩值。换句话说,这是⼀个能让神经⽹络学习的规则。

应⽤梯度下降规则有很多挑战。我们将在下⼀章深⼊讨论。但是现在只提及⼀个问题。为了理解问题是什么,我们先回顾(6) 中的⼆次代价。注意这个代价函数有着这样的形式即,它是遍及每个训练样本代价的平均值。在实践中,为了计算梯度 ∇C,我们需要为每个训练输⼊ x 单独地计算梯度值 ,然后求平均值,不幸的是,当训练输⼊的数量过⼤时会花费很⻓时间,这样会使学习变得相当缓慢。

有种叫做随机梯度下降的算法能够加速学习。其思想就是通过随机选取⼩量训练输⼊样本来计算 \( ∇C_x\),进⽽估算梯度 ∇C。通过计算少量样本的平均值我们可以快速得到⼀个对于实际梯度 ∇C 的很好的估算,这有助于加速梯度下降,进⽽加速学习过程。

更准确地说,随机梯度下降通过随机选取⼩量的 m 个训练输⼊来⼯作。我们将这些随机的训练输⼊标记为 \( X_1, X_2, . . . , X_m\),并把它们称为⼀个⼩批量数据(mini-batch)。假设样本数量m ⾜够⼤,我们期望 \(∇CX_j\) 的平均值⼤致相等于整个 \( ∇C_x\) 的平均值,即, 这⾥的第⼆个求和符号是在整个训练数据上进⾏的。交换两边我们得到证实了我们可以通过仅仅计算随机选取的⼩批量数据的梯度来估算整体的梯度。为了将其明确地和神经⽹络的学习联系起来,假设 \( w_k\) 和 \(b_l\) 表⽰我们神经⽹络中权重和偏置。随即梯度下降通过随机地选取并训练输⼊的⼩批量数据来⼯作,其中两个求和符号是在当前⼩批量数据中的所有训练样本 \( X_j\) 上进⾏的。然后我们再挑选另⼀随机选定的⼩批量数据去训练。直到我们⽤完了所有的训练输⼊,这被称为完成了⼀个训练迭代期(epoch)。然后我们就会开始⼀个新的训练迭代期。

另外值得提⼀下,对于改变代价函数⼤⼩的参数,和⽤于计算权重和偏置的⼩批量数据的更新规则,会有不同的约定。在⽅程 (6) 中,我们通过因⼦ 1/n 来改变整个代价函数的⼤⼩。⼈们有时候忽略 1/n,直接取单个训练样本的代价总和,⽽不是取平均值。这对我们不能提前知道训练数据数量的情况下特别有效。例如,这可能发⽣在有更多的训练数据是实时产⽣的情况下。同样,⼩批量数据的更新规则 (20) 和 (21) 有时也会舍弃前⾯的 1/m。从概念上这会有⼀点区别,因为它等价于改变了学习速率 η 的⼤⼩。但在对不同⼯作进⾏详细对⽐时,需要对它警惕。

我们可以把随机梯度下降想象成⼀次⺠意调查:在⼀个⼩批量数据上采样⽐对⼀个完整数据集进⾏梯度下降分析要容易得多,正如进⾏⼀次⺠意调查⽐举⾏⼀次全⺠选举要更容易。例如,如果我们有⼀个规模为 n = 60, 000 的训练集,就像 MNIST,并选取⼩批量数据 ⼤⼩为 m = 10,这意味着在估算梯度过程中加速了 6, 000 倍!当然,这个估算并不是完美的 —— 存在统计波动 —— 但是没必要完美:我们实际关⼼的是在某个⽅向上移动来减少 C,⽽这意味着我们不需要梯度的精确计算。在实践中,随机梯度下降是在神经⽹络的学习中被⼴泛使⽤、⼗分有效的技术,它也是本书中展开的⼤多数学习技术的基础。

练习2

梯度下降算法⼀个极端的版本是把⼩批量数据的⼤⼩设为 1。即,假设⼀个训练输⼊ x,我们按照规则更新我们的权重和偏置。然后我们选取另⼀个训练输⼊,再⼀次更新权重和偏置。如此重复。这个过程被称为在线、online、on-line、或者递增学习。在 online 学习中,神经⽹络在⼀个时刻只学习⼀个训练输⼊(正如⼈类做的)。对⽐具有⼀个⼩批量输⼊⼤⼩为 20 的随机梯度下降,说出递增学习的⼀个优点和⼀个缺点。

让我们讨论⼀个令刚接触梯度下降的⼈困惑的问题来总结这部分的内容。在神经⽹络中,代价函数 C 是⼀个关于所有权重和偏置的多元函数,因此在某种意义上来说,就是在⼀个⾼维空间定义了⼀个平⾯。有些⼈可能会担⼼地想:“嘿,我必须要想象其它多出的维度”。他们会开始发愁:“我不能想象出四维空间,更不⽤说五维(或者五百万维)”。是不是他们缺少某种只有“超级”数学家才有的超能⼒?当然不是。即使⼤多数专业的数学家也不能想象出四维空间的样⼦。他们⽤的技巧,是扩展出其它的⽅法来描绘发⽣了什么事。正如我们上⾯所做的那样,我们⽤代数(⽽不是图像)描绘 ∆C 来计算如何变化才能让 C 减少。那些善于思考⾼维的⼈内⼼有着包含有许多不同的技术的知识库;我们的代数技巧也是⼀个例⼦。这些技术可能没有我们习惯于思考三维时的那么简单,但⼀旦你构建起这样的知识库,你能够更从容应对更⾼的维度。我不想在这⾥详细展开,如果你感兴趣,你可以阅读这个关于专业的数学家如何思考⾼维空间的讨论。我们讨论的⼀些技术可能会有点复杂,但很多最好的内容还是⽐较直观并容易理解的,任何⼈都能熟练掌握。