【问题标题】:Calling Stan routines from a C++ program从 C++ 程序调用 Stan 例程
【发布时间】:2015-08-08 01:21:36
【问题描述】:

我读到here 说可以(而且我解释得很简单)从 C++ 程序调用 Stan 例程。

我有一些复杂的对数似然函数,我用 C++ 编写了这些函数,但我真的不知道如何使用 Stan 语言编写它们。是否可以使用我已经用 C++ 编写的对数似然函数在 Stan 中调用 Monte Carlo 例程?如果是这样,有什么例子吗?

这似乎是一件很自然的事情,但我找不到任何关于如何做到这一点的示例或指示。

【问题讨论】:

    标签: c++ bayesian mcmc stan


    【解决方案1】:

    经过进一步审查(您可能不想接受我之前的回答),您可以试试这个:在 functions 块中编写一个具有用户定义函数的 .stan 程序,该程序具有正确的签名(和解析)但基本上什么也没做。像这样 functions { real foo_log(real[] y, vector beta, matrix X, real sigma) { return not_a_number(); // replace this after parsing to C++ } } data { int<lower=1> N; int<lower=1> K; matrix[N,K] X; real y[N]; } parameters { vector[K] beta; real<lower=0> sigma; } model { y ~ foo(beta, X, sigma); // priors here } 然后,使用 CmdStan 编译该模型,这将生成一个 .hpp 文件作为中间步骤。在foo_log 的正文中编辑该 .hpp 文件以调用您的模板化 C++ 函数以及 #include 定义您的内容的头文件。然后重新编译并执行二进制文件。

    这实际上可能对您有用,但是如果您所做的任何事情都具有广泛的用途,我们希望您贡献 C++ 的东西。

    【讨论】:

    • 我刚刚在周末工作,但我现在需要在其他事情上工作一段时间:(我正在尝试一个非均匀泊松过程模型,其中瞬时速率相当复杂,所以似然函数中的积分。它非常具体,所以我不认为这是一个有价值的贡献,不幸的是。除非我能想出一种方法来进一步概括模型 - 我会想一想。再次感谢。
    • 我把它用于一些基本的例子,再次感谢您的解决方案!我想知道您是否认为有人会对一些示例以及我可以在哪里发布它感兴趣?
    • 也许是 GitHub wiki? (github.com/stan-dev/stan/wiki) 我不知道它是否会让您创建一个新页面,但我们中的一个可以为您推送它,或者我们可能会更改权限。
    • 我已经把它全部放在了 GitHub 上 (github.com/jeffpollock9/StanExample)。我使用 y ~ N(mu, sigma) 的 50 个观测值对 mu 和 sigma 的后验进行采样的示例大约是正常 Stan 等效值的两倍。我猜是因为我没有编写任何渐变代码?
    【解决方案2】:

    我认为您的问题与您所链接的问题有点不同。他有一个完整的 Stan 程序并想从 C++ 驱动它,而您问是否可以通过调用外部 C++ 函数来评估对数似然度来规避编写 Stan 程序。但这不会让你走得太远,因为你仍然必须以 Stan 可以处理的形式传递数据,向 Stan 声明未知参数是什么(加上它们的支持)等等。所以,我认为你不能(或应该)避免学习 Stan 语言。

    但是将 C++ 函数暴露给 Stan 语言是相当容易的,这基本上只需将您的 my_loglikelihood.hpp 文件添加到 ${STAN_HOME}/lib/stan_math_${VERSION}/stan/math/ 下的正确位置,然后在该子目录中的 math.hpp 文件中添加一条包含语句,并编辑${STAN_HOME}/src/stan/lang/function_signatures.h。那时,您的 .stan 程序可能看起来很简单 data { // declare data like y, X, etc. } parameters { // declare parameters like theta } model { // call y ~ my_logliklihood_log(theta, X) } 但我认为你问题的真正答案是,如果你已经编写了一个 C++ 函数来评估对数似然,那么用 Stan 语言重写它应该不会超过几分钟。 Stan 语言非常类似于 C,因此更容易将 .stan 文件解析为 C++ 源文件。这是我为回归上下文中条件高斯结果的对数似然编写的 Stan 函数: functions { /** * Increments the log-posterior with the logarithm of a multivariate normal * likelihood with a scalar standard deviation for all errors * Equivalent to y ~ normal(intercept + X * beta, sigma) but faster * @param beta vector of coefficients (excluding intercept) * @param b precomputed vector of OLS coefficients (excluding intercept) * @param middle matrix (excluding ones) typically precomputed as crossprod(X) * @param intercept scalar (assuming X is centered) * @param ybar precomputed sample mean of the outcome * @param SSR positive precomputed value of the sum of squared OLS residuals * @param sigma positive value for the standard deviation of the errors * @param N integer equal to the number of observations */ void ll_mvn_ols_lp(vector beta, vector b, matrix middle, real intercept, real ybar, real SSR, real sigma, int N) { increment_log_prob( -0.5 * (quad_form_sym(middle, beta - b) + N * square(intercept - ybar) + SSR) / square(sigma) - # 0.91... is log(sqrt(2 * pi())) N * (log(sigma) + 0.91893853320467267) ); } } 这基本上只是我将原本可能是 C 语法的内容转储到 Stan 语言的函数体中,然后可以在 .stan 程序的 model 块中调用。

    所以,简而言之,我认为将 C++ 函数重写为 Stan 函数可能是最简单的。但是,您的对数似然可能涉及一些奇异的东西,目前没有相应的 Stan 语法。在这种情况下,您可以退回到将该 C++ 函数公开给 Stan 语言,并在理想情况下向 GitHub 上 stan-dev 下的数学和 stan 存储库发出拉取请求,以便其他人可以使用它(尽管那时您还必须编写单元测试、文档等)。

    【讨论】:

    • 谢谢你的详细回答,本。我的问题是我编写的对数似然包含 100 行 C++ 代码,并使用了我编写的许多 C++ 类 - 所以将整个东西重新编写成 stan 语言感觉很浪费stan 编译器可以将其转换回 C++。我希望有一种方法可以为先验和对数似然编写 C++ 函数,然后将它们传递给 stan HMC 函数——这可能吗?
    • 也许你可以编写一个 .stan 程序来填充除model 之外的所有块,使用 CmdStan 将其解析为 C++,从创建的类继承,覆盖 log_prob 中的方法继承类来调用您的 C++ 函数(需要对其进行模板化,以便它可以处理 Stan 的自定义标量类型),克服任何意想不到的复杂情况,编译修改后的 C++ 源代码,并希望最好。但我仍然认为最好采用我的主要答案中提到的路线之一。无论在这个 Stan 项目上浪费多少时间,下一个项目都会为您提供良好的服务。
    • 我想我会在 .stan 文件中编写模型 - 看起来更简单!非常感谢您的帮助,本。
    猜你喜欢
    • 2015-09-30
    • 2014-01-14
    • 2012-01-02
    • 1970-01-01
    • 2019-08-29
    • 2016-03-09
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    相关资源
    最近更新 更多