想象你是一位主厨,负责一家有上万道菜的餐厅。每道菜想做得更好吃,关键问题是:每种调料多加一小勺,最终味道会变化多少? 这个“变化比例”,数学上叫做导数;把所有调料的影响排成一张表,就是梯度。传统做法叫手动微分——厨师拿纸笔,为每道菜重新推导一遍“调料影响公式”,再一行行写代码实现,耗时、易错、难维护。而自动微分像给厨房流水线装上传感器:每道工序自动记录“这一步对成品的推动力”,再沿着工序图把影响力一层层传回给每一份原料,一次运行同时得到菜谱数值和所有调料的影响表。这篇文章会用这座“传感器厨房”贯穿始终,从直觉到公式、从原理到实践,让你彻底看懂自动微分和手动微分差在哪里。

岗位关联

对 AI 从业者而言,自动微分是深度学习框架的“隐形引擎”。理解它与手动微分的差异,能帮你正确设计网络、诊断梯度问题、优化显存,也是跨入 AI 编译器方向的必修课。

目录
  1. 可视化演示
  2. 导数基础直觉:尝一口汤就知道变化方向
  3. 手动微分世界:纸笔配方的痛苦
  4. 计算图与链式法则:给厨房装传感器
  5. 前向模式:从第一道工序一路推到成品
  6. 反向模式:从成品倒推每一道工序的影响
  7. 模式对比与工程选择:选对传菜路线
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

导数基础直觉:尝一口汤就知道变化方向

老主厨王师傅判断一锅汤咸不咸,只需抿一小口,就能说出该补半勺盐还是两勺糖。他凭的不是玄学,而是常年积累的“变化敏感度”:汤的咸味对盐量的敏感程度是多少。数学上把这个“输出随输入变化的即时比例”叫做导数。如果你的函数是一锅汤,输入变量是每味调料,那么导数回答的就是:“这味调料动一点点,汤的味道整体动多少。”

把视角拉宽到人工智能领域,一个模型的“味道”就是损失函数——一个用来衡量模型答得对不对的数值。模型里有成千上万种“调料”,也就是参数。想要让损失变小,就要知道每个参数该往哪个方向调、调多大幅度。这个“该往哪调”的信息,正是由梯度提供的。梯度是导数的自然延伸:它把所有输入各自的变化敏感度打包成一个向量,向量的方向就是函数上升最快的方向,反方向则是下降最快的方向。

核心公式是导数的定义,它把一个“平均变化率”不断压缩到某一个点:

王师傅的舌头能尝出咸淡,靠的是无数次实践。而计算机没有舌头,它需要一套系统的方法来“尝”出函数的变化方向——这正是后面几节展开的:从手工计算到自动传感器。

f′(x)=lim⁡Δx→0f(x+Δx)−f(x)Δxf'(x) = \lim_{\Delta x \to 0} \frac{f(x+\Delta x) - f(x)}{\Delta x}
这个极限告诉我们:当自变量的步子小到不能再小,函数值的平均变化率就退化为那一点的瞬时敏感度。
  1. 函数增量分子写的是 \(f(x+\Delta x) - f(x)\),表示自变量移动一小步后,函数值变化了多少。放在厨房里,就是多加 \(\Delta x\) 勺盐后,咸味评分变化了多少。
    f(x+Δx)−f(x)f(x+\Delta x) - f(x)
  2. 自变量步长分母 \(\Delta x\),表示自变量的移动距离,对应“一小勺盐”的量。
    Δx\Delta x
  3. 极限取瞬时变化率把步长无限压向 0,平均变化率就退化为某个具体调料量上的瞬时敏感度,也就是导数本身。
    lim⁡Δx→0ΔfΔx=f′(x)\lim_{\Delta x \to 0} \frac{\Delta f}{\Delta x} = f'(x)

手动微分世界:纸笔配方的痛苦

老式厨房里没有传感器,王师傅要推一道新菜的“影响配方表”,只能搬出纸笔。他先根据菜谱结构,用数学规则把“每种配料对成品的导数公式”一步步推出来,再把这些公式写进程序里代值计算。这条路,就叫手动微分。

