User Guide#
This guide walks through the main concepts you will use when combining
existing samples with new inference runs. It focuses on the high-level Python
API exposed by aspire.Aspire.
Workflow overview#
Describe your problem via
log_likelihoodandlog_priorcallables that acceptaspire.samples.Samplesor compatible objects.Package initial draws with
aspire.samples.Samples(oraspire.samples.BaseSamples) to benefit from consistent typing, plotting helpers, and device-aware conversions.Fit a proposal with
aspire.Aspire.fit()to learn a proposal tailored to the current posterior (normalising flow by default).Sample the posterior using
aspire.Aspire.sample_posterior()with either importance sampling or an adaptive SMC kernel (MiniPCN, BlackJAX, or custom samplers).Inspect, save, and reuse the resulting
aspire.samples.Samples,aspire.history.Historyobjects, and the fitted flow.
Working with samples#
aspire uses dataclasses defined in aspire.samples to keep sample
arrays, weights, and evidence estimates together. Key features:
Automatic conversion between array namespaces (NumPy, JAX, PyTorch) via the
xpargument.Convenience exporters (
aspire.samples.BaseSamples.to_dict(),aspire.samples.BaseSamples.save()) for logging or serialisation.Plotting helpers (
aspire.samples.BaseSamples.plot_corner()) that integrate withcornerwhile respecting weights.
When constructing your own samples, provide parameter names to enable labelled
plots and dataframes. Use aspire.samples.Samples.from_samples() to
switch namespaces or merge multiple runs with
aspire.samples.Samples.concatenate().
Flows and transforms#
Aspire can work with any flow that implements sample_and_log_prob and
log_prob. Flows are defined via
aspire.flows.base.Flow and instantiated by
aspire.Aspire.init_flow(). By default Aspire uses the zuko
implementation of Masked Autoregressive Flows on top of PyTorch. The flow is
automatically wrapped with aspire.transforms.FlowTransform (or a
composite of bounded / periodic transforms) so you can work with native
parameter ranges while still optimising in unconstrained space.
You can choose a backend by setting flow_backend="flowjax" to leverage JAX
or by providing a fully constructed flow instance. When flow_matching
is enabled, Aspire trains a score-based model instead of a classical density
estimator (requires the zuko backend).
External flow implementations can be plugged in via the
aspire.flows entry point group. See Custom Flows for details.
Transform mechanics#
Aspire keeps a clear separation between your native parameters and the space where flows or kernels operate:
aspire.transforms.FlowTransformis attached to every flow created byaspire.Aspire.init_flow(). By default, it maps bounded parameters to the real line (probitorlogit), and recentres / rescales dimensions with an affine transform learned from the training samples. Log-Jacobian terms are tracked so calls tolog_proborsample_and_log_probremain properly normalised.bounded_to_unboundedandaffine_transformcan be specified when creating the Aspire instance to control this behaviour.The same components are exposed via
aspire.transforms.CompositeTransformif you want to opt out of the bounded-to-unbounded step or the affine whitening when building custom transports.
Preconditioning inside samplers#
SMC and MCMC samplers also work in a transformed space. They fit the chosen
preconditioning transform to the initial particles, perform moves there, and
then call inverse(...) (including the log-Jacobian) whenever the likelihood
or prior is evaluated. Configure it via
aspire.Aspire.sample_posterior():
"default"/"standard"usesaspire.transforms.CompositeTransformwith bounded-to-unbounded and affine scaling turned off by default; periodic wrapping still applies. To whiten dimensions or map bounds to the real line, passpreconditioning_kwargs={"affine_transform": True, "bounded_to_unbounded": True}."flow"fits a lightweightaspire.transforms.FlowPreconditioningTransformto the current particles and treats it as a transport map during SMC/MCMC updates. This reuses the same bounded / periodic handling while providing a richer geometry for the kernels.Noneleaves the sampler in the original parameterisation with an identity transform. The importance sampler defaults to this; other samplers default to"standard"so periodic parameters are at least kept consistent with their bounds.
Note
By default, the preconditioning transform does not include bounded-to-unbounded
steps. This means your log-prior and log-likelihood must handle points that
lie outside the specified bounds (e.g. by returning -inf). If you want
the sampler to automatically map bounded parameters to an unconstrained
space, enable the bounded_to_unbounded option in
preconditioning_kwargs.
Sampling strategies#
The aspire.Aspire.sample_posterior() method orchestrates several
samplers, grouped below by inference style.
Importance sampling#
importanceDraws independent samples from the fitted flow and reweights them using the provided likelihood/prior functions. Perfect for quick sanity checks or sanity bounds on evidence estimates.
Markov chain Monte Carlo#
minipcnRuns the
aspire.samplers.mcmc.MiniPCNkernel directly (no SMC temperature ladder). Configuren_samplesand pass MCMC kwargs such asn_stepsorstep_fnviasampler_kwargs.emceeUses the
aspire.samplers.mcmc.Emceeensemble sampler for gradient-free proposals. Providesampler_kwargslikenwalkersorn_stepsto control the chain length.
Sequential Monte Carlo#
smc/minipcn_smcRuns adaptive SMC with the MiniPCN MCMC kernel. Configure the number of particles via
n_samplesand pass kernel settings insampler_kwargs(for examplen_steps,target_acceptance_rateorstep_fn).blackjax_smcUses BlackJAX kernels (requires the
blackjaxextra) while keeping the same adaptive temperature schedule as the MiniPCN backend.emcee_smcReplaces the internal MCMC move with the
emceeensemble sampler, providing a gradient-free option that still benefits from SMC tempering.
History, diagnostics, and persistence#
Every sampler attaches a history object (see aspire.history) with
diagnostic metrics such as effective sample size, intermediate temperatures,
or acceptance rates. Plot them via aspire.history.SMCHistory.plot() or
specialised helpers like aspire.history.SMCHistory.plot_beta().
Use the following methods to persist and later resume work:
aspire.Aspire.save_flow()/aspire.Aspire.load_flow()to snapshot the trained flow.aspire.Aspire.save_config()oraspire.Aspire.save_config_to_json()to capture all hyperparameters.aspire.samples.BaseSamples.save()to store weighted samples in HDF5 for downstream analysis.
Together these utilities support iterative workflows where you continuously refine the proposal distribution, reuse expensive likelihood evaluations, and relaunch SMC runs with minimal boilerplate.