mixle.inference.em module¶
Expectation-maximization strategy helpers.
The strategies in this module are deliberately orchestration-level objects: they move encoded data through existing estimators/kernels and never contain distribution-specific likelihood math.
- class EMStepResult(model, objective=None, accepted=True, metadata=None)[source]
Bases:
objectResult from one EM-family strategy step.
- class SampledSufficientStatistics(suff_stat, nobs=None)[source]
Bases:
objectUnambiguous Monte-Carlo EM payload for an optional observation count.
- class EMStrategy(*args, **kwargs)[source]
Bases:
ProtocolStructural contract for an EM-family strategy consumed by
run_em().Every strategy object in this module (
StandardEM,PosteriorTransformEM,AnnealedEM, …) satisfies this Protocol structurally by exposing astep(...) -> EMStepResultmethod.run_emand_em_step_fndispatch on it polymorphically; membership is decided byisinstance().- step(enc_data, estimator, model, engine=..., objective=...)[source]
Run one EM-style update and return the resulting model and objective metadata.
- class StandardEM[source]
Bases:
objectThe ordinary Dempster-Laird-Rubin EM update with an exact M-step.
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Run one exact EM update and return the new model.
- class CompiledEM(*, compute_dtype=None)[source]
Bases:
objectLocal full-mixture EM using the profiled fused component kernels.
This is the reusable form of the full-tree execution path used by block EM. It keeps the ordinary EM fixed point and update semantics, but can avoid generic accumulator traversal for fusible subtrees of a
MixtureDistribution. Unsupported models or remote execution engines fall back toStandardEM.- Parameters:
compute_dtype (Any)
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Run one compiled full-mixture E/M sweep.
- class PosteriorTransformEM(temperature=1.0, hard=False)[source]
Bases:
objectEM update that transforms mixture posteriors before the M-step.
temperature=1gives the usual soft EM responsibilities.hard=Truegives classification/hard EM. Intermediate temperatures implement a simple deterministic-annealing style generalized EM update.- step(enc_data, estimator, model, engine=None, objective=None)[source]
Run one posterior-transformed E-step followed by the estimator M-step.
- class HardEM[source]
Bases:
PosteriorTransformEMClassification EM using maximum-posterior component assignments.
- class AnnealedEM(temperatures, hard_final=False)[source]
Bases:
objectDeterministic-annealing EM over a temperature schedule.
Temperatures greater than one flatten mixture responsibilities early in a run, then later entries in the schedule can cool toward ordinary EM at temperature one or hard/classification EM at temperature zero. The object owns only the schedule; posterior math and M-steps remain delegated to
PosteriorTransformEMand the estimator.- property current_temperature: float
Return the schedule temperature for the next annealed step.
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Run one annealed posterior-transform EM step and advance the schedule.
- reset()[source]
Restart the annealing schedule for a new EM run.
- Return type:
None
- class GeneralizedEM(candidate_fn, require_improvement=True)[source]
Bases:
objectGeneralized EM wrapper around a caller-supplied candidate step.
The candidate function is called as
candidate_fn(enc_data, estimator, model, engine). Whenrequire_improvementis true, the candidate is accepted only if the supplied objective (or observed log likelihood by default) does not decrease.- Parameters:
candidate_fn (Callable[[Any, ParameterEstimator, Any, Any | None], Any])
require_improvement (bool)
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Evaluate and optionally objective-gate one caller-supplied GEM step.
- class MonotonicEM(base_strategy=None, require_improvement=True, tolerance=1.0e-9)[source]
Bases:
objectObjective-gated wrapper that rejects log-likelihood-decreasing or non-finite steps.
Wraps any base EM-family strategy (
StandardEMby default). After the base step it evaluates the objective on the candidate; if the candidate objective is non-finite, or (withrequire_improvement) it decreases beyondtolerance, the previous model is kept and the step is marked rejected. This is the robust-path guard against the singular-covariance / NaN cascade and against EM steps that overshoot.- step(enc_data, estimator, model, engine=None, objective=None)[source]
Run the base step, then reject it if the objective is non-finite or decreases.
- class ConditionalMaximizationEM(conditional_steps, require_improvement=True)[source]
Bases:
objectExpectation/conditional-maximization over caller-supplied CM steps.
- Parameters:
conditional_steps (Sequence[Callable[[Any, ParameterEstimator, Any, Any | None], Any]])
require_improvement (bool)
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Run each conditional maximization step with optional objective gates.
- class MonteCarloEM(sample_suff_stat_fn, num_samples=1, seed=None)[source]
Bases:
objectMonte-Carlo EM over sampled sufficient statistics.
sample_suff_stat_fnis called asfn(enc_data, estimator, model, rng, num_samples, engine). Return a bare sufficient statistic, orSampledSufficientStatisticswhen the estimator also needs an explicit observation count. A two-tuple is always treated as a statistic because tuple-valued statistics are common.- Parameters:
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Estimate sufficient statistics by sampling latent completions.
- class VariationalEM(variational_step_fn, m_step_fn, initial_state=None, free_energy_fn=None)[source]
Bases:
objectFree-energy EM over an explicit variational state.
variational_step_fnupdates or creates the variational state. Them_step_fnmaps that state to a new model. A suppliedfree_energy_fncan report the model/state objective without requiring the generic observed-likelihood objective to know about the variational state.- Parameters:
variational_step_fn (Callable[[Any, ParameterEstimator, Any, Any, Any | None], Any])
m_step_fn (Callable[[Any, ParameterEstimator, Any, Any, Any | None], Any])
initial_state (Any)
free_energy_fn (Callable[[Any, ParameterEstimator, Any, Any, Any | None], float] | None)
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Update the variational state, then map it to a candidate model.
- class OnlineEM(schedule=None, init_estimator=None, init_p=0.1, rng=None, encoder=None, num_chunks=1, dataset_size=None)[source]
Bases:
objectDecay-mode stochastic/online EM over encoded mini-batches.
This adapter exposes
StreamingEstimatorthrough the strategy interface used byrun_em: each step folds one batch into decayed sufficient statistics and then reuses the estimator’s ordinary M-step.- Parameters:
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Fold one mini-batch into decayed sufficient statistics.
- reset()[source]
Drop running statistics before a new online EM run.
- Return type:
None
- class IncrementalEM(chunk_id_fn=None, init_estimator=None, init_p=0.1, rng=None, encoder=None, num_chunks=1)[source]
Bases:
objectNeal-Hinton style incremental EM over replaceable encoded chunks.
Revisited chunks replace their previous sufficient-statistic contribution, allowing repeated passes over partitioned data without re-accumulating the whole dataset each iteration.
- Parameters:
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Replace the chunk chosen by
chunk_id_fnand update the model.
- step_chunk(chunk_id, enc_data, estimator, model, engine=None, objective=None)[source]
Replace one named chunk’s sufficient statistics and update the model.
- chunk_value(chunk_id)[source]
Return a stored chunk sufficient-statistic payload.
- reset()[source]
Drop stored chunks and running statistics before a new incremental EM run.
- Return type:
None
- class AcceleratedEM(proposal_fn, base_strategy=None, step_factors=(1.0, 0.5, 0.25), require_improvement=True, tolerance=1.0e-12)[source]
Bases:
objectObjective-gated acceleration wrapper around an EM-family strategy.
The wrapped
base_strategyperforms the ordinary EM/GEM step. The caller-suppliedproposal_fnmay then propose extrapolated candidates from(old_model, base_model, step_factor, enc_data, estimator, engine). This class owns only the orchestration and objective gate; model-specific extrapolation stays with the caller/model layer.- Parameters:
- step(enc_data, estimator, model, engine=None, objective=None)[source]
Run the base strategy, test extrapolated candidates, and keep the best.
- class SquaremEM(base_strategy=None, packer=None, tolerance=1.0e-12, step_growth=4.0)[source]
Bases:
objectSQUAREM acceleration (Varadhan & Roland 2008, SqS3) with an objective gate.
One
stepruns one SQUAREM cycle – THREE base-strategy sweeps: two ordinary EM sweeps give the secant pairr = theta1 - theta0,v = (theta2 - theta1) - r; the squared-extrapolation proposaltheta0 - 2*alpha*r + alpha^2*vwithalpha = min(-1, -sqrt(r.r/v.v))is then stabilized by a third EM sweep. The gate keeps the stabilized proposal only if its objective is at least the plain two-sweep result’s; otherwise the cycle falls back to that plain result, so the accepted sequence is monotone whenever the base strategy is (StandardEM’s exact M-step is). An unpack that rejects the proposal (a constraint violation surfacing asValueError/FloatingPointError/OverflowError) counts as a rejected cycle, never a crash.Cost accounting is honest:
max_itsiterations ofoptimize(strategy=SquaremEM())spend up to3 * max_itsE-step sweeps. The probe receipt for the win (overlapping 6-component GMM, n=100k): plain EM needed 200 sweeps to a target log-likelihood that SQUAREM reached in 33 sweeps, every cycle accepted, monotone throughout.packer:(pack, unpack)between the model and an unconstrained parameter vector; defaultsquarem_packer()(supported families documented there).The strategy is STATEFUL across steps (the adaptive trust-region cap on
alpha): use a fresh instance per fit, exactly asoptimize(strategy=SquaremEM())constructs one.- Parameters:
- step(enc_data, estimator, model, engine=None, objective=None)[source]
One SQUAREM cycle: two base sweeps, one gated extrapolation sweep.
- class RestartEM(initial_models, strategy=None, max_its=10, delta=1.0e-9, max_iter=None)[source]
Bases:
objectRun an EM-family strategy from several initial models and keep the best.
- Parameters:
- run(enc_data, estimator, engine=None, objective=None)[source]
Run each initial model through EM and return the best final model.
- run_em(enc_data, estimator, initial_model, strategy=None, max_its=10, delta=1.0e-9, engine=None, objective=None, max_iter=None, monotone=True, tolerance=1.0e-12)[source]
Run an EM-family strategy until convergence or
max_its.objectivetakes the same values asoptimize():None(MLE), a selection string ('auto'/'mle'/'map'/'vb'), or a readymodel -> floatcallable.max_itsis the canonical iteration-cap spelling (matchingoptimize/fit/best_of);max_iteris accepted as a back-compat alias and overridesmax_itswhen given.monotone=Truetransactionally rejects an objective decrease independently of whetherdeltais disabled. Set it toFalseonly for a strategy whose changing surrogate objective intentionally permits temporary decreases in the supplied reporting objective.The returned model carries a
FitProvenancereceipt (model.fit_provenance()): iterations actually run, whether the run converged ondeltaor stopped at themax_itscap (or on a rejected step), and the final objective. A run exiting on the cap reportsconverged=False, so a truncated fit is distinguishable from a finished one. A run whose very first step is rejected accepts nothing and returnsinitial_modelunchanged; that case additionally raises aUserWarning, because the returned model is the initialization rather than a fit and the receipt alone does not say so.- Parameters:
- Return type:
SequenceEncodableProbabilityDistribution