手动微分有两种常见做法。第一种是符号求导:像解代数题一样,用求导规则(乘积法则、链式法则)把表达式变换成导数的解析表达式。比如给定 \(\sin x \cdot x^2\),你能算出一个新表达式 \(\cos x \cdot x^2 + \sin x \cdot 2x\),之后代入任何 x 都能用。第二种是数值微分:不推公式,直接用定义近似,给 x 加上一个极小的扰动 \(\varepsilon\),用差商估计斜率。前者准确但表达式会越推越长,后者简单却在每一步都引入近似误差。

ddx(sin⁡x⋅x2)=cos⁡x⋅x2+sin⁡x⋅2x\frac{\mathrm{d}}{\mathrm{d}x}\left( \sin x \cdot x^2 \right) = \cos x \cdot x^2 + \sin x \cdot 2x

1. 识别乘积结构:\(\sin x\) 和 \(x^2\) 相乘,手动求导第一步是认出这里藏着乘积法则。

u(x)v(x),u=sin⁡x, v=x2u(x)v(x), \quad u=\sin x,\ v=x^2

2. 分别求因子导数:\(u' = \cos x\),\(v' = 2x\),这是两个查表可得的基础导数。

u′=cos⁡x,v′=2xu' = \cos x, \quad v' = 2x

3. 套用乘积法则:结果等于 \(u'v + uv'\),展开成两项相加,最终得到完整公式。

u′v+uv′=cos⁡x⋅x2+sin⁡x⋅2xu'v + uv' = \cos x \cdot x^2 + \sin x \cdot 2x

再看数值微分公式:

f′(x)≈f(x+ε)−f(x−ε)2εf'(x) \approx \frac{f(x+\varepsilon) - f(x-\varepsilon)}{2\varepsilon}

1. 对称采样:在 x 左右两侧各取距离为 \(\varepsilon\) 的点,分别计算函数值。

f(x+ε),f(x−ε)f(x+\varepsilon), \quad f(x-\varepsilon)

2. 差商表达变化:两个函数值相减,表示这段区间上函数的总变化量。

f(x+ε)−f(x−ε)f(x+\varepsilon) - f(x-\varepsilon)

3. 除以区间长度:用总变化量除以 \(2\varepsilon\),得到平均斜率;\(\varepsilon\) 越小,结果越接近真实导数。

Δf2ε≈f′(x)\frac{\Delta f}{2\varepsilon} \approx f'(x)

手动微分的问题在“菜谱”规模变大时彻底暴露:模型几十层、参数几百万个,符号求导的公式能铺满整面墙,数值微分要对每个参数各做一次前后采样,计算量惊人,而且任何一处笔误都会让梯度方向错乱。王师傅写几道菜的配方还可以,管理整条中央厨房流水线就力不从心了。

text5 行
符号求导示例\frac{d}{dx}(\sin x \cdot x^2) = \cos x \cdot x^2 + \sin x \cdot 2x 数值微分示例f'(x) \approx \frac{f(x+\varepsilon) - f(x-\varepsilon)}{2\varepsilon}

计算图与链式法则:给厨房装传感器

王师傅决定改革:他先画出每道菜的完整工序图——从备料、切配、加热到调味、摆盘,每一步都画成节点,节点之间用箭头连接,箭头代表半成品流向。然后他在每个工序节点上装一个读数表,记录“这个工序的输出对它的输入有多敏感”。这就是计算图:把复杂函数拆成一系列基础运算组成的有向无环图,图中每个节点是一次基本运算,每条边是一个中间结果。

装好传感器后,影响怎么传递?靠的是链式法则。假设成品是 \(z\),中间经过了一个中转工序 \(u\),再连到原料 \(x\)。那么原料对成品的总影响,等于“成品对中转的影响”乘以“中转对原料的影响”。就像你想知道辣椒多了对最终菜品的辣度影响,可以先看辣椒对辣汤的影响,再看辣汤对成品的影响,两个系数相乘。

通用公式如下,它把一条长链上的影响逐级串起来:

