0%

使用神经网络识别手写数字——梯度下降算法

原文链接:CHAPTER 1 Using neural nets to recognize handwritten digits

神经网络的架构

假设我们有这样的网络:

前面提过,这个网络中最左边的称为输入层,其中的神经元称为输入神经元。最右边的,即输出层包含有输出神经元,在本例中,输出层只有一个神经元。中间层,既然这层中的神经元既不是输入也不是输出,则被称为隐藏层。“隐藏”这一术语也许听上去有些神秘,我第一次听到这个词,以为它必然有一些深层的哲学或数学涵意,但它实际上仅仅意味着“既非输入也非输出”。上面的网络仅有一个隐藏层,但有些网络有多个隐藏层。例如,下面的四层网络
有两个隐藏层:

有些令人困惑的是,由于历史的原因,尽管是由 S 型神经元而不是感知器构成,这种多层网络有时被称为多层感知器或者 MLP。 在这本书中我不会使用 MLP 这个术语,因为我认为这会引起混淆,但这里想提醒你它的存在。

目前为止,我们讨论的神经网络,都是以上一层的输出作为下一层的输入。这种网络被称为前馈神经网络。这意味着网络中是没有回路的,信息总是向前传播,从不反向回馈。如果确实有回路,我们最终会有这样的情况:$\sigma$ 函数的输入依赖于输出。这将难于理解,所以我们不允许这样的环路。

然而,也有一些人工神经网络的模型,其中反馈环路是可行的。它们原理上比前馈网络更接近我们大脑的实际工作。并且循环网络能解决一些重要的问题,这些问题如果仅仅用前馈网络来解决,则更加困难。然而为了篇幅,本书将专注于使用更广泛的前馈网络。

一个简单的分类手写数字的网络

我们将使用一个三层神经网络来识别单个数字:

网络的输入层包含给输入像素的值进行编码的神经元。就像下一节会讨论的,我们给网络的训练数据会有很多扫描得到的 $28 \times 28$ 的手写数字的图像组成,所有输入层包含有 $784 = 28 \times 28$ 个神经元。为了简化,上图中我已经忽略了 $784$ 中大部分的输入神经元。输入像素是灰度级的,值为 $0.0$ 表示白色,值为 $1.0$ 表示黑色,中间数值表示逐渐暗淡的灰色。

网络的第二层是一个隐藏层。我们用 $n$ 来表示神经元的数量,我们将给 $n$ 实验不同的数值。示例中用一个小的隐藏层来说明,仅仅包含 $n=15$ 个神经元。

网络的输出层包含有 $10$ 个神经元。如果第一个神经元激活,即输出 $\approx 1$,那么表明网络认为数字是一个 $0$。如果第二个神经元激活,就表明网络认为数字是一个 $1$。依此类推。更确切地说,我们把输出神经元的输出赋予编号 $0$ 到 $9$,并计算出那个神经元有最高的激活值。比如,如果编号为 $6$ 的神经元激活,那么我们的网络会猜到输入的数字是 $6$。其它神经元相同。

为什么用 10 个输出神经元

你可能会好奇为什么我们用 $10$ 个输出神经元。毕竟我们的任务是能让神经网络告诉我们哪个数字( $0, 1, 2, \ldots, 9$ )能和输入图片匹配。一个看起来更自然的方式就是使用 $4$ 个输出神经元,把每一个当做一个二进制值,结果取决于它的输出更靠近 $0$ 还是$1$。四个神经元足够编码这个问题了,因为 $2^4 = 16$ 大于 $10$ 种可能的输入。为什么我们反而要用 $10$ 个神经元呢?这样做难道效率不低吗? 最终的判断是基于经验主义的:我们可以实验两种不同的网络设计,结果证明对于这个特定的问题而言,$10$ 个输出神经元的神经网络比4个的识别效果更好。但是令我们好奇的是为什么使用 $10$ 个输出神经元的神经网络更有效呢。 有没有什么启发性的方法能提前告诉我们用10个输出编码比使用 $4$个输出编码更有好呢?

为了理解为什么我们这么做,我们需要从根本原理上理解神经网络究竟在做些什么。首先考虑有 $10$ 个神经元的情况。我们首先考虑第一个输出神经元,它告诉我们一个数字是不是0。它能那么做是因为可以权衡从隐藏层来的信息。隐藏层的神经元在做什么呢?假设隐藏层的第一个神经元只是用于检测如下的图像是否存在:

