autodiff 有效但符号微分无效的示例?

计算科学 符号计算 自动分化 分化
2021-12-10 02:28:18

根据关于 autodiff (linked) 的调查论文,Autodiff 适用于无法以封闭形式指定但可以通过一系列代码描述的输入,其中每个组件都是可微的。Autodiff 也适用于可以符号区分的代码,但在后一种情况下,好处不那么明显而且更微妙。但是,我无法想出一个 autodiff 有效但符号 diff 不起作用的示例。

我的问题是:是否存在一个简单的 autodiff 示例,其代码输入不适用于符号差异?

注意:我意识到 simple 的定义有些随意,所以让我们说少于 20 行代码,这样答案就不会太长而难以阅读。如果 20 行还不够,那么代码中的最少行数就可以了。

4个回答

这是一个与状态相关的控制流问题。

function f(u)
  z = 0.0
  while z < 10.0
    z += u
    u += z^2
  end
  return u
end

计算导数的程序是什么?自动微分将为您提供:

function f(_u)
  u = (_u,1.0) # seed the input derivative for the jvp in direction of basis e1
  z = (0.0,0.0)
  while z[1] < 10.0
    z += u
    u += (z[1]^2,2z[1]*z[2]) # by d(z^2)/dz = 2z
  end
  return u # first output is the primal, second is the derivative w.r.t. input
end

这就是双数算术实际上将在引擎盖下构建的内容。现在什么是符号导数?你需要知道什么u是完整的表达,所以这很难。如果您知道输入值u是什么,则元组第二项的计算图恰好是 input 的导数_u,因此如果您知道循环多少次,您就可以得到这个符号表达式。使用自动微分这没问题,因为您只需要输出值,因此您可以从该程序中获取值。但是这个程序不能明确地给你 LaTeX 粘贴到你的论文中以获得任何可能的导数_u,这就是为什么“它不是符号可微的”。

所以这个故事的寓意是,广告和象征性的区别是相同的而不是不同的。我生成该代码的方式是通过象征性地采用程序步骤的导数来构建导数的程序作为元组的第二部分。但是拥有一个为您提供符号表达式的程序并不一定是“给我符号导数”的令人满意的答案。

您链接的论文回答了这个问题。Autodiff(或手动区分)可以区分分支程序语句。例如,限制器、熵修复通量语句中的分支等。它对 min max 语句也很有帮助。您可以在下面看到一个示例:

 Function(Vn_bar, a_bar, ul, cl, ur, cr)
   lambda1    = abs(Vn_bar-a_bar)
   lambda2    = abs(Vn_bar)
   lambda4    = abs(Vn_bar+a_bar)

   epsdummy   = max(lambda1-(ul-cl), (ur-cr)-lambda1)
   eps1       = max(0, epsdummy)
   epsdummy   = max(lambda2-ul, ur-lambda2)
   eps2       = max(0, epsdummy)
   epsdummy   = max(lambda4-ul-cl, ur+cr-lambda4)
   eps4       = max(0, epsdummy)

   if (lambda1 < eps1) lambda1 = .5_dp*(lambda1**2/eps1+eps1)
   if (lambda2 < eps2) lambda2 = .5_dp*(lambda2**2/eps2+eps2)
   if (lambda4 < eps4) lambda4 = .5_dp*(lambda4**2/eps4+eps4)
   y = sqrt(lambda1**2 + lambda2**2 + lambda4**2)
   do while(y < 10) 
      y = y**2
   end do
   return y

这是一个示例,我们提供了 6 个输入,我们可以根据 (Vn_bar, a_bar, ul, cl, ur, cr) 和函数 y 进行区分,我们正在对其进行导数。您可以看到我们这里有许多分支语句、max 和 min 函数以及一个循环,所有这些都依赖于状态本身。AD 或手牌区分可以处理这个问题,即使它没有真正的符号导数。

可以重构自动微分程序以输出符号表示,而不是数字表示。因此这两种形式是等价的。

请在此处查看不接受的答案: https ://stackoverflow.com/a/55607008/104910

AD 是计算机代码每一行的符号区分。但更有用的是,因为它为您提供了另一个计算机代码,您不必自己重新编码导数。

如果您有一些奇特的函数,其导数对于您使用的 AD 工具来说是未知的,那么它当然不能给您答案。

如果你有一个显式的函数,那么符号差异总是可以完成的,但是如果你有一个复杂的表达式,就会变得笨拙/繁琐/容易出错,就像其他人在上面给出的例子一样。

不连续函数也将通过单边导数由 AD 微分。

例如f(x)=max(x,0)可以在代码中实现为

f(x)={0x0xx>0

然后 AD 将给出导数为

f(x)={0x01x>0

因此,即使代码中存在分支,也可以写下一个潜在的符号导数。

一个更复杂的例子是一个隐式函数

F(x,a)=0,y=G(x)
在哪里F被实现为计算机代码。在这里,您可能无法写出明确的公式dy/da? 因为没有明确的公式x=x(a). 甚至 AD 也不能在这里给你导数,因为它不知道函数x=x(a). 在实践中,我们得到一个近似值xxh通过应用一些牛顿方法。
xh=Fh1(a),yh=G(xh)
在哪里Fh1表示牛顿法。现在AD可以工作了,但它背后还有一个象征性的衍生物,但这是你自己不想写下来的东西。