mixle.task.model module

TaskModel – a fitted small model wrapped as a plain callable: task(raw_input) -> result.

The artifact contract (mixle.task.artifact) makes a model durable; this makes it usable. A task model pairs a fitted model (a torch module or a mixle distribution) with an I/O adapter that turns raw input (a string, a record) into the model’s input and the model’s output into a result (a label, a number). The adapter is serialized into the manifest’s io block, so TaskModel.load(path) reconstructs the whole raw -> result function in a fresh process – the point of the package: a regular program loads a small local model and just calls it.

Adapters self-describe and self-rebuild through a registry (register_adapter / IOAdapter.from_spec). The built-in TextClassifierIO is the workhorse for the distillation path: a dependency-free hashed character n-gram featurizer feeds a small classifier whose argmax indexes a stored label list – the shape of a “scrape this field” / “classify this line” model you distill from a big teacher and run locally.

class HashedNGram(n=3, dim=256, seed=0)[source]

Bases: object

Map a string to a fixed-width float vector by hashing its character n-grams into dim buckets.

Deterministic and dependency-free (stdlib hashlib), so it serializes as three numbers and rebuilds identically anywhere – no fitted vocabulary, no external tokenizer. Counts are L2-normalized per row.

Parameters:
transform(texts)[source]
Parameters:

texts (list[str])

Return type:

ndarray

to_spec()[source]
Return type:

dict[str, Any]

classmethod from_spec(spec)[source]
Parameters:

spec (dict[str, Any])

Return type:

HashedNGram

class HashedRecord(dim=256, seed=0)[source]

Bases: object

Map a heterogeneous record (tuple or dict) to a fixed vector by the hashing trick – tabular tasks.

Each field is hashed by key: a categorical/string/bool value contributes a 1 at hash("key=value"); a numeric value contributes a bounded tanh(value) at hash("num:key") (and its presence at a second bucket). Stateless and deterministic – no fitted encoder or vocabulary – so it serializes as two numbers and rebuilds identically. The shape of a “classify this record / route this ticket / flag this transaction” model.

Parameters:
transform(records)[source]
Parameters:

records (list[Any])

Return type:

ndarray

to_spec()[source]
Return type:

dict[str, Any]

classmethod from_spec(spec)[source]
Parameters:

spec (dict[str, Any])

Return type:

HashedRecord

register_adapter(kind, from_spec)[source]

Register an adapter’s from_spec factory under kind so a saved io block can rebuild it.

Parameters:
Return type:

None

adapter_from_spec(spec)[source]

Rebuild an adapter from its io spec (the kind field selects the factory).

Parameters:

spec (dict[str, Any])

Return type:

Any

class TextClassifierIO(featurizer, labels)[source]

Bases: _ClassifierIO

str -> label: hashed character n-gram features into a small classifier.

Parameters:
  • featurizer (HashedNGram)

  • labels (list[str])

kind = 'text_classifier'
class RecordClassifierIO(featurizer, labels)[source]

Bases: _ClassifierIO

record -> label: hashed-record features into a small classifier (tuples/dicts of mixed fields).

Parameters:
  • featurizer (HashedRecord)

  • labels (list[str])

kind = 'record_classifier'
class StructuredClassifierIO(field_keys, label_index, labels)[source]

Bases: object

record -> label through a structured probabilistic model instead of a neural net.

The model is a fitted joint over (field_1, ..., field_m, label) – a DependencyTreeDistribution (or mixture) discovered by mixle.inference.structure.learn_structure(). Classification is the generative rule argmax_label P(features, label): score each candidate label and pick the best. Because softmax_label log P(features, label) = P(label | features) exactly (the feature evidence is a shared constant across labels), proba_batch() returns the true posterior – not a softmax over arbitrary logits – so conformal calibration (mixle.task.calibrate) and the density gate operate on a real probability.

The student is interpretable (model.edges() shows the discovered dependencies), kilobytes on disk, and round-trips through the json artifact path. It assumes a fixed schema: every record exposes the same fields (field_keys for dicts, positional for tuples) – the variable set a Bayesian network is defined over.

Parameters:
kind = 'structured_classifier'
logits_batch(model, raw_inputs)[source]

Per-label log-joint log P(features, label) as an (m, K) score matrix (the classifier logits).

Parameters:
Return type:

ndarray

proba_batch(model, raw_inputs)[source]

The exact posterior P(label | features) – softmax of the per-label log-joints (shared evidence cancels).

Parameters:
Return type:

ndarray

predict_batch(model, raw_inputs)[source]
Parameters:
Return type:

list[str]

predict(model, raw_input)[source]
Parameters:
Return type:

str

to_spec()[source]
Return type:

dict[str, Any]

classmethod from_spec(spec)[source]
Parameters:

spec (dict[str, Any])

Return type:

StructuredClassifierIO

class TaskModel(model, adapter, *, builder=None, config=None, payload='torch', task='', meta=None)[source]

Bases: object

A fitted small model plus its I/O adapter, callable as task(raw) -> result and saveable to a directory.

Parameters:
  • model (Any)

  • adapter (Any)

  • builder (str | None)

  • config (dict[str, Any] | None)

  • payload (str)

  • task (str)

  • meta (dict[str, Any] | None)

batch(raw_inputs)[source]
Parameters:

raw_inputs (list[Any])

Return type:

list[Any]

save(path)[source]

Persist as a task artifact: the model payload plus the adapter’s io spec and metadata.

Parameters:

path (str)

Return type:

str

classmethod load(path, *, device='cpu')[source]

Rebuild a TaskModel (model + adapter) from a saved artifact directory.

Parameters:
Return type:

TaskModel