为了达到这个目的,它通过对此图像对应部分的像素赋予较大权重,对其它部分赋予较小的权重。同理,我们可以假设隐藏层的第二,第三,第四个神经元是为检测下列图片是否存在:

就像你能猜到的,这四幅图像组合在一起构成了前面显示的一行数字图像中的 $0$:

假设神经网络以上述方式运行,我们可以给出一个貌似合理的理由去解释为什么用 $10$ 个输出而不是 $4$ 个。如果我们有 $4$ 个输出,那么第一个输出神经元将会尽力去判断数字的最高有效位是什么。 把数字的最高有效位和数字的形状联系起来并不是一个简单的问题。很难想象出有什么恰当的历史原因,一个数字的形状要素会和一个数字的最高有效位有什么紧密联系。

上面我们说的只是一个启发性的方法。没有什么理由表明这个三层的神经网络必须按照我所描述的方式运行,即隐藏层是用来探测数字的组成形状。可能一个聪明的学习算法将会找到一些合适的权重能让我们仅仅用4个输出神经元就行。但是这个启发性的方法通常很有效,它会节省你大量时间去设计一个好的神经网络结构。

使用梯度下降算法进行学习

现在我们有了神经网络的设计,它怎样可以学习识别数字呢?我们需要的第一样东西是一个用来学习的数据集称为训练数据集。我们将使用 MNIST 数据集。

我们将用符号 $x$ 来表示一个训练输入。为了方便,把每个训练输入 $x$ 看作一个 $28
\times 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) \approx 0$,精确地说,是当对于所有的训练输入 $x$,$y(x)$ 接近于输出 $a$ 时。因此如果我们的学习算法能找到合适的权重和偏置,使得 $C(w,b) \approx 0$,它就能很好地工作。相反,当 $C(w,b)$ 很大时就不怎么好了,那意味着对于大量地输入, $y(x)$ 与输出 $a$ 相差很大。因此我们的训练算法的目的,是最小化权重和偏置的代价函数 $C(w,b)$。换句话说,我们想要找到一系列能让代价尽可能小的权重和偏置。我们将采用称为梯度下降的算法来达到这个目的。

为什么使用二次代价函数

为什么要介绍二次代价呢?毕竟我们最初感兴趣的内容不是能正确分类的图像数量吗?为什么不试着直接最大化这个数量,而是去最小化一个类似二次代价的间接评量呢?这么做是因为在神经网络中,被正确分类的图像数量所关于权重和偏置的函数并不是一个平滑的函数。 大多数情况下,对权重和偏置做出的微小变动完全不会影响被正确分类的图像的数量。这会导致我们很难去解决如何改变权重和偏置来取得改进的性能。而用一个类似二次代价的平滑代价函数则能更好地去解决如何用权重和偏置中的微小的改变来取得更好的效果。 这就是为什么我们首先专注于最小化二次代价,只有这样,我们之后才能测试分类精度。

即使已经知道我们需要使用一个平滑的代价函数,你可能仍然想知道为什么我们选择二次函数。这是临时想出来的吗?是不是我们选择另一个不同的代价函数将会得到完全不同的最小化的权重和偏置呢?这种顾虑是合理的,我们后面会再次回到这个代价函数,并做一些修改。尽管如此,二次代价函数让我们更好地理解神经网络中学习算法的基础,所以目前我们会一直使用它。

重复一下,我们训练神经网络的目的是找到能最小化二次代价函数 $C(w,b)$ 的权重和偏置。这是一个适定问题,但是现在它有很多让我们分散精力的结构,对权重 $w$ 和偏置 $b$的解释,晦涩不清的 $\sigma$ 函数,神经网络结构的选择,MNIST 等等。事实证明我们可以忽略结构中大部分,把精力集中在最小化方面来理解它。现在我们打算忘掉所有关于代价函数的具体形式、神经网络的连接等等。现在让我们想象只要最小化一个给定的多元函数。我们打算使用一种被称为梯度下降的技术来解决这样的最小化问题。然后我们回到在神经网络中要最小化的特定函数上来。

梯度下降算法

