我们正在研究用于时空过程的贝叶斯模型,并且正在使用 No-U-Turn 采样器 (NUTS),该采样器需要对数概率模型及其相对于模型参数的梯度。更简洁地说,我们有相当复杂的对数概率函数,涉及统计分布、克罗内克积、指数、比率、if-else语句等,需要提供它和它的梯度到NUTS。几个包(Stan和 Julia 的 MCMC)使用运算符重载(据我所知)自动获取梯度。
如果我们能够创建自己的梯度函数,也许使用源代码转换自动差异工具,我们会获得更好的性能,还是 OO 一样好还是更好?
我们正在研究用于时空过程的贝叶斯模型,并且正在使用 No-U-Turn 采样器 (NUTS),该采样器需要对数概率模型及其相对于模型参数的梯度。更简洁地说,我们有相当复杂的对数概率函数,涉及统计分布、克罗内克积、指数、比率、if-else语句等,需要提供它和它的梯度到NUTS。几个包(Stan和 Julia 的 MCMC)使用运算符重载(据我所知)自动获取梯度。
如果我们能够创建自己的梯度函数,也许使用源代码转换自动差异工具,我们会获得更好的性能,还是 OO 一样好还是更好?
源到源的转换被认为是性能方面的黄金标准。OO 方法似乎几乎一样好,因为那里有更多的 OO 包,并且没有提到性能是一个明显的缺点。如果您找到适合您正在使用的语言的 OO 库,我会先使用它,然后再确定您是否绝对需要源到源转换,以及是否存在满足您需求的此类工具。将事物放在上下文中,自动微分生成的导数的典型成本大约是函数评估的三到五倍。
有更多的 OO 包,因为使用运算符重载实现自动微分工具比使用源到源转换更容易。实现源到源的翻译器相当于编写编译器:必须对源代码进行解析和标记化,然后必须将转换规则应用于生成的表达式树。Andreas Griewank 的书 Evaluating Derivatives: Principles and Techniques of Algorithmic Differences, Second Edition 更详细地介绍了权衡。
对于梯度计算,您使用 AD 的反向模式。这两种情况都需要构建操作数栈,OO版本也需要构建操作栈,需要在代码的反向遍历中进行解释。源代码转换后的代码将逆序操作写出作为额外的源代码进行编译。在代码中使用操作解释器的开销可能很大。Tapenade 生成的代码和 Adol-C 的比较结果支持 Tapenade。