有了工序图和局部读数表,自动微分就有了物理基础。接下来的问题是:传感器该怎么跑?是从头到尾推一遍,还是从成品倒着查一遍?下面两节就是两条路线。

∂z∂x=∂z∂u⋅∂u∂x\frac{\partial z}{\partial x} = \frac{\partial z}{\partial u} \cdot \frac{\partial u}{\partial x}
链式法则的本质:把“端到端的变化率”拆成“每段的变化率”相乘。厨师只需要关心相邻两道工序之间的影响系数。
  1. 插入中间环节把从 x 到 z 的长链路拆开,找到中转站 u。
    z=f(u),u=g(x)z = f(u), \quad u = g(x)
  2. 外层影响\(\partial z/\partial u\) 是成品对中间工序的敏感度,相当于最后一道工序的局部影响读数。
    ∂z∂u\frac{\partial z}{\partial u}
  3. 内层影响\(\partial u/\partial x\) 是中间工序对原料的敏感度,相当于当前工序的局部影响读数。
    ∂u∂x\frac{\partial u}{\partial x}
  4. 相乘传递把两段读数相乘,得到原料到成品的总影响系数,这就是链式法则。
    ∂z∂u⋅∂u∂x\frac{\partial z}{\partial u} \cdot \frac{\partial u}{\partial x}

前向模式:从第一道工序一路推到成品

王师傅想算“主料加一克,成品会变多少”。他采取的策略是:从第一道工序开始,在手里捏着一个虚拟的“影响种子”——假设主料的变化率是 1,其他原料是 0——然后带着这个数字走完整条流水线。每经过一道工序,就把当前影响乘以该工序的局部影响系数,得到下一步的影响数值。等走到成品时,手里拿到的就是“主料对成品的完整影响”。这套方法就是前向模式自动微分。

前向模式的特点是同步计算:一边算函数值,一边算导数。它把普通的数据流 \(v_i\) 扩展成一对数据:数值本身和它对种子输入的导数 \(\dot{v}_i\)。每个基础运算都同时更新这两个量。因为计算顺序是从输入到输出,天然符合流水线的方向,所以叫“前向”。

数学上,前向模式沿计算图的拓扑序传递导数:

前向模式每运行一次,只能得到一个输入对全部输出的影响。如果一个模型有 1000 万个参数,就要跑 1000 万遍——太奢侈了。但在“输入很少、输出很多”的场景,比如机器人关节力矩计算,它反而非常高效。王师傅想:要是能倒过来,从成品反向查一遍,也许一次就能拿到所有配料的贡献?

v˙i=∑j∈pre(i)∂vi∂vj v˙j\dot{v}_i = \sum_{j \in \mathrm{pre}(i)} \frac{\partial v_i}{\partial v_j}\, \dot{v}_j
每个中间变量的方向导数,等于所有上游节点传来的方向导数乘以本工序局部偏导的和。
  1. 带点记号\(\dot{v}_i\) 表示节点 \(v_i\) 对当前种子输入的敏感度,即“这道工序的结果跟着种子走了多远”。
    v˙i=∂vi∂x\dot{v}_i = \frac{\partial v_i}{\partial x}
  2. 遍历前驱节点\(\sum_{j \in \mathrm{pre}(i)}\) 把所有直接上游工序 \(j\) 都纳入考虑。
    ∑j∈pre(i)\sum_{j \in \mathrm{pre}(i)}
  3. 局部偏导乘上传入导数上游传来的敏感度 \(\dot{v}_j\) 乘以本工序的局部影响系数,把所有通路求和。
    ∂vi∂vj v˙j\frac{\partial v_i}{\partial v_j}\,\dot{v}_j

反向模式:从成品倒推每一道工序的影响

王师傅换了个思路:不再从原料往成品推,而是从成品倒着走。他先给成品贴上一个“单位影响标签”——假设成品变化 1 个单位。然后走到倒数第一道工序,问它:成品的变化里,有多少是你贡献的?得到答案后,把这个影响系数继续往上一道工序传。每传一次,影响标签就被乘上该工序的局部导数。走到原料端时,每份原料都拿到一个完整的“成品对它的影响值”。这就是反向模式自动微分,也叫伴随模式。

