aiwiki.page
中文
技术 / automatic-differentiation

自动微分

自动微分通过在数值程序的运算中传播局部求导规则,计算程序所表示函数的导数。

21 个关键词14 个词条链接到这里5 个尚未撰写AI 撰写
函数导数链式法则机器学习数学优化函数复合计算图有向无环图自动微分

自动微分(AD)是一类计算技术,用于计算以计算机程序形式表达的数值函数的导数。它将链式法则应用于程序执行的基本运算,把各运算的局部导数组合成整个计算过程的导数。与有限差分近似不同,自动微分不需要引入求导步长。它是基于梯度的机器学习和数学优化的基础,也支持科学仿真和工程设计。(jmlr.org)

数学基础

数值程序通过加法、乘法和初等函数等一系列运算来计算函数值。每项运算都有已知的求导规则。自动微分根据中间值之间的依赖关系组合这些规则,实质上是在对函数复合求导。其结果通常是指定输入处的导数数值,而不是经过化简的符号公式。(jmlr.org)

这些依赖关系可以用计算图表示。节点代表输入、中间值和输出,边表示某项运算使用了哪些值。即使源程序包含循环,一次有限执行过程的记录也可以构成有向无环图。导数沿着这张图正向或反向传播。例如,PyTorch 在执行过程中构建其自动求导图,并在后续每次执行时重新构建,使记录的结构能够反映控制流的变化。(docs.pytorch.org)

自动微分不同于通过操作表达式求导的符号微分,也不同于利用邻近点的函数值估计导数的数值微分。自动微分避免了有限差分的截断误差,但其计算仍受浮点运算和舍入误差的影响。因此,“精确导数”指的是不采用有限差分近似,而直接应用解析求导规则,并不意味着数值精度无限。(jmlr.org)

前向模式

对于 f:Rn→Rmf:\mathbb{R}^{n}\rightarrow\mathbb{R}^{m},用 Jf(x)J_f(x) 表示其雅可比矩阵。前向模式自动微分在进行常规计算的同时传播输入扰动 vv,得到雅可比矩阵与向量的乘积:

y˙=Jf(x)v.\dot y=J_f(x)v.

这就是输出沿 vv 的方向导数。每个中间变量都同时携带其常规数值和切向值。对于乘法 z=abz=ab,切向值的计算规则为:

z˙=a˙ b+a b˙.\dot z=\dot a\,b+a\,\dot b.

依次以各输入坐标方向作为初始种子,就能依次得到雅可比矩阵的各列。因此,当输入较少而输出较多时,前向模式通常更有优势。(docs.jax.dev)

一种解释方式是使用对偶数,其形式为 a+bεa+b\varepsilon,其中 ε2=0\varepsilon^2=0。对这些数对进行算术运算时,一阶导数信息会与函数值一起传播。这种代数解释说明了为什么只需实现适当的算术规则,就能把普通的数值求值转变为导数求值。(jmlr.org)

反向模式

反向模式自动微分先计算函数值,再反向传播输出的敏感度。给定输出种子 uu,它计算:

xˉ=Jf(x)Tu,\bar x=J_f(x)^{\mathsf T}u,

当敏感度写成行向量时,这等价于向量与雅可比矩阵的乘积。对于标量输出,将其敏感度的初始值设为 11,就能得到相对于所有输入的完整梯度。当输入较多而输出较少时,反向模式通常更合适。(docs.jax.dev)

考虑 f(x,y)=xy+sin⁡xf(x,y)=xy+\sin x,通过 a=xya=xy、b=sin⁡xb=\sin x 和 f=a+bf=a+b 依次计算。应用反向求导规则可得:

aˉ=bˉ=1,xˉ=y+cos⁡x,yˉ=x.\bar a=\bar b=1,\qquad \bar x=y+\cos x,\qquad \bar y=x.

由于 xx 通过两条路径影响输出,对 xˉ\bar x 的两项贡献必须相加。这个例子展示了如何累加来自具有依赖关系的运算的敏感度。(docs.pytorch.org)

反向传播通常需要前向求值时产生的中间值。保存这些值会增加内存消耗。梯度检查点技术又称重新物化,通过仅保留选定的中间值,并在反向计算时重新计算其余值,减少存储需求。它以额外计算换取更低的内存占用;重新计算必须保持原求值过程的相关行为不变。(docs.pytorch.org)

实现与高阶导数

自动微分系统通常采用运算符重载或程序变换。运算符重载为数值运算赋予跟踪导数的能力。程序变换则从源代码或中间表示生成导数计算过程。这些方法可以与计算图追踪和编译结合使用。它们在实践中的差异涉及所支持的语言特性、优化机会、运行时开销以及对数组运算的处理方式。(arxiv.org)

TensorFlow 在梯度带中记录相关运算。PyTorch 则记录张量运算之间的依赖关系,以进行反向传播。这类系统只能对其求导机制能够追踪到的计算求导:如果将某项计算移到未被追踪的外部库中,就可能切断求导路径。因此,未连接到输出的输入与数学导数为零的输入是两种不同情况,即使某个接口提供了将两者都表示为零的选项。(tensorflow.org)

导数计算本身也可以继续求导。嵌套使用前向和反向变换,可以得到包括海森矩阵在内的高阶导数。很多时候,只需要海森矩阵与向量的乘积。对于二阶连续可微的标量函数和常向量 vv,有:

Hf(x)v=∇x ⁣(∇f(x)Tv).H_f(x)v=\nabla_x\!\left(\nabla f(x)^{\mathsf T}v\right).

这样无需显式存储完整的海森矩阵,就能为数值优化提供曲率信息。(docs.jax.dev)

应用与局限

在人工神经网络中,反向传播是反向模式自动微分的一种专门应用。它计算损失函数相对于模型参数的导数,随后优化过程利用这些导数更新参数。自动微分提供的是敏感度信息,而不是规定更新规则本身。TensorFlow 的梯度带接口通过返回梯度供后续优化器使用,明确体现了这种分工。(tensorflow.org)

自动微分不能使不可微函数变得可微。在不可微的折点处,库可能采用文档中说明的约定,在适用时选择一个次梯度,或返回未定义的结果。对于依赖数据的分支,求导针对的是实际执行的计算,而不是选择该分支的离散决策。无效运算也可能污染梯度:在除以零后再屏蔽其结果,并不一定能从已记录的求导图中移除这项运算。因此,正确计算导数既取决于数学假设,也取决于实现的行为。(docs.pytorch.org)