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

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

作者: 砥砺前行的人 | 来源:发表于2021-10-20 23:08 被阅读0次

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

    关于代价函数的两个假设

    反向传播的目标是计算代价函数 C 相对于网络中的任何权重 w 或偏差 b 的偏导数 \frac {∂C}{∂w}\frac {∂C}{∂b}。为了使反向传播起作用,我们需要对代价函数的形式做出两个主要假设。不过,在陈述这些假设之前,先看一个示例代价函数。
    C = \frac{1}{2n}\sum_{x} ||y(x) - a^L(x)||^2
    其中:n 是训练样本的总数; y=y(x) 是对应的期望输出; L 表示网络层数; a^L(x) 是输入 x 时网络输出的向量。

    我们需要进行的第一个假设是:代价函数可以写成均值形式 C=\frac{1}{n} \sum_xC_x ,其中单个训练示例的代价是 C_x=\frac {1}{2}‖y−a^{L}‖^2。这个假设也适用于我们将在本书中遇到的所有其他代价函数。

    我们需要这个假设的原因是因为反向传播实际上让我们做的是计算单个训练示例的偏导数 \frac {∂C_x}{∂w}\frac {∂C_x} {∂b}。然后,我们通过对训练样本求平均来恢复 \frac {∂C}{∂w}\frac {∂C}{∂b}。我们假设训练示例 x 固定,将代价 C_x 写为 C。我们最终会把 x 放回去,但现在暂时先隐藏。

    我们对代价做出的第二个假设是,它可以写成神经网络输出的函数:


    例如,代价函数满足这个要求,因为单个训练样本 x 的二次代价可以写成
    C =\frac {1}{2}‖y−a^{L}‖^2 = \frac {1}{2} \sum_j(y_j - a^L_j)^2

    当然,这个代价函数也取决于期望的输出 y,你可能想知道为什么我们不把代价函数也看作 y 的函数。请记住,输入训练示例 x 是固定的,因此输出 y 也是一个固定参数。特别的,它不是我们可以通过改变权重和偏差能够修改的东西,也就是说,它不是神经网络需要学习的东西。因此,将 C 单独视为输出激活 a^L 的函数才有意义,而 y 只是一个有助于定义该函数的参数。

    反向传播算法基于常见的线性代数运算,例如向量加法、向量乘以矩阵等。但其中一种操作不太常用。假设 st 是两个相同维度的向量。然后我们用 s⊙t 来表示两个向量的元素乘积。因此(s⊙t)_j=s_jt_j。举个例子:
    \begin{bmatrix} 1 \\ 2\end{bmatrix} ⊙ \begin{bmatrix} 3 \\ 4\end{bmatrix} = \begin{bmatrix} 1 * 3 \\ 2 * 4\end{bmatrix} = \begin{bmatrix} 3 \\ 8\end{bmatrix}

    这种逐元素乘法有时称为 Hadamard 乘积 或 Schur 乘积。好的矩阵库通常提供 Hadamard 乘积的快速实现,这在实现反向传播时会派上用场。

    反向传播背后的四个基本方程


    反向传播是关于分析改变网络中的权重和偏差时如何影响代价函数的过程。即计算偏导数\frac {∂C}{∂w^l_{jk}}\frac {∂C}{∂b^l_j}。但为了计算这些,我们首先引入一个中间量 δ^l_j,我们将其称为第 l^{th} 层中第 j^{th} 个神经元的误差(error)。反向传播将为我们提供一个计算误差 δ^l_j 的过程,然后将 δ^l_j\frac {∂C}{∂w^l_{jk}}\frac {∂C}{∂b^l_j}相关联。

    要了解误差是如何定义的,请想象我们的神经网络中有一个恶魔:


    恶魔位于第 l 层的第 j^{th} 个神经元。当神经元的输入进来时,恶魔会扰乱神经元的操作。它给神经元的加权输入增加了一点变化Δz^l_j,这样神经元输出不再是σ(z^l_j),而是σ(z^l_j+Δz^l_j)。这种变化通过网络中的后续层传播,最终导致总代价发生变化 \frac {∂C}{∂z^l_j}Δz^l_j

    当前,恶魔干得不错,他正在尝试帮助您改善代价,他试图找到一个 Δz^l_j 使代价更小。假设\frac {∂C}{∂z^l_j}的值很大(正或负)。然后恶魔可以通过选择 Δz^l_j\frac {∂C}{∂z^l_j} 具有相反的符号来降低代价。相比之下,如果\frac {∂C}{∂z^l_j} 接近于零,那么恶魔通过影响加权输入z^l_j 无法继续改善代价了。这时恶魔可以说:神经元已经非常接近最佳状态。因此我们可以这么说:\frac {∂C}{∂z^l_j} 是神经元误差(error)的度量。

    受这个故事的启发,我们将第 l 层第 j 个神经元的 误差 δ^l_j 定义为:
    δ^l_j = \frac {∂C}{∂z^l_j}

    按照惯例,我们使用 δ^l 来表示与第 l 层的误差向量。反向传播将为我们提供一种计算每一层的 δ^l 的方法,然后将这些误差与我们真正感兴趣的东西关联起来:\frac {∂C}{∂w^l_{jk}}\frac {∂C}{∂b^l_j}

    您可能想知道为什么恶魔会改变加权输入 z_j^l。当然,想象恶魔改变输出激活 a^l_j 会更自然,我们将使用 \frac {∂C}{∂a^l_j} 作为我们的误差度量。如果你这样做,事情的结果与下面的讨论非常相似。但事实证明,这会导致反向传播的表示在代数上变得复杂。因此,我们将坚持使用 δ^l_j=\frac {∂C}{∂z^l_j} 作为我们的误差度量。

    反向传播基于四个基本方程。这些方程为我们提供了一种计算误差 δ^l 和代价函数梯度的方法。我会在下面列出四个等式。事实上,随着你逐渐深入研究方程,反向传播方程会越来越多,理解它们需要相当多的时间和耐心。理解这些会利于今后使用神经网络。本节中的讨论仅仅是一个开始,帮助您逐渐理解方程式。

    输出层误差方程 δ^Lδ^L 的分量由下式给出(BP1):
    δ^L_j = \frac {∂C}{∂a^L_j}σ^{'}(z^L_j)

    这是一个非常自然的表达。右边的第一项 \frac {∂C}{∂a^L_j}只是衡量第 j^{th} 个输出激活函数随代价函数变化的速度。如果 C 不太依赖于特定的输出神经元 j,那么 δ^L_j 就会很小,这正是我们所期望的。右侧的第二项 σ^{'}(z^L_j) 正是激活函数 σz^L_j 处的变化速度。

    (BP1)中的所有内容都较容易计算。z^L_jσ^{'}(z^L_j) 都是有着很小的计算开销。当然,\frac {∂C}{∂a^L_j}的确切形式将取决于代价函数的形式。然而,如果成本函数已知,计算\frac {∂C}{∂a^L_j}应该不会有什么问题。例如,如果我们使用二次成本函数,则 C=\frac{1}{2} \sum_j(y_j−a^L_j)^2\frac {∂C}{∂a^L_j}=(a^L_j−y_j),这显然很容易计算。

    方程 (BP1) 是 δ^L 的分量表达式。这是一个非常好的表达式,但我们想要反向传播是基于矩阵的形式。以基于矩阵的形式重写方程(BP1a):
    δ^L=∇_aC⊙σ^{′}(z^L)

    这里,∇_aC 被定义为一个向量,其分量是偏导数\frac {∂C}{∂a^L_j}。您可以将 ∇_aC 视为表示 C 相对于激活输出的变化率。很容易看出方程 (BP1a) 和 (BP1) 是等价的,因此从现在开始我们将使用 (BP1) 来表示这两个方程。例如,在二次代价函数的情况下,我们有 ∇_aC=(a^L−y),因此 (BP1) 的完全基于矩阵的形式变为:
    δ^L=(a^L−y)⊙σ^′(z^L).
    如您所见,此表达式中的所有内容都具有很好的向量形式,并且可以使用诸如 Numpy 之类的库轻松计算。

    δ^l关于下一层误差δ^{l+1}的方程(BP2):
    δ^l=((w^{l+1})^Tδ^{l+1})⊙σ^′(z^l)

    其中 (w^{l+1})^T 是第 (l+1)^{th} 层的权重矩阵 w^{l+1} 的转置。这个等式看起来很复杂,但每个元素都有很好的解释。假设我们知道第l+1^{th}层的误差δ^{l+1}。当我们应用矩阵 (w^{l+1})^T 时,我们可以直观地将其视为通过网络向后移动误差,从而为我们提供了对输出端误差在第 l 层某种度量。这将误差通过第 l 层中的激活函数向后移动,从而为我们提供第 l 层的加权输入中的误差 δ^l

    通过将 (BP2) 与 (BP1) 结合,我们可以计算网络中任何层的误差 δ^l。我们首先使用(BP1)计算δ^L,然后应用方程(BP2)计算δ^{L-1},然后再次应用方程(BP2)计算δ^{L-2},依此类推,一直通过网络回溯。

    相对于网络中的任何偏差的代价函数变化率的方程(BP3):
    \frac {∂C}{∂b^l_j} = δ^l_j

    也就是说,误差δ^l_j 正好等于变化率\frac {∂C}{∂b^l_j}。这是个好消息,因为 (BP1) 和 (BP2) 已经告诉我们如何计算 δ^l_j。我们可以将 (BP3) 重写为:
    \frac {∂C}{∂b} = δ

    代价函数相对于网络中任何权重的变化率的方程(BP4):
    \frac {∂C}{∂w^l_{jk}}=a^{l−1}_kδ^l_j

    这告诉我们如何根据量 δ^la^{l−1} 计算偏导数 \frac {∂C}{∂w^l_{jk}}。该等式可以用索引较少的符号重写为:
    \frac {∂C}{∂w} = a_{in}δ_{out}

    其中,a_{in} 是神经元输入对权重 w 的激活,δ_{out} 是神经元输出对权重 w 的误差。仅由该权重连接的两个神经元,我们可以将其描述为:

    方程\frac {∂C}{∂w} = a_{in}δ_{out}的一个很好的结果是,当激活 a_{in} 很小时,梯度项 \frac {∂C}{∂w} 也将趋于小。在这种情况下,我们会说权重学习很缓慢,这意味着它在梯度下降期间变化不大。换句话说,(BP4)的一个推论是低激活神经元输出的权重学习缓慢。

    从 BP1 ~ 4 可以获得沿着这些路线的其他推论。让我们从输出层开始。考虑 (BP1) 中的项 σ^{'}(z^L_j)。回忆上一章的 sigmoid 函数图,当 σ(z^L_j) 大约为 0 或 1 时,σ 函数变得非常平坦,σ^{'}(z^L_j)≈0。所以如果输出神经元是低激活(≈0)或高激活(≈1),那么最后一层的权重将学习缓慢。在这种情况下,通常会说输出神经元已饱和,因此权重已停止学习(或学习缓慢)。类似的评论也适用于输出神经元的偏差。

    我们可以对较早的层获得类似的见解。特别要注意 (BP2) 中的 σ^{'}(z^l) 项。这意味着如果神经元接近饱和,δ_j^l 可能会变小。这反过来意味着任何输入到饱和神经元的权重都会缓慢学习(如果 (w^{l+1})^Tδ^{l+1} 有足够大的条目来补偿 σ′(z^l_j)。但我说的是总体趋势)。

    总而言之,我们已经了解到,如果输入神经元处于低激活状态,或者如果输出神经元已经饱和,即高激活或低激活,权重将学习缓慢。

    这些观察结果都不是太令人惊讶。尽管如此,它们仍然有助于改善我们对神经网络学习情况的心理模型。此外,我们可以扭转这种推理方式。四个基本方程证明适用于任何激活函数,而不仅仅是标准的 sigmoid 函数(这是因为,正如我们稍后将看到的,证明不使用 σ 的任何特殊属性)。因此,我们可以使用这些方程来设计具有特定所需学习特性的激活函数。作为给你这个想法的一个例子,假设我们要选择一个(非 sigmoid)激活函数 σ 以便 σ^′ 总是正的,并且永远不会接近于零。这将防止在普通 sigmoid 神经元饱和时发生的学习速度减慢。在本书的后面,我们将看到对激活函数进行这种修改的示例。牢记这四个方程 (BP1)-(BP4) 可以帮助解释为什么要尝试这种修改,以及它们会产生什么影响。

    四大基本方程的证明

    我们现在将证明四个基本方程 (BP1)-(BP4)。所有四个都是多变量微积分链式法则的结果。

    让我们从方程 (BP1) 开始,它给出了输出误差 δ^L 的表达式。为了证明这个等式,回忆一下根据定义:
    δ^L_j = \frac {∂C}{∂z^L_j}

    应用链式法则,我们可以用关于输出激活的偏导数重新表达上面的偏导数:
    δ^L_j = \frac {∂C}{∂a^L_j} \frac {∂a^L_j}{∂z^L_j}

    因为 a^L_j=σ(z^L_j),右边的第二项可以写成σ′(z^L_j),方程变为
    δ^L_j = \frac {∂C}{∂a^L_j} σ′(z^L_j)
    这正是 (BP1a)

    接下来,我们将证明 (BP2),它根据下一层的误差 δ^{l+1} 给出了误差δ^l 的方程。为此,我们想根据 δ^{l+1}_k=\frac {∂C}{∂z^{l+1}_{k}} 重写 δ^l_j = \frac {∂C}{∂z^l_j}。我们可以使用链式法则来做到这一点:
    δ^L_j = \frac {∂C}{∂z^l_j} \\ = \sum_k \frac {∂z^{l+1}_{k}}{∂z^l_j} \frac {∂C}{∂z^{l+1}_{k}} \\ = \sum_k \frac {∂z^{l+1}_{k}}{∂z^l_j} δ^{l+1}_k

    因为:
    z^{l+1}_k=\sum_j w^{l+1}_{kj} a^l_j + b^{l+1}_k = \sum_j w^{l+1}_{kj} σ(z^l_j) +b^{l+1}_k

    σ(z^l_j)求微分后,我们得到:
    \frac {∂z^{l+1}_{k}}{∂z^L_j} = w^{l+1}_{kj} σ^′(z^l_j)

    代入\sum_k \frac {∂z^{L+1}_{k}}{∂z^L_j} δ^{l+1}_k我们得到:
    δ^l_j=\sum_k w^{l+1}_{kj}δ^{l+1}_k σ^′(z^l_j)

    对于 (BP3),同样利用链式法则:
    δ^l_j = \frac {∂C}{∂z^l_j} \\ = \frac {∂C}{∂b^l_j} \frac {∂b^l_j}{∂z^l_j} \\ \frac {∂C}{∂b^l_j} = δ^l_j \frac {∂z^l_j} {∂b^l_j} \\ = δ^{l}_j \frac {∂{w^l_ja^l_j + b^l_j}} {∂b^l_j} \\ = δ^l_j

    对于 (BP4),同样利用链式法则:
    δ^l_j = \frac {∂C}{∂z^l_j} \\ = \frac {∂C}{∂w^l_{jk}}\frac {∂w^l_{jk}}{∂z^l_j} \\ \frac {∂C}{∂w^l_{jk}} = δ^l_j \frac {∂z^l_j}{∂w^l_{jk}} \\ = δ^l_j\frac {∂w^l_k a^{l-1}_{k}+b^l_j}{∂w^l_{jk}} \\ = δ^l_j a^{l-1}_k

    相关文章

      网友评论

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

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