好了,假设我们要最小化某些函数,$C(v)$。它可以是任意的多元实值函数,$v = v_1,
v_2, \ldots$。注意我们用 $v$ 代替了 $w$ 和 $b$ 以强调它可能是任意的函数,我们现在先不局限于神经网络的环境。为了最小化 $C(v)$,想象 $C$ 是一个只有两个变量$v1$ 和 $v2$ 的函数:

为什么要使用梯度下降算法

一种解决这个问题的方式是用微积分来解析最小值。我们可以计算导数去寻找 $C$ 的极值点。运气好的话,$C$ 是一个只有一个或少数几个变量的函数。但是变量过多的话那就是噩梦。而且神经网络中我们经常需要大量的变量——最大的神经网络有依赖数亿权重和偏置的代价函数,极其复杂。用微积分来计算最小值已经不可行了。

好吧,微积分是不能用了。幸运的是,有一个漂亮的推导法暗示有一种算法能得到很好的效果。首先把我们的函数想象成一个山谷。只要瞄一眼上面的绘图就不难理解。我们想象有一个小球从山谷的斜坡滚落下来。我们的日常经验告诉我们这个球最终会滚到谷底。也许我们可以用这一想法来找到函数的最小值?我们会为一个(假想的)球体随机选择一个起始位置,然后模拟球体滚落到谷底的运动。我们可以通过计算 $C$ 的导数(或者二阶导数)来简单模拟——这些导数会告诉我们山谷中局部“形状”的一切,由此知道我们的球将怎样滚动。 注意小球不必遵常规的循物理学理论,我们在这里就是上帝,能够支配球体可以如何滚动,那么我们将会采取什么样的运动学定律来让球体能够总是滚落到谷底呢?我们让小球要往代价函数梯度的反方向滚动。

为什么小球要往梯度的反方向滚动

为了更精确地描述这个问题,让我们思考一下,当我们在 $v1$ 和 $v2$ 方向分别将球体移动一个很小的量,即 $\Delta v1$ 和 $\Delta v2$ 时,球体将会发生什么情况。微积分告诉我们 $C$ 将会有如下变化:

我们要寻找一种选择 $\Delta v_1$ 和 $\Delta v_2$ 的方法使得 $\Delta C$ 为负;即,我们选择它们是为了让球体滚落。为了弄明白如何选择,需要定义 $\Delta v$ 为 $v$ 变化的向量,$\Delta v \equiv (\Delta v_1, \Delta v_2)^T$,$T$ 是转置符号。我们也定义 $C$ 的梯度为偏导数的向量,$\left(\frac{\partial C}{\partial v_1},\frac{\partial C}{\partial v_2}\right)^T$。我们用 $\nabla C$ 来表示梯度向量,即:

有了这些定义,$\Delta C$ 的表达式可以被重写为:

这个表达式解释了为什么 $\nabla C$ 被称为梯度向量:$\nabla C$ 把 $v$ 的变化关联为 $C$ 的变化,正如我们期望的用梯度来表示。但是这个方程真正让我们兴奋的是它让我们看到了如何选取 $\Delta v$ 才能让 $\Delta C$ 为负数。假设我们选取:

这里的 $\eta$ 是个很小的正数(称为学习率)。方程$\Delta v = -\eta \nabla C$告诉我们 $\Delta C \approx -\eta \nabla C \cdot \nabla C = -\eta |\nabla C|^2$。由于 $| \nabla C |^2 \geq 0$,这保证了$\Delta C \leq 0$,即,如果我们按照方程$\Delta v = -\eta \nabla C$的规则去改变 $v$,那么 $C$ 会一直减小,不会增加。(当然,要在方程$\Delta C \approx \nabla C \cdot \Delta v$的近似约束下)。这正是我们想要的特性!因此我们把方程$\Delta v = -\eta \nabla C$ 用于定义球体在梯度下降算法下的“运动定律”。也就是说,我们用方程$\Delta v = -\eta \nabla C$计算 $\Delta v$,来移动球体的位置 $v$:

然后我们用它再次更新规则来计算下一次移动。如果我们反复持续这样做,我们将持续减小$C$ 直到,正如我们希望的,获得一个全局的最小值。

总结一下,梯度下降算法工作的方式就是重复计算梯度 $\nabla C$,然后沿着相反的方向移动,沿着山谷“滚落”。我们可以想象它像这样:

