函数通过了包内部的测试,并从小插图失败(由于cpp_object_initializer)

时间:2019-05-22 18:23:04

标签: r package

我正在编写一个将rstan用于贝叶斯的R包 采样。 (Here 如果您想重现此问题,则是特定的提交。)我仅在 运行一个从小插图调用rstan的函数(如果我使用的话) library(rstan),但没有一些解决方法。

设置

包中的一个函数调用rstan(为清楚起见进行了编辑):

#' @importFrom Rcpp cpp_object_initializer
#' @export
run_variational_bayes <- function(x, y, output_samples, beta_sd, stan_file) {

  n_input <- length(y)
  p <- ncol(x)

  train_dat <- list(n = n_input, p = p, x = x, y = y, beta_sd = beta_sd)

  stan_model <- rstan::stan_model(file = stan_file)

  stan_vb <- rstan::vb(object = stan_model, data = train_dat,
                 output_samples = output_samples)

  return(rstan::extract(stan_vb)$beta)
}

我在软件包中测试了此功能:

context("RStan variational Bayes model")

test_that("Rstan variational Bayes model runs", {

  german <- PosteriorBootstrap::get_german_credit_dataset()
  n_bootstrap <- 10
  prior_variance <- 100

  stan_vb_sample <- PosteriorBootstrap::run_variational_bayes(x = german$x,
                                          y = german$y,
                                          output_samples = n_bootstrap,
                                          beta_sd = sqrt(prior_variance),
                                          iter = 10)
  expect_true(nrow(stan_vb_sample) == n_bootstrap)
  expect_true(ncol(stan_vb_sample) == ncol(german$x))
})

测试在本地和Travis上通过,因此该功能可从 包。

问题

如果我包含library(rstan),小插图代码将起作用:

library(rstan)
prior_sd <- 10
n_bootstrap <- 1000
german <- PosteriorBootstrap::get_german_credit_dataset()
stan_vb_sample <- PosteriorBootstrap::run_variational_bayes(x = german$x,
                                                            y = german$y,
                                                            output_samples = n_bootstrap,
                                                            beta_sd = prior_sd)
dim(stan_vb_sample)
#> [1] 1000   25                                                            

但是我认为用户需要将另一个软件包附加到 用我的包裹。如果我使用requireNamespace(),则可以构建小插图,但是 Stan模型无法运行:

requireNamespace("PosteriorBootstrap", quietly = TRUE)
# ...
stan_vb_sample <- PosteriorBootstrap::run_variational_bayes(x = german$x,
                                                            y = german$y,
                                                            output_samples = n_bootstrap,
                                                            beta_sd = prior_sd)
#> Error in cpp_object_initializer(.self, .refClassDef, ...) : 
#>   could not find function "cpp_object_initializer"
#> failed to create the model; variational Bayes not done
#> Stan model 'bayes_logit' does not contain samples.
dim(stan_vb_sample)
#> NULL

请注意,我在Roxygen中使用了#' @importFrom Rcpp cpp_object_initializer 注释,应该导入rstan说的功能丢失。

与另一个使用rstan的软件包的比较

This packageDESCRIPTION中具有相似的值,但是我测试了它不需要library(rstan) 运行rstan。我在一个函数中使用了@import Rcpp 通过替换@importFrom Rcpp cpp_object_initializer 功能并出现相同的错误。

失败的解决方法

requireNamespace()library()之间的区别在于后者 将包的名称空间导入当前环境。但 rstan进行了import(Rcpp),因此该对象应该可用。

(1)我在小插图中尝试了library("PosteriorBootstrap"),因为 包将该对象导入其名称空间:我遇到了相同的错误( @import Rcpp@importFrom Rcpp cpp_object_initializer)。

(2)我将该对象复制到函数的环境中:

requireNamespace("Rcpp", quietly = TRUE)

#' @import Rcpp
#' @export
run_variational_bayes <- function(x, y, output_samples, beta_sd,
                                  stan_file = get_stan_file(),
                                  iter = 10000, seed = 123, verbose = FALSE) {

  cpp_object_initializer <- Rcpp:cpp_object_initializer
  # ...
}

