训练神经网络包括迭代地调整模型参数(权重和偏置)以最小化损失函数。这种调整依赖于知晓每个参数的微小变化如何影响最终的损失值。从数学上讲,这种敏感性由损失函数对每个参数的梯度来体现。对于损失 $L$ 和参数 $w$,我们需要计算 $\frac{\partial L}{\partial w}$。对于非常简单的模型,手动使用微积分规则计算这些梯度是可行的,但对于当今常见的深度多层网络来说,这很快就会变得异常复杂且容易出错。想象一下为拥有数百万参数的模型推导导数!这时,**自动微分(AD)**就派上用场了。AD 是一系列以数值方式评估由计算机程序定义的函数导数的方法。与符号微分(它操作数学表达式,常导致复杂且低效的公式)或数值微分(它使用有限差分近似导数,可能存在截断和舍入误差)不同,AD 通过在构成整体计算的基本运算(加法、乘法、三角函数等)层面系统地应用微积分的链式法则,高效地计算出精确的梯度。链式法则:AD 的核心其核心是,AD 依赖于链式法则。如果有一系列函数,例如 $y = f(x)$ 和 $z = g(y)$,链式法则告诉我们如何找到复合函数 $z = g(f(x))$ 对 $x$ 的导数:$$ \frac{dz}{dx} = \frac{dz}{dy} \cdot \frac{dy}{dx} $$AD 将复杂的计算分解为一系列基本运算。然后,它计算每个小步骤的局部导数,并使用链式法则将它们组合起来以得到整体梯度。考虑一个简单例子:$L = (w \cdot x + b)^2$。令 $y = w \cdot x + b$。则 $L = y^2$。 要找到 $\frac{\partial L}{\partial w}$,链式法则给出:$$ \frac{\partial L}{\partial w} = \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial w} $$我们知道 $\frac{\partial L}{\partial y} = 2y$ 和 $\frac{\partial y}{\partial w} = x$。将 $y$ 代回,我们得到:$$ \frac{\partial L}{\partial w} = (2(w \cdot x + b)) \cdot x $$AD 自动完成这个过程,即使运算链非常长。正向模式与反向模式在 AD 中应用链式法则主要有两种方式:正向模式(正向累积): 通过从输入到输出遍历计算步骤来计算导数。它计算一个输入的改变如何影响所有中间变量和最终输出。当输入数量相对于输出数量较少时,它比较高效。反向模式(反向累积): 通过从最终输出到输入反向遍历计算步骤来计算导数。它计算最终输出的改变如何受到所有中间变量和输入的影响。当输出数量相对于输入数量较少时,这种模式明显更高效,这正是深度学习中的情况,因为我们通常只有一个标量损失值和数百万个参数(损失函数的输入)。PyTorch 的 Autograd 系统使用反向模式自动微分。Autograd 如何使用 AD当您对 requires_grad 属性设置为 True 的 PyTorch 张量执行操作时,PyTorch 会在后台构建一个有向无环图(DAG)。这个图通常被称为计算图,它记录了操作序列(节点)和涉及的张量(边)。让我们直观地看一下 $L = (a \cdot x + b)^2$ 的简单计算图,假设 $a$、$x$ 和 $b$ 是输入张量(或之前计算的结果),并且我们想得到 $\frac{\partial L}{\partial a}$、$\frac{\partial L}{\partial x}$ 和 $\frac{\partial L}{\partial b}$。digraph G { rankdir=LR; node [shape=box, style=filled, color="#ced4da"]; edge [color="#495057"]; subgraph cluster_inputs { label = "输入"; rank=same; style=filled; color="#f8f9fa"; a [label="a", color="#a5d8ff"]; x [label="x", color="#a5d8ff"]; b [label="b", color="#a5d8ff"]; } subgraph cluster_ops { label = "运算"; style=filled; color="#f8f9fa"; mul [label="*", color="#b2f2bb"]; add [label="+", color="#b2f2bb"]; pow [label="^2", color="#b2f2bb", shape=ellipse]; } L [label="L (损失)", shape=ellipse, style=filled, color="#ffc9c9"]; a -> mul; x -> mul; mul -> add; b -> add; add -> pow; pow -> L; // 表示反向传播(虚线) edge [style=dashed, color="#f03e3e", constraint=false, arrowhead=odot]; L -> pow [label="dL/dL=1"]; pow -> add [label="dL/dy"]; // y = a*x+b add -> mul [label="dL/d(a*x)"]; add -> b [label="dL/db"]; mul -> a [label="dL/da"]; mul -> x [label="dL/dx"]; }$L = (a \cdot x + b)^2$ 计算图的表示。实线表示正向传播,构建图。虚线表示反向传播期间梯度的流动,应用链式法则。当您在最终输出张量(通常是标量损失 $L$)上调用 .backward() 时,Autograd 会从该输出开始并反向遍历图。在每个步骤(节点),它根据后续节点的梯度和当前节点执行运算的局部导数来计算梯度,有效地应用了链式法则。然后,对每个需要梯度的张量(如模型参数)计算出的梯度会累积到它们的 .grad 属性中。这种机制使 PyTorch 能够自动计算由张量运算序列定义的任意复杂模型的梯度,让您摆脱手动推导的繁琐且容易出错的任务。接下来的章节将演示如何实际使用 Autograd 的功能:定义需要梯度的张量、隐式构建计算图、触发反向传播、访问梯度以及控制梯度计算。