反向模式先做一遍前向传播,把每道工序的中间值都记录并存储下来;然后从输出节点开始,沿反方向传播梯度。这里最关键的量叫伴随量 \(\bar{v}_i\),表示最终输出对节点 \(v_i\) 的梯度。它的计算顺序和正向相反:先算靠近输出的节点,再算靠近输入的节点。

计算公式为:

这就是深度学习中大名鼎鼎的反向传播算法。它和反向模式自动微分是一回事:一次反向传播,就可以得到损失函数对每一层权重、每一个偏置的梯度,然后交给优化器去更新参数。王师傅的整条流水线,现在只需要“尝一口成品”就能同时知道所有配料该加减多少——效率发生了质变。

vˉi=∑j∈succ(i)vˉj⋅∂vj∂vi\bar{v}_i = \sum_{j \in \mathrm{succ}(i)} \bar{v}_j \cdot \frac{\partial v_j}{\partial v_i}
反向模式的威力:跑一次反向传播,就能拿到所有输入的梯度。深度学习中“损失函数”只有一个输出,参数有上千万个,这正好是它的主场。
  1. 伴随记号\(\bar{v}_i\) 表示最终输出对 \(v_i\) 的梯度,也就是“成品对这道工序的最终影响”。
    vˉi=∂z∂vi\bar{v}_i = \frac{\partial z}{\partial v_i}
  2. 遍历后继节点每个下游工序 \(j\) 的伴随量 \(\bar{v}_j\),沿着它们之间的边传回当前节点。
    vˉj\bar{v}_j
  3. 乘局部偏导并累加把下游的伴随量乘上这条边对应的局部导数,所有后继路径求和,得到当前节点的伴随量。
    vˉj⋅∂vj∂vi\bar{v}_j \cdot \frac{\partial v_j}{\partial v_i}

模式对比与工程选择:选对传菜路线

王师傅总结了两种传菜路线:从原料到成品叫前向,从成品回原料叫反向。到底选哪种,取决于厨房的格局——是原料种类多,还是成品菜式多。如果原料只有几种、成品却有几百道菜,从头到尾推一遍,每种原料跑一次就能算出所有成品的影响,非常划算;反过来,如果原料上千种、成品只有一种(比如一锅汤的咸淡),那从成品倒推一次,就能拿到所有原料的影响,效率最高。

用数学语言说:假设函数有 \(m\) 个输入、\(n\) 个输出。前向模式要跑 \(m\) 次(每输入一个种子),反向模式要跑 \(n\) 次(每输出一个种子)。深度学习模型通常是上千万个参数(输入维度 m 巨大),但损失函数只有 1 个标量输出(n=1),所以反向模式成为绝对主流。

工程中还有一个不可忽视的因素:内存。反向模式为了回传梯度,必须存下前向传播的所有中间结果,网络越深,显存占用越大。工程师们的应对招数是“检查点”:每隔几层存一次中间值,反向时再重算丢失的部分,用时间换空间。此外,前向模式实现简单、内存占用低,在科学计算场景仍有重要地位。今天的 PyTorch、TensorFlow 等框架,已经把自动微分内化成张量的基本能力,调用一次 backward() 就能拿到全部梯度。王师傅的传感器厨房最终落地成了一整套自动化产线,手动微分那本厚厚的纸笔配方,退居为理解原理的教材。

前向复杂度:O(m)反向复杂度:O(n)\text{前向复杂度:} O(m) \qquad \text{反向复杂度:} O(n)
选型规则:输入远多于输出用反向,输出远多于输入用前向。深度学习的“百万参数 + 单个损失”,天然指向反向模式。
  1. m 次前向种子前向模式对每个输入变量播撒一次种子,所以总传播次数正比于输入数量 m。
    O(m)O(m)
  2. n 次反向种子反向模式对每个输出变量放置一个单位梯度,总传播次数正比于输出数量 n。
    O(n)O(n)
  3. 深度学习的判据当 \(m \gg n\),反向模式效率远超前向模式,这也是框架默认选择反向的原因。
    m≫n⇒反向模式m \gg n \Rightarrow \text{反向模式}

