mixle.models.energy module¶
EnergyModel – an energy-based density p(x) ∝ exp(-E(x)) as a composable Mixle leaf.
The one neural density whose normalizer is intractable: p(x) = exp(-E(x)) / Z with Z = ∫ exp(-E(x)) dx
unavailable in closed form. So unlike the flows (exact) it is trained and scored approximately, and this is
part of the model contract.
Training is Noise-Contrastive Estimation (Gutmann & Hyvärinen 2010), not maximum likelihood: the model learns to tell data from samples of a known noise distribution, and in doing so learns a scalar log-normalizer
calongside the energy net. NCE is consistent – as data grow,c -> log Zand-E(x) + c -> log p(x)– solog_density(x) = -E(x) + cis an approximately normalized log-density, usable directly (no per-evaluation partition estimate). It composes in a mixture, but because it is only approximately normalized it can bias mixture weights against an exact leaf.Sampling is unnormalized-density MCMC: a few steps of Langevin dynamics
x <- x - s ∇E(x) + sqrt(2s) ε.
Its value over the flows is the inductive bias: an energy net imposes no ordering and no invertibility – it scores
compatibility, so it captures undirected/symmetric structure a coupling or autoregressive flow parameterizes
awkwardly. build_energy_net() is a ready MLP energy to wrap.
- class EnergyModel(module, *, m_steps=200, lr=5e-3, noise_ratio=1, langevin_steps=40, langevin_step=0.05, device='cpu', name=None)[source]
Bases:
SequenceEncodableProbabilityDistributionlog p(x) ≈ -E(x) + cfor an energy module (module.energy(x) -> (n,)and a learned scalarlog_norm).Approximately normalized (trained by NCE);
log_densityreturns-E(x) + c. Composes like any leaf.- Parameters:
- log_density(x)[source]
Return the approximate normalized log density for one observation.
- seq_log_density(x)[source]
Return approximate normalized log densities for a batch of observations.
- sampler(seed=None)[source]
Return a Langevin sampler for the learned energy model.
- Parameters:
seed (int | None)
- Return type:
EnergyModelSampler
- estimator(pseudo_count=None)[source]
Return the NCE estimator used as the model’s M-step.
- Parameters:
pseudo_count (float | None)
- Return type:
EnergyModelEstimator
- dist_to_encoder()[source]
Return the encoder for vectorized energy-model scoring.
- Return type:
EnergyModelEncoder
- to_dict()[source]
Serialize hyperparameters and module bytes for registry-based round trips.
- class EnergyModelSampler(dist, seed=None)[source]
Bases:
DistributionSamplerLangevin dynamics on the (unnormalized) energy:
x <- x - s ∇E(x) + sqrt(2 s) ε.- Parameters:
dist (EnergyModel)
seed (int | None)
- class EnergyModelEncoder[source]
Bases:
DataSequenceEncoderEncode observations for vectorized energy-model scoring and fitting.
- class EnergyModelAccumulator[source]
Bases:
SequenceEncodableStatisticAccumulatorBuffers responsibility-weighted data for the NCE M-step (weights = the E-step soft counts).
- update(x, weight, estimate)[source]
Add one weighted observation to the NCE accumulator.
- seq_update(enc, weights, estimate)[source]
Add an encoded batch and responsibility weights to the accumulator.
- initialize(x, weight, rng)[source]
Initialize from one observation using the ordinary update path.
- seq_initialize(enc, weights, rng)[source]
Initialize from an encoded batch using the ordinary batch update path.
- combine(other)[source]
Merge the value tuple from another energy-model accumulator.
- Parameters:
other (Any)
- Return type:
EnergyModelAccumulator
- from_value(v)[source]
Restore accumulator buffers from a value tuple.
- Parameters:
v (tuple)
- Return type:
EnergyModelAccumulator
- acc_to_encoder()[source]
Return the encoder expected by this accumulator.
- Return type:
EnergyModelEncoder
- class EnergyModelAccumulatorFactory[source]
Bases:
StatisticAccumulatorFactoryFactory for energy-model accumulators.
- make()[source]
Create a fresh accumulator.
- Return type:
EnergyModelAccumulator
- class EnergyModelEstimator(module, *, m_steps=200, lr=5e-3, noise_ratio=1, langevin_steps=40, langevin_step=0.05, device='cpu', name=None)[source]
Bases:
ParameterEstimatorM-step: Noise-Contrastive Estimation against a Gaussian noise fit to the (weighted) data.
Learns the energy net and the scalar log-normalizer
log_normby logistic discrimination of data from noise – so the resulting-E(x) + log_normis a consistent, approximately-normalized log-density.- Parameters:
- accumulator_factory()[source]
Return an accumulator factory for weighted NCE batches.
- Return type:
EnergyModelAccumulatorFactory
- build_energy_net(dim, *, hidden=64, layers=3)[source]
An MLP energy
E(x): R^dim -> R(plus a learned scalarlog_norm) – ready to wrap in an EnergyModel.Lower energy = higher (unnormalized) density.
log_normis the NCE-learned normalizer, so the pairedEnergyModelscores-E(x) + log_norm. Swap in any module exposingenergy(x) -> (n,), alog_normparameter and adimattribute.
- build_convex_energy_net(dim, *, hidden=64, layers=3)[source]
An input-convex MLP energy
E(x): R^dim -> R, convex inxBY CONSTRUCTION – ready to wrap in anEnergyModelexactly likebuild_energy_net(). A convex energy gives Langevin sampling (EnergyModelSampler) a unimodal target with no spurious local minima to get stuck in, and gives any consumer of the fitted energy a certified-convex scalar-valued potential (e.g. a verified optimum for a downstreammixle.doesearch over-E(x)). See_convex_energy_net_class()for the construction.
- build_product_energy_net(experts)[source]
Combine expert energy modules multiplicatively: one module with
energy(x) = sum_k experts[k].energy(x).A product of experts,
p(x) ∝ prod_k p_k(x)– a conjunction (each expert a soft constraint, the product their intersection), as opposed to a mixture’s disjunction. This is the ENERGY-BASED, arbitrary-density complement tomixle.ops.product_of_experts(), which pools tractable families (Categorical, Gaussian) in closed form but deliberately raises on the general continuous case because the product normalizer is then intractable. That intractable normalizer is exactly what the energy stack already handles: wrap the result here in anEnergyModelto fit the sharedlog_normby NCE and sample by Langevin, no new machinery.Each expert must expose
energy(x) -> (n,)and adimattribute (e.g. anybuild_energy_net()/build_convex_energy_net()module, all sharing one input dim), and stays individually inspectable via the built module’s.experts/.expert_energies(x). Fit it in one line:model = EnergyModel(build_product_energy_net([expert_a, expert_b]), m_steps=250)