后向自动微分
阐述
在自动微分中从输出变量开始,依次计算它对各个中间变量的导数,从而逐渐推出对输入变量的导数。
考虑由 个步骤复合成的函数
对应的 Jacobian 矩阵为 。
- 前向微分计算的是
- 后向微分计划的是
后拉函数
也即对于一个输入 ,我们构造一个类似于闭包的函数 ,它作用于 来将导数向后传播一步。
如果输出是多个数,则我们需要多次不同的后向传播过程,每次的种子可以选取 ,这样就可以计算出整个 Jacobian。
类似于前向自动微分的多个种子,后向自动微分也可以一次性算多个后向传播。
后向自动微分也可以使用稀疏自动微分的技术。
实例
静态图实现
Tensorflow 要求用户使用嵌入在 Python 中的图语言来编写计算过程,这个图语言结构简单,所以很容易后向微分。但是,把已经存在的程序重写成这种图并不容易。
基于痕迹的微分,Wengert 列表
注意到构造 需要知道前向计算中 的值,而不仅仅是 。所以,在前向计算的时候需要以某种形式把 记录下来成为一个列表,也称为痕迹。
Tracker.jl, ReverseDiff.jl, PyTorch, Tensorflow Eager, Autograd, Autograd.jl 都属于这一类别。
但是这种微分有很大的冗余,因为每个实数都变成了一个需要堆分配的
mutable struct TrackedReal{T<:Real} <: Real
data::T
tracker::Tracked{T}
end
所以仅仅是一个 +
都需要至少 500 ns;另外痕迹取决于值,它不能被 JIT 编译,所以对每个新的值都需要构建一回新的 trace。
源到源微分
源到源微分的冗余比较小,因为栈分配的值可以保持在栈上,而且编译一次的函数可以用于所有值。但是源到源微分的实现非常困难。