Numerical Optimization Ch8. Calculating Derivatives

第八章: 优化中的导数计算


大多非线性优化和求解非线性方程的算法都需要导数的信息, 从而在计算过程中更加充分地考虑问题的性态、掌握更多关于问题的信息, 以获得较快的收敛性. 手算导数有时是可行的, 当然更加方便的做法是写一串代码让计算机帮我们算. 但在其他情形下, 函数会过于复杂, 手算显然不可取. 这时我们只能寻求自动计算或 近似计算导数的方法. 以下是较为常用的一些方法:

  1. 有限差分法. 这一方法根植于Taylor定理. 通过观察在给定点 x x x处基于微小扰动函数值的变动, 我们可以估计函数对于无穷小"扰动"的变化速率, 也就是导数. 例如光滑函数 f : R n → R f:\mathbb{R}^n\to\mathbb{R} f:RnR对于自变量 x x x的第 i i i个分量 x i x_i xi的偏导数就可以用如下中心差分公式近似计算: ∂ f ∂ x i ≈ f ( x + ϵ e i ) − f ( x − ϵ e i ) 2 ϵ , \frac{\partial f}{\partial x_i}\approx\frac{f(x+\epsilon e_i)-f(x-\epsilon e_i)}{2\epsilon}, xif2ϵf(x+ϵei)f(xϵei),其中 ϵ \epsilon ϵ为一较小的正标量, e i e_i ei为第 i i i单位向量. 利用Taylor定理, 易得这一公式计算的误差在 O ( ϵ 2 ) O(\epsilon^2) O(ϵ2).
  2. 自动微分法. 这一方法则来源于计算机计算函数值的机理. 一般地, 计算机代码计算函数值的过程可以分解为一系列基本运算, 其中我们可以应用微积分中的链式法则. 一些软件具有计算函数值和导数值的功能. 而另一些软件则是记录计算函数在一点 x x x处函数值所进行的一系列基本运算, 最后再用这些信息计算同一个点 x x x处的导数值.
  3. 符号微分法. 这一方法中, 计算机将使用符号运算的工具对函数 f f f代数表示进行操作, 从而产生对于每个分量导数的新的代数表示.

本章中, 我们主要讨论前两种方法——有限差分法与自动微分法.
导数的作用不仅仅在优化上. 设计优化与经济领域也经常涉及后验最佳灵敏度分析(post-optimal sensitivity analysis), 其中我们需要最优值(或最优点)对于参数或约束中微小扰动的敏感度. 导数也在非线性微分方程和模拟中发挥着重要作用.

1. 有限差分

有限差分法是一种近似计算导数的方法, 其根植于Taylor定理. 许多软件包不论用户是否能够或乐意提供计算精确导数的方法或代码, 都会自动实施有限差分. 尽管这一方法只能提供导数的近似值, 但在许多情形下得到的结果都较为令人满意.
由定义, 导数实际就是对函数对于变量上微小扰动敏感度的一种度量. 本节我们采用的方法就是在 x x x的取值上加入一些微小的、有限的扰动, 再观察相应函数值的变化. 最终导数在一点处的近似值将由后者与前者的比值得到.

1.1 近似梯度

一种近似梯度向量 ∇ f ( x ) \nabla f(x) f(x)的方法是, 计算 f f f ( n + 1 ) (n+1) (n+1)个点处的值, 之后进行一些基本的运算. 下面我们将介绍这种方法, 同时介绍其基于更多函数值的一种改进方案.

一种广泛使用的近似偏导 ∂ f / ∂ x i \partial f/\partial x_i f/xi x x x处取值的方法是前向差分法(或单边差分法), 定义为 ∂ f ∂ x i ( x ) ≈ f ( x + ϵ e i ) − f ( x ) ϵ . \frac{\partial f}{\partial x_i}(x)\approx\frac{f(x+\epsilon e_i)-f(x)}{\epsilon}. xif(x)ϵf(x+ϵei)f(x).而梯度就可以通过 i i i遍历 1 , … , n 1,\ldots,n 1,,n来获取. 这一过程总共需要 ( n + 1 ) (n+1) (n+1)个函数值: f ( x ) , f ( x + ϵ e 1 ) , … , f ( x + ϵ e n ) f(x),f(x+\epsilon e_1),\ldots,f(x+\epsilon e_n) f(x),f(x+ϵe1),,f(x+ϵen).
上述方法来源于Taylor定理: 当 f f f二次连续可微, 我们有 f ( x + p ) = f ( x ) + ∇ f ( x ) T p + 1 2 p T ∇ 2 f ( x + t p ) p , t ∈ ( 0 , 1 ) . f(x+p)=f(x)+\nabla f(x)^Tp+\frac{1}{2}p^T\nabla^2f(x+tp)p,\quad t\in(0,1). f(x+p)=f(x)+f(x)Tp+21pT2f(x+tp)p,t(0,1).若取 L L L为在 x x x附近 ∥ ∇ 2 f ( ⋅ ) ∥ \Vert\nabla^2f(\cdot)\Vert 2f()的上界, 则有 ∣ f ( x + p ) − f ( x ) − ∇ f ( x ) T p ∣ ≤ 1 2 L ∥ p ∥ 2 . | f(x+p)-f(x)-\nabla f(x)^Tp|\le\frac{1}{2}L\Vert p\Vert^2. f(x+p)f(x)f(x)Tp21Lp2.选取 p p p ϵ e i \epsilon e_i ϵei, 从而 ∇ f ( x ) T p = ϵ ∇ f ( x ) T e i = ϵ ∂ f / ∂ x i . \nabla f(x)^Tp=\epsilon\nabla f(x)^Te_i=\epsilon\partial f/\partial x_i. f(x)Tp=ϵf(x)Tei=ϵf/xi. 代入可得 ∣ ∂ f ∂ x i − f ( x + ϵ e i ) − f ( x ) ϵ ∣ ≤ δ ϵ = 1 2 L ϵ . \left|\frac{\partial f}{\partial x_i}-\frac{f(x+\epsilon e_i)-f(x)}{\epsilon}\right|\le\delta_{\epsilon}=\frac{1}{2}L\epsilon. xifϵf(x+ϵei)f(x)δϵ=21Lϵ.若忽略 δ ϵ \delta_{\epsilon} δϵ就有前向差分公式, 而这一误差会随着 ϵ → 0 \epsilon\to0 ϵ0而趋于0.

前向差分公式应用时需要重点考量的一个方面就是参数 ϵ \epsilon ϵ的选取. 仅从误差 δ ϵ \delta_{\epsilon} δϵ上看我们应当将 ϵ \epsilon ϵ取得越小越好, 但这样就忽略了计算机进行浮点运算时产生的舍入误差. 机器精度 u \mathrm{u} u是计算机对两个浮点数进行单次运算时产生的相对误差的上界. 在双精度IEEE浮点运算下 u ≈ 1.1 × 1 0 − 16 \mathrm{u}\approx1.1\times10^{-16} u1.1×1016. 这些误差最终将如何影响计算的函数值将取决于 f f f的计算方式, 例如一个运算公式、一个微分方程的求解器.
下面仅做粗略估计. 假设计算的 f f f的相对误差以 u \mathrm{u} u为上界, 从而 f ( x ) f(x) f(x) f ( x + ϵ e i ) f(x+\epsilon e_i) f(x+ϵei)的计算值与精确值具有如下关联: ∣ f ^ ( x ) − f ( x ) ∣ ≤ u L f , ∣ f ^ ( x + ϵ e i ) − f ( x + ϵ e i ) ∣ ≤ u L f , \begin{aligned}|\hat{f}(x)-f(x)|&\le\mathrm{u} L_f,\\|\hat{f}(x+\epsilon e_i)-f(x+\epsilon e_i)|&\le\mathrm{u} L_f,\end{aligned} f^(x)f(x)f^(x+ϵei)f(x+ϵei)uLf,uLf,其中 f ^ ( ⋅ ) \hat{f}(\cdot) f^()表示计算值, L f L_f Lf ∣ f ( ⋅ ) ∣ |f(\cdot)| f() x x x附近的上界. 如果以计算值代入偏导数的计算, 则之前式子的误差将以 ( L / 2 ) ϵ + 2 u L f / ϵ (L/2)\epsilon+2\mathrm{u}L_f/\epsilon (L/2)ϵ+2uLf/ϵ为上界. 自然地, 我们希望选取 ϵ \epsilon ϵ使得这一误差尽可能小. 易得这一对勾型函数的最小点为 ϵ 2 = 4 L f u L ( 而 不 是 越 小 越 好 ) . \epsilon^2=\frac{4L_f\mathrm{u}}{L}(而不是越小越好). ϵ2=L4Lfu().若我们还假设问题是尺度良好的, 则 L f / L L_f/L Lf/L就可以用一个不太大的数控制. 因此我们可以取 ϵ = u ( 事 实 上 许 多 优 化 软 件 包 均 取 ϵ 为 此 值 计 算 有 限 差 分 ) . \epsilon=\sqrt{\mathrm{u}}(事实上许多优化软件包均取\epsilon为此值计算有限差分). ϵ=u (ϵ).此时, 前向差分近似的误差有上界(约为) u \sqrt{\mathrm{u}} u .