我很惊讶地得到一个小插图错误:

E  creating vignettes (1.8s)
   Quitting from lines 151-157 (anpl.Rmd) 
   Error: processing vignette 'anpl.Rmd' failed with diagnostics:
   object 'Rcpp' not found
   Execution halted

临时解决方案

作为一个临时解决方案,我将函数中的代码移到了小插图 完全。小插图以requireNamespace()失败:

requireNamespace("rstan")
#> Loading required namespace: rstan
prior_sd <- 10
n_bootstrap <- 1000
german <- PosteriorBootstrap::get_german_credit_dataset()
train_dat <- list(n = length(german$y), p = ncol(german$x), x = german$x, y = german$y, beta_sd = prior_sd)
stan_file <- PosteriorBootstrap::get_stan_file()
stan_model <- rstan::stan_model(file = stan_file)
stan_vb <- rstan::vb(object = stan_model, data = train_dat, seed = seed,
                 output_samples = n_bootstrap)
#> Error in cpp_object_initializer(.self, .refClassDef, ...) : 
#>   could not find function "cpp_object_initializer"
#> failed to create the model; variational Bayes not done
stan_vb_sample <- rstan::extract(stan_vb)$beta
#> Stan model 'bayes_logit' does not contain samples.
dim(stan_vb_sample)
#> NULL

并以library(rstan)成功:

library("rstan")
#> Loading required package: ggplot2
# ...
stan_model <- rstan::stan_model(file = stan_file)
stan_vb <- rstan::vb(object = stan_model, data = train_dat, seed = seed,
                 output_samples = n_bootstrap)
#> Chain 1: ------------------------------------------------------------
# ...
#> Chain 1: COMPLETED.
stan_vb_sample <- rstan::extract(stan_vb)$beta
dim(stan_vb_sample)
#> [1] 1000   25

在将代码移出软件包时,我意识到一个使用 library("rstan")并直接调用rstan程序包,例如

context("Adaptive non-parametric learning function")
library("rstan")
# ...
test_that("Adaptive non-parametric learning with posterior samples works", {

  german <- get_german_credit_dataset()

  n_bootstrap <- 100

  # Get posterior samples
  seed <- 123
  prior_sd <- 10
  train_dat <- list(n = length(german$y), p = ncol(german$x), x = german$x,
                    y = german$y, beta_sd = prior_sd)
  stan_model <- rstan::stan_model(file = get_stan_file())
  stan_vb <- rstan::vb(object = stan_model, data = train_dat, seed = seed,
                       output_samples = n_bootstrap)
  stan_vb_sample <- rstan::extract(stan_vb)$beta
  # ...
}

通过软件包内的测试:

✔ | 24       | Adaptive non-parametric learning function [53.1 s]

══ Results ═════════════════════════════════════════════════════════════════════
Duration: 53.2 s

OK:       24
Failed:   0
Warnings: 0
Skipped:  0

但使用requireNamespace("rstan")进行的相同测试未通过:

⠋ | 21       | Adaptive non-parametric learning functionError in cpp_object_initializer(.self, .refClassDef, ...) : 
  could not find function "cpp_object_initializer"
Stan model 'bayes_logit' does not contain samples.
...
══ Results ═════════════════════════════════════════════════════════════════════
Duration: 51.7 s

OK:       22
Failed:   1
Warnings: 0
Skipped:  0

结论

我想知道rstan代码是否在不使用{ 限定符,如果它是在不继承 调用环境中的对象。

我承认我没有使用cpp_object_initializer来启动程序包 (我的雇主决定坚持使用MIT许可证,并选择不重新启动 包结构从头开始)和我正在编译 通话时的模型。我想用户提供自己的模型会 使用rstantools代替requireNamespace()时会遇到相同的错误。

如何允许用户运行调用library()的程序包函数而无需 rstan,还没用library(rstan)从头开始重启软件包吗?

0 个答案:

没有答案