AI 应用场景

深度神经网络训练的反向传播

阶段:模型训练与优化

解决的问题:传统手动微分要人工推导损失函数对每层权重的梯度公式,网络结构一改就得重推,极易出错。自动微分把整个计算过程记录成计算图,调用 loss.backward() 即自动完成梯度计算,让“改网络结构”像改菜谱一样轻松。

具体案例:在 PyTorch 中训练一个 ResNet 图像分类模型,前向传播算损失,反向传播自动填充每个参数的 .grad 值,优化器随后更新参数。整个过程无需手写任何一个梯度公式。

机器人控制中的前向自动微分

阶段:物理仿真与最优控制

解决的问题:机器人逆动力学中,状态参数可能只有几个,但需要输出的关节力矩、速度、加速度观测值非常多。前向自动微分一次传播即可得到雅可比矩阵的一列,配合数值优化能大幅减少计算量。

具体案例:在四足机器人步态规划中,用自动微分求动力学方程的雅可比矩阵,使模型预测控制(MPC)能在 1kHz 频率下实时求解最优关节力矩。

AI编译器中的自动微分代码生成

阶段:AI编译器与系统软件优化

解决的问题:编译期自动微分把用户写好的前向计算 IR(中间表示)自动变换为梯度计算 IR,避免运行时动态构图的开销,同时能插入算子融合、内存复用等优化。

具体案例:MindSpore 和 TensorFlow XLA 等编译器在静态图上做自动微分变换,把反向算子提前生成好并融合进设备端代码,从而在推理和训练加速中获得可观的吞吐提升。

Python 演示

python57 行
# 最小前向自动微分(对偶数)演示import math  class Dual:    # value 储存函数值, deriv 储存对目标输入的导数    def __init__(self, value, deriv=0.0):        self.value = value        self.deriv = deriv     def __add__(self, other):        other = other if isinstance(other, Dual) else Dual(other)        return Dual(self.value + other.value,                    self.deriv + other.deriv)     def __sub__(self, other):        other = other if isinstance(other, Dual) else Dual(other)        return Dual(self.value - other.value,                    self.deriv - other.deriv)     def __mul__(self, other):        other = other if isinstance(other, Dual) else Dual(other)        return Dual(self.value * other.value,                    self.deriv * other.value + self.value * other.deriv)     def __truediv__(self, other):        other = other if isinstance(other, Dual) else Dual(other)        return Dual(self.value / other.value,                    (self.deriv * other.value - self.value * other.deriv)                    / (other.value ** 2))  def f(x, y):    # 例子: z = (x + y) * (x - y) = x^2 - y^2    return (x + y) * (x - y)  # 自动微分: 让 x 的种子导数为 1, y 的为 0x = Dual(3.0, 1.0)y = Dual(4.0, 0.0)z = f(x, y)print(f"自动微分结果: z={z.value}, dz/dx={z.deriv}") # 手动微分对照: z = x^2 - y^2, dz/dx = 2xprint(f"手动微分结果: dz/dx={2 * 3.0}") # 换个种子: 关注 yx = Dual(3.0, 0.0)y = Dual(4.0, 1.0)z = f(x, y)print(f"自动微分结果: dz/dy={z.deriv}")print(f"手动微分结果: dz/dy={-2 * 4.0}") # 数值微分对比eps = 1e-6num = (f(3.0 + eps, 4.0) - f(3.0 - eps, 4.0)) / (2 * eps)print(f"数值微分结果: dz/dx={num:.6f}")
目的:用 40 行代码实现前向模式自动微分,自动算出 \(z=(x+y)(x-y)\) 对 x 和 y 的导数,并与手动微分、数值微分结果对照。
  1. class Dual:定义一个“带导数”的数。每个值除了本身数值,还额外背着一个导数,像厨师手中拿着数值和影响系数两份账单。
  2. def __mul__(self, other):重载乘法运算,乘法法则对应 \(u'v + uv'\),保证自动跟随求导规则。
  3. x = Dual(3.0, 1.0)给输入播撒种子导数:想求对 x 的偏导,就把 x 的种子设为 1,其他输入设为 0。
  4. z = f(x, y)运行同一套函数代码,值和导数一路同步计算,不需要单独写梯度公式。
  5. num = (f(3.0 + eps, 4.0) - f(3.0 - eps, 4.0)) / (2 * eps)数值微分用差商近似导数,验证自动微分结果的正确性。