注意具有这一规则的梯度下降并不是模仿实际的物理运动。在现实中一个球体有动量,使得它岔开斜坡滚动,甚至(短暂地)往山上滚。只有在克服摩擦力的影响,球体才能保证滚到山谷。相比之下,我们选择 $\Delta v$ 规则只是说:“往下,现在”。这仍然是一个寻找最小值的非常好的规则!

为了使梯度下降能够正确地运行,我们需要选择足够小的学习率 $\eta$ 使得方程$\Delta C \approx \nabla C \cdot \Delta v$ 能得到很好的近似。如果不这样,我们会以 $\Delta C > 0$ 结束,这显然不好。同时,我们也不想 $\eta$ 太小,因为这会使 $\Delta v$ 的变化极小,梯度下降算法就会运行得非常缓慢。在真正的实现中,$\eta$ 通常是变化的,以至方程$\Delta C \approx \nabla C \cdot \Delta v$能保持很好的近似度,但算法又不会太慢。我们后面会看这是如何工作的。

梯度下降算法的形式化证明

我已经解释了具有两个变量的函数 $C$ 的梯度下降。但事实上,即使 $C$ 是一个具有更多变量的函数也能很好地工作。我们假设 $C$ 是一个有 $m$ 个变量 $v_1,\ldots,v_m$ 的多元函数。那么对 $C$ 中自变量的变化 $\Delta v = (\Delta v_1, \ldots, \Delta v_m)^T$,$\Delta C$ 将会变为:

这里的梯度 $\nabla C$ 是向量

正如两个变量的情况,我们可以选取

而且 $\Delta C$ 的(近似)表达式 $\Delta C \approx \nabla C \cdot \Delta v$ 保证是负数。这给了我们一种方式从梯度中去取得最小值,即使 $C$ 是任意的多元函数,我们也能重复运用更新规则

你可以把这个更新规则看做定义梯度下降算法。这给我们提供了一种方式去通过重复改变 $v$ 来找到函数 $C$ 的最小值。这个规则并不总是有效的,有几件事能导致错误,让我们无法从梯度下降来求得函数 $C$ 的全局最小值,这个观点我们会在后面的章节中去探讨。但在实践中,梯度下降算法通常工作地非常好,在神经网络中这是一种非常有效的方式去求代价函数的最小值,进而促进网络自身的学习。

事实上,甚至有一种观点认为梯度下降法是求最小值的最优策略。假设我们正在努力去改变 $\Delta v$ 来让 $C$ 尽可能地减小。这相当于最小化 $\Delta C \approx \nabla C \cdot \Delta v$。我们首先限制步长为小的固定值,即 $| \Delta v | = \epsilon$,$ \epsilon > 0$。当步长固定时,我们要找到使得 $C$ 减小最大的下降方向。可以证明,使得 $\nabla C \cdot \Delta v$ 取得最小值的 $\Delta v$ 为 $\Delta v = - \eta \nabla C$,这里 $\eta = \epsilon / |\nabla C|$ 是由步长限制 $|\Delta v| = \epsilon$ 所决定的。因此,梯度下降法可以被视为一种在 $C$ 下降最快的方向上做微小变化的方法。

人们已经研究出很多梯度下降的变化形式,包括一些更接近真实模拟球体物理运动的变化形式。这些模拟球体的变化形式有很多优点,但是也有一个主要的缺点:它最终必需去计算$C$ 的二阶偏导,这代价可是非常大的。 为了理解为什么这种做法代价高,假设我们想求所有的二阶偏导 $\partial^2 C/ \partial v_j \partial v_k$。如果我们有上百万的变量$v_j$,那我们必须要计算数万亿(即百万次的平方)级别的二阶偏导(实际上,更接近万亿次的一半,因为$\partial^2 C/ \partial v_j \partial v_k = \partial^2 C/ \partial v_k \partial v_j$。同样,你知道怎么做。!)这会造成很大的计算代价。不过也有一些避免这类问题的技巧,寻找梯度下降算法的替代品也是个很活跃的研究领域。但在这本书中我们将主要用梯度下降算法(包括变化形式)使神经网络学习。

随机梯度下降算法

神经网络中如何使用梯度下降算法

我们怎么在神经网络中用梯度下降算法去学习呢?其思想就是利用梯度下降算法去寻找能使得方程代价函数取得最小值的权重 $w_k$ 和偏置 $b_l$。为了清楚这是如何工作的,我们将用权重和偏置代替变量 $v_j$。也就是说,现在“位置”变量有两个分量组成:$w_k$ 和 $b_l$,而梯度向量 $\nabla C$ 则有相应的分量 $\partial C / \partial w_k$和$\partial C / \partial b_l$。用这些分量来写梯度下降的更新规则,我们得到:

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