还有另外一种更加精确的近似方式——中心差分公式, 定义为 ∂ f ∂ x i ( x ) ≈ f ( x + ϵ e i ) − f ( x − ϵ e i ) 2 ϵ . \frac{\partial f}{\partial x_i}(x)\approx\frac{f(x+\epsilon e_i)-f(x-\epsilon e_i)}{2\epsilon}. xif(x)2ϵf(x+ϵei)f(xϵei).除去精度的优势不谈, 这种计算方式要比前向差分昂贵: 我们需要计算 f f f ( 2 n + 1 ) (2n+1) (2n+1)个点处的值. 下面我们利用Taylor定理说明其精度上的优点. 当 f f f的二阶导存在且是Lipshcitz连续时, 我们有 f ( x + p ) = f ( x ) + ∇ f ( x ) T p + 1 2 p T ∇ 2 f ( x + t p ) p t ∈ ( 0 , 1 ) = f ( x ) + ∇ f ( x ) T p + 1 2 p T ∇ 2 f ( x ) p + O ( ∥ p ∥ 3 ) . \begin{aligned}f(x+p)&=f(x)+\nabla f(x)^Tp+\frac{1}{2}p^T\nabla^2f(x+tp)p\quad t\in(0,1)\\&=f(x)+\nabla f(x)^Tp+\frac{1}{2}p^T\nabla^2f(x)p+O(\Vert p\Vert^3).\end{aligned} f(x+p)=f(x)+f(x)Tp+21pT2f(x+tp)pt(0,1)=f(x)+f(x)Tp+21pT2f(x)p+O(p3).分别令 p = ϵ e i , − ϵ e i p=\epsilon e_i, -\epsilon e_i p=ϵei,ϵei, 则有 f ( x + ϵ e i ) = f ( x ) + ϵ ∂ f ∂ x i + 1 2 ϵ 2 ∂ 2 f ∂ x i 2 + O ( ϵ 3 ) , f(x+\epsilon e_i)=f(x)+\epsilon\frac{\partial f}{\partial x_i}+\frac{1}{2}\epsilon^2\frac{\partial^2f}{\partial x_i^2}+O(\epsilon^3), f(x+ϵei)=f(x)+ϵxif+21ϵ2xi22f+O(ϵ3), f ( x − ϵ e i ) = f ( x ) − ϵ ∂ f ∂ x i + 1 2 ϵ 2 ∂ 2 f ∂ x i 2 + O ( ϵ 3 ) . f(x-\epsilon e_i)=f(x)-\epsilon\frac{\partial f}{\partial x_i}+\frac{1}{2}\epsilon^2\frac{\partial^2f}{\partial x_i^2}+O(\epsilon^3). f(xϵei)=f(x)ϵxif+21ϵ2xi22f+O(ϵ3).两式相加消去 ϵ \epsilon ϵ的一次项, 整理后可得 ∂ f ∂ x i ( x ) = f ( x + ϵ e i ) − f ( x − ϵ e i ) 2 ϵ + O ( ϵ 2 ) . \frac{\partial f}{\partial x_i}(x)=\frac{f(x+\epsilon e_i)-f(x-\epsilon e_i)}{2\epsilon}+O(\epsilon^2). xif(x)=2ϵf(x+ϵei)f(xϵei)+O(ϵ2).我们看到这一表达式的误差在 O ( ϵ 2 ) O(\epsilon^2) O(ϵ2), 与前向差分的 O ( ϵ ) O(\epsilon) O(ϵ)具有很大的提升. 不过将计算 f f f时的误差纳入考虑后, 类似地有最优的 ϵ \epsilon ϵ u 1 / 3 \mathrm{u}^{1/3} u1/3, 此时误差大约为 u 2 / 3 \mathrm{u}^{2/3} u2/3, 精度改进就不是那么明显了. 不过在某些情形下, 我们能够在计算值获取上更多精确的位数. 此时多余的耗费就变得相当有意义.

1.2 近似Jacobi矩阵

