链式法则
机器人里的函数几乎都是一层套一层:电机角度 → 关节角 → 末端位置 → 误差 → 损失。链式法则说:每一层的"放大倍数"相乘,就是整条链的放大倍数。神经网络的反向传播、机械臂速度的逐关节传递,都只是这一句话。
1为什么机器人需要它
一台机械臂的电机经过减速器带动关节,关节带动连杆,连杆末端的高度又决定任务完成得好不好。你想知道"电机多转一点点,末端高度变多少",答案不会写在任何一个零件上,而是每一级放大倍数的乘积:减速比 × 连杆几何 × 误差对高度的敏感度。
训练一个控制策略时也一样:损失依赖于动作,动作依赖于网络输出,网络输出依赖于几百万个参数。要用梯度下降调参数,就得算出"损失对每个参数的导数",这正是链式法则,从后往前反复使用。这个过程叫反向传播,是现代机器学习和可微仿真的核心。
2直觉:放大倍数相乘
2.1 节说,导数是"输入动一点点,输出动多少倍"。现在把两个函数接起来:\(u=g(x)\),\(y=f(u)\)。\(x\) 动了 \(\Delta x\),\(u\) 先动 \(g'\,\Delta x\);\(u\) 的这一点点变化再被 \(f\) 放大 \(f'\) 倍,所以 \(y\) 动了 \(f'\cdot g'\,\Delta x\)。倍数是一级一级乘上去的。
下面三条数轴依次是 \(x\)、\(u=g(x)\)、\(y=f(u)\)。细线表示"这个点被送到了哪里"。拖动 \(x_0\),看琥珀色小区间怎么被一级一级拉长或压扁。
- 找到一个位置,使整条链的放大倍数几乎为 0(某一级把区间压成了一个点)。
- 找到一个位置,第一级 \(g'\) 为正,但整条链的倍数为负(第二级把方向翻了过来)。
复合函数的导数 = 各级导数的乘积,但每一级的导数要在它自己的输入点上求:\(g'\) 在 \(x_0\) 处求,\(f'\) 在 \(u_0=g(x_0)\) 处求。这一条是最常见的出错点。
3动手玩:前向与反向
真实的程序没有"数轴",只有一连串小运算。把计算写成一张图,每个节点只做一件简单的事,那么每条边上的局部导数都很好写。前向从左往右算出各节点的值;反向从右往左,把 \(\partial L/\partial(\text{节点})\) 一级一级乘回来。下面的例子是 \(L=(\sin(x^2)-c)^2\),可以想成"一个非线性传感器读数与目标值 \(c\) 的平方误差"。
- 点"下一步",一步一步走完前向和反向。
- 调 x 和 c,让 \(\partial L/\partial x\) 几乎为 0 但 \(L\) 并不为 0(哪一级的局部导数为 0?)。
很长的链:乘积会消失,也会爆炸
链越长,乘积里的因子越多。若每一级的因子都略小于 1,乘起来就趋于 0(梯度消失);若略大于 1,就爆炸。下面把同一个小函数 \(y_i=\tanh(w\,y_{i-1})\) 连接 \(n\) 层,看输出对输入的敏感度 \(\mathrm{d}y_n/\mathrm{d}x\) 怎样随层数变化。这和深度网络难训练、长时间序列的状态对初值极其敏感,是同一个原因。
- 让 20 层以上的链敏感度小于 \(10^{-6}\)(梯度消失)。
- 找一组 w、x₀,使敏感度在前几层先增长到 10 以上,然后再塌下去。
4再看数学
提示:悬停在公式带底色的符号上,FIG 1 里对应的那一级会高亮。
链式法则
设 \(u=g(x)\),\(y=f(u)\),两者都可导,则
为什么?用 2.1 节的线性近似:\(\Delta u\approx g'(x)\Delta x\),\(\Delta y\approx f'(u)\Delta u\),代入就得 \(\Delta y\approx f'(u)\,g'(x)\,\Delta x\)。右边那个"分式相消"只是记忆口诀,\(\mathrm{d}y/\mathrm{d}u\) 并不是真的分数;真正成立的是上面这条线性近似。
多层与多元
三层就是三个因子:\(\dfrac{\mathrm{d}}{\mathrm{d}x}f(g(h(x)))=f'(g(h(x)))\cdot g'(h(x))\cdot h'(x)\)。输入输出是向量时,"倍数"变成雅可比矩阵(3.3 节),乘法变成矩阵乘法(1.4 节):
矩阵乘法不可交换,所以顺序必须与"先做哪一级"一致。
前向模式与反向模式
因子相乘满足结合律,可以从左往右乘,也可以从右往左乘,结果相同,代价却不同。设输入 \(n\) 维、输出 \(m\) 维:从输入端开始乘(前向模式)一遍只能得到对一个输入的导数,要跑 \(n\) 遍;从输出端开始乘(反向模式)一遍得到一个输出对所有输入的导数,要跑 \(m\) 遍。训练神经网络时损失是标量(\(m=1\))而参数有百万个(\(n\) 很大),所以用反向模式:一次反向传播的代价只相当于一次前向。
对计算图中的节点 \(v_i\),设它的后继节点为 \(v_j\),则 \(\bar v_i=\sum_j \bar v_j\,\dfrac{\partial v_j}{\partial v_i}\),从 \(\bar L=1\) 开始,按拓扑序倒着算。若一个节点被多条路径使用,各路径的贡献要相加。
5机器人中的它:带减速器的机械臂
一根长为 \(\ell\) 的连杆由电机经减速比 \(N\) 驱动:关节角 \(q=\theta_m/N\),末端高度 \(z=\ell\sin q\)。我们希望末端到达目标高度 \(z^\star\),损失 \(L=(z-z^\star)^2\)。用链式法则:
减速比越大,最后一个因子 \(1/N\) 越小,梯度整体变小,同样的学习率就走得很慢。拖动末端或目标线,调整减速比和学习率,点"梯度下降"看看。
- 用默认设置点"梯度下降",观察它要走很多步才靠近目标。
- 把减速比调到 40 以上,调大学习率,让下降在 200 步内把末端误差压到 0.01 以内。
不同量纲的参数(电机弧度、关节弧度、米)混在一起时,梯度大小可以差几个数量级,就像这里的 \(1/N\)。所以优化器要做尺度归一化(预条件、Adam、给关节加权),6.3 节和 6.6 节会回到这件事。机械臂速度运动学也是同一条链:关节速度 → 每个连杆 → 末端速度,雅可比就是这条链上各级矩阵的乘积(3.4 节)。
6常见误区
\((\sin x^2)'\) 是 \(\cos(x^2)\cdot 2x\),不是 \(\cos(x)\cdot 2x\)。外层的导数要在内层的输出上求。
\((\sin 3x)'=3\cos 3x\)。少乘的那个 3,在机器人里常表现为"单位忘了换":角度换成度、时间换成毫秒、经过减速比,都是内层函数,都会在导数里多出一个常数。
\(J_{f\circ g}=J_f J_g\),外层在左。检查维度是最简单的自检:\(J_g\) 是 \(p\times n\),\(J_f\) 是 \(m\times p\),乘出来才是 \(m\times n\)。
梯度是很多因子之积,只要典型因子偏离 1,乘积就是指数级的。长时程的轨迹优化和循环网络都会遇到。常见对策:缩短链(多重打靶)、归一化、残差连接、梯度裁剪。
7小练习
8延伸阅读
- 3Blue1Brown, Essence of Calculus — 第 4 章:链式法则与乘积法则的可视化
- A. Griewank & A. Walther, Evaluating Derivatives — 自动微分的前向 / 反向模式
- I. Goodfellow, Y. Bengio & A. Courville, Deep Learning, Ch. 6.5 — 反向传播与计算图
- K. Lynch & F. Park, Modern Robotics, Ch. 5 — 速度运动学与雅可比