从C ++程序调用Stan例程

时间:2015-08-06 18:06:17

标签: c++ bayesian mcmc stan

我阅读here我可以(并且我直截了当地解释)从C ++程序中调用Stan例程。

我有一些复杂的对数似然函数,我用C ++编写,实际上不知道如何使用Stan语言对它们进行编码。是否可以使用我已用C ++编写的对数似然函数在Stan中调用蒙特卡洛例程?如果是这样的话有什么例子吗?

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

2 个答案:

答案 0 :(得分:2)

I think your question is a bit different from the one you linked to. He had a complete Stan program and wanted to drive it from C++, whereas you are asking if you could circumvent writing a Stan program by calling an external C++ function to evaluate the log-likelihood. But that would not get you very far because you still have to pass in the data in a form that Stan can handle, declare to Stan what are the unknown parameters (plus their support), etc. So, I don't think you can (or should) evade learning the Stan language.

But it is fairly easy to expose a C++ function to the Stan language, which essentially just involves adding your my_loglikelihood.hpp file in the right place under ${STAN_HOME}/lib/stan_math_${VERSION}/stan/math/, adding an include statement to the math.hpp file in that subdirectory, and editing ${STAN_HOME}/src/stan/lang/function_signatures.h. At that point, your .stan program could look as simple as data { // declare data like y, X, etc. } parameters { // declare parameters like theta } model { // call y ~ my_logliklihood_log(theta, X) } But I think the real answer to your question is that if you have already written a C++ function to evaluate the log-likelihood, then rewriting it in the Stan language shouldn't take more than a few minutes. The Stan language is very C-like so that it is easier to parse the .stan file into a C++ source file. Here is a Stan function I wrote for the log-likelihood of a conditionally Gaussian outcome in a regression context: 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) ); } } which is basically just me dumping what could otherwise be C-syntax into the body of a function in the Stan language that is then callable in the model block of a .stan program.

So, in short, I think it would probably be easiest for you to rewrite your C++ function as a Stan function. However, it is possible that your log-likelihood involves something exotic for which there is currently no corresponding Stan syntax. In that case, you could fall back to exposing that C++ function to the Stan language and ideally making pull requests to the math and stan repositories on GitHub under stan-dev so that other people could use it (although then you would also have to write unit-tests, documentation, etc.).

答案 1 :(得分:2)

进一步审核(您可能想要取消我之前的答案),您可以尝试这样做:在具有正确签名的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 ++的东西。