考虑向量值函数 r : R n → R m r:\mathbb{R}^n\to\mathbb{R}^m r:RnRm, 例如我们将在下一章考察的残差向量或者将在第十一章讨论的非线性方程组. 这一向量值函数的一阶导数Jacobi矩阵 J ( x ) J(x) J(x)定义为 J ( x ) = [ ∂ r j ∂ x i ] j = 1 , 2 , … , m , i = 1 , 2 , … , n = [ ∇ r 1 ( x ) T ∇ r 2 ( x ) T ⋮ ∇ r m ( x ) T ] m × n , J(x)=\left[\frac{\partial r_j}{\partial x_i}\right]_{j=1,2,\ldots,m,i=1,2,\ldots,n}=\begin{bmatrix}\nabla r_1(x)^T\\\nabla r_2(x)^T\\\vdots\\\nabla r_m(x)^T\end{bmatrix}_{m\times n}, J(x)=[xirj]j=1,2,,m,i=1,2,,n=r1(x)Tr2(x)Trm(x)Tm×n,其中 r j , j = 1 , 2 , … , m r_j,j=1,2,\ldots,m rj,j=1,2,,m r r r的分量.

  1. Jacobi的某一列: 前一小节中介绍的方法自然可以直接(一次)用来计算 J ( x ) J(x) J(x)的一列. 当 r r r二次连续可微时, 我们可用Taylor定理得到 ∥ r ( x + p ) − r ( x ) − J ( x ) p ∥ ≤ ( L / 2 ) ∥ p ∥ 2 , \Vert r(x+p)-r(x)-J(x)p\Vert\le(L/2)\Vert p\Vert^2, r(x+p)r(x)J(x)p(L/2)p2,其中 L L L J J J x x x附近的Lipschitz常数.

  2. Jacobi-向量乘积: 若我们需要获取Jacobi矩阵与某一给定向量 p p p的乘积 J ( x ) p J(x)p J(x)p(这在十一章使用非精确牛顿法求解非线性方程时会提到), 上述不等式立刻就给出了一种近似计算的方法: J ( x ) p ≈ r ( x + ϵ p ) − r ( x ) ϵ , J(x)p\approx\frac{r(x+\epsilon p)-r(x)}{\epsilon}, J(x)pϵr(x+ϵp)r(x),其中误差在 O ( ϵ ) O(\epsilon) O(ϵ). 类似地也有中心型的近似公式.

  3. 完整Jacobi: 若得寸进尺, 需要求得完整的Jacobi矩阵 J ( x ) J(x) J(x), 我们可以通过一次计算一列的方式得到. 其中第 i i i列的计算方法为: 令 p = ϵ e i p=\epsilon e_i p=ϵei, ∂ r ∂ x i ( x ) ≈ r ( x + ϵ e i ) − r ( x ) ϵ . \frac{\partial r}{\partial x_i}(x)\approx\frac{r(x+\epsilon e_i)-r(x)}{\epsilon}. xir(x)ϵr(x+ϵei)r(x).从上面公式可知, 要得到完整的Jacobi矩阵估计, 需要求 n + 1 n+1 n+1次向量函数值 r r r. 不过当Jacobi矩阵稀疏时, 我们通常可以小得多的代价(有时甚至只需求3-4次向量函数值)得到类似的结果. 这种方法操作的关键在于, 同时估计Jacobi矩阵的多个不同列. 当然这需要对 p p p的选择加以斟酌.
    我们以一个简单的例子介绍这一方法. 考虑向量值函数 r : R n → R n r:\mathbb{R}^n\to\mathbb{R}^n r:RnRn, 定义为 r ( x ) = [ 2 ( x 2 3 − x 1 2 ) 3 ( x 2 3 − x 1 2 ) + 2 ( x 3 3 − x 2 2 ) 3 ( x 3 3 − x 2 2 ) + 2 ( x 4 3 − x 3 2 ) ⋮ 3 ( x n 3 − x n − 1 2 ) ] . r(x)=\begin{bmatrix}2(x_2^3-x_1^2)\\3(x_2^3-x_1^2)+2(x_3^3-x_2^2)\\3(x_3^3-x_2^2)+2(x_4^3-x_3^2)\\\vdots\\3(x_n^3-x_{n-1}^2)\end{bmatrix}. r(x)=2(x23x12)3(x23x12)+2(x33x22)3(x33x22)+2(x43x32)3(xn3xn12).注意到 r r r的每个分量均只依赖于2-3个 x x x的分量, 从而可知Jacobi矩阵的每行也仅包含2-3个非零元素. 对于 n = 6 n=6 n=6的情形, Jacobi矩阵就具有如下的三对角结构: [ × × × × × × × × × × × × × × × × ] . \begin{bmatrix}\times & \times & & & &\\\times & \times & \times & & &\\ & \times & \times & \times & & & \\ & & \times & \times & \times &\\ & & & \times & \times & \times\\ & & & & \times & \times \end{bmatrix}. ××××××××××××××××.现在我们要计算Jacobi的近似. 我们做一个比较.

    • 首先使用原来的"笨办法". 对 x x x的第一个分量作扰动 p = ϵ e 1 p=\epsilon e_1 p=ϵe1将只能影响 r r r的第1和第2分量, 而其余分量将保持不变. 从而计算出的 ∂ r ∂ x 1 \frac{\partial r}{\partial x_1} x1r在第3,4,5,6分量上都是0. 如果我们提前已经知道了这些分量是什么, 再去重复计算显然是不应该的.
    • 再使用"新方法". 相比于 ϵ e 1 \epsilon e_1 ϵe1这样的只能改变2个分量的扰动向量, 我们更想要寻求能够影响后4个分量的扰动向量. 这将成为我们同时扰动多列方法的基础. 在这个例子中不难看出 ϵ e 4 \epsilon e_4 ϵe4就(差不多)具有这样的性质: 它会改变 r r r中第3,4,5分量的值, 但会保持第1,2分量的值不变. 进一步地, 我们可以说 ϵ e 1 \epsilon e_1 ϵe1 ϵ e 4 \epsilon e_4 ϵe4带来的扰动是互补影响的.
      为严格地进行数学推导, 我们令 p = ϵ ( e 1 + e 4 ) p=\epsilon(e_1+e_4) p=ϵ(e1+e4)并注意到 r ( x + p ) 1 , 2 = r ( x + ϵ ( e 1 + e 4 ) ) 1 , 2 = r ( x + ϵ e 1 ) 1 , 2 , r(x+p)_{1,2}=r(x+\epsilon(e_1+e_4))_{1,2}=r(x+\epsilon e_1)_{1,2}, r(x+p)1,2=r(x+ϵ(e1+e4))1,2=r(x+ϵe1)1,2, r ( x + p ) 3 , 4 , 5 = r ( x + ϵ ( e 1 + e 4 ) ) 3 , 4 , 5 = r ( x + ϵ e 4 ) 3 , 4 , 5 . r(x+p)_{3,4,5}=r(x+\epsilon(e_1+e_4))_{3,4,5}=r(x+\epsilon e_4)_{3,4,5}. r(x+p)3,4,5=r(x+ϵ(e1+e4))3,4,5=r(x+ϵe4)3,4,5.代入可得 r ( x + p ) 1 , 2 = r ( x ) 1 , 2 + ϵ [ J ( x ) e 1 ] 1 , 2 + O ( ϵ 2 ) . r(x+p)_{1,2}=r(x)_{1,2}+\epsilon[J(x)e_1]_{1,2}+O(\epsilon^2). r(x+p)1,2=r(x)1,2+ϵ[J(x)e1]1,2+O(ϵ2).重新整理式子, 我们就可计算Jacobi矩阵的(1,1)元和(2,1)元: [ ∂ r 1 ∂ x 1 ( x ) ∂ r 2 ∂ x 1 ( x ) ] = [ J ( x ) e 1 ] 1 , 2 ≈ r ( x + p ) 1 , 2 − r ( x ) 1 , 2 ϵ . \begin{bmatrix}\frac{\partial r_1}{\partial x_1}(x)\\\frac{\partial r_2}{\partial x_1}(x)\end{bmatrix}=[J(x)e_1]_{1,2}\approx\frac{r(x+p)_{1,2}-r(x)_{1,2}}{\epsilon}. [x1r1(x)x1r2(x)]=[J(x)e1]1,2ϵr(x+p)1,2r(x)1,2.类似地, [ ∂ r 3 ∂ x 4 ( x ) ∂ r 4 ∂ x 4 ( x ) ∂ r 5 ∂ x 4 ( x ) ] = [ J ( x ) e 4 ] 3 , 4 , 5 ≈ r ( x + p ) 3 , 4 , 5 − r ( x ) 3 , 4 , 5 ϵ . \begin{bmatrix}\frac{\partial r_3}{\partial x_4}(x)\\\frac{\partial r_4}{\partial x_4}(x)\\\frac{\partial r_5}{\partial x_4}(x)\end{bmatrix}=[J(x)e_4]_{3,4,5}\approx\frac{r(x+p)_{3,4,5}-r(x)_{3,4,5}}{\epsilon}. x4r3(x)x4r4(x)x4r5(x)=[J(x)e4]3,4,5ϵr(x+p)3,4,5r(x)3,4,5.这就是说, 我们可通过只扰动一次、只计算一次函数值 r ( x + ϵ ( e 1 + e 4 ) ) r(x+\epsilon(e_1+e_4)) r(x+ϵ(e1+e4))便可同时得到Jacobi矩阵两列的估计.

    我们也可以经济地估计 J ( x ) J(x) J(x)剩下的几列. 比如第2,5列就可通过设置 p = ϵ ( e 2 + e 5 ) p=\epsilon(e_2+e_5) p=ϵ(e2+e5)同时得到, 第3,6列可通过设置 p = ϵ ( e 3 + e 6 ) p=\epsilon(e_3+e_6) p=ϵ(e3+e6)同时得到. 总之, 我们仅需计算3次函数值.
    事实上, 对于上述例子的任意 n n n的情形, 计算3次函数值都足够估计整个Jacobi了. 对应的扰动向量 p p p p = ϵ ( e 1 + e 4 + e 7 + e 10 + ⋯   ) , p = ϵ ( e 2 + e 5 + e 8 + e 11 + ⋯   ) , p = ϵ ( e 3 + e 6 + e 9 + e 12 + ⋯   ) . p=\epsilon(e_1+e_4+e_7+e_{10}+\cdots),\\p=\epsilon(e_2+e_5+e_8+e_{11}+\cdots),\\p=\epsilon(e_3+e_6+e_9+e_{12}+\cdots). p=ϵ(e1+e4+e7+e10+),p=ϵ(e2+e5+e8+e11+),p=ϵ(e3+e6+e9+e12+).这种设置扰动向量的方式也可启发其他向量值函数的情形.
    事实上, 选取扰动向量的算法可以用图和图着色的语言简洁的表示出来. 瑞昱任一向量值函数 r : R n → R m r:\mathbb{R}^n\to\mathbb{R}^m r:RnRm, 我们可建立有 n n n个顶点的列关联图 G G G, 其中若 r r r有分量同时依赖于 x i , x k x_i,x_k xi,xk(即 J ( x ) J(x) J(x)的第 i , k i,k i,k列均在某个第 j j j行有非零元), 对应地在 G G G中节点 i , k i,k i,k之间就有边连接. 前面的 n = 6 n=6 n=6的例子对应的列关联图如下所示.
    列关联图

    下面以某种规则对 G G G进行着色, 规则: 任意两相邻接的顶点颜色不同. 最终我们将根据颜色选取扰动向量: 若节点 i 1 , i 2 , … , i l i_1,i_2,\ldots,i_l i1,i2,,il有相同的颜色, 则就有扰动向量 p = ϵ ( e i 1 + e i 2 + ⋯ + e i l ) p=\epsilon(e_{i_1}+e_{i_2}+\cdots+e_{i_l}) p=ϵ(ei1+ei2++eil).
    一般地, 满足上述规则的图着色方案不止一种. 最简单的方式就是对每个节点均赋以不同的颜色, 不过这样就对应了 n n n个扰动向量, 这样的效率也是最低的. 找寻一个图所需的最少着色数是一个NP-完全问题1, 不过我们可以使用低成本的算法求得近似最优的解. Newsam和Ramsdell2表示通过考虑更广泛的一类扰动向量, 我们甚至可能仅用不超过 n z n_z nz个函数值便可得到完整Jacobi矩阵的近似. 这里 n z n_z nz J ( x ) J(x) J(x)中最大的行非零元个数.
    对于一些具有良好结构(已经被深入研究了)的Jacobi矩阵(大量可见于微分算子的离散或能够得到带型Jacobi的情形), 最优的着色方案是已知的. 例如对于上图中的三对角结构, 3种颜色的方案就是最佳方案.

1.3 近似Hessian矩阵

有时, 我们可能可以计算梯度 ∇ f ( x ) \nabla f(x) f(x)而不能计算Hessian矩阵 ∇ 2 f ( x ) \nabla^2f(x) 2f(x). 我们当然可以通过上面介绍的方法计算(将 r r r换成 ∇ f \nabla f f). 通过图着色, 我们可以以极小的代价近似稀疏的Hessian. 然而这些做法都忽略了Hessian矩阵对称性的特征, 且这一忽略可能最终导致算得的Hessian并不对称. 我们当然可以通过加转置除2的方式获取Hermite部分. 但这种方式所带来的影响难以估计. 下面我们介绍一种将 ∇ 2 f ( x ) \nabla^2f(x) 2f(x)的对称性纳入考量的差分法.

  1. Hessian-向量乘积: 一些重要的算法——比如第七章描述的Newton-CG算法——并不需要完整的Hessian矩阵, 而仅需要我们提供矩阵-向量乘积 ∇ 2 f ( x ) p , ∀ p \nabla^2f(x)p,\forall p 2f(x)p,p. 我们可以用Taylor定理再一次地估计这一乘积: 当 f f f的二阶导数存在且在 x x x附近Lipschitz连续时, 我们有 ∇ f ( x + ϵ p ) = ∇ f ( x ) + ϵ ∇ 2 f ( x ) p + O ( ϵ 2 ) , \nabla f(x+\epsilon p)=\nabla f(x)+\epsilon\nabla^2f(x)p+O(\epsilon^2), f(x+ϵp)=f(x)+ϵ2f(x)p+O(ϵ2),从而 ∇ 2 f ( x ) p ≈ ∇ f ( x + ϵ p ) − ∇ f ( x ) ϵ . \nabla^2f(x)p\approx\frac{\nabla f(x+\epsilon p)-\nabla f(x)}{\epsilon}. 2f(x)pϵf(x+ϵp)f(x).这一表达式的误差在 O ( ϵ ) O(\epsilon) O(ϵ), 此时额外的代价是计算在 x + ϵ p x+\epsilon p x+ϵp处的梯度. 上面这一公式对应之前的前向差分法. 自然若计算 ∇ f ( x − ϵ p ) \nabla f(x-\epsilon p) f(xϵp)我们也有中心差分法.
  2. 完整Hessian: 当梯度都无法计算时, 我们只能只用函数值来近似Hessian矩阵的元素. 此时依然要用到Taylor定理. 此时令 p = ϵ e i , ϵ e j , ϵ ( e i + e j ) p=\epsilon e_i,\epsilon e_j,\epsilon(e_i+e_j) p=ϵei,ϵej,ϵ(ei+ej), 则 f ( x + ϵ e i ) = f ( x ) + ϵ ∇ f ( x ) T e i + ϵ 2 1 2 e i T ∇ 2 f ( x ) e i + O ( ϵ 3 ) , f ( x + ϵ e j ) = f ( x ) + ϵ ∇ f ( x ) T e j + ϵ 2 1 2 e j T ∇ 2 f ( x ) e j + O ( ϵ 3 ) , f ( x + ϵ ( e i + e j ) ) = f ( x ) + ϵ ∇ f ( x ) T ( e i + e j ) + ϵ 2 1 2 ( e i + e j ) T ∇ 2 f ( x ) ( e i + e j ) + O ( ϵ 3 ) . f(x+\epsilon e_i)=f(x)+\epsilon\nabla f(x)^Te_i+\epsilon^2\frac{1}{2}e_i^T\nabla^2f(x)e_i+O(\epsilon^3),\\f(x+\epsilon e_j)=f(x)+\epsilon\nabla f(x)^Te_j+\epsilon^2\frac{1}{2}e_j^T\nabla^2f(x)e_j+O(\epsilon^3),\\f(x+\epsilon(e_i+e_j))=f(x)+\epsilon\nabla f(x)^T(e_i+e_j)+\epsilon^2\frac{1}{2}(e_i+e_j)^T\nabla^2f(x)(e_i+e_j)+O(\epsilon^3). f(x+ϵei)=f(x)+ϵf(x)Tei+ϵ221eiT2f(x)ei+O(ϵ3),f(x+ϵej)=f(x)+ϵf(x)Tej+ϵ221ejT2f(x)ej+O(ϵ3),f(x+ϵ(ei+ej))=f(x)+ϵf(x)T(ei+ej)+ϵ221(ei+ej)T2f(x)(ei+ej)+O(ϵ3).从而经整理可得 ∂ 2 f ∂ x i ∂ x j ( x ) = f ( x + ϵ ( e i + e j ) ) − f ( x + ϵ e i ) − f ( x + ϵ e j ) + f ( x ) ϵ 2 + O ( ϵ ) . \frac{\partial^2f}{\partial x_i\partial x_j}(x)=\frac{f(x+\epsilon(e_i+e_j))-f(x+\epsilon e_i)-f(x+\epsilon e_j)+f(x)}{\epsilon^2}+O(\epsilon). xixj2f(x)=ϵ2f(x+ϵ(ei+ej))f(x+ϵei)f(x+ϵej)+f(x)+O(ϵ).若我们想用这个公式近似Hessian的每一个元素, 我们就需要计算 f f f x + ϵ ( e i + e j ) , ∀ i , j x+\epsilon(e_i+e_j),\forall i,j x+ϵ(ei+ej),i,j处的取值(至多 n ( n + 1 ) / 2 n(n+1)/2 n(n+1)/2个不同取值), 以及另外 n n n个点 x + ϵ e i , i = 1 , 2 , … , n x+\epsilon e_i,i=1,2,\ldots,n x+ϵei,i=1,2,,n处的值. 如果Hessian稀疏, 且我们知道哪些元素是零的话, 当然这一步就可以跳掉.