为什么使用随机梯度下降算法

应用梯度下降规则有很多挑战。我们将在下一章深入讨论。但是现在只提及一个问题。为了理解问题是什么,我们先回顾 $C(w,b) \equiv \frac{1}{2n} \sum_x | y(x) - a|^2$ 中的二次代价函数。注意这个代价函数有着这样的形式 $C = \frac{1}{n} \sum_x C_x$,即,它是遍及每个训练样本代价 $C_x \equiv \frac{|y(x)-a|^2}{2}$ 的平均值。在实践中,为了计算梯度 $\nabla C$,我们需要为每个训练输入 $x$ 单独地计算梯度值 $\nabla C_x$,然后求平均值,$\nabla C = \frac{1}{n} \sum_x \nabla C_x$。不幸的是,当训练输入的数量过大时会花费很长时间,这样会使学习变得相当缓慢。

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

怎么使用随机梯度下降算法

准确地说,随机梯度下降通过随机选取小量的 $m$ 个训练输入来工作。我们将这些随机的训练输入标记为$X_1, X_2, \ldots, X_m$,并把它们称为一个小批次。假设样本数量 $m$ 足够大,我们期望 $\nabla C_{X_j}$ 的平均值大致相等于整个 $\nabla C_x$的平均值,即,

这里的第二个求和符号是在整个训练数据上进行的。交换两边我们得到

证实了我们可以通过仅仅计算随机选取的小批量数据的梯度来估算整体的梯度。

为了将其明确地和神经网络的学习联系起来,假设 $w_k$ 和 $b_l$ 表示我们神经网络中权重和偏置。随机梯度下降通过随机地选取并训练输入的小批量数据来工作,

其中两个求和符号是在当前小批量数据中的所有训练样本 $X_j$ 上进行的。然后我们再挑选另一随机选定的小批量数据去训练。直到我们用完了所有的训练输入,这被称为完成了一个训练周期。然后我们就会开始一个新的训练周期。

另外值得提一下,对于改变代价函数大小的参数,和用于计算权重和偏置 的小批量数据的更新规则,会有不同的约定。在方程$C(w,b) \equiv \frac{1}{2n} \sum_x | y(x) - a|^2$ 中,我们通过因子 $\frac{1}{n}$ 来改变整个代价函数的大小。人们有时候忽略 $\frac{1}{n}$,直接取单个训练样本的代价总和,而不是取平均值。这对我们不能提前知道训练数据数量的情况下特别有效。例如,这可能发生在有更多的训练数据是实时产生的情况下。同样,小批量数据的更新规则有时也会舍弃前面的 $\frac{1}{m}$。从概念上这会有一点区别,因为它等价于改变了学习率 $\eta$ 的大小。但在对不同工作进行详细对比时,需要对它警惕。

随机梯度下降算法与梯度下降算法比较

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

梯度下降算法一个极端的版本是把小批量数据的大小设为 $1$。即,假设一个训练输入 $x$,我们按照规则 $w_k \rightarrow w_k’ = w_k - \eta \partial C_x / \partial w_k$ 和 $b_l \rightarrow b_l’ = b_l - \eta \partial C_x / \partial
b_l$ 更新我们的权重和偏置。然后我们选取另一个训练输入,再一次更新权重和偏置。如此重复。这个过程被称为在线、online、on-line、或者递增学习。在 online 学习中,神经网络在一个时刻只学习一个训练输入(正如人类做的)。

理解梯度和导数

CSDN : [机器学习] ML重要概念:梯度(Gradient)与梯度下降法(Gradient Descent)

知乎 : 如何直观形象的理解方向导数与梯度以及它们之间的关系?

知乎 : 什么是全导数?

拓展阅读

全局最优解?为什么 SGD 能令神经网络的损失降到零


参考文献

[1] Michael Nielsen. CHAPTER 1 Using neural nets to recognize handwritten digits[DB/OL]. http://neuralnetworksanddeeplearning.com/chap1.html, 2018-06-18.

[2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap1.tex, 2018-06-18.

本站所有文章和源码均免费开放,如您喜欢,可以请我喝杯咖啡