Blog Edition 文本附件:保留技术内容,仅适配路径/链接与运行命令。 # 三阶求导的两种顺序 基线:HIPS/autograd 1.9.1,commit `f53a21734fdfae636f448744d9097d8d35a643a0`。对应 [Lesson 10](https://zdd14990.github.io/blog/applied-math/autograd/10-higher-order-ad/) 与既有实验 `experiments/higher_order.py`。这是对象/时序示意,R/P/B 都是教学标签。 ## 调用栈先建立 0,再建立 1、2 ```text grad(grad(grad(f)))(2.0) outer grad begins trace0, B0(value=2,node=R0) middle grad begins trace1, B1(value=B0,node=R1) inner grad begins trace2, B2(value=B1,node=R2) original f receives B2 ``` ## 从原 f 看到的包裹层次是 2 -> 1 -> 0 ```text B2 [ArrayBox, _trace=2, _node=R2] |_value v B1 [ArrayBox, _trace=1, _node=R1] |_value v B0 [ArrayBox, _trace=0, _node=R0] |_value v 2.0 [float] ``` ## primitive 递归进入与返回 ```text power(B2,3) -> select trace2 -> args=(B1,3), parents=(R2,) power(B1,3) -> select trace1 -> args=(B0,3), parents=(R1,) power(B0,3) -> select trace0 -> args=(2,3), parents=(R0,) raw power(2,3) -> 8 create P0 -> return Box0(value=8,node=P0) create P1 -> return Box1(value=Box0,node=P1) create P2 -> return Box2(value=Box1,node=P2) ``` ## 反向计算仍在外层被观察 ```text inner forward trace2 finishes -> top=1 inner VJP uses x=Box1 -> computes 3*x^2 -> derivative value12 in Box1 middle forward trace1 finishes -> top=0 middle VJP differentiates the derivative program -> value12 in Box0 outer forward trace0 finishes -> top=-1 outer VJP -> third derivative6 as an ordinary value ``` 只解最高层让每个 trace 保留自己的依赖;VJP 使用可微 primitives 让 derivative program 本身可被外层观察。两者缺一不可。实验直接验证输入 Box 层次和12/12/6;P 节点的递归示意依据当前 primitive 源码推演。