1.4 近似稀疏Hessian矩阵

之前我们提到, 可以对 ∇ f \nabla f f进行差分以得到Hessian的近似. 下面我们介绍如何在Hessian稀疏时,利用Hessian的对称性来减少获取完整近似所需的扰动向量 p p p的个数. 关键的一点就是, 对于 [ ∇ 2 f ( x ) ] i , j [\nabla^2f(x)]_{i,j} [2f(x)]i,j的估计同样也是对 [ ∇ 2 f ( x ) ] j , i [\nabla^2f(x)]_{j,i} [2f(x)]j,i的估计.
我们以一个简单函数 f : R n → R f:\mathbb{R}^n\to\mathbb{R} f:RnR说明, 其定义为 f ( x ) = x 1 ∑ i = 1 n i 2 x i 2 . f(x)=x_1\sum_{i=1}^ni^2x_i^2. f(x)=x1i=1ni2xi2.利用微积分, 我们知道 ∇ 2 f \nabla^2f 2f具有"爪型"结构, 以 n = 6 n=6 n=6为例: [ × × × × × × × × × × × × × × × × ] . \begin{bmatrix}\times & \times & \times & \times & \times & \times\\\times & \times & & & &\\\times & & \times & & &\\\times & & & \times & &\\\times & & & & \times &\\\times & & & & &\times\end{bmatrix}. ××××××××××××××××.若建立对 ∇ f \nabla f f的列关联图, 则我们会发现图中每两个节点都是相邻接的, 这是因为 ∇ 2 f \nabla^2f 2f的第一行无0元. 由图着色的规则, 我们就需要给不同的节点赋不同的颜色, 即需要计算 ∇ f \nabla f f n + 1 n+1 n+1个点处的值.

我们可以利用对称性建立更加高效的方法. 假设我们先令 p = ϵ e 1 p=\epsilon e_1 p=ϵe1估计 ∇ 2 f ( x ) \nabla^2f(x) 2f(x)的第一列. 由对称性, 同样的估计也适用于 ∇ 2 f ( x ) \nabla^2f(x) 2f(x)的第一行. 此时我们只剩下 ∇ 2 f ( x ) 22 , ∇ 2 f ( x ) 33 , … , ∇ 2 f ( x ) 66 \nabla^2f(x)_{22},\nabla^2f(x)_{33},\ldots,\nabla^2f(x)_{66} 2f(x)22,2f(x)33,,2f(x)66没有估计. 但注意到此时剩下的节点2-6构成的子图中, 节点之间互不邻接. 这就是说, 我们可以赋给它们相同的颜色, 即令扰动向量为 p = ϵ ( e 2 + e 3 + ⋯ + e 6 ) = ϵ ( 0 , 1 , 1 , 1 , 1 , 1 ) T . p=\epsilon(e_2+e_3+\cdots+e_6)=\epsilon(0,1,1,1,1,1)^T. p=ϵ(e2+e3++e6)=ϵ(0,1,1,1,1,1)T.注意到 ∇ f \nabla f f的第2个分量与未知向量的第3,4,5,6个分量无关, 而第3个分量与未知向量的第2,4,5,6个分量无关, 以此类推. 因此, 对于第 i i i个分量, ∇ f ( x + p ) i = ∇ f ( x + ϵ ( e 2 + e 3 + ⋯ + e 6 ) ) i = ∇ f ( x + ϵ e i ) i . \nabla f(x+p)_i=\nabla f(x+\epsilon(e_2+e_3+\cdots+e_6))_i=\nabla f(x+\epsilon e_i)_i. f(x+p)i=f(x+ϵ(e2+e3++e6))i=f(x+ϵei)i.对这些单独的分量应用前向差分公式可得 ∂ 2 f ∂ x i 2 ( x ) ≈ ∇ f ( x + ϵ e i ) i − ∇ f ( x ) i ϵ = ∇ f ( x + ϵ p ) i − ∇ f ( x ) i ϵ , i = 2 , 3 , … , 6. \frac{\partial^2f}{\partial x_i^2}(x)\approx\frac{\nabla f(x+\epsilon e_i)_i-\nabla f(x)_i}{\epsilon}=\frac{\nabla f(x+\epsilon p)_i-\nabla f(x)_i}{\epsilon},\quad i=2,3,\ldots,6. xi22f(x)ϵf(x+ϵei)if(x)i=ϵf(x+ϵp)if(x)i,i=2,3,,6.这样, 我们利用对称性, 仅需要计算 ∇ f \nabla f f x x x和另外两个点处的值就可以估计出整个稀疏的Hessian.

图着色技巧可以再次用来经济地选取我们的扰动向量 p p p. 此处, 我们使用邻接图代替之前使用的列关联图. 邻接图具有 n n n个顶点, 且当 i ≠ k i\ne k i̸=k, ∂ 2 f ( x ) / ( ∂ x i ∂ x k ) ≠ 0 \partial^2f(x)/(\partial x_i\partial x_k)\ne0 2f(x)/(xixk)̸=0时在节点 i , k i,k i,k邻接. 此时的图着色规则也比之前的更加复杂: 我们不仅要求邻接的节点具有不同的颜色, 且要求任一图中长度为3的路径包含至少3种颜色. 换句话说, 若在图中有节点 i 1 , i 2 , i 3 , i 4 i_1,i_2,i_3,i_4 i1,i2,i3,i4且有边 ( i 1 , i 2 ) , ( i 2 , i 3 ) , ( i 3 , i 4 ) (i_1,i_2),(i_2,i_3),(i_3,i_4) (i1,i2),(i2,i3),(i3,i4), 则在给这4个节点着色时必须至少用3种不同的颜色. 扰动向量的构造与之前相同: 若节点 i 1 , i 2 , … , i l i_1,i_2,\ldots,i_l i1,i2,,il具有相同颜色, 则设置扰动向量为 p = ϵ ( e i 1 + e i 2 + ⋯ + e i l ) . p=\epsilon(e_{i_1}+e_{i_2}+\cdots+e_{i_l}). p=ϵ(ei1+ei2++eil).

2. 自动微分

自动微分是一类技术的统称, 这类技术使用函数的计算表示来产生导数的解析值. 其中一些直接通过对函数值进行操作获取导数. 其他的则会保留计算某点 x x x处函数值的计算过程并回过头来利用这些信息计算 x x x处的导数值.

自动微分的详细理论、软件工具和应用可见 www.autodiff.org.

自动微分技术建立在这样的观察上: 任何函数, 不论多复杂, 想要计算它的值都是通过一系列的一元或二元运算. 二元运算包括加法、乘法、除法和求幂. 一元运算有比如三角函数、指数函数和对数函数(作为媒介). 自动微分的另一个共同的要素就是, 它们均会使用微积分中的链式法则.
有两种基本的自动微分的模式: 前向模式与反向模式. 它们的区别可以用一个简单的例子说明. 我们还将利用这个例子阐述这些技术如何延展到一般函数上, 包括向量值函数.

