mixle.inference.production package¶
Production / MLOps layer for fitted mixle models.
The deployment-facing half of inference, kept out of the core mixle.inference namespace: reproducible
model artifacts (provenance headers + verifiable training lineage), drift detection, a versioned model
registry, a scoring service, and a drift-triggered monitor.
provenance:
fit_with_provenance-> aHeader(config, data hash, model hash, convergence trace, timing, env);verify_lineagechecks the per-iteration model-hash chain.drift:
detect_drift->DriftReport(feature PSI/KS + model score drift).registry / serving / monitor:
Registry(versioned store + alias swap + checkpointer),Service(batch scoring + activity logging),Monitor(drift -> retrain -> swap).
The container/Kubernetes serving layer that wraps Service lives in the separate mixle-deploy
package.
- fit_with_provenance(data, estimator, *, seed=None, lineage=True, **optimize_kw)[source]
Fit
estimatorondatavia EM (mixle.inference.optimize()) and return(model, header), the model carrying a.headerHeaderwith the data hash, the final model hash, schema, training settings + per-iteration convergence trace, timing, final log-likelihood, and environment. Pass your ownout=to print iterations (then the trace is not captured).With
lineage=True(default) each iteration in the convergence trace also records the accepted model’smodel_hashand the previous iteration’sparent_hash, forming a verifiable hash chain (check it withverify_lineage()). This fingerprints the model every iteration; passlineage=Falseto skip it for very large models. Any useron_step=is still called.
- verify_lineage(header)[source]
Check that a header’s per-iteration convergence trace is an intact model-hash chain.
Returns True when every iteration that recorded a
model_hashnames the previous such iteration’s hash as itsparent_hash(so iteration i+1 provably descends from i), and True vacuously when the trace carries no lineage (fit_with_provenance(lineage=False)or a customout). Returns False on the first broken link. Accepts aHeaderor itsto_dict.
- class Header(model_type, model_summary, schema, n_records, dataset_hash, final_loglik, model_hash=None, training=<factory>, timing=<factory>, resources=<factory>, environment=<factory>, created_at='')[source]
Bases:
objectA descriptive, serializable provenance record for a fitted model.
- Parameters:
- model_type: str
- model_summary: str
- dataset_hash: str
- training: dict
- timing: dict
- resources: dict
- environment: dict
- created_at: str = ''
- build_header(model, data, *, training=None, started=None, finished=None, final_loglik='auto', resources=None, hash_sort=False, hash_max_records=None)[source]
Build a
Headerformodeltrained ondata(does not run any fitting).
- environment_info()[source]
Snapshot of the software/hardware environment for reproducibility.
- Return type:
- detect_drift(model, reference, current, *, psi_threshold=0.25, ks_threshold=0.2, loglik_shift_threshold=-0.5, per_feature=True)[source]
Combine score drift and per-feature drift into a single
DriftReport.driftis flagged if the score-distribution KS exceedsks_threshold, OR the mean log-likelihood drops by more than-loglik_shift_threshold(i.e.mean_loglik_shift < loglik_shift_threshold), OR any feature’s PSI exceedspsi_threshold.
- score_drift(model, reference, current)[source]
The model-native drift signal: how the model’s log-density distribution shifts from reference to current data. Returns the KS statistic between the two log-likelihood samples and their mean shift (mean current log-density minus mean reference; negative => current data is less likely under the model).
- class DriftReport(drift: 'bool', score: 'dict', per_feature: 'dict' = <factory>, thresholds: 'dict' = <factory>)[source]
Bases:
object- drift: bool
- score: dict
- per_feature: dict
- thresholds: dict
- class Registry(root)[source]
Bases:
objectA directory of named models, each with numbered versions and movable aliases.
- Parameters:
root (str)
- versions(name)[source]
Version ids for
namein registration order (v1,v2, …).
- register(model, name, *, header=None, metadata=None)[source]
Store
modelundernameas a new version; return its version id.headerdefaults tomodel.headerif present. The model is serialized with the safe mixle registry; the header (aHeaderor dict) andmetadataare stored alongside.
- checkpointer(name, *, every=1)[source]
Return an
optimize(on_step=...)callback that snapshots the model undernameeveryeveryiterations (recording the iteration + log-density in the version metadata).Each checkpoint records its model
model_hashand the previous checkpoint’sparent_hash, so the saved snapshots form a verifiable chain (seeverify_chain()). Resume an interrupted run from the latest checkpoint:reg = Registry("ckpts") optimize(data, est, on_step=reg.checkpointer("run", every=5)) model, _ = reg.get("run") # latest checkpoint optimize(data, est, prev_estimate=model) # continue training
- get(name, version='latest')[source]
Load
(model, header)for a version ("latest"= highest-numbered).
- header(name, version='latest')[source]
Just the provenance header of a version (no model deserialization).
- metadata(name, version='latest')[source]
Just the
metadataof a version (no model deserialization) – e.g. a checkpoint’s iteration.
- promote(name, version, alias='production')[source]
Point
alias(e.g."production") atversion– the atomic model swap.
- current(name, alias='production')[source]
Load the model an
aliaspoints at (falls back tolatestif the alias is unset).
- verify_chain(name)[source]
Verify the persisted checkpoint lineage for
name(seecheckpointer()).For each version carrying a
model_hash, checks that itsparent_hashmatches the previous such version’s hash and that re-hashing the loaded model reproduces the stored hash (catching corruption or tampering). Returns True when every link holds, or vacuously when no version carries lineage metadata.
- class Service(model, *, name=None, reference=None, log_path=None, keep=1000)[source]
Bases:
objectA deployed model that scores batches and logs each computation for monitoring.
- classmethod from_registry(registry, name, *, alias='production', **kw)[source]
Load the model an alias points at in
registryand serve it (carrying its provenance header).
- score(records)[source]
Return per-record log-densities and log the computation (timing, mean log-lik, unscorable count).
- check_drift(records)[source]
Drift of
recordsversus the service’s reference sample (requires areference).
- class Monitor(model, estimator, reference, *, psi_threshold=0.25, ks_threshold=0.2, loglik_shift_threshold=-0.5)[source]
Bases:
objectStateful monitor for one deployed model: drift detection + retrain-and-swap + DOE-driven sampling.
- Parameters:
- check(current)[source]
Drift report of
current(production) data against the reference under the current model.- Parameters:
current (Any)
- Return type:
DriftReport
- update(current, *, retrain=True, combine_reference=True, **fit_kw)[source]
Check drift on
currentand, if drift is flagged andretrain, fit a fresh model (with a new provenance header) and swap it in. Returns{report, action, model, header}and appends tohistory.combine_referenceretrains on reference + current (else current only).
- suggest_samples(bounds, n=10, *, method='lhs', objective=None, seed=None)[source]
Use
mixle.doeto propose where to collect new data (e.g. after drift, or to meet an objective).method='lhs'/'sobol'gives a space-filling batch overbounds(list of(lo, hi)); pass anobjective(x)->floatto switch to active learning (ALC/ALM) that targets where the model is most informative.