从 C++ 程序调用 Stan 例程
Calling Stan routines from a C++ program
我从 C++ 程序中读取了 that it is possible (and I interpreted straightforward) to call Stan 个例程。
我有一些复杂的对数似然函数,我用 C++ 编写了它们,但真的不知道如何使用 Stan 语言编写它们。是否可以使用我已经用 C++ 编写的对数似然函数在 Stan 中调用 Monte Carlo 例程?如果有,有这方面的例子吗?
这似乎是一件很自然的事情,但我找不到任何关于如何做到这一点的例子或指示。
我认为你的问题与你链接到的问题有点不同。他有一个完整的 Stan 程序并想从 C++ 驱动它,而你问是否可以通过调用外部 C++ 函数来评估对数似然来规避编写 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 语言,并理想地向 stan-dev 下 GitHub 上的 math 和 stan 存储库发出拉取请求,以便其他人可以使用它(尽管那样您会还必须编写单元测试、文档等)。
经过进一步审查(您可能想取消接受我之前的回答),您可以尝试这样做:在具有正确签名的 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++ 的东西。
我从 C++ 程序中读取了
我有一些复杂的对数似然函数,我用 C++ 编写了它们,但真的不知道如何使用 Stan 语言编写它们。是否可以使用我已经用 C++ 编写的对数似然函数在 Stan 中调用 Monte Carlo 例程?如果有,有这方面的例子吗?
这似乎是一件很自然的事情,但我找不到任何关于如何做到这一点的例子或指示。
我认为你的问题与你链接到的问题有点不同。他有一个完整的 Stan 程序并想从 C++ 驱动它,而你问是否可以通过调用外部 C++ 函数来评估对数似然来规避编写 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 语言,并理想地向 stan-dev 下 GitHub 上的 math 和 stan 存储库发出拉取请求,以便其他人可以使用它(尽管那样您会还必须编写单元测试、文档等)。
经过进一步审查(您可能想取消接受我之前的回答),您可以尝试这样做:在具有正确签名的 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++ 的东西。