Variational Guides¶
Variational guide distributions for approximate inference. The guides
live in submodules of quivers.inference.guides and share the Guide
ABC and LatentRegistry introspection layer. They are
AutoNormalGuide, AutoDeltaGuide, AutoMultivariateNormalGuide,
AutoLowRankMultivariateNormalGuide, AutoLaplaceApproximation,
AutoNormalizingFlow, AutoIAFGuide, AutoNeuralSplineGuide,
AutoMixtureGuide, AutoGuideList, and AutoStructured.
quivers.inference re-exports every guide, and quivers.inference.guides
adds the Pyro-style short names (AutoNormal, AutoMultivariateNormal,
AutoLowRankMVN, AutoDelta, AutoLaplace, AutoIAFNormal), each bound
to the guide class it names, and the type aliases that configure
AutoStructured.
guides
¶
Variational guide families.
Public surface (re-exported by the parent quivers.inference
package): one ABC (Guide) plus a zoo of concrete
Auto*Guide subclasses spanning the standard variational-family
ladder from mean-field Normal to normalizing-flow stacks and
hierarchical / mixture / structured guides.
Every concrete guide is built against a single
quivers.inference.registry.LatentRegistry and obeys the
shape contract documented on Guide.
Short-name aliases matching the Pyro AutoGuide naming
(AutoNormal, AutoMultivariateNormal, AutoLowRankMVN,
AutoDelta, AutoLaplace, AutoIAFNormal) are re-exported for
users switching over from Pyro. The longer *Guide names remain
the canonical quivers names.
AutoNormal
module-attribute
¶
AutoNormal = AutoNormalGuide
Pyro-style short name for AutoNormalGuide.
AutoMultivariateNormal
module-attribute
¶
AutoMultivariateNormal = AutoMultivariateNormalGuide
Pyro-style short name for AutoMultivariateNormalGuide.
AutoLowRankMVN
module-attribute
¶
AutoLowRankMVN = AutoLowRankMultivariateNormalGuide
Pyro-style short name for AutoLowRankMultivariateNormalGuide.
AutoLaplace
module-attribute
¶
AutoLaplace = AutoLaplaceApproximation
Pyro-style short name for AutoLaplaceApproximation.
AutoIAFNormal
module-attribute
¶
AutoIAFNormal = AutoIAFGuide
Pyro-style short name for AutoIAFGuide.
ConditionalSpec
¶
The per-site marginal families of an AutoStructured guide: one
family name ("delta", "normal", or "mvn") for every site,
or a mapping from site name to family name.
DependencyKind
¶
One dependency edge of an AutoStructured guide: the string
"linear" for a learned linear shift, or a callable mapping the
parent's unconstrained flat draw to a shift on the child's
unconstrained flat location.
DependencySpec
¶
DependencySpec = Mapping[str, Mapping[str, DependencyKind]]
The dependency edges of an AutoStructured guide, keyed first by
child site and then by parent site.
AutoGuideList
¶
AutoGuideList(parts: dict[str, Guide])
Bases: Guide
A block-composed variational guide.
| PARAMETER | DESCRIPTION |
|---|---|
parts
|
Named subguides, each covering a disjoint set of latent
site names. Keys are labels used for parameter-namespacing
and error messages; values are any
TYPE:
|
Source code in src/quivers/inference/guides/auto_guide_list.py
registry
property
¶
The list-guide has no single fused registry; downstream
code that needs one should walk part_labels and pull each
sub-guide's Guide.registry directly.
part
¶
part(label: str) -> Guide
Look up a sub-guide by label.
Source code in src/quivers/inference/guides/auto_guide_list.py
rsample
¶
Concatenate per-part reparameterized draws.
Source code in src/quivers/inference/guides/auto_guide_list.py
log_prob
¶
Sum per-part log-densities.
Each sub-guide receives only the site keys it owns; a
missing key raises KeyError in the sub-guide.
Source code in src/quivers/inference/guides/auto_guide_list.py
AutoStructured
¶
AutoStructured(model: MonadicProgram, observed_names: set[str], conditionals: ConditionalSpec, dependencies: DependencySpec | None = None, init_scale: float = 0.1)
Bases: Guide
Per-site / per-edge structured variational guide.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model to build a guide for.
TYPE:
|
observed_names
|
Variable names treated as observations.
TYPE:
|
conditionals
|
Per-site marginal-family choice. A single string sets every site to the same family. A dict maps site name to family. Allowed families:
TYPE:
|
dependencies
|
Directed edges.
TYPE:
|
init_scale
|
Initial scale of every
TYPE:
|
Source code in src/quivers/inference/guides/auto_structured.py
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | |
conditionals
property
¶
Per-site marginal family, as resolved at construction.
dependencies
property
¶
dependencies: dict[str, dict[str, DependencyKind]]
The declared per-edge dependence structure.
rsample
¶
Ancestral reparameterized draw.
Source code in src/quivers/inference/guides/auto_structured.py
log_prob
¶
Pushforward log-density at the supplied constrained sites.
Source code in src/quivers/inference/guides/auto_structured.py
Guide
¶
Bases: Module, ABC
Abstract variational guide.
Subclasses MUST implement rsample and log_prob
and expose latent_names. They MAY override
registry if they construct their registry lazily, but
the default implementation expects self._registry to be
set in __init__.
latent_names
abstractmethod
property
¶
Names of latent variables this guide covers.
build_registry
classmethod
¶
build_registry(model: MonadicProgram, observed_names: set[str] | frozenset[str]) -> LatentRegistry
Convenience wrapper around
LatentRegistry.from_model so guide constructors
can do self._registry = self.build_registry(model, obs)
without an extra import.
Source code in src/quivers/inference/guides/base.py
rsample
abstractmethod
¶
Reparameterized sample from :math:q_\phi(z \mid x).
| PARAMETER | DESCRIPTION |
|---|---|
x
|
Program input. Shape
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, Tensor]
|
Per-site constrained samples shaped to match the model's trace-side convention. |
Source code in src/quivers/inference/guides/base.py
AutoDeltaGuide
¶
AutoDeltaGuide(model: MonadicProgram, observed_names: set[str], init_value: float = 0.0)
Bases: Guide
Dirac-delta MAP guide with per-site constrained bijector.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model.
TYPE:
|
observed_names
|
Variable names treated as observations.
TYPE:
|
init_value
|
Initial unconstrained-space coordinate for every latent.
Default
TYPE:
|
Source code in src/quivers/inference/guides/delta.py
rsample
¶
Return the learned point estimates in the prior's support.
Source code in src/quivers/inference/guides/delta.py
log_prob
¶
Delta log-density: zero everywhere (the delta term and its Jacobian cancel in the ELBO under the standard score-function trick).
Source code in src/quivers/inference/guides/delta.py
AutoIAFGuide
¶
AutoIAFGuide(model: MonadicProgram, observed_names: set[str], num_flows: int = 4, hidden_dim: int | None = None, num_hidden_layers: int = 2)
Bases: AutoNormalizingFlow
Inverse-autoregressive-flow guide.
Default normalizing-flow guide for variational inference
(Kingma-Salimans-Jozefowicz et al. 2016). Stack of
InverseAutoregressiveTransform layers, each separated
by a reverse permutation so successive layers have different
autoregressive orderings.
Sampling is parallel (one MLP forward per layer); density evaluation is sequential (one coordinate at a time per layer), so this guide should be used with objectives that sample more than they score the same flow (ELBO, IWAE).
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model.
TYPE:
|
observed_names
|
Variable names treated as observations.
TYPE:
|
num_flows
|
Number of IAF blocks in the stack. Default
TYPE:
|
hidden_dim
|
Hidden width of every MADE inside the stack. Default
TYPE:
|
num_hidden_layers
|
Number of hidden layers in each MADE. Default
TYPE:
|
Source code in src/quivers/inference/guides/flow.py
AutoNeuralSplineGuide
¶
AutoNeuralSplineGuide(model: MonadicProgram, observed_names: set[str], num_flows: int = 4, num_bins: int = 8, tail_bound: float = 3.0, hidden_dim: int | None = None, num_hidden_layers: int = 2)
Bases: AutoNormalizingFlow
Neural-spline-flow guide (Durkan-Bekasov-Murray-Papamakarios 2019).
Stack of monotone rational-quadratic spline coupling layers
(NeuralSplineCouplingTransform) with alternating
half-masks. Sharper than IAF for posteriors with bounded
support or sharp modes; comparable runtime.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model.
TYPE:
|
observed_names
|
Variable names treated as observations.
TYPE:
|
num_flows
|
Number of coupling layers. Default
TYPE:
|
num_bins
|
Number of spline bins per coordinate. Default
TYPE:
|
tail_bound
|
Inputs outside
TYPE:
|
hidden_dim
|
Hidden width of the coupling MLPs. Default
TYPE:
|
num_hidden_layers
|
Hidden layers in each coupling MLP. Default
TYPE:
|
Source code in src/quivers/inference/guides/flow.py
AutoNormalizingFlow
¶
AutoNormalizingFlow(model: MonadicProgram, observed_names: set[str], transforms: list[TransformModule])
Bases: Guide
Normalising-flow variational guide over the flat latent vector.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model to build a guide for.
TYPE:
|
observed_names
|
Variable names treated as observations.
TYPE:
|
transforms
|
Flow stack applied to the standard-Normal base. Each
TYPE:
|
Source code in src/quivers/inference/guides/flow.py
rsample
¶
One flow draw, unflattened and bijected to constrained space.
Source code in src/quivers/inference/guides/flow.py
log_prob
¶
Log-density at the supplied constrained sites.
Source code in src/quivers/inference/guides/flow.py
AutoLaplaceApproximation
¶
AutoLaplaceApproximation(model: MonadicProgram, observed_names: set[str], init_value: float = 0.0)
Bases: Guide
Laplace-approximation guide.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model.
TYPE:
|
observed_names
|
Variable names treated as observations.
TYPE:
|
init_value
|
Initial unconstrained-space MAP estimate. Default
TYPE:
|
Source code in src/quivers/inference/guides/laplace.py
fit_hessian
¶
fit_hessian(model: MonadicProgram, x: Tensor, observations: dict[str, Tensor], *, jitter: float = 0.0001) -> None
Compute and cache the Hessian-derived Cholesky factor.
Solves the eigenproblem of the negative-log-joint Hessian at
the current MAP, projects negative eigenvalues to jitter
(so the resulting Gaussian is always positive-definite), and
stores the matching lower-triangular Cholesky factor of the
inverse Hessian as the posterior scale_tril.
Call this after MAP optimisation has converged. Subsequent
rsample / log_prob calls sample from
:math:\mathcal{N}(z^\star, H^{-1}).
Source code in src/quivers/inference/guides/laplace.py
rsample
¶
Sample from the Laplace posterior, unflatten, and biject.
Source code in src/quivers/inference/guides/laplace.py
log_prob
¶
Log-density at the supplied constrained sites.
Returns zero before fit_hessian (MAP-phase delta
convention); after fit_hessian returns the Gaussian
log-density plus the per-site bijector Jacobian correction.
Source code in src/quivers/inference/guides/laplace.py
AutoMixtureGuide
¶
AutoMixtureGuide(components: list[Guide], init_temperature: float = 1.0)
Bases: Guide
Finite mixture variational guide.
| PARAMETER | DESCRIPTION |
|---|---|
components
|
Component guides. All components must share the same
TYPE:
|
init_temperature
|
Initial Gumbel-Softmax temperature. Default
TYPE:
|
Source code in src/quivers/inference/guides/mixture.py
set_temperature
¶
Anneal the Gumbel-Softmax temperature.
Source code in src/quivers/inference/guides/mixture.py
rsample
¶
Reparameterized mixture draw via Gumbel-Softmax.
Each call samples a Gumbel-Softmax weight vector
:math:w \in \Delta^{K-1} and returns
:math:\sum_k w_k \cdot v^{(k)} per site, where
:math:v^{(k)} is component k's constrained-space
sample. Because the constrained-space sites' supports are
not in general convex (e.g. a Cholesky factor on
torch.distributions.constraints.corr_cholesky), the
soft mixture can drift outside any single component's
support during training; the categorical-pick fallback in
hard_rsample returns a single component's sample
for use at inference time.
Source code in src/quivers/inference/guides/mixture.py
hard_rsample
¶
Categorical-pick variant: sample a component index and return that component's draw verbatim. Use at inference time when soft-mixture interpolation would violate a support constraint.
Source code in src/quivers/inference/guides/mixture.py
log_prob
¶
Mixture log-density via logsumexp over components.
Source code in src/quivers/inference/guides/mixture.py
AutoLowRankMultivariateNormalGuide
¶
AutoLowRankMultivariateNormalGuide(model: MonadicProgram, observed_names: set[str], rank: int = 5, init_scale: float = 0.1)
Bases: _MVNCommon
Low-rank-plus-diagonal multivariate-Normal guide.
Covariance :math:\Sigma = W W^\top + \mathrm{diag}(\sigma^2)
with W of shape :math:(D, r) and :math:\sigma \in
\mathbb{R}^{D}_{>0}. Memory :math:O(Dr); sampling and
log-density via Woodbury / matrix-determinant lemma in
torch.distributions.LowRankMultivariateNormal.
Captures the dominant r posterior correlation directions
while remaining tractable for D in the hundreds-to-
thousands range, where full-rank is infeasible.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model to build a guide for.
TYPE:
|
observed_names
|
Variable names treated as observations.
TYPE:
|
rank
|
Number of correlated directions. Default
TYPE:
|
init_scale
|
Initial diagonal scale.
TYPE:
|
Source code in src/quivers/inference/guides/multivariate_normal.py
AutoMultivariateNormalGuide
¶
AutoMultivariateNormalGuide(model: MonadicProgram, observed_names: set[str], init_scale: float = 0.1)
Bases: _MVNCommon
Full-rank multivariate-Normal variational guide.
Parameterises a joint Gaussian over the registry's flat unconstrained vector with a learnable lower-triangular Cholesky factor. Captures every pairwise posterior correlation across every latent site, the right choice when posterior couplings are strong (hierarchical regression with crossed random effects, parameter pairs with multiplicative interaction).
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model to build a guide for.
TYPE:
|
observed_names
|
Variable names treated as observations.
TYPE:
|
init_scale
|
Initial diagonal of the Cholesky factor. Default
TYPE:
|
Source code in src/quivers/inference/guides/multivariate_normal.py
AutoNormalGuide
¶
AutoNormalGuide(model: MonadicProgram, observed_names: set[str], init_scale: float = 0.1)
Bases: Guide
Mean-field Normal guide with per-site constrained-support bijector.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Generative model to build a guide for.
TYPE:
|
observed_names
|
Variable names treated as observations (skipped in the guide; their values flow through the conditioning data dict at trace time).
TYPE:
|
init_scale
|
Initial scale (in unconstrained space) of every latent.
Default
TYPE:
|
Source code in src/quivers/inference/guides/normal.py
rsample
¶
Reparameterized mean-field Normal-then-bijector sample.
Source code in src/quivers/inference/guides/normal.py
log_prob
¶
Pushforward log-density at constrained values sites.
Uses the change-of-variables identity:
log q(v) = log Normal(z; loc, scale) + log|det J_{T^{-1}}(v)|
where z = bijector.inv(v). The plate / scalar shape
dispatch matches rsample's convention.
Source code in src/quivers/inference/guides/normal.py
Latent registry¶
Every guide and MCMC kernel reads the model's latent sites through a
LatentRegistry.
registry
¶
Latent-site registry: the canonical introspection surface that every variational guide and MCMC kernel consumes.
A LatentRegistry is built once from a
quivers.continuous.programs.MonadicProgram and a set of
observed site names. It walks the model's steps linear IR
exactly once, classifies each latent into "plate" vs "scalar",
records the prior support and per-site dimensionality, builds the
matching torch.distributions.transforms.Transform via
torch.distributions.constraint_registry.biject_to, and
caches a fused flatten / unflatten pipeline so a single
unconstrained vector can be turned into a fully constrained site
dict (and back) in one pass.
The registry is the only place in the inference layer that knows
about PlateDraw, the layout
of MonadicProgram.steps, or the per-site
constraint-to-bijector mapping. Every downstream component
(Guide,
MCMCKernel, the
flow-based / structured / mixture guides) receives a fully
populated registry and operates against its flat-vector and
per-site dict APIs.
Categorical interpretation¶
Each latent site corresponds to a draw in the model's Kleisli
arrow Γ → 𝒢(τ). The site's prior is a parameterized family
F : Θ → 𝒢(B) with a support constraint
C ⊆ B. The bijector T : ℝ^d → C is the
biject_to lift of C; its log-determinant gives the
change-of-variables term in any pushforward density.
For a plate v : A → B the latent lives in C^|A|; the
registry handles the leading plate axis (size |A|) separately
from the trailing event axis (the support dimension), and the
unconstrained flat vector concatenates plate × event across every
site in declaration order.
LatentSite
dataclass
¶
LatentSite(name: str, morphism: ContinuousMorphism, support: Constraint, bijector: Transform, constrained_dim: int, unconstrained_dim: int, is_plate: bool, plate_index_size: int, spec_index: int, flat_offset: int, flat_length: int)
Frozen record describing a single latent site.
| ATTRIBUTE | DESCRIPTION |
|---|---|
name |
Variable name (the bound name in the program body).
TYPE:
|
morphism |
The site's runtime morphism (the prior). Held by reference
so guides / kernels can call
TYPE:
|
support |
Support of the prior. Drives the choice of bijector.
TYPE:
|
bijector |
TYPE:
|
constrained_dim |
Event dimension on the constrained side (for a scalar
site,
TYPE:
|
unconstrained_dim |
Event dimension on the unconstrained side (for a Dirichlet
on a 5-simplex,
TYPE:
|
is_plate |
Whether this site is a plate draw
(
TYPE:
|
plate_index_size |
TYPE:
|
spec_index |
Position in
TYPE:
|
flat_offset |
Index of this site's first element in the registry's flat unconstrained vector.
TYPE:
|
flat_length |
Number of elements this site occupies in the flat vector
(=
TYPE:
|
LatentRegistry
¶
LatentRegistry(sites: dict[str, LatentSite], observed_names: frozenset[str], model: MonadicProgram)
The complete introspection result for one (model, observed-set) pair.
Constructed once via from_model; immutable thereafter.
Provides:
- Iteration over latent sites in declaration order
(
sites,plate_sites,scalar_sites). - Total unconstrained dimensionality
(
total_unconstrained_dim), the dim of the flat vector HMC and full-rank Gaussian guides operate on. - Round-tripping between a flat unconstrained vector and a
dict of constrained per-site tensors
(
unflatten_unconstrained,flatten_constrained). - Bijector forward / inverse with Jacobian accumulation
(
to_constrained,to_unconstrained).
All operations are vectorized, with no per-site Python loops on the hot path beyond the construction-time setup.
Source code in src/quivers/inference/registry.py
sites
property
¶
sites: dict[str, LatentSite]
Every latent site, keyed by name, in declaration order.
plate_sites
property
¶
plate_sites: dict[str, LatentSite]
The subset of sites that are PlateDraw-shaped.
scalar_sites
property
¶
scalar_sites: dict[str, LatentSite]
The subset of sites that are not plates.
observed_names
property
¶
The observed-name set used to build this registry.
total_unconstrained_dim
property
¶
Sum of every site's flat-vector length.
This is the dim of the unconstrained vector that full-rank Gaussian guides and HMC operate on.
from_model
classmethod
¶
from_model(model: MonadicProgram, observed_names: set[str] | frozenset[str]) -> 'LatentRegistry'
Walk model.steps and assemble the registry.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Compiled probabilistic program.
TYPE:
|
observed_names
|
Variable names treated as observations. Sample sites with names in this set are skipped (their values come from the conditioning data dict at trace time, not from a guide).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
LatentRegistry
|
Fully populated registry with each latent's morphism, support, bijector, dims, and flat-vector offsets. |
Source code in src/quivers/inference/registry.py
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
unflatten_unconstrained
¶
Reshape a flat unconstrained vector into per-site unconstrained tensors.
| PARAMETER | DESCRIPTION |
|---|---|
vec
|
Shape
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, Tensor]
|
|
Source code in src/quivers/inference/registry.py
flatten_unconstrained
¶
Concatenate per-site unconstrained tensors into a single flat vector.
Inverse of unflatten_unconstrained (up to leading
batch axes). The trailing batch axes of every site tensor
must agree.
Source code in src/quivers/inference/registry.py
to_constrained
¶
Push every site's unconstrained value through its bijector.
| RETURNS | DESCRIPTION |
|---|---|
constrained
|
Per-site constrained values shaped according to
TYPE:
|
log_abs_dets
|
Per-site
TYPE:
|
Source code in src/quivers/inference/registry.py
to_unconstrained
¶
Inverse of to_constrained.
Source code in src/quivers/inference/registry.py
aggregate_log_abs_det
staticmethod
¶
aggregate_log_abs_det(log_abs_dets: dict[str, Tensor], leading_shape: tuple[int, ...] = ()) -> Tensor
Sum every per-site log_abs_det over its event axes
and produce a single tensor broadcast to leading_shape.
This is the canonical aggregation an ELBO needs. Objectives that want particle-aware or per-site granularity can skip this helper and aggregate themselves.
Source code in src/quivers/inference/registry.py
zero_unconstrained
¶
zero_unconstrained(*, leading_shape: tuple[int, ...] = (), device: device | None = None, dtype: dtype | None = None) -> dict[str, Tensor]
Return a dict of zero-initialized unconstrained site tensors with the supplied leading batch shape.
Useful for HMC chain initialisation and AutoLaplace's MAP starting point.
Source code in src/quivers/inference/registry.py
randn_unconstrained
¶
randn_unconstrained(*, leading_shape: tuple[int, ...] = (), device: device | None = None, dtype: dtype | None = None, scale: float = 1.0) -> dict[str, Tensor]
Standard-normal-initialized unconstrained site tensors.
Source code in src/quivers/inference/registry.py
Flow transforms¶
The learnable bijections that AutoNormalizingFlow and its subclasses
stack. A custom flow subclasses TransformModule.
transforms
¶
Bijector and normalizing-flow primitives.
This module collects the differentiable bijections quivers's
variational guides chain through. Every primitive is a subclass
of torch.distributions.transforms.Transform, so they
compose under torch.distributions.transforms.ComposeTransform,
plug into torch.distributions.transforms.biject_to-style
pipelines, and interop cleanly with
torch.distributions.transformed_distribution.TransformedDistribution.
Coverage¶
AffineCouplingTransform: RealNVP coupling layer (Dinh, Sohl-Dickstein, Bengio 2017,doi:10.48550/arXiv.1605.08803 <https://doi.org/10.48550/arXiv.1605.08803>_). Splits the input into two halves, scales / shifts one half conditional on the other.MaskedAutoregressiveTransform: MAF (Papamakarios, Pavlakou, Murray 2017,doi:10.48550/arXiv.1705.07057 <https://doi.org/10.48550/arXiv.1705.07057>_). Forward pass is parallel (single masked MLP call); inverse is sequential (per-coordinate). The mass-density form used by variational inference.InverseAutoregressiveTransform: IAF (Kingma, Salimans, Jozefowicz et al. 2016,doi:10.48550/arXiv.1606.04934 <https://doi.org/10.48550/arXiv.1606.04934>_). The dual of MAF: sampling is parallel, density evaluation is sequential. Preferred when you sample more often than score (which is true for variational guides).NeuralSplineCouplingTransform: monotone rational-quadratic spline coupling (Durkan, Bekasov, Murray, Papamakarios 2019,doi:10.48550/arXiv.1906.04032 <https://doi.org/10.48550/arXiv.1906.04032>_). Strictly more expressive than affine coupling at the same parameter budget.LULinearTransform: LU-decomposed linear permutation (Kingma, Dhariwal 2018 Glow,doi:10.48550/arXiv.1807.03039 <https://doi.org/10.48550/arXiv.1807.03039>_). Cheap learnable invertible linear layer; the standard inter- coupling-layer mixer.BatchNormTransform: running-statistics-based BN as a normalizing-flow transform (Dinh, Sohl-Dickstein, Bengio 2017, same paper as RealNVP).
Every primitive is fully implemented (forward, inverse,
log_abs_det_jacobian). No primitive raises NotImplementedError
under any input its type signature accepts. The masked-network
factories are designed so callers can pass a callable / module
rather than configuring topology through string flags.
TransformModule
¶
Cooperative base for transforms that also need to register
torch.nn.Parameter and torch.nn.Module.register_buffer
attributes.
torch.distributions.transforms.Transform is not a
torch.nn.Module, so subclassing both is required for
any flow primitive that holds learnable parameters or buffers
(every primitive in this module). The cooperative base calls
both __init__\ s in MRO order, nn.Module first
so attribute storage is set up before Transform
populates the cache-size machinery.
Source code in src/quivers/inference/transforms.py
AffineCouplingTransform
¶
Bases: TransformModule
RealNVP-style affine coupling transform.
Splits the input vector into two parts: an "identity" part
x_a and a "transformed" part x_b. The transformed part
is shifted and scaled by parameters output from a neural
network that sees only the identity part. The Jacobian is
triangular, so its log-determinant is the sum of the log-scales
on x_b.
| PARAMETER | DESCRIPTION |
|---|---|
dim
|
Total event dimension.
TYPE:
|
net
|
Module mapping
TYPE:
|
mask
|
Boolean mask of shape
TYPE:
|
Source code in src/quivers/inference/transforms.py
MADE
¶
MADE(dim: int, n_per_dim: int, *, hidden: int = 64, n_hidden_layers: int = 2, ordering: Tensor | None = None)
Bases: Module
Masked Autoencoder for Distribution Estimation
(Germain, Gregor, Mnih, Larochelle 2015,
doi:10.48550/arXiv.1502.03509 <https://doi.org/10.48550/arXiv.1502.03509>_).
Outputs n_per_dim parameters per input coordinate. The
masking guarantees that output parameters for coordinate j
depend only on input coordinates < j in the supplied
ordering, which is the autoregressive property MAF / IAF
exploit.
Source code in src/quivers/inference/transforms.py
MaskedAutoregressiveTransform
¶
MaskedAutoregressiveTransform(made: MADE)
Bases: TransformModule
Masked Autoregressive Flow (MAF) layer.
Forward (density) is parallel, one MADE call. Inverse (sampling) is sequential in the autoregressive order.
| PARAMETER | DESCRIPTION |
|---|---|
made
|
Masked network producing per-coordinate
TYPE:
|
Source code in src/quivers/inference/transforms.py
InverseAutoregressiveTransform
¶
InverseAutoregressiveTransform(made: MADE)
Bases: TransformModule
Inverse Autoregressive Flow (IAF) layer.
Dual of MaskedAutoregressiveTransform: sampling
(forward) is parallel, density (inverse) is sequential. The
preferred direction for variational guides because we sample
more often than we score.
| PARAMETER | DESCRIPTION |
|---|---|
made
|
Masked network producing per-coordinate
TYPE:
|
Source code in src/quivers/inference/transforms.py
NeuralSplineCouplingTransform
¶
NeuralSplineCouplingTransform(dim: int, net: Module, mask: Tensor, *, num_bins: int = 8, tail_bound: float = 3.0)
Bases: TransformModule
Monotone rational-quadratic spline coupling (Durkan-Bekasov-Murray-Papamakarios 2019).
Same coupling structure as AffineCouplingTransform,
but the per-coordinate transform on x_b is a monotone
rational-quadratic spline rather than an affine map. The
network outputs (unnormalized_widths, unnormalized_heights,
unnormalized_derivatives) per transformed coordinate;
num_bins knots per coordinate.
| PARAMETER | DESCRIPTION |
|---|---|
dim
|
Event dimension.
TYPE:
|
net
|
Maps
TYPE:
|
mask
|
Boolean mask of shape
TYPE:
|
num_bins
|
Number of spline knots.
TYPE:
|
tail_bound
|
Domain of the spline; outside
TYPE:
|
Source code in src/quivers/inference/transforms.py
LULinearTransform
¶
LULinearTransform(dim: int, perm: Tensor | None = None)
Bases: TransformModule
Invertible linear layer parameterized as :math:A = P L U
(Kingma & Dhariwal 2018 Glow).
The unit-lower-triangular L and unit-upper-triangular U
factors are stored along with their respective off-diagonal
weights; the diagonal of U is stored as a log-scale so the
layer remains invertible and the log-determinant is the sum
of the log-scales. P is a fixed permutation chosen at
construction.
Source code in src/quivers/inference/transforms.py
BatchNormTransform
¶
Bases: TransformModule
Batch-normalisation as a normalizing-flow layer (Dinh, Sohl-Dickstein, Bengio 2017).
In training mode uses the batch statistics; in
eval mode uses the cached running statistics. This module
is an torch.nn.Module to register the running buffers,
and a torch.distributions.transforms.Transform so it
composes with the rest of the flow stack.
Source code in src/quivers/inference/transforms.py
make_coupling_mlp
¶
make_coupling_mlp(n_in: int, n_out: int, *, hidden: int = 64, n_hidden_layers: int = 2, activation: type[Module] = ReLU) -> Module
Build an MLP for use as the net argument of
AffineCouplingTransform or
NeuralSplineCouplingTransform.
The output layer is initialized to zero so the transform starts as the identity, which is a standard normalizing-flow initialisation (see Glow, Real NVP).
Source code in src/quivers/inference/transforms.py
alternating_mask
¶
alternating_mask(dim: int, *, even: bool = True) -> Tensor
Boolean mask alternating True / False. Even-indexed
entries are True when even=True.
Source code in src/quivers/inference/transforms.py
Annealed importance sampling¶
dais
¶
Differentiable Annealed Importance Sampling (DAIS) guide.
DAIS sits between variational inference and MCMC: it runs a short
chain of HMC-like leapfrog steps along an annealing path between
a tractable base distribution :math:q_0 (typically
AutoNormalGuide) and the target posterior. The
trajectory's per-step parameters (step size, base mean / scale,
and the inverse-temperature schedule) are all variational
parameters trained by SVI. Concretely, every leapfrog operation
is reparameterized through the momentum and position so gradients
flow end-to-end through the trajectory.
DAIS gives an unbiased lower-bound estimator of the model
evidence (Geffner-Domke 2021,
doi:10.48550/arXiv.2102.07501
<https://doi.org/10.48550/arXiv.2102.07501>; Zhang et al. 2021,
doi:10.48550/arXiv.2107.10211
<https://doi.org/10.48550/arXiv.2107.10211>) that strictly
dominates the base guide's ELBO for num_steps >= 1. Combined
with multimodal base guides (AutoMixtureGuide) it
recovers multimodal posteriors that plain VI misses.
The implementation tracks the auxiliary "extended-target" form: a fresh momentum is sampled at the start of each transition and discarded at the end (no Metropolis correction in the differentiable variant; the integrator is deterministic and the trajectory length is fixed). The variational lower bound absorbs the change-of-variables for the leapfrog flow and the momentum prior / posterior contributions.
AutoDAIS
¶
AutoDAIS(base: Guide, model: MonadicProgram, observations: dict[str, Tensor], x: Tensor | None = None, num_steps: int = 8, leapfrog_steps: int = 1, init_step_size: float = 0.1, init_temperature: float = 0.1)
Bases: Guide
Annealed-importance-sampling guide wrapping a base guide.
| PARAMETER | DESCRIPTION |
|---|---|
base
|
Base variational guide (the bridge's start). Must be built
against the same model + observed-name set the DAIS guide
is for.
TYPE:
|
model
|
Generative model. Required because DAIS needs the target log-density at each annealing step.
TYPE:
|
observations
|
Observed-site values that pin the model's likelihood.
The DAIS bridge anneals between
TYPE:
|
x
|
Program input fed to the model's log-joint. Default
TYPE:
|
num_steps
|
Number of HMC-style leapfrog transitions along the path.
TYPE:
|
leapfrog_steps
|
Inner leapfrog substeps per transition. Default
TYPE:
|
init_step_size
|
Initial leapfrog step size. Adapted as a learnable scalar.
TYPE:
|
init_temperature
|
Initial first-bridge inverse temperature. The schedule
anneals from this value at step 1 to
TYPE:
|
Source code in src/quivers/inference/dais.py
log_prob
¶
Effective log-density of the trajectory's endpoint.
DAIS does not admit a closed-form density at the endpoint
because the trajectory is stochastic in the momentum. The
differentiable lower-bound estimator instead substitutes
:math:\log \pi(z) - \mathrm{log\_weight} for
:math:\log q(z) in the ELBO, so when this guide is used
with an ELBO objective the per-step ELBO is the
DAIS lower bound. We return that quantity here.