Sampling and Integration¶
Sampling answers one question: given a model, how are samples produced? The library covers the spectrum from Markov chain methods on a fixed energy to deterministic integration of a learned velocity field, and factors the numerics into a shared integrator layer. The current family, generated from the installed package at build time:
graph TD
BaseSampler(["BaseSampler"])
BaseSampler --> FlowSampler
BaseSampler --> GradientDescentSampler
BaseSampler --> HamiltonianMonteCarlo
BaseSampler --> LangevinDynamics
BaseSampler --> NesterovSampler
BaseSampler --> RiemannianManifoldHMC MCMC on an energy¶
Langevin dynamics descends the energy gradient (equivalently, ascends the model score \(-\nabla_x E\)) with injected noise,
and is the workhorse behind contrastive-divergence negatives and annealed generation:
Hamiltonian Monte Carlo augments the state with momentum and integrates Hamiltonian dynamics with a symplectic leapfrog before a Metropolis accept/reject, trading gradient evaluations for long, decorrelated proposals. Riemannian manifold HMC replaces the flat metric with a position-dependent one and integrates the resulting non-separable Hamiltonian with a generalised (implicit) leapfrog; it is the geometry-aware option for ill-conditioned targets.
Optimization-based samplers (plain gradient descent and momentum variants such as NesterovSampler) are the noise-free members of the family: mode seekers rather than samplers, useful for finding minima of a trained energy.
Three conventions hold across all of them:
- Chains are a batch dimension.
n_sampleschains advance as one tensor program; scaling chains costs one integer, not a loop. - Diagnostics are dictionaries.
return_diagnostics=Truereturns per-step tensors (means, variances, energies, acceptance rates) rather than opaque state. - Hyperparameters are schedulable. Step sizes and noise scales accept schedulers, which is how annealed Langevin and temperature sweeps are expressed.
Continuous-time generation¶
For trained flow, diffusion, and equilibrium models, FlowSampler integrates the learned field from noise to data:
prediction declares what the network outputs ("velocity", "score", or "noise"); the interpolant converts between them internally, so one sampler serves flow matching, score-based diffusion, and noise-prediction models. The process is chosen at construction: mode="ode" (default) integrates the probability-flow ODE, mode="sde" adds a diffusion term with selectable form (diffusion_form=, last_step=). sample() follows the same contract as every other sampler; with a fixed-step integrator it supports thin, return_trajectory, and return_diagnostics, while adaptive integrators (dopri5, ...) return the final state only. Equilibrium-matching models set negate_velocity=True, since they learn the data-to-noise direction.
The integrator layer¶
Both worlds sit on torchebm.integrators, which covers the standard solver families: explicit Runge-Kutta schemes of increasing order (e.g. heun, rk4), adaptive step-size solvers (e.g. dopri5), implicit schemes for stiff dynamics, and symplectic integrators for Hamiltonian ones (e.g. leapfrog). The shipped set, generated from the installed package:
graph TD
BaseIntegrator(["BaseIntegrator"])
BaseRungeKuttaIntegrator(["BaseRungeKuttaIntegrator"])
BaseSDERungeKuttaIntegrator(["BaseSDERungeKuttaIntegrator"])
BaseSymplecticIntegrator(["BaseSymplecticIntegrator"])
BaseRungeKuttaIntegrator --> AdaptiveHeunIntegrator
BaseIntegrator --> BaseRungeKuttaIntegrator
BaseSDERungeKuttaIntegrator --> BackwardEulerMaruyamaIntegrator
BaseRungeKuttaIntegrator --> BaseSDERungeKuttaIntegrator
BaseRungeKuttaIntegrator --> Bosh3Integrator
BaseRungeKuttaIntegrator --> Dopri5Integrator
BaseRungeKuttaIntegrator --> Dopri8Integrator
BaseSDERungeKuttaIntegrator --> EulerMaruyamaIntegrator
BaseSymplecticIntegrator --> GeneralisedLeapfrogIntegrator
BaseIntegrator --> BaseSymplecticIntegrator
BaseSDERungeKuttaIntegrator --> HeunIntegrator
BaseSymplecticIntegrator --> LeapfrogIntegrator
BaseRungeKuttaIntegrator --> MidpointIntegrator
BaseRungeKuttaIntegrator --> RK438Integrator
BaseRungeKuttaIntegrator --> RK4Integrator Every sampler accepts integrator= as a registry name or an instance, and get_integrator constructs one directly:
Higher-order solvers buy accuracy per step; adaptive solvers buy robustness on stiff fields; symplectic solvers preserve the phase-space volume HMC's correctness depends on. The integrator comparison example measures the orders directly against an exact solution.