训练神经网络需要调整其权重以最小化损失函数 $L$。梯度下降要求计算该损失函数相对于网络中每个权重和偏置的梯度,通常表示为 $ \nabla L $。对于一个可能拥有数百万个参数并分布在多层中的网络,计算网络内部较深层权重对最终损失的影响是一项挑战。损失函数并非该特定权重的直接函数;它是网络输出的函数,而网络输出又依赖于中间激活值,中间激活值又进一步依赖于更早的激活值和权重,形成了一条长长的依赖链。微积分中的一个基本原理在此发挥作用:链式法则。链式法则提供了一种计算复合函数(即相互嵌套的函数)导数的方法。这正是我们在神经网络中遇到的情况。链式法则:复合函数的导数让我们回顾一下基本思路。假设我们有一个简单的函数组合。如果变量 $y$ 依赖于变量 $u$,写作 $y = f(u)$,而 $u$ 又依赖于另一个变量 $x$,写作 $u = g(x)$,那么 $y$ 通过 $u$ 间接依赖于 $x$:$y = f(g(x))$。链式法则告诉我们如何求 $y$ 相对于 $x$ 的变化率,表示为 $dy/dx$。它表明这个导数是“外层”函数相对于其输入的导数与“内层”函数相对于其输入的导数的乘积:$$ \frac{dy}{dx} = \frac{dy}{du} \times \frac{du}{dx} $$可以将其视为敏感度的传递。如果 $x$ 发生微小变化, $y$ 会变化多少?这取决于当 $x$ 变化时 $u$ 变化了多少 ($du/dx$),再乘以当 $u$ 变化时 $y$ 变化了多少 ($dy/du$)。我们可以将此推广到更长的链条。如果 $z = f(y)$,$y = g(x)$,且 $x = h(w)$,那么 $z$ 通过这个链条依赖于 $w$。$z$ 相对于 $w$ 的导数可以通过将路径上的导数相乘得到:$$ \frac{dz}{dw} = \frac{dz}{dy} \times \frac{dy}{dx} \times \frac{dx}{dw} $$将链式法则应用于神经网络现在,让我们将其与神经网络联系起来。考虑一个非常简单的网络,它有一个输入 $x$,一个隐藏神经元 $h$,和一个输出神经元 $y$。计算步骤如下:隐藏神经元的预激活值:$z_1 = w_1 x + b_1$隐藏神经元的激活值:$h = \sigma(z_1)$(其中 $\sigma$ 是激活函数)输出神经元的预激活值:$z_2 = w_2 h + b_2$输出神经元的激活值(预测值):$y = \sigma(z_2)$损失计算:$L = \text{Loss}(y, y_{true})$(例如,平方误差 $L = (y - y_{true})^2$)digraph G { rankdir=LR; node [shape=circle, style=filled, color="#ced4da", fontname="Helvetica"]; edge [fontname="Helvetica"]; subgraph cluster_input { label="输入层"; style=filled; color="#e9ecef"; x [label="x", shape=rect, style=filled, color="#a5d8ff"]; w1 [label="w₁", shape=rect, style=filled, color="#ffe066"]; b1 [label="b₁", shape=rect, style=filled, color="#ffd8a8"]; } subgraph cluster_hidden { label="隐藏层"; style=filled; color="#e9ecef"; z1 [label="z₁", color="#91a7ff"]; sigma1 [label="σ", shape=diamond, color="#74c0fc"]; h [label="h", color="#748ffc"]; w2 [label="w₂", shape=rect, style=filled, color="#ffe066"]; b2 [label="b₂", shape=rect, style=filled, color="#ffd8a8"]; } subgraph cluster_output { label="输出层"; style=filled; color="#e9ecef"; z2 [label="z₂", color="#5c7cfa"]; sigma2 [label="σ", shape=diamond, color="#4dabf7"]; y [label="y", color="#4c6ef5"]; } subgraph cluster_loss { label="损失计算"; style=filled; color="#e9ecef"; y_true [label="y_{true}", shape=rect, style=filled, color="#ffc9c9"]; L [label="L", color="#f03e3e"]; } {x, w1, b1} -> z1 [label="w₁x+b₁"]; z1 -> sigma1; sigma1 -> h [label="h=σ(z₁)"]; {h, w2, b2} -> z2 [label="w₂h+b₂"]; z2 -> sigma2; sigma2 -> y [label="y=σ(z₂)"]; {y, y_true} -> L [label="Loss(y, y_{true})"]; }简单神经网络中的前向传播计算。箭头表示依赖关系。计算损失 $L$ 相对于早期权重(如 $w_1$)的梯度,需要使用链式法则,通过这些依赖关系向后传递导数。假设我们要找到损失 $L$ 相对于权重 $w_1$ 的梯度。$L$ 依赖于 $y$, $y$ 依赖于 $z_2$, $z_2$ 依赖于 $h$, $h$ 依赖于 $z_1$,而 $z_1$ 依赖于 $w_1$。使用链式法则,我们可以将导数 $ \partial L / \partial w_1 $ 写为:$$ \frac{\partial L}{\partial w_1} = \frac{\partial L}{\partial y} \times \frac{\partial y}{\partial z_2} \times \frac{\partial z_2}{\partial h} \times \frac{\partial h}{\partial z_1} \times \frac{\partial z_1}{\partial w_1} $$让我们逐项分析:$ \partial L / \partial y $:损失函数如何随最终预测值 $y$ 变化。这取决于所使用的具体损失函数。对于 $L = (y - y_{true})^2$,其值为 $2(y - y_{true})$。$ \partial y / \partial z_2 $:输出激活值如何随其预激活值 $z_2$ 变化。这是输出激活函数的导数,即 $\sigma'(z_2)$。$ \partial z_2 / \partial h $:输出预激活值 $z_2$ 如何随隐藏激活值 $h$ 变化。由于 $z_2 = w_2 h + b_2$,此导数即为 $w_2$。$ \partial h / \partial z_1 $:隐藏激活值如何随其预激活值 $z_1$ 变化。这是隐藏层激活函数的导数,即 $\sigma'(z_1)$。$ \partial z_1 / \partial w_1 $:隐藏预激活值 $z_1$ 如何随权重 $w_1$ 变化。由于 $z_1 = w_1 x + b_1$,此导数即为 $x$。将这个特定例子中的所有项组合起来:$$ \frac{\partial L}{\partial w_1} = \underbrace{2(y - y_{true})}{\partial L / \partial y} \times \underbrace{\sigma'(z_2)}{\partial y / \partial z_2} \times \underbrace{w_2}{\partial z_2 / \partial h} \times \underbrace{\sigma'(z_1)}{\partial h / \partial z_1} \times \underbrace{x}_{\partial z_1 / \partial w_1} $$注意,此计算涉及到在前向传播过程中计算出的项(如 $x, h, y, z_1, z_2$),以及在预激活值处评估的激活函数导数。链式法则提供了一种系统方法,可以将这些局部导数相乘,以求得损失函数对特定权重的整体敏感度,无论该权重在网络中处于何层。在每层有多个神经元的多层网络中,依赖关系变得更加复杂(一个神经元的输出会影响下一层中的多个神经元),涉及导数的求和。然而,核心原理不变:链式法则允许我们通过逐层向后传播导数信息来计算梯度。链式法则的这种系统应用正是反向传播算法所实现的,我们将在接下来的章节中详细说明。理解链式法则,是理解神经网络如何学习的重要一步。