From bf875dd4928e0170dba7079388e9373cd828bce7 Mon Sep 17 00:00:00 2001 From: hyunjimoon Date: Sat, 4 Sep 2021 02:16:40 -0400 Subject: [PATCH 1/4] backend work for stan supported nonHMC samplers --- NAMESPACE | 6 ++ R/backends.R | 81 ++++++++++++++++++++++++++ R/results.R | 2 +- man/SBC_backend_cmdstan_optimize.Rd | 18 ++++++ man/SBC_backend_cmdstan_variational.Rd | 18 ++++++ man/compute_results.Rd | 4 +- 6 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 man/SBC_backend_cmdstan_optimize.Rd create mode 100644 man/SBC_backend_cmdstan_variational.Rd diff --git a/NAMESPACE b/NAMESPACE index c0b5cae..2750c14 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,13 +3,17 @@ S3method("[",SBC_datasets) S3method("[",SBC_results) S3method(SBC_fit,SBC_backend_brms) +S3method(SBC_fit,SBC_backend_cmdstan_optimize) S3method(SBC_fit,SBC_backend_cmdstan_sample) +S3method(SBC_fit,SBC_backend_cmdstan_variational) S3method(SBC_fit,SBC_backend_rstan_sample) S3method(SBC_fit_to_diagnostics,CmdStanMCMC) S3method(SBC_fit_to_diagnostics,brmsfit) S3method(SBC_fit_to_diagnostics,default) S3method(SBC_fit_to_diagnostics,stanfit) S3method(SBC_fit_to_draws_matrix,CmdStanMCMC) +S3method(SBC_fit_to_draws_matrix,CmdStanMLE) +S3method(SBC_fit_to_draws_matrix,CmdStanVB) S3method(SBC_fit_to_draws_matrix,brmsfit) S3method(SBC_fit_to_draws_matrix,default) S3method(check_all_SBC_diagnostics,SBC_results) @@ -33,7 +37,9 @@ S3method(summary,SBC_nuts_diagnostics) S3method(summary,SBC_results) export(SBC_backend_brms) export(SBC_backend_brms_from_generator) +export(SBC_backend_cmdstan_optimize) export(SBC_backend_cmdstan_sample) +export(SBC_backend_cmdstan_variational) export(SBC_backend_rstan_sample) export(SBC_datasets) export(SBC_diagnostic_messages) diff --git a/R/backends.R b/R/backends.R index f2d113a..ce4df9a 100644 --- a/R/backends.R +++ b/R/backends.R @@ -267,6 +267,87 @@ SBC_fit_to_diagnostics.CmdStanMCMC <- function(fit, fit_output, fit_messages, fi res } +#' Backend based on variational approximation via `cmdstanr`. +#' +#' @param model an object of class `CmdStanModel` (as created by `cmdstanr::cmdstan_model`) +#' @param ... other arguments passed to the `$variational()` method of the model. The `data` and +#' `parallel_chains` arguments cannot be set this way as they need to be controlled by the SBC +#' package. +#' @export +SBC_backend_cmdstan_variational <- function(model, ...) { + stopifnot(inherits(model, "CmdStanModel")) + if(length(model$exe_file()) == 0) { + stop("The model has to be already compiled, call $compile() first.") + } + args <- list(...) + unacceptable_params <- c("data", "parallel_chains ", "cores", "num_cores") + if(any(names(args) %in% unacceptable_params)) { + stop(paste0("Parameters ", paste0("'", unacceptable_params, "'", collapse = ", "), + " cannot be provided when defining a backend as they need to be set ", + "by the SBC package")) + } + structure(list(model = model, args = args), class = "SBC_backend_cmdstan_variational") +} + +#' @export +SBC_fit.SBC_backend_cmdstan_variational <- function(backend, generated, cores) { + fit <- do.call(backend$model$variational, + combine_args(backend$args, + list( + data = generated, + parallel_chains = cores))) + + if(all(fit$return_codes() != 0)) { + stop("No chains finished succesfully") + } + + fit +} + +#' @export +SBC_fit_to_draws_matrix.CmdStanVB <- function(fit) { + fit$draws(format = "draws_matrix") +} + +#' Backend based on optimize approximation via `cmdstanr`. +#' +#' @param model an object of class `CmdStanModel` (as created by `cmdstanr::cmdstan_model`) +#' @param ... other arguments passed to the `$optimize()` method of the model. The `data` and +#' `parallel_chains` arguments cannot be set this way as they need to be controlled by the SBC +#' package. +#' @export +SBC_backend_cmdstan_optimize <- function(model, ...) { + stopifnot(inherits(model, "CmdStanModel")) + if(length(model$exe_file()) == 0) { + stop("The model has to be already compiled, call $compile() first.") + } + args <- list(...) + unacceptable_params <- c("data") + if(any(names(args) %in% unacceptable_params)) { + stop(paste0("Parameters ", paste0("'", unacceptable_params, "'", collapse = ", "), + " cannot be provided when defining a backend as they need to be set ", + "by the SBC package")) + } + structure(list(model = model, args = args), class = "SBC_backend_cmdstan_optimize") +} +#' @export +SBC_fit.SBC_backend_cmdstan_optimize <- function(backend, generated, cores) { + fit <- do.call(backend$model$optimize, + combine_args(backend$args, + list( + data = generated))) + + if(all(fit$return_codes() != 0)) { + stop("Point optimization failed!") + } + + fit +} +#' @export +SBC_fit_to_draws_matrix.CmdStanMLE <- function(fit) { + fit$draws(format = "draws_matrix") +} + # For internal use, creates brms backend. new_SBC_backend_brms <- function(compiled_model, args diff --git a/R/results.R b/R/results.R index 2d94a68..aec1bb1 100644 --- a/R/results.R +++ b/R/results.R @@ -217,7 +217,7 @@ length.SBC_results <- function(x) { #' #' @param datasets an object of class `SBC_datasets` #' @param backend the model + sampling algorithm. The built-in backends can be constructed -#' using `SBC_backend_cmdstan_sample()`, `SBC_backend_rstan_sample()` and `SBC_backend_brms()`. +#' using `SBC_backend_cmdstan_sample()`, `SBC_backend_cmdstan_variational()`,`SBC_backend_cmdstan_optimize()`, `SBC_backend_rstan_sample()` and `SBC_backend_brms()`. #' (more to come). The backend is an S3 class supporting at least the `SBC_fit`, #' `SBC_fit_to_draws_matrix` methods. #' @param cores_per_fit how many cores should the backend be allowed to use for a single fit? diff --git a/man/SBC_backend_cmdstan_optimize.Rd b/man/SBC_backend_cmdstan_optimize.Rd new file mode 100644 index 0000000..6731809 --- /dev/null +++ b/man/SBC_backend_cmdstan_optimize.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/backends.R +\name{SBC_backend_cmdstan_optimize} +\alias{SBC_backend_cmdstan_optimize} +\title{Backend based on optimize approximation via \code{cmdstanr}.} +\usage{ +SBC_backend_cmdstan_optimize(model, ...) +} +\arguments{ +\item{model}{an object of class \code{CmdStanModel} (as created by \code{cmdstanr::cmdstan_model})} + +\item{...}{other arguments passed to the \verb{$variational()} method of the model. The \code{data} and +\code{parallel_chains} arguments cannot be set this way as they need to be controlled by the SBC +package.} +} +\description{ +Backend based on optimize approximation via \code{cmdstanr}. +} diff --git a/man/SBC_backend_cmdstan_variational.Rd b/man/SBC_backend_cmdstan_variational.Rd new file mode 100644 index 0000000..ad07463 --- /dev/null +++ b/man/SBC_backend_cmdstan_variational.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/backends.R +\name{SBC_backend_cmdstan_variational} +\alias{SBC_backend_cmdstan_variational} +\title{Backend based on variational approximation via \code{cmdstanr}.} +\usage{ +SBC_backend_cmdstan_variational(model, ...) +} +\arguments{ +\item{model}{an object of class \code{CmdStanModel} (as created by \code{cmdstanr::cmdstan_model})} + +\item{...}{other arguments passed to the \verb{$variational()} method of the model. The \code{data} and +\code{parallel_chains} arguments cannot be set this way as they need to be controlled by the SBC +package.} +} +\description{ +Backend based on variational approximation via \code{cmdstanr}. +} diff --git a/man/compute_results.Rd b/man/compute_results.Rd index af6a5ca..8ebe0a8 100644 --- a/man/compute_results.Rd +++ b/man/compute_results.Rd @@ -18,7 +18,7 @@ compute_results( \item{datasets}{an object of class \code{SBC_datasets}} \item{backend}{the model + sampling algorithm. The built-in backends can be constructed -using \code{SBC_backend_cmdstan_sample()}, \code{SBC_backend_rstan_sample()} and \code{SBC_backend_brms()}. +using \code{SBC_backend_cmdstan_sample()}, \code{SBC_backend_cmdstan_optimize()}, \code{SBC_backend_rstan_sample()} and \code{SBC_backend_brms()}. (more to come). The backend is an S3 class supporting at least the \code{SBC_fit}, \code{SBC_fit_to_draws_matrix} methods.} @@ -44,7 +44,7 @@ the work may be distributed less equally across workers. We recommend setting th enough that a single batch takes at least several seconds, i.e. for small models, you can often reduce computation time noticeably by increasing this value. You can use \code{options(SBC.min_chunk_size = value)} to set a minimum chunk size globally. -See documentation of \code{future.chunk.size} argument for \code{future_lapply()} for more details.} +See documentation of \code{future.chunk.size} argument for \code{future.apply::future_lapply()} for more details.} } \value{ An object of class \code{SBC_results} that holds: From b31ea60611708061ba8dd53ee3b882ce98b9cdf8 Mon Sep 17 00:00:00 2001 From: Dashadower Date: Mon, 6 Sep 2021 10:13:00 +0900 Subject: [PATCH 2/4] Support variational, disable optimize for now --- R/backends.R | 16 ++++++++-------- R/results.R | 7 +++++-- man/SBC_backend_cmdstan_optimize.Rd | 2 +- man/compute_results.Rd | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/R/backends.R b/R/backends.R index ce4df9a..450b3c7 100644 --- a/R/backends.R +++ b/R/backends.R @@ -294,8 +294,7 @@ SBC_fit.SBC_backend_cmdstan_variational <- function(backend, generated, cores) { fit <- do.call(backend$model$variational, combine_args(backend$args, list( - data = generated, - parallel_chains = cores))) + data = generated))) if(all(fit$return_codes() != 0)) { stop("No chains finished succesfully") @@ -307,6 +306,7 @@ SBC_fit.SBC_backend_cmdstan_variational <- function(backend, generated, cores) { #' @export SBC_fit_to_draws_matrix.CmdStanVB <- function(fit) { fit$draws(format = "draws_matrix") + } #' Backend based on optimize approximation via `cmdstanr`. @@ -317,6 +317,7 @@ SBC_fit_to_draws_matrix.CmdStanVB <- function(fit) { #' package. #' @export SBC_backend_cmdstan_optimize <- function(model, ...) { + stop("The optimize method is currently not supported.") stopifnot(inherits(model, "CmdStanModel")) if(length(model$exe_file()) == 0) { stop("The model has to be already compiled, call $compile() first.") @@ -334,14 +335,13 @@ SBC_backend_cmdstan_optimize <- function(model, ...) { SBC_fit.SBC_backend_cmdstan_optimize <- function(backend, generated, cores) { fit <- do.call(backend$model$optimize, combine_args(backend$args, - list( - data = generated))) + list(data = generated))) - if(all(fit$return_codes() != 0)) { - stop("Point optimization failed!") - } + if(all(fit$return_codes() != 0)) { + stop("Point optimization failed!") + } - fit + fit } #' @export SBC_fit_to_draws_matrix.CmdStanMLE <- function(fit) { diff --git a/R/results.R b/R/results.R index aec1bb1..3527957 100644 --- a/R/results.R +++ b/R/results.R @@ -271,7 +271,6 @@ compute_results <- function(datasets, backend, generated = datasets$generated[[i]] ) } - if(is.null(gen_quants)) { future.globals <- FALSE } else { @@ -288,6 +287,7 @@ compute_results <- function(datasets, backend, future.globals = future.globals, future.chunk.size = chunk_size) + print("reached1") # Combine, check and summarise fits <- rep(list(NULL), length(datasets)) @@ -306,8 +306,11 @@ compute_results <- function(datasets, backend, if(is.null(results_raw[[i]]$error)) { stats_list[[i]] <- results_raw[[i]]$stats stats_list[[i]]$dataset_id <- i + print(results_raw[[i]]$backend_diagnostics) backend_diagnostics_list[[i]] <- results_raw[[i]]$backend_diagnostics - backend_diagnostics_list[[i]]$dataset_id <- i + if(!is.null(results_raw[[i]]$backend_diagnostics)){ + backend_diagnostics_list[[i]]$dataset_id <- i + } } else { if(n_errors < max_errors_to_show) { diff --git a/man/SBC_backend_cmdstan_optimize.Rd b/man/SBC_backend_cmdstan_optimize.Rd index 6731809..6f4d16c 100644 --- a/man/SBC_backend_cmdstan_optimize.Rd +++ b/man/SBC_backend_cmdstan_optimize.Rd @@ -9,7 +9,7 @@ SBC_backend_cmdstan_optimize(model, ...) \arguments{ \item{model}{an object of class \code{CmdStanModel} (as created by \code{cmdstanr::cmdstan_model})} -\item{...}{other arguments passed to the \verb{$variational()} method of the model. The \code{data} and +\item{...}{other arguments passed to the \verb{$optimize()} method of the model. The \code{data} and \code{parallel_chains} arguments cannot be set this way as they need to be controlled by the SBC package.} } diff --git a/man/compute_results.Rd b/man/compute_results.Rd index 8ebe0a8..5a6aab0 100644 --- a/man/compute_results.Rd +++ b/man/compute_results.Rd @@ -18,7 +18,7 @@ compute_results( \item{datasets}{an object of class \code{SBC_datasets}} \item{backend}{the model + sampling algorithm. The built-in backends can be constructed -using \code{SBC_backend_cmdstan_sample()}, \code{SBC_backend_cmdstan_optimize()}, \code{SBC_backend_rstan_sample()} and \code{SBC_backend_brms()}. +using \code{SBC_backend_cmdstan_sample()}, \code{SBC_backend_cmdstan_variational()},\code{SBC_backend_cmdstan_optimize()}, \code{SBC_backend_rstan_sample()} and \code{SBC_backend_brms()}. (more to come). The backend is an S3 class supporting at least the \code{SBC_fit}, \code{SBC_fit_to_draws_matrix} methods.} From b26c87f8a543c483bcf083ffdad0734a01e33100 Mon Sep 17 00:00:00 2001 From: Dashadower Date: Mon, 6 Sep 2021 10:16:37 +0900 Subject: [PATCH 3/4] Remove debug code --- R/results.R | 3 --- 1 file changed, 3 deletions(-) diff --git a/R/results.R b/R/results.R index 3527957..0b4ac80 100644 --- a/R/results.R +++ b/R/results.R @@ -287,8 +287,6 @@ compute_results <- function(datasets, backend, future.globals = future.globals, future.chunk.size = chunk_size) - print("reached1") - # Combine, check and summarise fits <- rep(list(NULL), length(datasets)) outputs <- rep(list(NULL), length(datasets)) @@ -306,7 +304,6 @@ compute_results <- function(datasets, backend, if(is.null(results_raw[[i]]$error)) { stats_list[[i]] <- results_raw[[i]]$stats stats_list[[i]]$dataset_id <- i - print(results_raw[[i]]$backend_diagnostics) backend_diagnostics_list[[i]] <- results_raw[[i]]$backend_diagnostics if(!is.null(results_raw[[i]]$backend_diagnostics)){ backend_diagnostics_list[[i]]$dataset_id <- i From 5d5b3410e580f19e7eaa119ba9974f517b303e00 Mon Sep 17 00:00:00 2001 From: hyunjimoon Date: Tue, 7 Sep 2021 05:27:05 -0400 Subject: [PATCH 4/4] address variational backend issue 35 --- NAMESPACE | 3 -- R/.Rapp.history | 0 R/backends.R | 43 ++--------------------------- R/results.R | 6 ++-- man/SBC_backend_cmdstan_optimize.Rd | 18 ------------ man/compute_results.Rd | 6 ++-- 6 files changed, 8 insertions(+), 68 deletions(-) create mode 100644 R/.Rapp.history delete mode 100644 man/SBC_backend_cmdstan_optimize.Rd diff --git a/NAMESPACE b/NAMESPACE index 2750c14..6e6d874 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,7 +3,6 @@ S3method("[",SBC_datasets) S3method("[",SBC_results) S3method(SBC_fit,SBC_backend_brms) -S3method(SBC_fit,SBC_backend_cmdstan_optimize) S3method(SBC_fit,SBC_backend_cmdstan_sample) S3method(SBC_fit,SBC_backend_cmdstan_variational) S3method(SBC_fit,SBC_backend_rstan_sample) @@ -12,7 +11,6 @@ S3method(SBC_fit_to_diagnostics,brmsfit) S3method(SBC_fit_to_diagnostics,default) S3method(SBC_fit_to_diagnostics,stanfit) S3method(SBC_fit_to_draws_matrix,CmdStanMCMC) -S3method(SBC_fit_to_draws_matrix,CmdStanMLE) S3method(SBC_fit_to_draws_matrix,CmdStanVB) S3method(SBC_fit_to_draws_matrix,brmsfit) S3method(SBC_fit_to_draws_matrix,default) @@ -37,7 +35,6 @@ S3method(summary,SBC_nuts_diagnostics) S3method(summary,SBC_results) export(SBC_backend_brms) export(SBC_backend_brms_from_generator) -export(SBC_backend_cmdstan_optimize) export(SBC_backend_cmdstan_sample) export(SBC_backend_cmdstan_variational) export(SBC_backend_rstan_sample) diff --git a/R/.Rapp.history b/R/.Rapp.history new file mode 100644 index 0000000..e69de29 diff --git a/R/backends.R b/R/backends.R index 450b3c7..7366dbb 100644 --- a/R/backends.R +++ b/R/backends.R @@ -280,7 +280,7 @@ SBC_backend_cmdstan_variational <- function(model, ...) { stop("The model has to be already compiled, call $compile() first.") } args <- list(...) - unacceptable_params <- c("data", "parallel_chains ", "cores", "num_cores") + unacceptable_params <- c("data") if(any(names(args) %in% unacceptable_params)) { stop(paste0("Parameters ", paste0("'", unacceptable_params, "'", collapse = ", "), " cannot be provided when defining a backend as they need to be set ", @@ -297,7 +297,7 @@ SBC_fit.SBC_backend_cmdstan_variational <- function(backend, generated, cores) { data = generated))) if(all(fit$return_codes() != 0)) { - stop("No chains finished succesfully") + stop("Variational inference did not finish succesfully") } fit @@ -309,45 +309,6 @@ SBC_fit_to_draws_matrix.CmdStanVB <- function(fit) { } -#' Backend based on optimize approximation via `cmdstanr`. -#' -#' @param model an object of class `CmdStanModel` (as created by `cmdstanr::cmdstan_model`) -#' @param ... other arguments passed to the `$optimize()` method of the model. The `data` and -#' `parallel_chains` arguments cannot be set this way as they need to be controlled by the SBC -#' package. -#' @export -SBC_backend_cmdstan_optimize <- function(model, ...) { - stop("The optimize method is currently not supported.") - stopifnot(inherits(model, "CmdStanModel")) - if(length(model$exe_file()) == 0) { - stop("The model has to be already compiled, call $compile() first.") - } - args <- list(...) - unacceptable_params <- c("data") - if(any(names(args) %in% unacceptable_params)) { - stop(paste0("Parameters ", paste0("'", unacceptable_params, "'", collapse = ", "), - " cannot be provided when defining a backend as they need to be set ", - "by the SBC package")) - } - structure(list(model = model, args = args), class = "SBC_backend_cmdstan_optimize") -} -#' @export -SBC_fit.SBC_backend_cmdstan_optimize <- function(backend, generated, cores) { - fit <- do.call(backend$model$optimize, - combine_args(backend$args, - list(data = generated))) - - if(all(fit$return_codes() != 0)) { - stop("Point optimization failed!") - } - - fit -} -#' @export -SBC_fit_to_draws_matrix.CmdStanMLE <- function(fit) { - fit$draws(format = "draws_matrix") -} - # For internal use, creates brms backend. new_SBC_backend_brms <- function(compiled_model, args diff --git a/R/results.R b/R/results.R index 0b4ac80..385121b 100644 --- a/R/results.R +++ b/R/results.R @@ -212,13 +212,13 @@ length.SBC_results <- function(x) { #' #' Parallel processing is supported via the `future` package, for most uses, it is most sensible #' to just call `plan(multisession)` once in your R session and all -#' cores your computer has will be used. For more details refer to the documentation +#' cores your computer will be used. For more details refer to the documentation #' of the `future` package. #' #' @param datasets an object of class `SBC_datasets` #' @param backend the model + sampling algorithm. The built-in backends can be constructed -#' using `SBC_backend_cmdstan_sample()`, `SBC_backend_cmdstan_variational()`,`SBC_backend_cmdstan_optimize()`, `SBC_backend_rstan_sample()` and `SBC_backend_brms()`. -#' (more to come). The backend is an S3 class supporting at least the `SBC_fit`, +#' using `SBC_backend_cmdstan_sample()`, `SBC_backend_cmdstan_variational()`, `SBC_backend_rstan_sample()` and `SBC_backend_brms()`. +#' (more to come: issue 31, 38, 39). The backend is an S3 class supporting at least the `SBC_fit`, #' `SBC_fit_to_draws_matrix` methods. #' @param cores_per_fit how many cores should the backend be allowed to use for a single fit? #' Defaults to the maximum number that does not produce more parallel chains diff --git a/man/SBC_backend_cmdstan_optimize.Rd b/man/SBC_backend_cmdstan_optimize.Rd deleted file mode 100644 index 6f4d16c..0000000 --- a/man/SBC_backend_cmdstan_optimize.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/backends.R -\name{SBC_backend_cmdstan_optimize} -\alias{SBC_backend_cmdstan_optimize} -\title{Backend based on optimize approximation via \code{cmdstanr}.} -\usage{ -SBC_backend_cmdstan_optimize(model, ...) -} -\arguments{ -\item{model}{an object of class \code{CmdStanModel} (as created by \code{cmdstanr::cmdstan_model})} - -\item{...}{other arguments passed to the \verb{$optimize()} method of the model. The \code{data} and -\code{parallel_chains} arguments cannot be set this way as they need to be controlled by the SBC -package.} -} -\description{ -Backend based on optimize approximation via \code{cmdstanr}. -} diff --git a/man/compute_results.Rd b/man/compute_results.Rd index 5a6aab0..18cffab 100644 --- a/man/compute_results.Rd +++ b/man/compute_results.Rd @@ -18,8 +18,8 @@ compute_results( \item{datasets}{an object of class \code{SBC_datasets}} \item{backend}{the model + sampling algorithm. The built-in backends can be constructed -using \code{SBC_backend_cmdstan_sample()}, \code{SBC_backend_cmdstan_variational()},\code{SBC_backend_cmdstan_optimize()}, \code{SBC_backend_rstan_sample()} and \code{SBC_backend_brms()}. -(more to come). The backend is an S3 class supporting at least the \code{SBC_fit}, +using \code{SBC_backend_cmdstan_sample()}, \code{SBC_backend_cmdstan_variational()}, \code{SBC_backend_rstan_sample()} and \code{SBC_backend_brms()}. +(more to come: issue 31, 38, 39). The backend is an S3 class supporting at least the \code{SBC_fit}, \code{SBC_fit_to_draws_matrix} methods.} \item{cores_per_fit}{how many cores should the backend be allowed to use for a single fit? @@ -60,6 +60,6 @@ An object of class \code{SBC_results} that holds: \description{ Parallel processing is supported via the \code{future} package, for most uses, it is most sensible to just call \code{plan(multisession)} once in your R session and all -cores your computer has will be used. For more details refer to the documentation +cores your computer will be used. For more details refer to the documentation of the \code{future} package. }