单隐藏层神经网络——单样本情形#
前向传播#
首先,我们将具体讨论 图 1 中展示模型的前向传播计算过程。正如我们在 上一节 所讨论的那样,每个神经元包含线性变换和非线性变换(激活)两步运算,且不同神经元都对应着不同的偏置项和权重项。记 \(b_j^{[l]}\) 和 \(\bw_j^{[l]}\) 分别为神经元 \(a_j^{[l]}\) 所对应的(当前的)偏置项和权重项 2根据我们在 上一节 中所讨论的符号规则,第 \(t\) 步更新后的模型参数应该表达为 \(b_j^{[l](t)}\) 和 \(\bw_j^{[l](t)}\),但为了简化符号表达,本节省略表示迭代次数的上角标 \((t)\)。。
当神经网络的层数 \(l\) 为正整数时,为了计算神经元 \(a_j^{[l]}\) 在当前参数下的数值,我们通常将其上一层的结果 \(\{a_j^{[l-1]}:j=1,\ldots,d^{[l-1]}\}\) 作为该神经元的输入值。例如,对于 \(j=1,\ldots,d^{[1]}\),当我们计算 \(a_j^{[1]}\) 时,对应的输入特征为 \(\{a_j^{[0]}:j=1,\ldots,d^{[0]}\} =\{x_j:j=1,\ldots,d\}\)。此时,\(a_1^{[1]}\) 的计算过程为
更一般地,记 \(\ba^{[l]} = (a_1^{[l]},\ldots,a_{d^{[l]}}^{[l]})\trans\),则第 \(l\) 层的神经元 \(a_j^{[l]}\) 的计算规则如下:
这里用 \(g^{[l]}\) 表示第 \(l\) 层的激活函数。隐藏层可以选用 ReLU、tanh 等函数;二分类输出层通常使用 sigmoid 函数。不同层不必采用相同的激活函数。
通过以上计算可知,图 1 中模型的参数是每个神经元对应的偏置和权重:
需要指出的是,每个偏置项的维度均为 1,但对应于神经元 \(a_j^{[l]}\) 的权重项 \(\bw_j^{[l]}\) 的维度为 \(d^{[l-1]}\)。该神经网络前向传播的计算流程如下图所示。
为了提高模型的计算效率,我们需要对上述计算进行 向量化。对于神经网络的第 \(l\) 层,记 \(\bb^{[l]} = (b_1^{[l]},\ldots,b_{d^{[l]}}^{[l]})\trans\) 以及 \(\bW^{[l]}=[(\bw_1^{[l]})\trans;\ldots;(\bw_{d^{[l]}}^{[l]})\trans]\)。对于 \(l=1,\ldots,L\) 以及 \(j=1,\ldots,d^{[l]}\),\(\bb^{[l]}\) 和 \(\bW^{[l]}\) 中的第 \(j\) 行代表着第 \(l\) 层第 \(j\) 个神经元对应的偏置项和权重项。基于新定义的符号,我们可以得到 \(\ba^{[l]}\) 的向量化表达式 3对应于 \(\ba^{[l]}\),其输入特征为 \(\ba^{[l-1]}\)。
其中,对于向量 \(\bz=(z_1,\ldots,z_m)\trans\in\mathbb{R}^m\),定义 \(\sigma(\bz)=(\sigma(z_1),\ldots,\sigma(z_m))\trans\) 4对应于 Python 的 NumPy 包所涉及的 广播机制。,\(m\in\mathbb{N}\) 为任意正整数。
由于这里只考虑一个样本 \((\bx,y)\),图 1 中模型的向量化前向传播为
其中,\(a^{[2]}\) 是样本属于类别 1 的预测概率。对于单个样本,二元交叉熵损失为
以上计算结果对应的 计算图 如下图所示。
备注
前向传播的过程是基于当前参数计算神经网络各个神经元的结果。该过程有以下两个用途:
模型参数训练过程中,前向传播主要用于计算每个神经元在当前参数下的激活值,并计算相应的损失函数。前向传播为计算损失函数对参数的求导提供中间结果。
模型参数训练完毕后,前向传播用于计算并输出模型的估计结果。
后向传播#
当我们训练模型时,我们需要根据当前参数,计算损失函数对模型参数的偏导数,并利用梯度下降法对模型参数进行一步迭代更新。例如,对模型参数 \(\bb^{[1]}\) 的更新过程如下:
其中,\(\bb^{[1](t)}\) 是第 \(t\) 次更新前的第一层偏置向量,\(\alpha\) 是当前学习率 5学习率常随更新次数 \(t\) 增加而降低,但是否衰减以及如何衰减都属于需要验证的超参数选择。,\(\btheta^{(t)}\) 表示此时的全部模型参数。竖线记号强调梯度在同一组旧参数处计算。
与上一节的处理类似,为了简化符号,我们省略表示迭代次数的上角标 \((t)\)。本节主要分析二分类问题;对于回归或其他任务,需要相应更改输出层与损失函数。仍针对一个样本 \((\bx,y)\),考虑 图 1 所示的网络,其参数为 \(\btheta = \{\bb^{[1]},\bW^{[1]},b^{[2]},\bW^{[2]}\}\),损失函数参见式 (22)。这里输出层宽度为 1,所以 \(b^{[2]}\) 是标量,\(\bW^{[2]}\in\mathbb{R}^{1\times d^{[1]}}\) 是行向量。
备注
后向传播的数学基础是链式法则(chain rule),它用于求复合函数的导数。若 \(f(x)=g(h(x))\),并且 \(g\) 与 \(h\) 在相应点可导,则 那么,在一般条件下,\(f(x)\) 的导数 \(f'(x)\) 可以通过链式法则求得。当函数 \(g\) 和 \(h\) 都是一元函数时, 基于链式法则的求导结果如下(忽略自变量):
其中,\((g\circ h)\) 表示函数 \(g(h(x))\)。更具体地,如果 \(f(x) = g(h(x))\),我们有
其中,\(g'\{h(x)\}\) 表示函数 \(g\) 在 \(h(x)\) 处的导数,而 \(h'(x)\) 表示函数 \(h\) 在 \(x\) 处的导数。
当 \(h: \mathbb{R}^p\to\mathbb{R}^d\) 以及 \(g:\mathbb{R}^d\to\mathbb{R}\) 时,复合函数 \(f= g\circ h: \mathbb{R}^p\to\mathbb{R}\)。则对 \(\bx\in\mathbb{R}^p\),我们有如下结果
其中,\(h_j = h_j(\bx)\) 为函数 \(h\) 的第 \(j\) 个分量,\(\partial f/\partial h_j\) 是将函数 \(f\) 看做向量 \((h_1,\ldots,h_d)\trans\) 的函数时对其第 \(j\) 个分量求导的结果。
首先,我们以求解 \(\partial \mathcal{J}/\partial b^{[2]}\) 为例探讨后向传播的基本原理。根据 前向传播的计算图,基于参数 \(b^{[2]}\) 的计算结果为 \(z^{[2]}\)。因此,我们可将中间变量 \(z^{[2]}\) 视为参数 \(b^{[2]}\) 的函数,而损失函数 \(\mathcal{J}\) 可以被视为中间变量 \(z^{[2]}\) 的函数。为了求解损失函数对参数 \(b^{[2]}\) 的导数,我们可将损失函数 \(\mathcal{J}(\btheta)\) 视为复合函数形式 \(\mathcal{J}\circ z^{[2]}\),其中自变量为 \(b^{[2]}\)。则根据链式法则,我们有如下计算结果
根据式 (21) 计算结果可知,
进一步根据链式法则,我们可知
式 (25) 中所涉及的两个偏导数也可根据式 (21) 计算结果求得,即
类似地,我们可以求出损失函数对于其他三个参数的偏导数。
备注
上述推导说明:参数梯度可以沿计算图拆成若干局部导数,并复用前向传播在式 (21) 中计算的中间量。这正是后向传播能够高效实现链式法则的原因。
用误差信号组织后向传播
将第 \(l\) 层线性输入的梯度记为 \(\bdelta^{[l]}=\partial\mathcal{J}/\partial\bz^{[l]}\)。 对使用 sigmoid 函数的输出层与二元交叉熵的组合,两个导数恰好相消,因此
隐藏层误差信号由后一层向前传播:
其中 \(\odot\) 表示逐元素乘法。若隐藏层也使用 sigmoid 函数,则 \(g^{[1]\prime}(\bz^{[1]})=\ba^{[1]}\odot(1-\ba^{[1]})\)。 这种“先求每层误差信号,再求参数梯度”的写法更容易推广到深层网络。
经过代数运算,我们可得到如下梯度结果:
这四个梯度分别与 \(b^{[2]}\)、\(\bW^{[2]}\)、 \(\bb^{[1]}\) 和 \(\bW^{[1]}\) 同形。检查梯度与参数的维度是否一致,是发现后向传播实现错误的有效方法。
备注
后向传播会复用前向传播的中间量。对于本例使用 sigmoid 函数得到的激活值,缓存 \(\bx\)、\(\ba^{[1]}\) 和 \(a^{[2]}\) 已足够;在一般实现中通常缓存 \(\bz^{[l]}\) 与 \(\ba^{[l]}\),因为不少激活函数的导数需要线性输入 \(\bz^{[l]}\)。
后向传播以及梯度计算的总结如下图所示。
记 \(\btheta^{(t)}\) 为第 \(t\) 次更新前的全部参数。梯度下降对每个参数执行相同形式的更新:
其中,\(\btheta^{(t)}=\{\bb^{[1](t)},\bW^{[1](t)},b^{[2](t)},\bW^{[2](t)}\}\),且同一次更新中的所有梯度都应在同一组旧参数 \(\btheta^{(t)}\) 处计算。
再看后向传播#
后向传播可以看作重复应用同一个局部规则:先把后一层的误差信号传回当前层,再由当前层的输入计算参数梯度。下面分别展示隐藏层与输出层的依赖关系。
输出层