This vignette is intended to be read after the Getting started with CmdStanR vignette. Please read that first for important background. In this document we provide additional details about compiling models, passing in data, and how CmdStan output is saved and read back into R.
We will only use the $sample() method in examples, but
all model fitting methods work in a similar way under the hood.
The cmdstan_model() function creates a new
CmdStanModel object. The CmdStanModel object
stores the path to a Stan program as well as the path to a compiled
executable.
# Copy the example so the vignette does not modify the CmdStan installation.
example_stan_file <- file.path(
cmdstan_path(), "examples", "bernoulli", "bernoulli.stan"
)
stan_file <- tempfile(pattern = "bernoulli-", fileext = ".stan")
invisible(file.copy(example_stan_file, stan_file))
mod <- cmdstan_model(stan_file)
mod$print()
mod$stan_file()
mod$exe_file()Subsequently, if you create a CmdStanModel object from
the same Stan file then compilation will be skipped (assuming the file
hasn’t changed).
Internally, cmdstan_model() first creates the
CmdStanModel object from just the Stan file and then calls
its $compile()
method. Optional arguments to the $compile() method can be
passed via ....
It is also possible to delay compilation when creating the
CmdStanModel object by specifying
compile=FALSE and then later calling the
$compile() method directly.
CmdStanR will always check that your Stan program does not contain
any invalid syntax but with pedantic mode enabled the check
will also warn you about other potential issues in your model, for
example:
~ symbols).For the latest information on the checks performed in pedantic mode see the Pedantic mode section in the Stan User’s Guide.
Pedantic mode is available when compiling the model or when using the
separate $check_syntax() method of a
CmdStanModel object. Internally this corresponds to setting
the stanc (Stan transpiler) option
warn-pedantic. Here we demonstrate pedantic mode with a
Stan program that is syntactically correct but is missing a lower bound
and a prior for a parameter.
stan_file_pedantic <- write_stan_file("
data {
int N;
array[N] int y;
}
parameters {
// should have <lower=0> but omitting to demonstrate pedantic mode
real lambda;
}
model {
y ~ poisson(lambda);
}
")To turn on pedantic mode at compile time you can set
pedantic=TRUE in the call to cmdstan_model()
(or when calling the $compile() method directly if using
the delayed compilation approach described above).
To turn on pedantic mode separately from compilation use the
pedantic argument to the $check_syntax()
method.
Using pedantic=TRUE via the $check_syntax()
method also has the advantage that it can be used even if the model
hasn’t been compiled yet. This can be helpful because the pedantic and
syntax checks themselves are much faster than compilation.
You can obtain the names, types and dimensions of the data,
parameters, transformed parameters and generated quantities variables of
a Stan model using the $variables() method of the
CmdStanModel object. This method works whether or not the
model has been compiled. Here we use compile = FALSE
because compilation is not required.
stan_file_variables <- write_stan_file("
data {
int<lower=1> J;
vector<lower=0>[J] sigma;
vector[J] y;
}
parameters {
real mu;
real<lower=0> tau;
vector[J] theta_raw;
}
transformed parameters {
vector[J] theta = mu + tau * theta_raw;
}
model {
target += normal_lpdf(tau | 0, 10);
target += normal_lpdf(mu | 0, 10);
target += normal_lpdf(theta_raw | 0, 1);
target += normal_lpdf(y | theta, sigma);
}
")
mod_v <- cmdstan_model(stan_file_variables, compile = FALSE)
variables <- mod_v$variables()The $variables() method returns a list with
data, parameters,
transformed_parameters and
generated_quantities elements, each corresponding to
variables in their respective block of the program. Transformed data
variables are not listed as they are not used in the model’s input or
output.
names(variables)
names(variables$data)
names(variables$parameters)
names(variables$transformed_parameters)
names(variables$generated_quantities)Each variable is represented as a list containing the type
information (currently limited to real or int)
and the number of dimensions.
There are three data formats that CmdStanR allows when fitting a model:
Like the RStan interface, CmdStanR accepts a named list of R objects
where the names correspond to variables declared in the data block of
the Stan program. In the Bernoulli model the data is N, the
number of data points, and y an integer array of
observations.
# data block has 'N' and 'y'
data_list <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))
fit <- mod$sample(data = data_list)Because CmdStan doesn’t accept lists of R objects, CmdStanR will
first write the data to a temporary JSON file using
write_stan_json(). This happens internally, but it is also
possible to call write_stan_json() directly.
If you already have your data in a JSON file you can just pass that
file directly to CmdStanR instead of using a list of R objects. For
example, we could pass in the JSON file we created above using
write_stan_json():
CmdStanR also accepts data in the R dump format because CmdStan supports it. However, JSON is faster for CmdStan to process and is the recommended file format.
When fitting a model, the default behavior is to write the output from CmdStan to CSV files in a temporary directory.
These files will be lost if you end your R session or if you remove
the fit object and force (or wait for) garbage
collection.
To save these files to a non-temporary location there are two
options. You can either specify the output_dir argument to
mod$sample() or use fit$save_output_files()
after fitting the model.
With the exception of some diagnostic information, the CSV files are
not read into R until their contents are requested by calling a method
that requires them (e.g., fit$draws(),
fit$summary(), etc.). If we examine the structure of the
fit object, notice how the Private slot
draws_ is NULL, indicating that the CSV files
haven’t yet been read into R.
After we call a method that requires the draws then if we reexamine
the structure of the object we will see that the draws_
slot in Private is no longer empty.
For models with many parameters, transformed parameters, or generated
quantities, if only some are requested (e.g., by specifying the
variables argument to fit$draws()) then
CmdStanR will only read in the requested variables (unless they have
already been read in).
Internally, the read_cmdstan_csv() function is used to
read the CmdStan CSV files into R. This function is exposed to users, so
you can also call it directly.
If you need to manually create fitted model objects from CmdStan CSV
files use as_cmdstan_fit().
This is pointless in our case since we have the original
fit object, but this function can be used to create fitted
model objects (CmdStanMCMC, CmdStanMLE, etc.)
from CmdStan CSV files.
If save_latent_dynamics is set to TRUE when
running the $sample() method then additional CSV files are
created (one per chain) that provide access to quantities used under the
hood by Stan’s implementation of dynamic Hamiltonian Monte Carlo.
CmdStanR does not yet provide a special method for processing these files but they can be read into R using R’s standard CSV reading functions.
fit$latent_dynamics_files()
# read one of the files in
x <- utils::read.csv(fit$latent_dynamics_files()[1], comment.char = "#")
head(x)The column lp__ is also provided via
fit$draws(), and the columns accept_stat__,
stepsize__, treedepth__,
n_leapfrog__, divergent__, and
energy__ are also provided by
fit$sampler_diagnostics(), but there are several columns
unique to the latent dynamics file.
Our model has a single parameter theta and the three
columns above correspond to theta in the
unconstrained space (theta on the constrained
space is accessed via fit$draws()), the auxiliary momentum
p_theta, and the gradient g_theta. In general,
these three quantities are recorded for every parameter in the model.
Container parameters are organized into columns for each scalar element
in the unconstrained parameterization. CmdStan uses period-separated
indices for these elements, for example theta.1,
p_theta.1, and g_theta.1. See the diagnostic
CSV output documentation for more details.
CmdStanR can of course be used for developing other packages that require compiling and running Stan models as well as using new or custom Stan features available through CmdStan. Even though CmdStanR is not itself on CRAN, it can still be used by packages that are on CRAN.
Stan models used by an R package can be compiled at runtime or during installation from source. Installation-time compilation builds executables on the installing system so they can be reused without recompilation at runtime. This is different from including compiled executables in the source package: compiled artifacts are generally not portable across platforms, and CRAN source packages may not contain binary executable code.
The instantiate
package provides a current workflow for installation-time compilation.
See the instantiate documentation for requirements,
limitations, and advice on preparing for CRAN submission.
When developing or testing new features it might be useful to have
more information on how CmdStan is called internally and to see more
information printed when compiling or running models. This can be
enabled for an entire R session by setting the option
"cmdstanr_verbose" to TRUE.