2.1 一个例子

考虑以下具有3个变量的函数: f ( x ) = ( x 1 x 2 sin ⁡ x 3 + e x 1 x 2 ) / x 3 . f(x)=(x_1x_2\sin x_3+e^{x_1x_2})/x_3. f(x)=(x1x2sinx3+ex1x2)/x3.下图表示了计算这样的函数值可以分解为怎样的基本运算, 并也表明了这些运算的偏序如何.

computational graph

例如, 乘法 x 1 ∗ x 2 x_1*x_2 x1x2必须要先于指数运算 e x 1 x 2 e^{x_1x_2} ex1x2, 否则我们会得到错误的结果 e x 1 x 2 e^{x_1}x_2 ex1x2. 上图中引入了中间变量 x 4 , x 5 , … x_4,x_5,\ldots x4,x5,来储存计算过程中的中间值; 它们与图中最左边的独立变量 x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3不同. 我们可以算术形式表示计算 f f f值的过程: x 4 = x 1 ∗ x 2 , x 5 = sin ⁡ x 3 , x 6 = e x 4 , x 7 = x 4 ∗ x 5 , x 8 = x 6 + x 7 , x 9 = x 8 / x 3 . \begin{aligned}x_4&=x_1*x_2,\\x_5&=\sin x_3,\\x_6&=e^{x_4},\\x_7&=x_4*x_5,\\x_8&=x_6+x_7,\\x_9&=x_8/x_3.\end{aligned} x4x5x6x7x8x9=x1x2,=sinx3,=ex4,=x4x5,=x6+x7,=x8/x3.上图中最后的节点 x 9 x_9 x9则储存了函数值 f ( x ) f(x) f(x). 以图论的语言说, 当有一有向弧从节点 i i i指向节点 j j j, 我们称节点 i i i为节点 j j j的父节点, 节点 j j j为节点 i i i的子节点. 任一节点只有在它所有的父节点都已知的条件下才可以计算, 因此计算过程在图中从左向右. 这样的计算过程称作是前推(forward sweep). 需要指明的是, 用于做自动微分的软件工具并不需要用户将计算函数值的代码分解成计算一个又一个中间值的小组分. 中间值的体量识别和构建都可靠软件工具本身显式或隐式地完成.

2.2 前向模式

在自动微分的前向模式中, 我们将推进和计算每个中间变量 x i x_i xi对某一给定方向 p ∈ R n p\in\mathbb{R}^n pRn的方向导数, 同时计算 x i x_i xi本身. 对于上述3个独立变量的例子, 我们使用下述表达式来表示每个变量对 p p p的方向导数: D p x i = d e f ( ∇ x i ) T p = ∑ j = 1 3 ∂ x i ∂ x j p j , i = 1 , 2 , … , 9 , D_px_i\xlongequal{def}(\nabla x_i)^Tp=\sum_{j=1}^3\frac{\partial x_i}{\partial x_j}p_j,\quad i=1,2,\ldots,9, Dpxidef (xi)Tp=j=13xjxipj,i=1,2,,9,其中 ∇ \nabla 表示对3个独立变量求梯度. 我们的最终目标就是计算 ∇ p x 9 \nabla_px_9 px9, 即 ∇ f ( x ) T p \nabla f(x)^Tp f(x)Tp. 注意到独立变量 x i , i = 1 , 2 , 3 x_i,i=1,2,3 xi,i=1,2,3的方向导数分别为 p i , i = 1 , 2 , 3 p_i,i=1,2,3 pi,i=1,2,3. 方向 p p p称为种子向量(seed vector).
任意节点处只要得到了节点处的值 x i x_i xi, 我们就可用链式法则计算 D p x i D_px_i Dpxi. 例如我们已知 x 4 , D p x 4 , x 5 , D p x 5 x_4,D_px_4,x_5,D_px_5 x4,Dpx4,x5,Dpx5, 而由图我们知道 x 7 = x 4 x 5 x_7=x_4x_5 x7=x4x5. 由链式法则, ∇ x 7 = ∂ x 7 ∂ x 4 ∇ x 4 + ∂ x 7 ∂ x 5 ∇ x 5 = x 5 ∇ x 4 + x 4 ∇ x 5 . \nabla x_7=\frac{\partial x_7}{\partial x_4}\nabla x_4+\frac{\partial x_7}{\partial x_5}\nabla x_5=x_5\nabla x_4+x_4\nabla x_5. x7=x4x7x4+x5x7x5=x5x4+x4x5.上式两边与 p p p做内积可得 D p x 7 = ∂ x 7 ∂ x 4 D p x 4 + ∂ x 7 ∂ x 5 D p x 5 = x 5 D p x 4 + x 4 D p x 5 . D_px_7=\frac{\partial x_7}{\partial x_4}D_px_4+\frac{\partial x_7}{\partial x_5}D_px_5=x_5D_px_4+x_4D_px_5. Dpx7=x4x7Dpx4+x5x7Dpx5=x5Dpx4+x4Dpx5.于是方向导数 D p x i D_px_i Dpxi就被逐个获取, 并最终得到 D p x 9 = D p f = ∇ f ( x ) T p . D_px_9=D_pf=\nabla f(x)^Tp. Dpx9=Dpf=f(x)Tp.
前向模式的原理是很直接的, 但它的实际操作和计算需求又如何呢?

  1. 首先, 我们再次强调我们在实际应用时不需要构建计算图、将计算过程组分化或者是定义中间变量. 自动微分的软件工具会隐式、自动地帮助我们实施. 我们也不需要一直储存计算图中每一个节点的信息 x i , D p x i x_i,D_px_i xi,Dpxi. 这是因为当一个节点的所有子节点全都计算完毕后, 它的 x i , D p x i x_i,D_px_i xi,Dpxi也就不再需要了.
  2. 实际操作中的关键是逐步逐个地计算 x i , D p x i x_i,D_px_i xi,Dpxi. 自动微分的软件会在计算过程中对任何标量 w w w关联另一个标量 D p w D_pw Dpw. 只要 w w w在计算过程中有使用, 软件就会自动对这一计算过程附带关联上梯度向量 D p w D_pw Dpw. 例如, 若 w w w被用在一个除法运算中, z ← ∂ w ∂ y , z\leftarrow \frac{\partial w}{\partial y}, zyw,此时就会调用 w , z , D p w , D p y w,z,D_pw,D_py w,z,Dpw,Dpy计算方向导数 D p z D_pz Dpz: D p z ← 1 y D p w − w y 2 D p y . D_pz\leftarrow\frac{1}{y}D_pw-\frac{w}{y^2}D_py. Dpzy1Dpwy2wDpy.为获取完整的梯度向量, 我们可以同时对 n n n个种子向量 p = e 1 , e 2 , … , e n p=e_1,e_2,\ldots,e_n p=e1,e2,,en进行操作. 此时 p = e j p=e_j p=ej对应 D p f = ∂ f / ∂ x j , j = 1 , 2 , … , n D_pf=\partial f/\partial x_j,j=1,2,\ldots,n Dpf=f/xj,j=1,2,,n. 而从上面的例子我们发现, 计算 f f f ∇ f \nabla f f的额外耗费可能会相当大. 就此例而言, 单单一个 w w w除以 y y y就需要我们在计算 D e j z D_{e_j}z Dejz时计算 2 n 2n 2n次乘法和 n n n次加法, j = 1 , 2 , … , n j=1,2,\ldots,n j=1,2,,n. 而这仅仅是一个除法, 对于实际更复杂的关系将会使计算的耗费难以估计(这里还有获取调用和储存数据的耗费). 储存量可能会随着与 n n n同阶的因子增长, 这是因为我们现在需要对中间变量 x i x_i xi存储 n n n个额外的标量 D e j x i , j = 1 , 2 , … , n D_{e_j}x_i,j=1,2,\ldots,n Dejxi,j=1,2,,n. 此时若能了解到这些量有很多(甚至哪些)是零的话, 可能就能节省一些存储空间. 这点在计算初期(也就是计算图的左端)尤为重要, 此时我们就可以用稀疏的数据结构储存向量 D e j x i , j = 1 , 2 , … , n D_{e_j}x_i,j=1,2,\ldots,n Dejxi,j=1,2,,n.

自动微分前向模式可以一种预编译的方式实施. 它会将函数值计算的代码扩展为也能计算导数的代码. 另一种方式是使用C++等语言中可用的运算符重载工具, 以上述方式透明地扩展数据结构和运算.

2.3 反向模式

