mixle.inference.target module¶
Bring-your-own-target, engine-agnostic inference facade.
A small public surface so external consumers can run mixle’s samplers / VI on an arbitrary
differentiable target without reaching into mixle.ppl internals — and run it on whichever
engine fits their hardware and target:
nuts()— multi-chain No-U-Turn Sampler with R-hat / ESS diagnostics, dispatched to a registered backend (numpy/numba/torch/jax) selected bybackend="auto". Every backend returns the sameNutsResult, so downstream code is backend-blind.nuts_torch()— the torch-native NUTS, kept as a direct entry point (also the"torch"backend).advi()— automatic-differentiation VI over a user batched torch target.available_backends()— the installed inference engines.mixle.inference.diagnostics(re-exported asrhat()/ess()) — convergence diagnostics over plain(n_chains, n_draws, d)arrays.
The backend registry lives in mixle.inference.backends (register, don’t branch); each backend
self-registers at import, behind a try/except so a missing optional engine never breaks
import mixle.inference.
- class NutsResult(samples, chains, rhat, ess, num_target_evals, step_size, extra=<factory>)[source]
Bases:
objectDraws and diagnostics from a multi-chain
nuts()run.samplesis(chains * draws, d)pooled draws;chainsis(n_chains, draws, d).- Parameters:
- samples: ndarray
- chains: ndarray
- rhat: ndarray
- ess: ndarray
- num_target_evals: int
- step_size: float
- extra: dict
- class AdviResult(samples, mean, scale, objective=None)[source]
Bases:
objectResult of
advi(): posterior draws plus the fitted variational parameters.- samples: ndarray
- mean: ndarray
- scale: ndarray
- nuts(target, *, backend='auto', dim=None, init=None, num_samples=1000, warmup=1000, chains=1, mass=1.0, target_accept=0.8, max_tree_depth=10, thin=1, rng=None, parallel=None, **backend_kwargs)[source]
No-U-Turn Sampler over an arbitrary log-target, dispatched to a registered engine.
The
targetcontract depends on the backend (the kinds cannot be auto-converted across autodiff systems):numpy/numba: a fusedvalue_and_grad(theta) -> (logp, grad)(njit-jitted fornumba). The caller supplies the (analytic) gradient.torch/jax: a scalarlogp(theta); the backend buildsvalue_and_gradby autodiff (torch.func/ NumPyro).
- Parameters:
target (Callable[[...], Any]) – the log-target, per the contract above.
backend (str) –
"auto"(default), or one ofavailable_backends()."auto"honors an explicit choice elsewhere, otherwise prefers the always-presentnumpypath for a plain numpyvalue_and_grad; passbackend="numba"to run an@njittarget,"jax"/"torch"for an autodiff scalarlogp.dim (int | None) – parameter dimension. Required unless
initis given.init (Any) – initial state, shape
(dim,)or(chains, dim)for per-chain starts. Defaults to zeros. A 1-Dinitis reused (jittered after the first) across chains.num_samples (int) – retained post-warmup draws per chain.
warmup (int) – step-size adaptation / burn-in iterations per chain.
chains (int) – number of independent chains (>= 2 to get a meaningful R-hat).
mass (Any) – forwarded to the sampler.
target_accept (float) – forwarded to the sampler.
max_tree_depth (int) – forwarded to the sampler.
thin (int) – forwarded to the sampler.
rng (RandomState | int | None) – seed / RandomState for reproducibility.
parallel (bool | str | None) – run the
chainsindependent chains concurrently.None/False(default) runs them in the backend’s usual single call;"thread"uses a thread pool (real speedup for thenumba/torchbackends, whose inner loops release the GIL);Trueor"process"uses a process pool (real speedup for the pure-numpybackend; requires a picklabletarget). Ignored for thejaxbackend, which already vectorizes chains internally. Each chain still gets an independent seed, so results are valid multi-chain draws (R-hat / ESS across chains).**backend_kwargs (Any) – forwarded to the chosen backend (e.g.
compile=,device=fortorch;chain_method=forjax).
- Returns:
NutsResultwith pooledsamples(chains*draws, d), per-chainchains(chains, draws, d), per-dimensionrhatandess, the total target-evaluation count, the adaptedstep_size, andextra={"backend": name}.- Return type:
NutsResult
- nuts_torch(logp, *, dim=None, init=None, num_samples=1000, warmup=1000, chains=1, mass=1.0, target_accept=0.8, max_tree_depth=10, thin=1, rng=None, compile=True, dtype=None, device=None)[source]
Torch-native NUTS over a torch scalar
logp(theta) -> Tensor[()](GPU / large autodiff targets).The whole leapfrog/tree runs in torch tensors with a
torch.compile``d ``value_and_grad(no numpy round-trip / graph re-trace per gradient). Same multi-chain interface andNutsResultasnuts(). Also registered as the"torch"backend.Performance note (be deliberate about when to use this): on CPU this is typically slower than the numpy
nuts()(per-op torch dispatch + host syncs in the tree dominate when the target is cheap). Its value is GPU (device=) and large autodiff targets. For CPU work prefer the numpy backend, numba (analytic gradient), or the jax/NumPyro backend (XLA, vectorized multi-chain). Chains run in a Python loop (per-chain latency).
- advi(target_batch, u0, s0, *, samples=1000, mc=16, steps=2000, lr=0.05, batch_size=None, family='meanfield', alpha=1.0, rng=None)[source]
Automatic-differentiation VI over a user batched torch target.
- Parameters:
target_batch (Callable[[Any], Any]) –
target_batch(U: Tensor(B, d)) -> Tensor(B,)returning the (unnormalized) joint log-target for each ofBparameter draws. The caller owns any data minibatching/rescaling inside this callable;batch_sizehere is unused unless the caller wires it in (kept for signature parity with the internal ADVI).u0 – initial variational mean and (marginal) scale in the unconstrained space.
s0 – initial variational mean and (marginal) scale in the unconstrained space.
samples (int) – number of posterior draws to return.
mc (int) – Monte-Carlo samples per step, optimizer steps, Adam learning rate.
steps (int) – Monte-Carlo samples per step, optimizer steps, Adam learning rate.
lr (float) – Monte-Carlo samples per step, optimizer steps, Adam learning rate.
family (str) –
'meanfield'(diagonal) or'fullrank'(Cholesky covariance).alpha (float) – Renyi/tilted objective exponent (
1.0= standard KL-ELBO).rng (RandomState | int | None) – seed / RandomState.
batch_size (int | None)
- Returns:
AdviResultwithsamples(samples, d)drawn from the fitted Gaussian q (in the same spacetarget_batchconsumes), plus the fittedmeanandscale.- Return type:
AdviResult
- rhat(chains)[source]
Gelman-Rubin potential scale reduction factor (R-hat) per parameter dimension.
R-hat compares the variance between chains to the variance within chains. Values near 1.0 indicate the chains have mixed and are sampling a common target; values above ~1.01-1.1 flag non-convergence. Standard multi-chain check (Gelman & Rubin 1992).
- ess(samples, max_lag=None)[source]
Effective sample size per parameter from positive autocorrelation lags.
Accepts a single chain
(n_draws,)/(n_draws, d)or a stack of chains(n_chains, n_draws, d)(the chains are pooled into one autocorrelation estimate after centering each chain by its own mean). Uses the initial-positive-sequence truncation (Geyer): sum autocorrelations until the first non-positive lag.
- split_rhat(chains)[source]
Rank-normalized split-R-hat (Vehtari et al. 2021) – the robust, recommended R-hat.
Splits each chain in half (doubling the chain count, so within-chain non-stationarity is caught), rank-normalizes the pooled draws (robust to heavy tails / non-normality), then applies the Gelman-Rubin R-hat. Convergence is typically declared at
< 1.01.
- folded_split_rhat(chains)[source]
Folded rank-normalized split-R-hat (Vehtari et al. 2021): split-R-hat on
|x - median(x)|.The plain
split_rhat()compares chain locations; folding about the median makes it compare chain scales/tails, catching the case where chains share a mean but differ in spread. Use together withsplit_rhat()(orrhat_max()).
- rhat_max(chains)[source]
The recommended convergence R-hat:
max(split_rhat, folded_split_rhat)(Vehtari et al. 2021).A single number that flags non-convergence in either the location (bulk) or the scale (folded) of the chains; declare convergence at
< 1.01.
- mcse_mean(chains)[source]
Monte Carlo standard error of the posterior mean:
sd(x) / sqrt(ESS)per parameter.The sampling error in the estimated mean from autocorrelated draws – the posterior standard deviation deflated by the (autocorrelation-based) effective sample size of the raw chains.
- mcmc_summary(chains)[source]
Per-parameter posterior + convergence summary (the ArviZ-style
summarytable).Returns one dict per parameter with the posterior
mean/sdand 5/50/95% quantiles, plus the recommended convergence diagnostics:r_hat(=rhat_max(), the max of the bulk and folded rank-normalized split-R-hats),ess_bulk,ess_tail, andmcse_mean(Vehtari et al. 2021). Declare convergence atr_hat < 1.01withess_bulk/ess_tailcomfortably in the hundreds.
- ess_bulk(chains)[source]
Bulk effective sample size: ESS of the rank-normalized split chains (mixing in the distribution body).
- ess_tail(chains, prob=0.05)[source]
Tail effective sample size: the smaller ESS of the lower-/upper-
probtail indicators.Tail quantiles mix more slowly than the bulk; tail-ESS is
min(ESS[1(x <= q_prob)], ESS[1(x >= q_{1-prob})])over the split chains (Vehtari et al. 2021), surfacing poor tail exploration that bulk-ESS misses.
- geweke_z(chain, first=0.1, last=0.5)[source]
Geweke convergence z-score comparing the start and end of a single chain (per parameter).
Tests stationarity within one chain (Geweke 1992): if the chain has converged, the mean of its first
firstfraction and its lastlastfraction agree, so the z-statistic(mean_a - mean_b) / sqrt(se_a^2 + se_b^2)– with autocorrelation-adjusted standard errors (the segment variance divided by its effective sample size) – is approximately standard normal.|z| < 2indicates convergence; a large|z|flags a chain still drifting. Returns one z per parameter. Complements the multi-chainsplit_rhat().
- available_backends()[source]
Return the names of registered backends whose engine is importable, in registration order.
- class InferenceBackend(name, available, target_kind, nuts)[source]
Bases:
objectA registered inference engine: a name, an availability probe, a target contract, a sampler.
- Parameters:
- name: str
- available: Callable[[], bool]
- target_kind: str
- nuts: Callable[..., NutsResult]
- register_inference_backend(backend)[source]
Register (or replace) an inference backend under
backend.name.- Parameters:
backend (InferenceBackend)
- Return type:
None