FittedPipeline¶
The deployable artifact returned by AutoSupervised.fit. It
holds only what prediction needs (the AutoGluon predictor, the frozen recipe, and
the fitted calibration / thresholds / intervals / target-transform / baseline
layers) and applies them at predict time. See the
inference guide.
In short
FittedPipelineis whatAutoSupervised.fitreturns andparleml_ml4.load_pipelinereloads.- It holds the AutoGluon predictor, the frozen recipe and the post-fit layers, and applies
them at
predicttime. decision_basisanddecision_provenancemake the decision layer re-decidable without retraining.feature_insightcarries the fit-time "why" payload for raw text and categorical columns.
Two passengers are not prediction layers. decision_basis is what calibration, the
decision threshold and the baseline gate were fitted from, and decision_provenance
says which revision of those three is serving — together they are what makes the layer
re-decidable without retraining. See the decision layer.
The other is feature_insight, which carries the fit-time
"why" payload for the raw text / categorical columns. It rides here because
nothing downstream can rebuild it — the bundle keeps no training rows — so an
explanation surface that tried to derive it at serve time would have nothing to
read. See the
interpretability contract.
FittedPipeline
dataclass
¶
FittedPipeline(
predictor: TabularPredictor,
task: Tasks,
positive_class: Any = None,
calibration: Optional[CalibrationMap] = None,
calibration_report: Optional[CalibrationReport] = None,
decision_basis: Optional["DecisionBasis"] = None,
decision_provenance: Optional[
"DecisionLayerProvenance"
] = None,
threshold: Optional[BinaryThreshold] = None,
multiclass_thresholds: Optional[
MulticlassThresholds
] = None,
multiclass_thresholds_discarded: bool = False,
interval: Optional[IntervalLayer] = None,
interval_coverage: float = 0.9,
apply_calibration: bool = True,
baseline: Optional[BaselineReport] = None,
holdout_info: Optional[Dict[str, Any]] = None,
target_transform: Optional[TargetTransform] = None,
eval_metric: Optional[EvalMetric] = None,
recipe: Optional["FeatureRecipe"] = None,
monotone_evidence: Optional["MonotoneEvidence"] = None,
infer_cost_s_per_row: Optional[float] = None,
treelite: Optional["TreeliteAccelerator"] = None,
feature_insight: Optional["FeatureInsight"] = None,
requested_models: Tuple[str, ...] = (),
search: Optional["SearchReport"] = None,
fit_rows: Optional["FitRows"] = None,
out_of_sample: Optional["OutOfSampleProba"] = None,
)
A deployed model + its post-fit statistical layers.
Task-aware: classification serves predict / predict_proba; regression
serves predict / predict_interval. Each task's post-fit layers are
optional (fit only when applicable), so the same facade covers all three.
is_calibration_active
property
¶
Whether calibrated probabilities are served by default.
predict_is_expensive
property
¶
Whether serving is costly — MLI reads this to budget SHAP / permutation
sampling (§7.3). True when either (a) a foundation / in-context leaf is in the
deployed strongest model (it re-encodes its context on every predict), or (b) a measured
end-to-end cost exceeds :data:EXPENSIVE_S_PER_ROW (see :meth:measure_infer_cost).
ml_task
property
¶
Alias of :attr:task under the published InterpretablePipeline name (§7.3).
classes_
property
¶
The class labels MLI aligns explanations to; None for regression.
Deliberately the full column set, including any :meth:untrained_classes: this is a
column-alignment contract for :meth:predict_proba, and AutoGluon's frame carries a
(constantly zero) column for a deleted class. Dropping it here would misalign every
consumer that zips classes_ against a probability row. The place the distinction
matters is scoring, and that is where it is made (:mod:parleml_ml4.evaluation).
predict_proba ¶
Class probabilities; calibrated by default when a calibration is present.
predict ¶
Predictions: thresholded class labels (classification) or point values in
original units (regression). Classification with neither a decision layer nor an
active calibration delegates to AutoGluon's own predict to preserve its native
output; otherwise the label is decided on the served probabilities, as the baseline
gate, :func:~parleml_ml4.evaluation.evaluate and the export decide it.
There is deliberately no calibrated toggle here, unlike :meth:predict_proba
(CAL-5). ml4 fits ONE decision layer, on whichever probabilities actually serve —
decision_layer.fit_decision_layer tunes it on the calibrated frame when calibration
won its bake-off, raw otherwise — and stores no raw-scale twin. A toggle on this method
therefore offered a cutoff selected on one scale to numbers on another: for binary, a
threshold tuned at (say) 0.31 on calibrated probabilities applied to a raw column whose
operating point is nowhere near it; for multiclass, per-class divisors tuned one-vs-rest
on calibrated columns dividing a raw matrix. Both produce plausible-looking labels at an
operating point the model was never validated at, silently. predict_proba keeps the
toggle because a probability is meaningful on either scale; a decision is not.
The air-gapped :class:~parleml_ml4.delivery.export.ExportedPipeline has never had the toggle
and was always correct — this brings the in-process facade in line with the artifact it
ships.
main_thresholds ¶
The per-class operating points the SERVED decision rule uses; empty when no layer was fit.
Binary → {positive_class: cut}, the value predict compares P(positive)
against. Multiclass → {class: divisor}, the vector argmax_c P_c / d_c divides
by (:meth:~parleml_ml4.delivery.thresholds.MulticlassThresholds.divisors), not the raw
per-class sweep outcome in
:attr:~parleml_ml4.delivery.thresholds.MulticlassThresholds.thresholds.
The distinction is not cosmetic and this method used to get it wrong. A class whose
one-vs-rest sweep refused to run — or returned a bar at ~0 — keeps a degenerate marker
in thresholds that the served rule deliberately does not divide by (MET-2), so
publishing the raw map here meant every consumer of ml4's "published operating point"
(measures.json, the model card, MLI's case page, the backend's batch scorer) stated
a decision rule the deployed model does not implement, for precisely the classes whose
handling is least obvious. :meth:tuned_thresholds is where the measurement lives.
tuned_thresholds ¶
What each per-class sweep actually RETURNED, before the served rule reinterprets it.
Identical to :meth:main_thresholds for binary (a cut is served as measured) and for a
multiclass layer whose every class tuned to a usable bar. They diverge exactly on
:meth:substituted_threshold_classes, where the recorded value is a degenerate marker
rather than a measurement — which is the honest thing to publish under this name and
the dishonest thing to publish under the other.
substituted_threshold_classes ¶
Classes where :meth:main_thresholds and :meth:tuned_thresholds disagree — the
multiclass classes served a neutral divisor because their own bar is unusable. Always
empty for binary (there is nothing to substitute) and when no layer was fit.
main_decision_threshold ¶
The operating threshold MLI displays: for cls if given, else the binary
positive-class threshold; None when no decision layer was fit or (multiclass)
no single main threshold exists.
leaf_models ¶
The deployed strongest model's raw leaf estimators for MLI (§7.3) — exactly one on the regulated path. Each carries the library estimator MLI introspects directly (ml4 extracts no coefficients/rules/shapes itself).
scorecard_points ¶
The deployed scorecard's points table + its scale; None for any other model.
The regulated scorecard's deliverable is not its coefficients — it is
base + Σ points·attribute, in the attributes' own units. That table is computed
by :class:~parleml_ml4.engine.models.glassbox.GlassBoxModel and lives on the AutoGluon
wrapper, one level above the LogisticRegression a
:class:~parleml_ml4.contracts.pipeline_protocol.LeafModelHandle carries (whose coef_
is in standard deviations of an engineered column, not in an applicant's units).
So this accessor exists rather than a handle field: without it the audit artifact
the regulated path is for never left the library (REG-2).
None — not a guess — when the strongest model is bagged or an ensemble of scorecards.
Each fold child fits its own coefficients and AutoGluon averages probabilities,
so no single table reproduces the served score, and a table that does not reproduce
the score is not an audit artifact. A regulated run cannot hit that case
(its fit shape never bags and builds no weighted ensemble);
it is guarded because publishing one fold's points as "the scorecard" would be a
quiet lie if that ever changed.
best_introspectable_leaf ¶
The best introspectable basic-tree base leaf on the board — for MLI native rules (§7.3).
Unlike :meth:leaf_models (which unwraps the deployed strongest model), this scans the whole
AutoGluon board for the best-scoring readable tree — GBDT preferred, glass-box as a
fallback — so native rules are produced even when the strongest model is a weighted ensemble or
a foundation model. None when nothing introspectable survives on disk.
warmup ¶
Prime lazy model / feature-generator state so the first real predict isn't
cold (§7.9). Runs one throwaway prediction on a tiny slice of X; idempotent
and safe to call repeatedly. A no-op on an empty frame.
measure_infer_cost ¶
Measure END-TO-END serving cost in seconds/row (feature generation + model) over
a sample of X — the real latency an SLA sees, not AutoGluon's model-only
infer_limit (§7.9 / P16). Warms up first, takes the best of repeats timed
passes (least contended), records it on :attr:infer_cost_s_per_row, and returns it.
untrained_classes ¶
Classes AutoGluon deleted before training — see :func:untrained_classes_of (TYPE-3).
A class the model has no column to predict is not a class it scored 0 on, so the
evaluation harness excludes these from per_class and the headline (accounting for
their rows under unscored_rows) and names them under test.untrained_classes;
measures.json carries the same list for a run with no outer test.
served_model ¶
Which model predict serves, and whether it is a refit_full retrain.
Under ml4's default engine.refit_full and set_best_to_refit_full the
candidate that won selection (selected_as) is retrained on every training row —
AutoGluon's internal tuning rows included, never the reserved holdout or the outer test —
and that *_FULL twin is what ships. The run's reported scores (the reserved validation
rows and the outer test) are the served model's own; the selection-time validation score
belonged to the candidate before its refit. None for a predictor that cannot say.
text_embedding_records ¶
What this model's text embeddings came from: one record per embedded column.
A local model's pinned revision, or a provider's connection, model and fingerprint — the model's external dependencies, read off the fitted GLOBAL chain. Empty when the recipe embeds nothing (or embedded nothing because its backend was missing at fit).
transform ¶
Raw input → the model-input feature frame (the GLOBAL FE / feature generator).
MLI transforms once here, then reuses the frame across the methods below (the
per-leaf fold-local FE is applied by :meth:prepare_member_introspection_frame).
predict_proba_from_encoded ¶
predict_proba_from_encoded(
encoded: DataFrame,
*,
calibrated: bool = True,
member: Optional[str] = None
) -> DataFrame
Class probabilities from an already-:meth:transformed frame (skips re-running
the feature generator); member scores one leaf model by name, else the strongest model.
predict_point_from_encoded ¶
Regression point predictions in ORIGINAL units from an already-:meth:transformed
frame — the regression analogue of :meth:predict_proba_from_encoded. Per-row
explanation (justify) transforms once then reuses the frame, so it needs a
point predictor that skips the feature generator; the target transform is inverted
so callers see the same units as :meth:predict.
prepare_member_introspection_frame ¶
The introspected base tree's full post-FE matrix (global + its fold-local FE)
from a :meth:transformed frame — the member space MLI aligns SHAP / archetypes /
rules on. Uses the best introspectable base tree (see :meth:_introspection_leaf),
which matches what compute fits its artifacts on even when the strongest model is an
ensemble; raises only when nothing on the board is introspectable.
evaluate ¶
evaluate(
X_test: DataFrame,
y_test: Any,
*,
metric: Optional[EvalMetric] = None,
bootstrap: int = 1000,
cfg: Optional["Ml4Config"] = None
) -> Dict[str, Any]
Fit-time measures + reported scores on a labelled test set.
Lives here, not only on :class:~parleml_ml4.facade.AutoSupervised, because this is the object
you actually hold after :func:parleml_ml4.load_pipeline — a reloaded bundle had predict and
save but no way to score itself, so evaluating one meant knowing to reach past the
published surface into :mod:parleml_ml4.evaluation.
metric overrides the pipeline's own evaluation metric for this report; bootstrap
is the resample count behind the headline score's 95% CI (0 skips it).
cfg is only needed for a run whose metric was beta / user_defined_metric: the
custom scorer cannot be rebuilt from the bundle alone, so without it the report falls back
to the task default and says so rather than silently mislabelling the number (DL-6).
:meth:AutoSupervised.evaluate <parleml_ml4.facade.AutoSupervised.evaluate> passes its own config
for you; pass it here when you reloaded from disk and used a custom metric.
save ¶
Persist this pipeline as a bundle directory (predictor + post-fit layers).
load
classmethod
¶
Restore a pipeline from a bundle written by :meth:save.
A pipeline that pseudonymises identifier columns predicts only where
$ML4_PSEUDONYMISATION_KEY holds the key it was fitted with — the bundle stores the
key's fingerprint, never the key (see :func:~parleml_ml4.delivery.bundle.load_pipeline).
threshold_report ¶
Honest vs optimistic F-β on a labelled set — the deployed operating point (tuned on validation) vs a threshold re-tuned on this set (leaks → an upper bound, never the real score). Binary only; scores calibrated proba, matching how the operating threshold was tuned.
predict_intervals ¶
Regression prediction + every configured band: prediction plus lo_<L> / hi_<L>
per level (adaptive width under CQR). Bands obey lo <= prediction <= hi and nest by level.
predict_interval ¶
Regression prediction + a single band (prediction / lower / upper) at
coverage (default: the widest configured level). For all configured levels at once
use :meth:predict_intervals.