自动微分的反向模式并不同时计算函数值和梯度, 而是在完成函数值的计算后, 再反过来看 f f f对各个变量 x i x_i xi——诸如独立变量和中间变量——的偏导数. 这一步是通过对计算图的反推(reverse sweep)实现的. 在这一过程的最后, 梯度向量 ∇ f \nabla f f就从偏导数 ∂ f / ∂ x i , i = 1 , 2 , … , n \partial f/\partial x_i,i=1,2,\ldots,n f/xi,i=1,2,,n组装起来.
不像前向模式中使用 D p x i D_px_i Dpxi, 反向模式将对图中每个节点关联一个标量变量 x ˉ i \bar{x}_i xˉi; 在反推过程中, 关于偏导数 ∂ f / ∂ x i \partial f/\partial x_i f/xi的信息就储存在 x ˉ i \bar{x}_i xˉi中. x ˉ i \bar{x}_i xˉi有时称作
伴随变量(adjoint variables)
, 其初始值设成0, 除了图最右边的节点 N N N我们设 x ˉ N = 1 \bar{x}_N=1 xˉN=1. 这一设置是合理的, 这是因为 x N x_N xN储存了最终的函数值 f f f, 从而 ∂ f / ∂ x N = 1 \partial f/\partial x_N=1 f/xN=1.
反推的过程也是基于链式法则: 对任一节点 i i i, 偏导 ∂ f / ∂ x i \partial f/\partial x_i f/xi可以从其子节点 j j j的偏导 ∂ f / ∂ x j \partial f/\partial x_j f/xj中计算: ∂ f ∂ x i = ∑ j   a   c h i l d   o f   i ∂ f ∂ x j ∂ x j ∂ x i . \frac{\partial f}{\partial x_i}=\sum_{j\mathrm{\,a\,child\,of\,}i}\frac{\partial f}{\partial x_j}\frac{\partial x_j}{\partial x_i}. xif=jachildofixjfxixj.对每个节点 i i i, 只要上式右端有一项已知, 我们就把它加到 x ˉ i \bar{x}_i xˉi上; 即 x ˉ i + = ∂ f ∂ x j ∂ x j ∂ x i . \bar{x}_i+=\frac{\partial f}{\partial x_j}\frac{\partial x_j}{\partial x_i}. xˉi+=xjfxixj.当节点 i i i所有的子节点全都算完, 我们就有 x ˉ i = ∂ f / ∂ x i \bar{x}_i=\partial f/\partial x_i xˉi=f/xi, 此时我们声明节点 i i i已完成计算(finalized). 之后, 节点 i i i就将作为其父节点的子节点进一步计算. 这一过程以这种方式进行直至所有的节点均以完成计算.

在反推的过程中, 我们的计算仅涉及数值, 而不涉及公式或者计算变量 x i x_i xi、偏导 ∂ f / ∂ x i \partial f/\partial x_i f/xi的计算机代码. 而在前推(注意反向模式也有前推)——计算 f f f——我们不仅需要计算每个变量 x i x_i xi, 还需要计算并储存每个偏导 ∂ x j / ∂ x i \partial x_j/\partial x_i xj/xi的数值. 每个偏导都与计算图中一段特定的弧相关. 在反推过程中就要用到在前推过程中计算的数值 ∂ x j / ∂ x i \partial x_j/\partial x_i xj/xi.
我们以之前2.1中的例子再一次地阐释反向模式. 在下图中我们以一个特定点 x = ( 1 , 2 , π / 2 ) T x=(1,2,\pi/2)^T x=(1,2,π/2)T填充. 每个节点上的数值代表了之间变量的计算值, 有向边上的数值则代表了偏导.
reverse sweep

设置 x ˉ i = 0 , x ˉ 9 = 1 \bar{x}_i=0,\bar{x}_9=1 xˉi=0,xˉ9=1. 此时节点9已经完成计算(由于没有子节点).
节点9是节点3和节点8的子节点, 从而更新 x ˉ 3 , x ˉ 8 \bar{x}_3,\bar{x}_8 xˉ3,xˉ8的值: x ˉ 3 + = ∂ f ∂ x 9 ∂ x 9 ∂ x 3 = − 2 + e 2 ( π / 2 ) 2 = − 8 − 4 e 2 π 2 , x ˉ 8 + = ∂ f ∂ x 9 ∂ x 9 ∂ x 8 = 1 π / 2 = 2 π . \begin{aligned}\bar{x}_3&+=\frac{\partial f}{\partial x_9}\frac{\partial x_9}{\partial x_3}=-\frac{2+e^2}{(\pi/2)^2}=\frac{-8-4e^2}{\pi^2},\\\bar{x}_8&+=\frac{\partial f}{\partial x_9}{\partial x_9}{\partial x_8}=\frac{1}{\pi/2}=\frac{2}{\pi}.\end{aligned} xˉ3xˉ8+=x9fx3x9=(π/2)22+e2=π284e2,+=x9fx9x8=π/21=π2.此时节点3还未完成计算, 而节点8已经完成, 从而 ∂ f ∂ x 8 = 2 / π \frac{\partial f}{\partial x_8}=2/\pi x8f=2/π. 接着更新节点8的两个父节点: x ˉ 6 + = ∂ f ∂ x 8 ∂ x 8 ∂ x 6 = 2 π , x ˉ 7 + = ∂ f ∂ x 8 ∂ x 8 ∂ x 7 = 2 π . \begin{aligned}\bar{x}_6&+=\frac{\partial f}{\partial x_8}\frac{\partial x_8}{\partial x_6}=\frac{2}{\pi},\\\bar{x}_7&+=\frac{\partial f}{\partial x_8}\frac{\partial x_8}{\partial x_7}=\frac{2}{\pi}.\end{aligned} xˉ6xˉ7+=x8fx6x8=π2,+=x8fx7x8=π2.此时节点6,7已完成计算. 之后更新节点4,5. 最终, 所有节点均计算完成, 在节点1,2,3上有 [ x ˉ 1 x ˉ 2 x ˉ 3 ] = ∇ f ( x ) = [ ( 4 + 4 e 2 ) / π ( 2 + 2 e 2 ) / π ( − 8 − 4 e 2 ) / π 2 ] , \begin{bmatrix}\bar{x}_1\\\bar{x}_2\\\bar{x}_3\end{bmatrix}=\nabla f(x)=\begin{bmatrix}(4+4e^2)/\pi\\(2+2e^2)/\pi\\(-8-4e^2)/\pi^2\end{bmatrix}, xˉ1xˉ2xˉ3=f(x)=(4+4e2)/π(2+2e2)/π(84e2)/π2,从而导数计算完成.

  1. 反向模式的主要优点在于, 其对于标量函数 f : R n → R f:\mathbb{R}^n\to\mathbb{R} f:RnR计算复杂度较低, 而计算梯度的额外计算量至多是单独计算函数值的计算量的4-5倍. 以上例中更新节点3,8的过程为例, x ˉ 3 \bar{x}_3 xˉ3的更新用了2次乘法、1次除法和一次加法, 而 x ˉ 8 \bar{x}_8 xˉ8的更新用了1次除法和1次加法. 这大概就是在前推过程计算函数值时的1次除法运算量的五倍.
    2.2中提到, 前向模式可能需要多于 n n n倍计算函数值的计算量用于计算梯度 ∇ f \nabla f f, 这使得它相比于反向模式毫无竞争力. 不过我们在下节会提到, 当我们考虑向量值函数 r : R n → R m r:\mathbb{R}^n\to\mathbb{R}^m r:RnRm时, 前向模式和反向模式的相对计算耗费随着 m m m的增大将逐渐相近.
  2. 反向模式也有一个很显然的缺陷, 那就是它需要储存整个计算图用于反推过程. 原则上, 计算图的存储并不难以实施: 每当在前推进行一次基本运算, 我们就可以构造储存一个新的节点用于包容中间的计算结果, 并将这一节点指向(1个或2个)父节点, 同时计算与这些边相关的偏导数. 在反推过程中, 节点就可以写入的逆序读取. 构造和写入计算图的过程可看做基本运算(通过运算符重载)的直接扩展. 反推过程或者是梯度计算的过程可直接以函数形式调用.
    不幸的是, 储存计算图所需计算量可能甚是庞大. 如果每个节点都用20个字节储存, 在每秒1亿次浮点运算的计算机上需要1秒评估时间的函数可最多产生2千兆字节大小的图. 若加以额外的计算(如在计算图的一部分上进行部分前推和后推), 则存储量就可减少.

2.4 向量值函数与部分可分性

我们已经讨论了对于一般标量值函数 f : R n → R f:\mathbb{R}^n\to\mathbb{R} f:RnR的自动微分方法. 而在(第十章就将接触的)非线性最小二乘问题和(第十一章中的)非线性方程组中, 我们必须处理向量值函数 r : R n → R m r:\mathbb{R}^n\to\mathbb{R}^m r:RnRm, 其中有 m m m个分量 r j , j = 1 , 2 , … , m r_j,j=1,2,\ldots,m rj,j=1,2,,m. 此时计算图的最右列就有 m m m个节点, 它们都没有任何的子节点, 这与之前标量值函数对应计算图中只有1个节点形成鲜明对比. 显然前向模式和反向模式可以直接推广至近似计算Jacobi矩阵 J ( x ) J(x) J(x).

向量值函数的自动微分除了在最小二乘与非线性方程问题中有应用之外, 也是处理部分可分函数的有效方法. 根据上一章最后部分介绍的, 部分可分性常见于大规模优化, 而我们可以巧妙地利用这一结构应用高效的拟牛顿方法. 当前对于给定函数 f f f, 我们能够使用一些自动化的工具探测它的部分可分表示. 这为我们挖掘这一性质具有的高效性提供了可能. 我们不需要再向用户索要更多关于函数的信息.
在最简单的情形下, 函数 f f f部分可分, 如果我们能把它表示成以下形式 f ( x ) = ∑ i = 1 n e f i ( x ) , f(x)=\sum_{i=1}^{ne}f_i(x), f(x)=i=1nefi(x),其中每个基本函数 f i ( ⋅ ) f_i(\cdot) fi()仅依赖于 x x x的少数分量. 若我们由部分可分性构建向量值函数 r r r, 即 r ( x ) = [ f 1 ( x ) f 2 ( x ) ⋮ f n e ( x ) ] , r(x)=\begin{bmatrix}f_1(x)\\f_2(x)\\\vdots\\f_{ne}(x)\end{bmatrix}, r(x)=f1(x)f2(x)fne(x), ∇ f ( x ) = J ( x ) T e , \nabla f(x)=J(x)^Te, f(x)=J(x)Te,其中 e = ( 1 , 1 , … , 1 ) T e=(1,1,\ldots,1)^T e=(1,1,,1)T. 由部分可分性, J ( x ) J(x) J(x)的大多列只有少数非零元. 这样我们就能通过下一小节中的图着色方法高效的计算 J ( x ) J(x) J(x). 而 ∇ f ( x ) \nabla f(x) f(x)那可以用上一公式获得.
在约束优化中, 同时计算目标函数 f f f和约束函数 c i , i ∈ I ∪ E c_i,i\in\mathcal{I}\cup\mathcal{E} ci,iIE往往能带来便利. 如此一来, 我们还能够有效利用相同的表达式(即在计算图中共享相同的中间节点)有效减少总的负载(亦如之前例子中, 节点4由节点6,7所共享). 此时向量值函数 r r r定义为 r ( x ) = [ f ( x ) [ c j ( x ) ] j ∈ I ∪ E ] . r(x)=\begin{bmatrix}f(x)\\ [c_j(x)]_{j\in\mathcal{I}\cup\mathcal{E}}\end{bmatrix}. r(x)=[f(x)[cj(x)]jIE].