常见误区

误区“反正都不用我手算,自动微分应该就是程序用差分法帮我算近似斜率吧?”

正解完全不是一回事。数值微分用差商近似,天生存在截断误差和舍入误差,结果只是一个估计值。自动微分则是沿着计算图精确应用链式法则,每一步都按规则的组合展开,得到的导数和手动推导的解析结果在数学上等价,只是不产生人看的公式而已。好比一个是靠“多放一丁点盐尝味道差异”来猜,另一个是直接用传感器读精确影响系数。

为何常见:两者都通过程序完成、都免去人工推导,名称里又都有“微分”,初学者很容易把它们混为一谈。

误区“自动微分不就是让计算机像人一样做符号运算,把导数公式打印出来嘛。”

正解符号求导会产生一个全新的、可能指数级膨胀的符号表达式,比如对 \(f(g(h(x)))\) 求导会得到一长串嵌套公式。自动微分从不构造全局符号表达式,它只在前向传播时记录中间数值,在反向传播时沿边乘上局部导数,始终操作的是数值而不是符号。就像照菜谱做菜时不把整本菜谱重写成数学公式,而是每道工序只看眼前这一步的读数。

为何常见:自动微分确实在“用求导规则”,和符号求导共享链式法则,容易让人误以为背后是同一套机制。

误区“深度学习都用反向传播,那反向模式是不是在所有场景下都比前向模式好?”

正解两种模式的复杂度取决于输入和输出的维度。反向模式只需传播输出数量 n 次,前向模式需要传播输入数量 m 次。当输出数量远大于输入数量时,前向模式反而更快、更省内存。深度学习之所以选反向,是因为它恰好是“百万参数、单个损失”的结构,而不是反向模式本身有绝对优势。

为何常见:人们常把“深度学习默认方案”错误泛化成“全场景最优解”。

误区“AI 调参不靠谱,还是自己手推梯度公式最放心。”

正解手动推导在简单函数上确实可行,但一旦网络变深,链式法则展开几十层后极容易弄错符号或漏掉某一项;而且公式写好后还要手动转成代码,又多一道出错环节。自动微分不是近似或取巧,它就是把链式法则的每一步严格程序化,理论上和手推解析解等价,实践上远更可靠。

为何常见:人们信任“自己亲手算”的确定性,却低估了复杂系统中的手误率和维护成本。

误区“PyTorch 都帮你算好梯度了,我只要会调 backward() 就够了。”

正解反向模式需要存中间结果,显存可能爆炸;某些自定义算子不参与自动微分,导致梯度中断;训练中出现 NaN 梯度时常需要你手动检查计算图。这些工程问题都要求你理解自动微分的基本原理。知其然不知其所以然,遇到梯度问题时会寸步难行。

为何常见:现代框架的高度封装让“调用”变得太容易,掩藏了背后的复杂机制。

面试题

Q1. 自动微分相比数值微分最大的优势是什么?

单选题 · easy

  • A.不需要手写代码
  • B.计算速度更快
  • C.完全没有截断误差← 正确答案
  • D.只能处理简单函数

答案:C。数值微分用差商近似导数,步长 \(\varepsilon\) 选大选小都会带来误差;自动微分沿计算图精确执行链式法则,结果与解析导数等价,没有截断误差。“不需要手写代码”和“计算速度快”都不是自动微分与数值微分的关键区别。

Q2. 在计算图 \(z=(x+y)\times w\) 中,\(\partial z/\partial x\) 等于多少?

单选题 · mid

  • A.局部导数 w← 正确答案
  • B.常数一
  • C.中间结果
  • D.w 乘 u 的积

