Every neuralsbi function that calls a simulator – npe(),
simulate_for_sbi(), npe_sequential(), sbc(), tarp(),
posterior_predictive() – runs it through one execution path. That path is
sequential by default and parallel as soon as you declare a future
plan:
Details
library(future)
plan(multisession) # or multicore, cluster, batchtools, ...
fit <- npe(prior, simulator, n_simulations = 10000)Nothing else changes: no argument to set, no variant of the function to
call. With no plan (or plan(sequential)) the simulations run in the
current process, and neuralsbi mentions the two lines above once per
session. Silence that hint with
options(neuralsbi.parallel_hint = FALSE).
Random numbers
Each simulation gets its own L'Ecuyer-CMRG random-number stream, derived
from the session's RNG state at the moment simulation starts. So
set.seed(42) before a fit (or npe(..., seed = 42)) gives the same
simulations whatever the plan and whatever the worker count: results depend
on the seed alone.
Because the simulations are drawn from separate streams, the simulator no longer consumes the caller's RNG state directly; the state advances by one draw per simulation phase.
Scheduling
Under a multi-process plan the draws are dealt out to workers in batches,
because one future per simulation would spend longer shipping the
simulator to a worker than running it. Batch sizes follow the worker count
and are not a setting: they cannot change a result, since every simulation
has its own RNG stream. Running sequentially there are no batches at all,
just a loop.
Each batch ships the simulator, and everything its environment captures, to
a worker. A simulator closing over a large object therefore pays for that
object once per batch, which is a reason to pass it through sim_args
instead of capturing it.
What is not parallelized
Training runs in the calling process. Torch tensors and modules are external
pointers that cannot be shipped to a worker, and libtorch already uses
multiple threads internally (torch::torch_set_num_threads()). The same
goes for the posterior-sampling loops in sbc() and tarp() – those call
the trained network, not the simulator, and are reported with their own
progress bar.
See also
nsbi_progress for controlling progress bars.