2.5 计算向量值函数的Jacobi矩阵

  1. 计算Jacobi-向量乘积:

    1. 应用前向模式时, 向量值函数与标量函数是相同的. 给定种子向量 p p p, 我们持续地将 D p x i D_px_i Dpxi关联到储存中间变量 x i x_i xi的节点上. 最右端的节点则会储存 D p r j = ( ∇ r j ) T p , j = 1 , 2 , … , m D_pr_j=(\nabla r_j)^Tp,j=1,2,\ldots,m Dprj=(rj)Tp,j=1,2,,m. 将这 m m m个量组装起来, 就得到了 J ( x ) p J(x)p J(x)p. 对于 m = 1 m=1 m=1的情形(即标量值函数), 我们可设置 p = e 1 , e 2 , … , e n p=e_1,e_2,\ldots,e_n p=e1,e2,,en并同时计算 n n n个量 D e j x i D_{e_j}x_i Dejxi得到Jacobi矩阵的估计. 而对于稀疏Jacobi, 我们可采用之前有限差分法中的图着色技巧来恰当选取种子向量 p p p. 相较于 r r r的单次函数值计算, 计算量上的增加的倍数大约是使用的种子向量的个数.
    2. 对向量值函数应用反向模式的关键在于种子向量 q ∈ R m q\in\mathbb{R}^m qRm的选取, 并将反向模式应用于标量值函数 r ( x ) T q r(x)^Tq r(x)Tq. 这一过程的结果是 ∇ [ r ( x ) T q ] = ∇ [ ∑ j = 1 m q j r j ( x ) ] = J ( x ) T q . \nabla[r(x)^Tq]=\nabla\left[\sum_{j=1}^mq_jr_j(x)\right]=J(x)^Tq. [r(x)Tq]=[j=1mqjrj(x)]=J(x)Tq.与前向模式获取Jacobi-向量乘积不同, 反向模式会给出Jacobi转置-向量乘积. 此时需设置储存 r 1 , r 2 , … , r m r_1,r_2,\ldots,r_m r1,r2,,rm m m m个依赖节点中的变量 x ˉ i \bar{x}_i xˉi q q q m m m个分量. 反推到最后, 储存独立变量 x 1 , x 2 , … , x n x_1,x_2,\ldots,x_n x1,x2,,xn的节点中就有 d d x i [ r ( x ) T q ] , i = 1 , 2 , … , n , \frac{d}{dx_i}[r(x)^Tq],\quad i=1,2,\ldots,n, dxid[r(x)Tq],i=1,2,,n,这些就是 J ( x ) T q J(x)^Tq J(x)Tq的分量.
  2. 计算完整Jacobi: 与之前相同, 我们通过设置 m m m个单位向量 q = e 1 , e 2 , … , e m q=e_1,e_2,\ldots,e_m q=e1,e2,,em获取完整的一般Jacobi估计. 而对于稀疏的Jacobi, 我们可应用之前的图着色技巧寻找更少的种子向量——唯一不同在于, 此时的图和着色策略均基于 J ( x ) T J(x)^T J(x)T, 而不是 J ( x ) J(x) J(x). 同时, 计算量的增加倍数也将超过5(注意5是对于标量函数的通常的上界). 储存计算图所需的空间与标量情形差不多. 我们仅需储存图的拓扑信息以及每条边上附带的偏导数.

    前向和反向模式可以混合使用以计算 J ( x ) J(x) J(x)的所有元素. 我们可为前向模式选取种子向量 p p p的集合得到 J J J的某些列, 再为反向模式选取种子向量 q q q的集合得到 J J J的包含剩下的元素的行. 也就是说, 我们可以通过行列分割的方式将前向与反向有机地结合在一起.

最后我们说明, 对于某些算法, 我们不需要提供Jacobi J ( x ) J(x) J(x)的完整信息. 例如对于非线性方程组使用的非精确牛顿法只需要提供对于任一向量 p p pJacobi与向量的乘积 J ( x ) p J(x)p J(x)p. 而这一点用一次前推就能做到, 计算量与单独计算函数值差不多.

2.6 计算Hessian矩阵: 前向模式

