Skip to content

Commit 9e9d513

Browse files
authored
Merge pull request #1125 from stan-dev/use-qs2
Add qs2 option for saving model objects
2 parents 862ada9 + 1d4bb91 commit 9e9d513

File tree

5 files changed

+56
-49
lines changed

5 files changed

+56
-49
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Suggests:
5252
ggplot2,
5353
knitr (>= 1.37),
5454
loo (>= 2.0.0),
55+
qs2,
5556
rmarkdown,
5657
testthat (>= 2.1.0),
5758
Rcpp

R/fit.R

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,19 @@ CmdStanFit <- R6::R6Class(
108108
#' read into R lazily (i.e., as needed), the `$save_object()` method is the
109109
#' safest way to guarantee that everything has been read in before saving.
110110
#'
111+
#' If you have a big object to save, use `format = "qs2"` to save using the
112+
#' **qs2** package.
113+
#'
111114
#' See the "Saving fitted model objects" section of the
112115
#' [_Getting started with CmdStanR_](https://mc-stan.org/cmdstanr/articles/cmdstanr.html)
113116
#' vignette for some suggestions on faster model saving for large models.
114117
#'
115118
#' @param file (string) Path where the file should be saved.
116-
#' @param ... Other arguments to pass to [base::saveRDS()] besides `object` and `file`.
119+
#' @param format (string) Serialization format for the object. The default is
120+
#' `"rds"`. The `"qs2"` format uses `qs2::qs_save()` and requires the **qs2**
121+
#' package.
122+
#' @param ... Other arguments to pass to [base::saveRDS()] (for `format = "rds"`)
123+
#' or `qs2::qs_save()` (for `format = "qs2"`).
117124
#'
118125
#' @seealso [`CmdStanMCMC`], [`CmdStanMLE`], [`CmdStanVB`], [`CmdStanGQ`]
119126
#'
@@ -129,12 +136,20 @@ CmdStanFit <- R6::R6Class(
129136
#' fit$summary()
130137
#' }
131138
#'
132-
save_object <- function(file, ...) {
139+
save_object <- function(file, format = c("rds", "qs2"), ...) {
133140
self$draws()
134141
try(self$sampler_diagnostics(), silent = TRUE)
135142
try(self$init(), silent = TRUE)
136143
try(self$profiles(), silent = TRUE)
137-
saveRDS(self, file = file, ...)
144+
format <- match.arg(format)
145+
if (format == "rds") {
146+
saveRDS(self, file = file, ...)
147+
} else {
148+
if (!requireNamespace("qs2", quietly = TRUE)) {
149+
stop("The 'qs2' package is required for format = \"qs2\".", call. = FALSE)
150+
}
151+
qs2::qs_save(self, file = file, ...)
152+
}
138153
invisible(self)
139154
}
140155
CmdStanFit$set("public", name = "save_object", value = save_object)

man/fit-method-save_object.Rd

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-fit-shared.R

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,16 @@ test_that("save_object() method works", {
178178
expect_identical(fit$summary(), s)
179179
})
180180

181+
test_that("save_object() method works with qs2 format", {
182+
skip_if_not_installed("qs2")
183+
fit <- fits[["sample"]]
184+
temp_qs_file <- tempfile(fileext = ".qs2")
185+
fit$save_object(temp_qs_file, format = "qs2")
186+
fit2 <- qs2::qs_read(temp_qs_file)
187+
expect_identical(fit2$summary(), fit$summary())
188+
expect_identical(fit2$return_codes(), fit$return_codes())
189+
})
190+
181191
test_that("save_object() method works with profiles", {
182192
mod <- testing_model("logistic_profiling")
183193
utils::capture.output(

vignettes/cmdstanr.Rmd

Lines changed: 17 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,9 @@ fit_pf$print("theta")
432432

433433

434434
Let's extract the draws, make the same plot we made after running the other
435-
algorithms, and compare them all. approximation, and compare them all. In this
436-
simple example the distributions are quite similar, but this will not always be
437-
the case for more challenging problems.
435+
algorithms, and compare them all. In this simple example the distributions are
436+
quite similar, but this will not always be the case for more challenging
437+
problems.
438438

439439
```{r plot-compare-pf, message = FALSE}
440440
mcmc_hist(fit_pf$draws("theta"), binwidth = 0.025) +
@@ -469,57 +469,29 @@ For more details on the `$optimize()`, `$laplace()`, `$variational()`, and
469469
## Saving fitted model objects
470470

471471
The [`$save_object()`](http://mc-stan.org/cmdstanr/reference/fit-method-save_object.html)
472-
method provided by CmdStanR is the most convenient way to save a fitted model object
473-
to disk and ensure that all of the contents are available when reading the object back into R.
472+
method provided by CmdStanR is the most convenient way to save a fitted model
473+
object to disk and ensure that all of the contents are available when reading
474+
the object back into R. By default, `fit$save_object()` will use the `RDS`
475+
format to save the object. The saved object can then be read back into R using
476+
`readRDS()`.
474477

475478
```{r save_object, eval=FALSE}
476479
fit$save_object(file = "fit.RDS")
477480
478-
# can be read back in using readRDS
479481
fit2 <- readRDS("fit.RDS")
480482
```
481483

482-
But if your model object is large, then
483-
[`$save_object()`](http://mc-stan.org/cmdstanr/reference/fit-method-save_object.html)
484-
could take a long time.
485-
[`$save_object()`](http://mc-stan.org/cmdstanr/reference/fit-method-save_object.html)
486-
reads the CmdStan results files into memory, stores them in the model object,
487-
and saves the object with `saveRDS()`. To speed up the process, you can emulate
488-
[`$save_object()`](http://mc-stan.org/cmdstanr/reference/fit-method-save_object.html)
489-
and replace `saveRDS` with the much faster `qsave()` function from the
490-
[`qs`](https://github.com/traversc/qs) package.
484+
But if your model object is large, then `fit$save_object()` can take a long time
485+
if saving in the default RDS format. For large objects, we recommend using the
486+
much faster [`qs2`](https://github.com/traversc/qs2) format. The saved object
487+
can then be read back into R using `qs2::qs_read()`.
491488

492489
```{r save_object_qs_full, eval = FALSE}
493-
# Load CmdStan output files into the fitted model object.
494-
fit$draws() # Load posterior draws into the object.
495-
try(fit$sampler_diagnostics(), silent = TRUE) # Load sampler diagnostics.
496-
try(fit$init(), silent = TRUE) # Load user-defined initial values.
497-
try(fit$profiles(), silent = TRUE) # Load profiling samples.
490+
fit$save_object(file = "fit.qs2", format = "qs2")
498491
499-
# Save the object to a file.
500-
qs::qsave(x = fit, file = "fit.qs")
501-
502-
# Read the object.
503-
fit2 <- qs::qread("fit.qs")
504-
```
505-
506-
Storage is even faster if you discard results you do not need to save.
507-
The following example saves only posterior draws and discards
508-
sampler diagnostics, user-specified initial values, and profiling data.
509-
510-
```{r save_object_qs_small, eval = FALSE}
511-
# Load posterior draws into the fitted model object and omit other output.
512-
fit$draws()
513-
514-
# Save the object to a file.
515-
qs::qsave(x = fit, file = "fit.qs")
516-
517-
# Read the object.
518-
fit2 <- qs::qread("fit.qs")
492+
fit2 <- qs2::qs_read("fit.qs2")
519493
```
520494

521-
See the vignette [_How does CmdStanR work?_](http://mc-stan.org/cmdstanr/articles/cmdstanr-internals.html)
522-
for more information about the composition of CmdStanR objects.
523495

524496
## Comparison with RStan
525497

@@ -537,7 +509,8 @@ To ask a question please post on the Stan forums:
537509

538510
* https://discourse.mc-stan.org/
539511

540-
To report a bug, suggest a feature (including additions to these vignettes), or to start contributing to CmdStanR
541-
development (new contributors welcome!) please open an issue on GitHub:
512+
To report a bug, suggest a feature (including additions to these vignettes), or
513+
to start contributing to CmdStanR development (new contributors welcome!) please
514+
open an issue on GitHub:
542515

543516
* https://github.com/stan-dev/cmdstanr/issues

0 commit comments

Comments
 (0)