mixle.task.distill module

Distill a teacher callable into a local TaskModel.

The teacher can be any callable that labels text: an LLM endpoint, a slow rule, or a human-reviewed map. The student is a compact classifier over dependency-free hashed n-gram features (HashedNGram), trained to reproduce the teacher’s labels and returned as a durable TaskModel. agreement measures held-out fidelity to the teacher and is the objective tune_recipe() optimizes when it searches student recipes with mixle.doe.

Only the student fit needs torch; the teacher is opaque. distill is deterministic given seed.

distill_for_routing/distill_records_for_routing are the routing-ready siblings: they hold out a calibration slice, fit the student on the rest, and return a CalibratedTaskModeldecide()-able out of the box, so it drops straight into Cascade or Router with no separate calibration step to remember or get wrong.

distill(teacher, texts, *, labels=None, n=3, dim=256, hidden=(64,), epochs=200, lr=1e-2, seed=0, task='', device='cpu', n_jobs=1)[source]

Label texts with teacher, fit a local student, and return a callable TaskModel.

n/dim size the hashed n-gram featurizer; hidden the student MLP. labels fixes the label set (else inferred from the teacher’s outputs). The student’s train-set agreement with the teacher is recorded in meta. n_jobs > 1 fans teacher labeling across that many threads (order-preserving; the win is parallel in-flight requests against a network-bound teacher) – every distill_* teacher entry point takes the same knob.

Parameters:
Return type:

TaskModel

distill_from_labels(texts, teacher_labels, *, labels=None, n=3, dim=256, hidden=(64,), epochs=200, lr=1e-2, seed=0, task='', device='cpu')[source]

Fit a student from already-labeled (texts, teacher_labels) – the teacher-free training core of distill.

Active labeling (mixle.task.active) uses this to avoid re-querying the teacher: it controls exactly which examples were paid for and passes their labels straight in. labels fixes the label set so a student trained on a partial sample still spans every class.

Parameters:
Return type:

TaskModel

distill_for_routing(teacher, texts, *, labels=None, calibration_frac=0.2, alpha=0.1, n=3, dim=256, hidden=(64,), epochs=200, lr=1e-2, seed=0, task='', device='cpu', density_gate=False, density_gate_alpha=0.05, n_jobs=1)[source]

Label texts with teacher, fit a student, and calibrate it for routing – all in one call.

A calibration_frac slice of the (teacher-)labeled data is held out from training and used to set a conformal threshold, so the returned CalibratedTaskModel is immediately decide()-able: confident, in-distribution inputs get the student’s label; everything else is ESCALATE. Pass it straight to Cascade (with teacher) or Router for tiered serving – no separate calibration split to manage by hand. Deterministic given seed; the calibration slice is disjoint from the student’s training data.

density_gate=True additionally escalates inputs a softmax cannot see are atypical: see distill_from_labels_for_routing().

Parameters:
Return type:

CalibratedTaskModel

distill_from_labels_for_routing(texts, teacher_labels, *, labels=None, calibration_frac=0.2, alpha=0.1, n=3, dim=256, hidden=(64,), epochs=200, lr=1e-2, seed=0, task='', device='cpu', density_gate=False, density_gate_alpha=0.05)[source]

Teacher-free training core of distill_for_routing(): fit + calibrate from labels already in hand.

Splits (texts, teacher_labels) into a training slice and a held-out calibration_frac slice (fixed by seed), trains the student on the former via distill_from_labels(), then calibrates (calibrate()) on the latter. labels (if given, else inferred from all of teacher_labels before the split) is shared by both slices so a class that lands entirely on one side of the split doesn’t shrink the label set out from under the other.

density_gate=True fits a DensityGate on the training slice’s features (reusing the student’s own featurizer, so there is no second feature space to keep in sync), calibrates its OOD floor (density_gate_alpha) on the disjoint calibration slice, and wires it into the returned model – an input whose log p(x) falls below that floor escalates even if the conformal set is a confident singleton.

Parameters:
Return type:

CalibratedTaskModel

distill_records(teacher, records, *, labels=None, dim=256, hidden=(64,), epochs=200, lr=1e-2, seed=0, task='', device='cpu', n_jobs=1)[source]

Distill a teacher into a record classifier (record -> label over tuples/dicts of mixed fields).

The structured-data sibling of distill(): classify a transaction, route a ticket, categorize a record. Uses the hashing-trick HashedRecord featurizer, so it needs no fitted encoder.

Parameters:
Return type:

TaskModel

distill_records_from_labels(records, teacher_labels, *, labels=None, dim=256, hidden=(64,), epochs=200, lr=1e-2, seed=0, task='', device='cpu')[source]

Teacher-free record-classifier training core (mirrors distill_from_labels() for structured records).

Parameters:
Return type:

TaskModel

distill_records_for_routing(teacher, records, *, labels=None, calibration_frac=0.2, alpha=0.1, dim=256, hidden=(64,), epochs=200, lr=1e-2, seed=0, task='', device='cpu', density_gate=False, density_gate_alpha=0.05, n_jobs=1)[source]

The structured-record sibling of distill_for_routing(): fit + calibrate a record classifier in one call, returning a routing-ready CalibratedTaskModel.

Parameters:
Return type:

CalibratedTaskModel

distill_records_from_labels_for_routing(records, teacher_labels, *, labels=None, calibration_frac=0.2, alpha=0.1, dim=256, hidden=(64,), epochs=200, lr=1e-2, seed=0, task='', device='cpu', density_gate=False, density_gate_alpha=0.05)[source]

Teacher-free training core of distill_records_for_routing() (mirrors distill_from_labels_for_routing() for structured records). density_gate=True fits the OOD gate on the training slice’s record features and calibrates it on the calibration slice, same as the text path.

Parameters:
Return type:

CalibratedTaskModel

distill_structured(teacher, records, *, labels=None, n_components=1, min_gain=0.0, n_bins=4, max_its=30, seed=0, task='', n_jobs=1)[source]

Distill a teacher into a structured probabilistic classifier – a learned Bayesian network, not an MLP.

The teacher labels records; mixle.inference.structure.learn_structure() then discovers the dependency forest over the joint (field_1, ..., field_m, label) and fits it. The student classifies by the generative rule argmax_label P(features, label) – and because softmax_label log P(features, label) = P(label | features) exactly, its confidence is a real posterior the cascade/calibration stack can trust. Unlike distill_records() (a hashed-feature MLP), this student is interpretable (model.edges() lists the discovered dependencies), a few kilobytes on disk, and needs no torch to run.

n_components > 1 fits a MixtureOfDependencyTrees – a latent-cluster student whose sub-structures differ by regime. Assumes a fixed record schema (see StructuredClassifierIO).

Parameters:
Return type:

TaskModel

distill_structured_from_labels(records, teacher_labels, *, labels=None, n_components=1, min_gain=0.0, n_bins=4, max_its=30, seed=0, task='')[source]

Teacher-free core of distill_structured(): fit a structured classifier from labeled records.

Parameters:
Return type:

TaskModel

agreement(student, teacher_labels, texts)[source]

Fraction of texts where the student’s label matches the teacher’s – distillation fidelity.

Parameters:
Return type:

float