至今, 我们已经介绍了如何使用前向模式与反向模式计算标量值和向量值函数的一阶导数. 下面我们概述如何扩展这些方法计算标量函数 f f f的Hessian矩阵 ∇ 2 f \nabla^2f 2f, 以及计算Hessian与给定向量 p p p的Hessian-向量乘积 ∇ 2 f ( x ) p \nabla^2f(x)p 2f(x)p.
回忆在前向模式中, 我们用到了 D p x i D_px_i Dpxi. 现对于给定种子向量对 p , q ∈ R n p,q\in\mathbb{R}^n p,qRn, 我们对计算图中的节点 i i i定义另一个标量 D p q x i = p T ( ∇ 2 x i ) q . D_{pq}x_i=p^T(\nabla^2x_i)q. Dpqxi=pT(2xi)q.我们可用前推基于 x i , D p x i x_i,D_px_i xi,Dpxi计算这些量. 在储存独立变量 x i x_i xi的节点上初始值 D p q D_{pq} Dpq为0(这是合理的). 当前推完成, 计算图中最右端的值 D p q x i D_{pq}x_i Dpqxi就是 p T ∇ 2 f ( x ) q p^T\nabla^2f(x)q pT2f(x)q.
计算 D p q x i D_{pq}x_i Dpqxi的公式同样来源于链式法则. 例如, 若 x i x_i xi是通过其两个父节点相加得来, x i = x j + x k x_i=x_j+x_k xi=xj+xk, 则在 D p x i D_px_i Dpxi D p q x i D_{pq}x_i Dpqxi上对应的加和运算为: D p x i = D p x j + D p x k , D p q x i = D p q x j + D p q x k . D_px_i=D_px_j+D_px_k,\quad D_{pq}x_i=D_{pq}x_j+D_{pq}x_k. Dpxi=Dpxj+Dpxk,Dpqxi=Dpqxj+Dpqxk.其他的二元运算 − , × , ÷ -,\times,\div ,×,÷也可类似处理. 若 x j x_j xj是通过对 x j x_j xj做酉变换得到的, 则我们有 x i = L ( x j ) , D p x i = L ′ ( x j ) ( D p x j ) , D p q x i = L ′ ′ ( x j ) ( D p x j ) ( D q x j ) + L ′ ( x j ) D p q x j . \begin{aligned}x_i&=L(x_j),\\D_px_i&=L'(x_j)(D_px_j),\\D_{pq}x_i&=L''(x_j)(D_px_j)(D_qx_j)+L'(x_j)D_{pq}x_j.\end{aligned} xiDpxiDpqxi=L(xj),=L(xj)(Dpxj),=L(xj)(Dpxj)(Dqxj)+L(xj)Dpqxj.我们可以看到第三个式子中 D p q x i D_{pq}x_i Dpqxi依赖于一阶导 D p x i , D q x i D_px_i,D_qx_i Dpxi,Dqxi, 因此这些量也必须在前推的时候累积起来.

  1. 完整Hessian: 若想计算一般完整的Hessian, 我们需要种子向量对 ( p , q ) (p,q) (p,q)取遍所有可能的单位向量 ( e j , e k ) , j = 1 , 2 , … , n , k = 1 , 2 , … , j (e_j,e_k),j=1,2,\ldots,n,k=1,2,\ldots,j (ej,ek),j=1,2,,n,k=1,2,,j的组合, 共 n ( n + 1 ) / 2 n(n+1)/2 n(n+1)/2对. 当我们知晓 ∇ 2 f ( x ) \nabla^2f(x) 2f(x)的稀疏结构后, 我们就只需要对 ∇ 2 f ( x ) \nabla^2f(x) 2f(x)可能非零的那些位置 ( j , k ) (j,k) (j,k)计算 D e j e k x i D_{e_je_k}x_i Dejekxi了.
    总的计算量大约是单独计算函数值计算量的 c ( 1 + n + N z ( ∇ 2 f ) ) c(1+n+N_z(\nabla^2f)) c(1+n+Nz(2f))倍, 其中 N z ( ∇ 2 f ) N_z(\nabla^2f) Nz(2f) ∇ 2 f \nabla^2f 2f中我们需要计算的元素个数. 这一数目反映了对于 N z ( ∇ 2 f ) N_z(\nabla^2f) Nz(2f)个向量对 ( e j , e k ) (e_j,e_k) (ej,ek)需要计算的量( x i , D e j x i ( j = 1 , 2 , … , n ) , D e j e k x i x_i,D_{e_j}x_i(j=1,2,\ldots,n),D_{e_je_k}x_i xi,Dejxi(j=1,2,,n),Dejekxi)有多少. 小量 c c c的存在则是因为更新 D p x i , D p q x i D_px_i,D_{pq}x_i Dpxi,Dpqxi需要比更新 x i x_i xi耗费更多的计算量(比如上面酉变换的例子). 至于存储量, 图中每个节点均需要存储 1 + n + N z ( ∇ 2 f ) 1+n+N_z(\nabla^2f) 1+n+Nz(2f)个量, 不过注意当一个节点的所有节点都计算完后它的存储是可以释放的.
  2. Hessian-向量乘积: 当我们不需要完整的Hessian, 而仅需矩阵-向量乘积(例如第七章的Newton-CG)时, 总的计算量必然会减小. 给定向量 q ∈ R n q\in\mathbb{R}^n qRn, 我们使用上面的方法计算一阶导数 D e 1 x i , … , D e n x i D_{e_1}x_i,\ldots,D_{e_n}x_i De1xi,,Denxi D q x i D_qx_i Dqxi以及二阶导数 D e 1 q x i , … , D e n q x i D_{e_1q}x_i,\ldots,D_{e_nq}x_i De1qxi,,Denqxi. 于是最后的节点会依次储存 e j T ( ∇ 2 f ( x ) ) q = [ ∇ 2 f ( x ) q ] j , j = 1 , 2 , … , n , e_j^T(\nabla^2f(x))q=[\nabla^2f(x)q]_j,\quad j=1,2,\ldots,n, ejT(2f(x))q=[2f(x)q]j,j=1,2,,n,而这就是 ∇ 2 f ( x ) q \nabla^2f(x)q 2f(x)q的分量. 由于在前推时除了 x i x_i xi还需要另外计算 2 n + 1 2n+1 2n+1个量, 因此在计算量上将仅增加 2 n 2n 2n倍.
  3. 稀疏Hessian: 计算稀疏Hessian的一种替代方案则基于单变量函数一阶和二阶导数的前向模式传播. 为说明, 注意Hessian的第 ( i , j ) (i,j) (i,j)元可以表示成 [ ∇ 2 f ( x ) ] i j = e i T ∇ 2 f ( x ) e j = 1 2 [ ( e i + e j ) T ∇ 2 f ( x ) ( e i + e j ) − e i T ∇ 2 f ( x ) e i − e j T ∇ 2 f ( x ) e j ] . \begin{aligned}[\nabla^2f(x)]_{ij}&=e_i^T\nabla^2f(x)e_j\\&=\frac{1}{2}[(e_i+e_j)^T\nabla^2f(x)(e_i+e_j)-e_i^T\nabla^2f(x)e_i-e_j^T\nabla^2f(x)e_j].\end{aligned} [2f(x)]ij=eiT2f(x)ej=21[(ei+ej)T2f(x)(ei+ej)eiT2f(x)eiejT2f(x)ej].当所有的节点 x k x_k xk处的二阶导数 D p p x k , p = e i , e j , e i + e j D_{pp}x_k,p=e_i,e_j,e_i+e_j Dppxk,p=ei,ej,ei+ej均在前推时计算完成时, 我们就可以用上面的插值公式计算 [ ∇ 2 f ( x ) ] i j [\nabla^2f(x)]_{ij} [2f(x)]ij.
    这种方法的一大好处就是, 我们不需要再考虑计算 D p q x k , p ≠ q D_{pq}x_k,p\ne q Dpqxk,p̸=q了. 而每个 D p p x k D_{pp}x_k Dppxk都是 x l , D p x l , D p p x l x_l,D_px_l,D_{pp}x_l xl,Dpxl,Dppxl的函数, 其中节点 l l l k k k的父节点.
    注意, 若我们定义单变量函数 ψ \psi ψ ψ ( t ) = f ( x + t p ) , \psi(t)=f(x+tp), ψ(t)=f(x+tp), D p f , D p p f D_pf,D_{pp}f Dpf,Dppf的值就是 ψ \psi ψ的一阶和二阶导数在 t = 0 t=0 t=0处的值, 即 D p f = p T ∇ f ( x ) = ψ ′ ( t ) ∣ t = 0 , D p p f = p T ∇ 2 f ( x ) p = ψ ′ ′ ( t ) ∣ t = 0 . D_pf=p^T\nabla f(x)=\psi'(t)|_{t=0},\quad D_{pp}f=p^T\nabla^2f(x)p=\psi''(t)|_{t=0}. Dpf=pTf(x)=ψ(t)t=0,Dppf=pT2f(x)p=ψ(t)t=0.将这一方法推广至计算三阶、四阶乃至更高阶的导数也是有可能的. 类似的插值公式可以与 p s i psi psi的更高阶的导数混合使用, 其中需恰当选取向量 p p p(由一些单位向量的和组成).

2.7 计算Hessian矩阵: 反向模式

我们也可以设计基于反向模式的算法计算Hessian-向量乘积 ∇ 2 f ( x ) q \nabla^2f(x)q 2f(x)q或者是整个Hessian矩阵 ∇ 2 f ( x ) \nabla^2f(x) 2f(x). 一种计算 ∇ 2 f ( x ) q \nabla^2f(x)q 2f(x)q的算法如下: 我们首先使用前向模式通过前推时累加两个变量 x i , D q x i x_i,D_qx_i xi,Dqxi, 计算 f f f ∇ f ( x ) T q \nabla f(x)^Tq f(x)Tq. 之后以反向模式应用于 ∇ f ( x ) T q \nabla f(x)^Tq f(x)Tq. 反推到最后, 计算图中代表独立变量的的节点 i = 1 , 2 , … , n i=1,2,\ldots,n i=1,2,,n就会含有 ∂ ∂ x i ( ∇ f ( x ) T q ) = [ ∇ 2 f ( x ) q ] i , i = 1 , 2 , … , n . \frac{\partial}{\partial x_i}(\nabla f(x)^Tq)=[\nabla^2f(x)q]_i,\quad i=1,2,\ldots,n. xi(f(x)Tq)=[2f(x)q]i,i=1,2,,n.以这种方式计算 ∇ 2 f ( x ) q \nabla^2f(x)q 2f(x)q的计算量相较于计算 f f f增加的并不多, 且独立于 n n n. 通常, 前向模式中计算 f f f ∇ f ( x ) T q \nabla f(x)^Tq f(x)Tq所需的计算量为单独计算 f f f的一个小倍数, 而反向模式则至多引入倍数因子5. 而总的增加倍数大约是12. 若我们需要整个 ∇ 2 f ( x ) \nabla^2f(x) 2f(x), 就得对 q = e 1 , e 2 , … , e n q=e_1,e_2,\ldots,e_n q=e1,e2,,en重复相同的过程, 从而倍数至多为 12 n 12n 12n.
再次地, 若Hessian稀疏且结构已知, 我们就能用图着色技术仅使用远少于 n n n个的种子向量计算整个Hessian. 选取 q q q的方式类似于有限差分中的选取方式. 而计算量的增加倍数至多为 12 N c ( ∇ 2 f ) 12N_c(\nabla^2f) 12Nc(2f).

2.8 当前的限制

当前自动微分已经彰显了它在大型的和困难的优化问题中的能力. 但这样的工具却有可能在一些常用的优化框架和计算机计算时使人陷入困境.

  1. 截断误差引发的导数危机. 例如, 若 f ( x ) f(x) f(x)的计算依赖于求解偏微分方程(PDE), 则 f f f的计算值会包含来自数值求解PDE时使用有限差分或有限元所引发的截断误差. 即我们有 f ^ ( x ) = f ( x ) + τ ( x ) \hat{f}(x)=f(x)+\tau(x) f^(x)=f(x)+τ(x), 其中 f ^ ( ⋅ ) \hat{f}(\cdot) f^() f ( ⋅ ) f(\cdot) f()的计算值, τ ( ⋅ ) \tau(\cdot) τ()为截断误差. 尽管 ∣ τ ( x ) ∣ |\tau(x)| τ(x)通常来讲较小, 但它的导数 τ ′ ( x ) \tau'(x) τ(x)可就不一定了, 从而计算导数值 f ^ ( ⋅ ) \hat{f}(\cdot) f^()中可能蕴含着巨大的误差(第1节中介绍的有限差分法也有相同的问题). 在计算机使用分段有理函数近似三角函数时, 也会出现类似的问题.
  2. 代码分段导致计算失误. 另外一个问题的来源是, 将代码分段以提高特定区域上函数计算的速度或精确度. 一个病态的例子是 f ( x ) = x − 1 f(x)=x-1 f(x)=x1. 若我们使用以下代码的分段计算该函数
    i f    ( x = 1.0 )    t h e n    f = 0.0    e l s e    f = x − 1.0 , \mathrm{if\,\,}(x=1.0)\mathrm{\,\,then\,\,}f=0.0\mathrm{\,\,else\,\,}f=x-1.0, if(x=1.0)thenf=0.0elsef=x1.0,于是使用自动微分时我们就会有 f ′ ( 1 ) = 0 f'(1)=0 f(1)=0.

总的来说, 自动微分应当被视作一类愈发复杂的技术, 它们可以用来增强优化算法的性能, 从而使算法能够用于更广、更复杂的问题. 若提供敏度分析, 我们就能从计算的结果中挖掘更多的信息. 自动微分不是万能的. 我们不能因为有了自动微分就认为自己可以逃脱导数计算.


  1. NP-completeness: https://en.wikipedia.org/wiki/NP-completeness ↩︎

  2. G. N. NEWSAM AND J. D. RAMSDELL, Estimation of sparse Jacobian matrices, SIAM Journal on Algebraic and Discrete Methods, 4 (1983), pp. 404–418. ↩︎

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值