Bayes' rule turns an nle() fit into a posterior,
\(p(\theta \mid x) \propto q_\phi(x \mid \theta)\,p(\theta)\), but the
result has no closed form and no direct sampler. posterior() on an
nsbi_nle therefore returns an object that samples with MCMC, and
sample() on it runs a chain rather than a forward pass.
Arguments
- fit
An
nsbi_nleobject fromnle().- x_obs
Observation to condition on. Rows are treated as independent observations from the same parameter, and the log-likelihood sums over them.
- sampler
"slice"(the default) or"stan".- n_chains
Number of chains. The default depends on the sampler: 20 for
"slice", which evaluates every chain in one batched call per step and so pays almost nothing for more of them, and 4 for"stan", where each chain is a separate process with its own warmup to pay for.- warmup
Steps discarded at the start of each chain.
- thin
Keep one draw in
thin. The default is 2: the slice width is adapted during warmup, and with that the retained draws are already close to independent – on a Gaussian target with 20 chains,thin = 2gives a bulk ESS of about 96% of them. Since each evaluation is a forward pass over every observation, thinning harder buys very little for what it costs. Raise it if the reported ESS says you need to. (Pythonsbithins by 1 by default; it thinned by 10 up to v0.21.)- init_strategy
"resample"(default, andsbi's) weights a pool of prior draws by the posterior density and resamples the starting points from it, drawing more pools as needed if the first one lands fewer thann_chainsdraws in the posterior's support;"proposal"skips the weighting and keeps whichever prior draws land inside the posterior's support, also drawing more pools as needed."proposal"is cheaper per accepted draw, but every draw the posterior excludes is wasted: if only a fractionaof the prior's mass survives, roughly1 / adraws are needed per starting point, so a posterior that rules out most of the prior can make"proposal"far slower than"resample"to find enough starting points, and it errors out once its draw budget is spent. The pool is 1000 draws, set withn_pool.sbiuses 10,000 per chain, which on a surrogate summed over thousands of observations is a large bill before the first MCMC step.- seed
Optional integer seed.
- max_batch
Largest number of
(theta, x)pairs evaluated in one call to the estimator, both at every MCMC step and inlog_prob(). Only affects memory and speed; seemax_batchonlog_lik()for the same knob on a direct likelihood evaluation.- ...
Further arguments to the sampler:
width,max_stepsandn_poolfor"slice", oriter_warmup,iter_samplingandrefreshfor"stan".
Details
Two samplers are available. "slice" is the default: a vectorized
univariate slice sampler (see nsbi_mcmc) with nothing to tune and no
dependencies. "stan" writes the fitted likelihood out as a Stan program
(see stan_code()) and runs NUTS on it through cmdstanr or
rstan, which mixes better on correlated posteriors at the cost of a
one-time model compile.
Examples
prior <- prior_uniform(c(mu = -3), c(mu = 3))
fit <- nle(prior, function(mu) c(y = rnorm(1, mu, 0.5)),
n_simulations = 1000, density_estimator = "linear_gaussian")
x_obs <- matrix(rnorm(50, mean = 1, sd = 0.5), ncol = 1)
post <- posterior(fit, x_obs, n_chains = 4, warmup = 50, thin = 2)
draws <- sample(post, 400)
colMeans(draws)
#> mu
#> 1.094471
