美文网首页
[神经网络这次真的搞懂了!] (4) 使用神经网络识别手写数字

[神经网络这次真的搞懂了!] (4) 使用神经网络识别手写数字

作者: 砥砺前行的人 | 来源:发表于2021-10-19 00:01 被阅读0次

    英文原文:http://neuralnetworksanddeeplearning.com/
    对原文的表达有部分改动

    通过梯度下降进行学习

    既然我们已经为神经网络设计好基本的框架了,那么如何让它学习识别数字呢?我们需要的第一件事是要了解即将学习的数据集(training data set)。我们将使用 MNIST 数据集,其中包含数万张手写数字的扫描图像以及它们的正确分类。 MNIST 的名字来源于它是 NIST
    所收集的两个数据集的修改子集。这是来自 MNIST 的一些图像:

    如您所见,这些数字实际上与本系列开头显示的数字相同,作为识别的挑战。当然,在测试我们的网络时,我们会要求它识别非训练集中的图像(例如:测试数据集 test data set)。

    MNIST 数据分为两部分,第一部分包含 60,000 张图像用作训练数据。这些图像是来自 250 人的扫描手写样本,其中一半是美国人口普查局的员工,一半是高中生。图像为灰度图像,大小为 28 x 28 像素。 MNIST 数据集的第二部分是用作测试数据的 10,000 张图像。同样,这些是 28 x 28 的灰度图像。我们将使用测试数据来评估我们的神经网络学习识别数字的能力。为了使这成为一个良好的性能测试,测试数据取自与原始训练数据不同的 250 人组成。这有助于让我们相信我们的系统可以识别那些在训练期间没有学习到的人的数字图像。

    我们将使用符号 x 来表示训练时的输入。将每个训练输入 x 视为一个 28×28=784 维的向量会很方便。向量中的每个条目代表图像中单个像素的灰度值。我们将用 y=y(x) 表示相应的期望输出,其中 y 是一个 10 维向量。例如,如果特定的训练图像 x 代表数字 “6”,则 y(x)=(0,0,0,0,0,0,1,0,0,0)^T 是网络的期望输出。注意这里的 ^T是转置操作,将一个行向量变成列向量。

    我们想要的是一种算法,它可以让我们找到权重和偏差,以便网络的输出近似于所有训练输入 xy(x)。为了量化我们实现这一目标的程度,我们定义了一个代价函数(Cost Function):
    C(w,b) \equiv \frac{1}{2n}\sum_{x} ||y(x) - a||^2

    这里,w 表示网络中所有权重的集合,b 表示所有偏差,n 是训练输入样本的总数,a 是输入 x 时网络的输出向量,当然,输出 a 取决于 xwb,但为了保持符号简单,我没有明确指出这种依赖性。我们将 C(w,b) 称为二次代价函数(Quadratic Cost Function);它有时也被称为均方误差(Mean Squared Error)或 MSE。检查二次代价函数的形式,我们看到当网络输出的结果与实际结果接近时,C(w,b)≈0。因此,如果我们的训练算法能够找到一组权重和偏差,使得 C(w,b)≈0,那么我们的训练算法就做得很好。相比之下,当 C 很大时,它的表现就不太好了,因为这意味着对于大量输入,y(x) 并不接近输出 a。因此,我们训练算法的目标是最小化代价函数 C(w,b)。换句话说,我们想找到一组权重和偏差,使代价函数尽可能小。我们将使用一种称为梯度下降(Gradient Descent)的算法来做到这一点。

    为什么要引入二次代价函数?毕竟,我们不是主要对网络正确分类的图像数量感兴趣吗?为什么不尝试直接最大化该数字,而不是最小化二次代价函数之类的间接度量?问题在于正确分类的图像数量不是网络中权重和偏差的平滑函数。在大多数情况下,对权重和偏差进行小的更改不会导致正确分类的训练图像数量发生任何变化。这使得很难弄清楚如何改变权重和偏差来提高性能。如果我们改为使用像二次代价函数这样的平滑函数,那么很容易弄清楚如何对权重和偏差进行小的更改,从而缩小代价函数。这就是为什么我们首先关注最小化二次代价函数,然后才检查分类准确度。

    即使我们想要使用平滑的代价函数,您可能仍然想好奇为什么我们选择方程中使用的二次函数。也许如果我们选择不同的代价函数,我们会得到一组完全不同的最小化权重和偏差?这是一个值得关注的问题,稍后我们将重新审视代价函数,并进行一些修改。然而,方程中的二次代价函数非常适合理解神经网络学习的基础知识,所以我们现在将坚持使用它。

    回顾一下,我们训练神经网络的目标是找到最小化二次代价函数 C(w,b) 的权重和偏差。这是一个明确的问题,但它有很多当前提出的令人分心的结构:wb 作为权重和偏差的解释,隐藏在背景中的 σ 函数,网络架构的选择,MNIST 等等。事实证明,我们可以通过忽略大部分结构而只关注最小化方面来理解大量的信息。所以现在我们将忘记代价函数的具体形式、与神经网络的连接等。相反,我们将想象我们只是简单地获得了一个包含许多变量的函数,并且我们想要最小化该函数。我们将开发一种称为梯度下降的技术,可用于解决此类最小化问题。然后我们将回到我们想要为神经网络最小化的特定函数的讨论上。

    好的,让我们假设我们试图最小化某个函数 C(v)。这可以是许多变量的任何实值函数,v=v_1,v_2,…。请注意,我已将 wb 符号替换为 v 以强调这可以是任何函数 - 我们不再专门考虑神经网络上下文。为了最小化 C(v),可以将 C 想象成只有两个变量的函数,我们称之为 v_1v_2

    我们想要的是找到 C 达到其全局最小值的位置。对于上面绘制的函数,我们可以观察图形并找到最小值。当然,我可能展示了一个过于简单的函数!一个通用函数 C 可能是一个包含许多变量的复杂函数,通常不可能仅仅通过观察图形来找到最小值。

    解决该问题的一种方法是使用微积分尝试通过分析找到最小值。我们可以计算导数,然后尝试使用它们来找到 C 是极值的地方。当 C 只是一个或几个变量的函数时,这可能会奏效。但是当我们有更多的变量时,它会变成一场噩梦。对于神经网络,我们通常需要更多的变量:大型的神经网络具有极其复杂的代价函数,其依赖于数十亿个权重和偏差。使用微积分来最小化是行不通的。

    梯度下降能够解决此类问题,这里通过类比简单介绍一下。我们首先将我们的代价函数视为一种山谷。我们想象一个球从山谷的斜坡上滚下来。我们的日常经验告诉我们,球最终会滚到谷底。也许我们可以用这个想法作为找到函数最小值的方法?我们会随机选择一个(假想的)球的起点,然后模拟球滚下山谷底部时的运动。我们可以简单地通过计算 C 的导数(可能还有一些二阶导数)来进行这个模拟——这些导数会告诉我们我们需要知道的关于山谷局部“形状”的一切,以告知我们的球应该如何滚动。

    为了让这个问题更精确,让我们考虑一下当我们将球在 v_1 方向上移动少量 \Delta v_1 并在 v_2 方向上移动少量 \Delta v_2 时会发生什么。微积分告诉我们 C 的变化如下:
    \Delta C ≈ \frac {\partial C}{\partial v_{1}} * \Delta v_1 + \frac {\partial C}{\partial v_{2}} * \Delta v_{2}

    我们将找到一种选择\Delta v_1\Delta v_2的方法,使\Delta C为负;即,我们将选择它们,以便球滚入山谷。为了弄清楚如何做出这样的选择,将 \Delta v 定义为 v 变化的向量会有所帮助,\Delta v \equiv (\Delta v_1, \Delta v_2)^T。我们还将 C 的梯度定义为由偏导数组成的向量,(\frac {\partial C}{\partial v_1}, \frac {\partial C}{\partial v_2})^T我们用∇C表示梯度向量,即:
    ∇C \equiv (\frac {\partial C}{\partial v_1}, \frac {\partial C}{\partial v_2})^T

    ∇C是一个梯度向量。

    有了这些定义,ΔC 的表达式可以改写为:
    ΔC≈∇C⋅Δv

    这个方程有助于解释为什么 ∇C 被称为梯度向量:∇Cv 的变化与 C 的变化联系起来,正是我们所期望的梯度。但这个方程真正令人兴奋的是,它让我们看到如何选择 Δv 以使 ΔC 为负。特别地,假设我们选择:
    Δv=−η∇C

    其中 η 是一个小的正参数(称为学习率)。ΔC≈−η∇C⋅∇C=−η‖∇C‖^2。因为‖∇C‖^2≥0,这就保证了 ΔC≤0,即如果我们按照式中的公式改变 vC 将永远减少,永远不会增加。这正是我们想要的属性!因此,我们将采用方程 Δv=−η∇C 来定义梯度下降算法中球的“运动定律”。也就是说,我们将使用等式Δv=−η∇C来计算 Δv 的值,然后将球的位置 v 移动该量:
    v→v′=v−η∇C

    然后我们将再次使用此更新规则,进行另一次移动。如果我们一遍又一遍地这样做,我们将持续降低 C,直到达到全局最小值。

    总结一下,梯度下降算法的工作方式是反复计算梯度∇C,然后向相反的方向移动,“下降”谷的斜率。我们可以像这样想象它:

    使用此规则梯度下降不会重现真实的物理运动。在现实生活中,球具有动量,而这种动量可能会使其滚过斜坡,甚至(暂时)滚上坡(这明显不是我们所需要的)。

    为了使梯度下降正确工作,我们需要选择足够小的学习率 η 以使等式 ΔC≈∇C⋅Δv 是一个很好的近似值。如果我们不这样做,我们最终可能会得到 ΔC > 0(类似于小球过最低点上坡后仍行驶了一段距离,导致变化后的小球更靠近山顶了),这显然是不好的!同时,我们不希望 η 太小,因为这会使 Δv 的变化量很小,因此梯度下降算法会变得非常缓慢。在实际实现中,η 经常变化,因此方程 ΔC≈∇C⋅Δv 仍然是一个很好的近似值,但算法不会太慢。我们稍后会看到它是如何工作的。

    C 只是两个变量的函数时,上述解释了梯度下降。但是,事实上,即使 C 是更多变量的函数,一切照旧。特别假设 Cm 个变量 v_1,...,v_m 所组成的函数。那么C中由微小变化Δv=(Δv_1,…,Δv_m)^T产生的变化ΔC为:
    ΔC≈∇C⋅Δv

    其中梯度 ∇C是向量:
    ∇C \equiv (\frac {\partial C}{\partial v_1}, ...,\frac {\partial C}{\partial v_m})^T

    对于两个变量的情况,我们可以选择:
    Δv=−η∇C

    并且我们保证 ΔC 的(近似)表达式将为负数。这为我们提供了一种通过重复应用更新规则来最小化梯度的方法,即使 C 是许多变量的函数:
    v→v′=v−η∇C

    您可以将此更新规则视为定义梯度下降算法。它为我们提供了一种反复改变位置 v 以找到函数 C 的最小值的方法。该规则并不总是有效:一些情况可能会出错并阻止梯度下降找到 C 的全局最小值,我们将在后面的章节中返回来探讨这一点。但是,在实践中,梯度下降通常效果非常好,在神经网络中,我们会发现这是一种最小化代价函数的强大方法,帮助神经网络进行学习。

    事实上,甚至在某种意义上来说梯度下降是搜索最小值的最佳策略。假设我们试图移动 Δv 以尽可能减少 C,这等效于最小化 ΔC≈∇CΔv。我们将限制移动的大小,使得 ‖Δv‖=\xi 其中 \xi > 0\xi 固定长度且较小。换句话说,我们想要一个固定大小的小步移动,我们重新尝试找到尽可能减少 C 的运动方向。可以证明,最小化∇C⋅ΔvΔv的选择是Δv=−η∇C,其中η=ϵ/‖∇C‖是由大小约束 ‖Δv‖=ϵ 确定。因此,梯度下降可以被视为一种在最大程度地立即减少 C 方向上采取小步变化的方法。

    人们已经研究了梯度下降的许多变化,但也有一个主要的缺点:结果证明计算 C 的二阶偏导数,成本可能非常昂贵。为了了解它为什么这么高,假设我们要计算所有的二阶偏导数∂^2C/∂v_j∂v_k。如果有一百万个这样的 v_j 变量,那么我们需要计算类似一万亿(即一百万平方)的二阶偏导数(实际上,更像是5kw次,因为 ∂^2C/∂v_j∂v_k=∂^2C /∂v_k∂v_j)。这将是计算成本高昂的行为。话虽如此,有一些技巧可以避免此类问题,而寻找梯度下降的替代方案是一个至今活跃的研究领域。但在本书中,我们将使用梯度下降(和变体)作为我们在神经网络中学习的主要方法。

    我们如何应用梯度下降在神经网络中学习?这个想法是使用梯度下降来找到权重 w_k 和偏差 b_l 以最小化代价函数。为了看看这是如何工作的,让我们重申梯度下降更新规则,用权重和偏差代替变量 v_j。换句话说,我们的“位置”现在有分量 w_kb_l,梯度向量 ∇C 有对应的分量 ∂C/∂w_k∂C/∂b_l。根据分量写出梯度下降更新规则,我们有
    w_k→w^′_k = w_k - η \frac{∂C}{∂w_{k}}
    b_l→b^′_l = b_l - η \frac{∂C}{∂b_{l}}

    通过反复应用这个更新规则,我们可以让“球滚下山”,并逐步找到代价函数的最小值。换句话说,这是一个可用于在神经网络中学习的规则。

    应用梯度下降规则存在许多挑战,我们将在后面的章节中深入研究这些。但现在我只想提一个问题。为了理解问题是什么,让我们回顾一下方程C(w,b) \equiv \frac{1}{2n}\sum_{x} ||y(x) - a||^2。请注意,此代价函数的形式为 C=\frac{1}{n}∑_xC_x,也就是说,它是单个训练的成本 C_x≡\frac {‖y(x)−a‖^2}{2} 的平均值例子。在实践中,为了计算梯度∇C,我们需要为每个训练输入分别计算梯度∇C_x,然后对它们求平均值,∇C=\frac{1}{n}∑_x∇C_x。不幸的是,当训练输入的数量非常大时,这可能需要很长时间,因此学习速度会很慢。

    一种称为随机梯度下降(Stochastic Gradient Descent)的方法可用于加速学习过程。这个想法是通过为随机选择的训练输入的小型样本计算∇C_x来估计梯度∇C。通过对这个小样本求平均,我们可以快速得到对真实梯度∇C的良好估计,这有助于加速梯度下降,从而加速学习。

    随机梯度下降方法通过随机挑选少量训练输入样本来工作。我们将标记这些随机训练输入 X_1,X_2,...,X_m,并将它们称为 mini-batch。如果样本大小 m 足够大,我们预计 ∇C_{X_j}的平均值将大致等于所有 ∇C_x 的平均值,即,
    \frac {\sum^{m}_{j=1}∇C_{X_j}}{m} ≈ \frac {\sum_{x}∇C_x}{n} ≈ ∇C

    其中第二个求和是整个训练数据集。交换双方我们得到:
    ∇C ≈ \frac {\sum^{m}_{j=1}∇C_{X_j}}{m}

    我们可以通过计算随机选择的mini-batch的梯度来估计整体梯度。

    为了将其明确地与神经网络中的学习联系起来,假设 w_kb_l 表示我们神经网络中的权重和偏差。然后随机梯度下降通过挑选随机选择的 mini-batch 训练样本来工作,并用这些输入进行训练:
    w_k→w_k′=w_k−\frac {η}{m} \sum_{j} \frac {∂C_{X_{j}}}{∂w_k}
    b_l→b_l′=b_l−\frac {η}{m} \sum_{j} \frac {∂C_{X_{j}}}{∂b_l}
    其中总和是当前 mini-batch 中所有训练示例 X_j 的梯度总和。然后我们挑选另一个随机选择的 mini-batch 并用它们进行训练。依此类推,直到我们用尽了训练输入,据说这将完成一个训练 epoch。那时我们会重新开始一个新的训练 epoch。

    值得注意的是,代价函数的缩放以及权重和偏差的小批量更新的约定各不相同。在C(w,b) \equiv \frac{1}{2n}\sum_{x} ||y(x) - a||^2中,我们将整体代价函数乘上 \frac {1}{n}。人们有时会省略 \frac {1}{n},将单个训练示例的代价相加而不是求平均值。当事先不知道训练示例的总数时,这特别有用。例如,如果实时生成训练数据,就会发生这种情况。而且,以类似的方式,mini-batch 更新有时会省略总和前面的 \frac {1}{m} 项。从概念上讲,这没什么区别,因为它相当于重新调整学习率 η。但是在对不同工作进行详细比较时,值得留意。

    我们可以将随机梯度下想象为政治投票:对 mini-batch 进行采样比对整个批次应用梯度下降要容易得多,就像进行民意调查比进行全面选举更容易一样。例如,如果我们有一个大小为n=60,000 的训练集,如在 MNIST 中,并选择一个小批量大小m=10,这意味着我们将得到一个6,000倍的梯度估算的加速!当然,估算不会是完美的,因为会有统计波动。但它不需要是完美的:我们真正关心的是朝着一个有助于减少 C 的大方向前进,这意味着我们不需要精确计算梯度。在实践中,随机梯度下降是一种常用且强大的神经网络学习技术,它是我们将在本书中开发的大多数学习技术的基础。

    相关文章

      网友评论

          本文标题:[神经网络这次真的搞懂了!] (4) 使用神经网络识别手写数字

          本文链接:https://www.haomeiwen.com/subject/ahqnoltx.html