--- title: "Guide to neural SBI methods" description: > The methods neuralsbi implements, the paper behind each one, and the function that runs it. output: rmarkdown::html_vignette bibliography: ../inst/REFERENCES.bib link-citations: true vignette: > %\VignetteIndexEntry{Guide to neural SBI methods} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- This page maps each method in `neuralsbi` to the paper it comes from and the function that runs it. For a worked example, read `vignette("neuralsbi")` instead. ## Key papers - @cranmer2020frontier survey the field and set the NPE/NLE/NRE naming used here. - @lueckmann2021benchmarking compare these methods on a shared set of tasks. - @deistler2025practical give the applied workflow, from simulator and prior through training to diagnostics. ## Neural posterior estimation (NPE) - @papamakarios2016npe introduced neural posterior estimation, training a conditional density estimator on prior draws so the fitted network is the posterior. - `npe()` implements the single-round amortized case. Conditioning on a new observation costs one forward pass through `posterior()`, then `sample()`. ## Sequential neural posterior estimation - @greenberg2019apt introduced automatic posterior transformation, which reweights the loss when draws come from a proposal rather than the prior. - @deistler2022tsnpe introduced truncated proposals, which restrict the prior to the current posterior's highest-probability region and leave the plain NPE loss valid. - `npe_sequential()` implements truncated proposals. The result is not amortized and holds only near the observation it was trained on. ## Neural likelihood estimation (NLE) - @papamakarios2019snl introduced sequential neural likelihood, learning the surrogate likelihood \(q(x \mid \theta)\) and recovering the posterior through Bayes' rule. - `nle()` implements the single-round case, so repeated independent observations are a sum over one trained density. Evaluate it with `log_lik()` and sample it through `posterior()`. - @neal2003slice introduced slice sampling, which `posterior()` uses by default. `stan_code()` writes the estimator out as Stan code instead. ## Neural likelihood-ratio estimation (NRE) - @hermans2020nre introduced amortized approximate likelihood-ratio estimation, training a binary classifier for \(r(\theta, x) = p(x \mid \theta) / p(x)\) rather than either density. - @durkan2020contrastive introduced the atomic contrastive objective, which scores the true parameter against contrasting draws from the same minibatch. - `nre()` implements the atomic objective with 10 atoms per simulation by default. Evaluate it with `log_ratio()` and sample it through `posterior()`. ## Density estimators Select one through `density_estimator=` in `npe()` or `nle()`. A closed-form `"linear_gaussian"` option is also available: it needs no `torch`, is exact for linear-Gaussian models, and serves as a test oracle. ### Mixture density network (MDN) - Bishop introduced mixture density networks in the 1994 technical report [Mixture Density Networks](https://publications.aston.ac.uk/id/eprint/373/), which has no DOI. - @papamakarios2016npe used an MDN as the density estimator for NPE. - `npe(density_estimator = "mdn")` maps `x` to the weights, means, and full covariances of a Gaussian mixture over \(\theta\). `n_components` and `hidden` size it. ### Masked autoregressive flow (MAF) - @germain2015made introduced the MADE masking scheme for autoregressive density estimation. - @papamakarios2017maf introduced masked autoregressive flows, stacking affine autoregressive transforms to a standard-normal base. - `npe(density_estimator = "maf")` is the default. `n_transforms` sets the depth. ### Neural spline flow (NSF) - @durkan2019nsf introduced neural spline flows, replacing the affine transform with a monotonic rational-quadratic spline for sharply non-Gaussian posteriors. - `npe(density_estimator = "nsf")` implements the autoregressive form. `n_bins` and `tail_bound` control the spline. ## Diagnostics ### Simulation-based calibration (SBC) - @talts2018sbc introduced simulation-based calibration, which ranks the true parameter among posterior draws over many prior draws. Calibrated posteriors give uniform ranks. - `sbc()` computes the ranks, one parameter at a time, and `plot_sbc()` displays them. ### Expected coverage - @hermans2022crisis showed that published SBI posteriors are often overconfident, and made coverage the check that exposes it. - `expected_coverage()` turns the SBC ranks into nominal against empirical coverage at each credible level, and `plot_coverage()` displays them. Calibrated posteriors lie on the diagonal. ### TARP - @lemos2023tarp introduced tests of accuracy with random points, which measure coverage of distance-based credible regions around random reference points. This is a joint test, so it catches a posterior with calibrated marginals but wrong correlations. - `tarp()` runs the test and `plot_tarp()` displays it. ### Classifier two-sample test (C2ST) - @lopezpaz2017c2st introduced the classifier two-sample test, which trains a classifier to tell two sets of draws apart. Accuracy near 0.5 means they are indistinguishable. - `c2st()` runs the procedure @lueckmann2021benchmarking use in `sbibm`, so its numbers are comparable with published benchmark results: a two-hidden-layer ReLU network of `10 * d` units per layer, 5-fold cross-validated accuracy, both sample sets z-scored by the moments of the first. The network trains on torch, so this classifier needs torch installed. `classifier = "logistic"` swaps in cross-validated logistic regression, which needs no torch and is faster, but is linear: it sees a shift in location and is close to blind to a difference in spread or dependence. ## References