自动微分、符号微分与数值微分
层级:B|建议先修:03-03、03-06、03-07、03-13
计算导数有三种常被混淆的方法:符号微分操作数学表达式,数值微分用有限差分近似,自动微分则把程序拆成基本运算并精确应用链式法则。深度学习反向传播是反向模式自动微分的特例。
1. 符号微分
符号微分根据代数规则把表达式变成新的导数表达式。例如
被转换为
优点是得到可读的闭式公式;缺点是可能发生表达式膨胀、难以处理循环和分支等一般程序结构。
2. 数值微分
前向差分:
截断误差为 。中心差分:
截断误差为 。
但 不能无限小:太大时 Taylor 截断误差大,太小时两个接近函数值相减导致舍入消去。最佳尺度常与机器精度和函数尺度有关。
3. 自动微分的核心
自动微分(AD)把计算写成基本运算序列,每个基本运算都有已知导数,然后机械应用链式法则。除浮点舍入外,它计算的是程序所定义函数的导数,不是有限差分近似。
例如
AD 沿计算图传播 、、 并组合。
4. 前向模式
前向模式同时传播原值和切向量。对输入方向 ,每个节点传播
最终得到 Jacobian–vector product(JVP):
若输入维数很小、输出维数很大,逐输入方向做前向模式较合适。
5. 对偶数直觉
前向 AD 可用对偶数表达:
代入函数并按代数规则运算:
系数自动携带方向导数。
6. 反向模式
反向模式先前向计算并记录中间值,再从标量输出反向传播伴随量
每个节点把上游梯度乘以局部导数并累加到父节点。它高效计算 vector–Jacobian product(VJP):
当输出是一个标量损失、输入是数百万参数时,一次反向传播即可得到全部参数梯度,所以机器学习主要使用反向模式。
7. 计算与内存代价
反向模式的运算时间通常是前向计算的常数倍,但需要保存中间激活供反向使用,内存可能很大。
梯度检查点用额外重算换内存:前向只保留部分节点,反向需要时重新计算中间值。
8. 动态图与静态图
- 动态图按程序实际执行路径即时构建,调试灵活;
- 静态图先捕获或编译完整计算,再做融合、内存和并行优化。
现代框架往往同时支持即时执行和编译模式。无论实现方式,AD 对实际执行的运算路径求导。
9. 分支、循环与不可导点
程序含分支时,AD 通常对本次执行的分支求导,不会对离散分支选择本身求导。循环按实际展开的运算应用链式法则。
ReLU 在 0 不可导,框架会选定一个次梯度约定,常取 0。排序、argmax、采样离散变量等运算可能没有普通梯度,需要替代松弛、估计器或其他优化方法。
10. 停止梯度与原地修改
stop_gradient/detach 让某个值参与前向计算但不让梯度穿过。它会改变优化目标的导数语义,应有明确理由。
原地修改可能覆盖反向传播需要的中间值或破坏版本追踪,框架常直接报错。写自定义算子时要保存正确上下文。
11. 高阶导数
对梯度再次使用 AD 可计算 Hessian 或 Hessian–vector product(HVP)。完整 Hessian 需要 存储,而 HVP 可在接近若干次梯度计算的代价下得到
适用于 Newton-CG、曲率分析和隐式求导。
12. 复数步微分
对解析函数,可用
避免实数差分的相减消去,允许很小的 。但它要求实现支持复数且函数路径保持解析,不适用于含绝对值、分支等一般情形。
13. 梯度检查
即便使用 AD,自定义算子和损失仍可能写错。可在小模型、float64、远离不可导点的位置,用中心差分检查:
是否足够小。随机抽查若干方向的方向导数比逐参数检查更省成本。
14. 三者比较
| 方法 | 结果 | 适用场景 | 主要局限 |
|---|---|---|---|
| 符号微分 | 解析表达式 | 公式推导、简化 | 表达式膨胀、程序控制流困难 |
| 数值微分 | 近似值 | 验证、小维黑盒 | 误差折中、维数成本高 |
| 自动微分 | 链式法则下的浮点导数 | 大规模可微程序 | 内存、不可导运算、自定义规则 |
15. 易错点
- 自动微分不是符号化简,也不是有限差分。
- 梯度为 0 可能来自模型饱和、detach 或不可导约定,不一定是 AD 出错。
- 对随机采样路径直接反传需要可重参数化或合适梯度估计器。
- 数值梯度检查在 float32、小步长或不可导点附近可能误报。
常见问答
Q1:为什么反向传播一次能求所有参数梯度?
标量损失对每个中间节点只有一个伴随量;反向按图累积它对所有父节点的贡献,共享子计算不会被为每个参数重复展开。
Q2:AD 的梯度是“精确”的吗?
它精确执行链式法则,但仍受浮点舍入影响,且只对程序实际定义和执行的函数求导。
Q3:什么时候前向模式更好?
输入方向很少、输出很多,或只需要 JVP 时;反向模式适合多输入、标量输出。
Q4:为什么梯度检查要用 float64?
有限差分需要在截断误差与舍入误差之间取小步长,更高精度扩大了可用区间。
练习
- 对 写出计算图及反向链式导数。
- 比较前向差分与中心差分的截断误差阶。
- 说明标量损失、大量参数时反向模式更高效的原因。
- 为什么 argmax 通常不能直接用于梯度训练?
答案与提示
- 依次令 ,导数为 。
- 分别为 与 。
- 反向一次得到输出对所有输入的 VJP;前向模式通常需对每个输入方向传播一次。
- argmax 的输出在大多数区域对输入保持常数,边界处不连续,普通梯度几乎处处为 0 或不存在。