A fit whose estimator is "maf", "mdn" or "nsf" holds a torch module,
and a torch module is an external pointer. saveRDS() writes the pointer,
not the network: the file reloads without complaint and the object prints
normally, but the first call that touches the network fails with
external pointer is not valid. save_npe() and load_npe() are the
round trip that works.
Usage
save_npe(fit, path)
load_npe(path)
save_nle(fit, path)
load_nle(path)
save_nre(fit, path)
load_nre(path)Arguments
- fit
An
nsbi_npeobject fromnpe()ornpe_sequential(), annsbi_nleobject fromnle(), or annsbi_nreobject fromnre().- path
File to write to (or read from). The convention is
.rds.load_npe()says so when there is no such file.
Details
save_npe() writes one .rds file holding the network's weights (via
torch::torch_save() on its state_dict) alongside everything else the fit
carries as ordinary R objects: the prior, the standardization centers and
scales, parameter and outcome names, the simulation count, and the training
history. load_npe() rebuilds the network from the recorded architecture
and restores the weights, returning an nsbi_npe that behaves exactly like
the one you trained.
A "linear_gaussian" fit holds no torch objects and round-trips through
saveRDS() unharmed; save_npe() accepts it anyway, so saving code does
not have to know which estimator was used.
npe()/nle()/nre() accept a custom density_estimator/classifier
function that returns its own S3-classed object around a torch module.
save_npe() only knows how to rebuild the estimators shipped with this
package ("mdn", "maf", "nsf", and the ratio-estimation network), so it
errors immediately, naming the offending class, on a torch-backed fit whose
estimator is none of those, rather than writing a file that only fails
later, in load_npe(), possibly in a different session.
Weights are saved, not code. A fit saved by one version of neuralsbi loads
into a later one as long as the estimator's architecture has not changed;
load_npe() reports the version that wrote the file when the rebuild fails.
save_nle()/load_nle() and save_nre()/load_nre() are aliases; every
pair handles every kind of fit, and the extra names exist only so calling
code reads the way the fit was made.
A fit trained with device = "cuda"/"mps" (see npe()/nle()) always
reloads onto CPU, never onto the original device: torch::torch_load()
defaults to device = "cpu" regardless of where the tensors were saved
from, and de_rebuild_net() builds the network fresh with no
torch::with_device() in effect. Move it back with
fit2$de$net$to(device = "cuda") if you want the reloaded fit on a GPU.
Examples
prior <- prior_uniform(c(mu = -2, nu = -2), c(mu = 2, nu = 2))
simulator <- function(mu, nu) c(a = mu + rnorm(1, sd = 0.1),
b = nu + rnorm(1, sd = 0.1))
fit <- npe(prior, simulator, n_simulations = 500,
density_estimator = "linear_gaussian")
path <- tempfile(fileext = ".rds")
save_npe(fit, path)
fit2 <- load_npe(path)
sample(posterior(fit2, x_obs = c(0.8, 0.6)), 100)
#> <nsbi_samples> 100 draws x 2 parameters
#> support acceptance rate: 1.000
#> mu nu
#> [1,] 0.7658278 0.5028461
#> [2,] 0.7329452 0.6633359
#> [3,] 0.8288333 0.4377881
#> [4,] 0.7131694 0.5457191
#> [5,] 0.7396945 0.6111406
#> [6,] 0.6878583 0.6829561
unlink(path)