答案:A。令 \(u=x+y\),则 \(z=u\times w\)。由链式法则 \(\partial z/\partial x = (\partial z/\partial u)\cdot(\partial u/\partial x)\),其中 \(\partial z/\partial u = w\),\(\partial u/\partial x = 1\),相乘得 \(w\)。选 B 的同学漏了外层求导这一步。

Q3. 关于手动微分,下列说法正确的有哪些?

多选题 · mid

  • A.符号求导可能膨胀← 正确答案
  • B.数值微分存在误差← 正确答案
  • C.手动一定比自动快
  • D.手动求导容易出错← 正确答案

答案:ABD。符号求导会产生越来越长的表达式,即表达式膨胀;数值微分用差商近似必然有误差;复杂网络手动推导容易漏项、错符号。“手动一定比自动快”显然是错误的,网络规模大时手动推导耗时惊人。

Q4. 深度学习训练默认使用哪种自动微分模式?

单选题 · easy

  • A.前向传播模式
  • B.反向传播模式← 正确答案
  • C.符号求导模式
  • D.数值差分模式

答案:B。深度学习模型参数上千上万,损失函数通常只有一个标量输出。反向模式传播次数正比于输出数量 n=1,一次反向就能拿到所有参数梯度,因此成为默认方案。

Q5. 前向模式最适合下列哪种场景?

单选题 · mid

  • A.输入少输出较多← 正确答案
  • B.输入多输出较少
  • C.参数规模巨大
  • D.网络层数很深

答案:A。前向模式每跑一次只能求一个输入对应的方向导数,所以总开销正比于输入数量。输入少、输出多时,它比反向模式更省计算资源;深度学习的参数多、输出单一,恰恰是前向模式的劣势区。

Q6. 反向模式为什么内存开销通常更大?

单选题 · mid

  • A.网络全部权重值
  • B.前向中间结果← 正确答案
  • C.输入原始数据
  • D.输出标签信息

答案:B。反向模式必须先做前向传播并记录每个中间节点的值,反向时才能用这些值计算局部导数。网络越深,需要存储的中间张量越多,显存占用越大。这就是工程师会用“检查点”技术来减少存储的原因。

Q7. 关于链式法则在自动微分中的运用,正确的是?

多选题 · hard

  • A.单条路径求导相乘← 正确答案
  • B.多条路径求导相加← 正确答案
  • C.只用于卷积层
  • D.和反向传播无关

答案:AB。自动微分中,一条路径上各边局部导数相乘得到该路径的贡献;若一个节点有多条路径汇入,则各路径贡献相加。链式法则是所有自动微分模式的基础,不仅适用于卷积层,也和反向传播密不可分。

Q8. 损失函数只有 1 个输出、模型有 1000 万个参数,理论上反向模式与前向模式相比少跑多少次?

单选题 · mid

  • A.反向一次即可← 正确答案
  • B.两者都需要万次
  • C.前向传播次数更少
  • D.无法进行对比

答案:A。反向模式的传播次数等于输出数量,这里是 1 次;前向模式的传播次数等于输入数量,即 1000 万次。所以反向模式只需要一次反向传播就能拿到所有参数梯度,效率远超逐输入前向。

Q9. 符号微分与自动微分的本质区别是什么?

单选题 · hard

  • A.自动只存计算顺序← 正确答案
  • B.两者都会表达式膨胀
  • C.符号微分适合做框架
  • D.自动只能求一阶导数

答案:A。自动微分不生成全局符号表达式,只沿计算图保存中间数值的计算顺序;符号微分则会对整个函数做代数变换,可能产生指数级膨胀的公式。自动微分也可以求高阶导数,只是实现更复杂。

Q10. 在深度学习框架中,自动微分能自动完成哪些步骤?

多选题 · easy

  • A.前向计算← 正确答案
  • B.反向求梯度← 正确答案
  • C.数据清洗
  • D.自动修复

答案:AB。自动微分负责前向计算函数值和反向传播梯度;优化器负责更新参数,数据清洗和调试修复则需要工程师自己完成。分清这几步职责,是理解框架工作流程的关键。