Skip to content

Presets, budget and resume

How to trade thoroughness for speed without touching the honesty contract: named presets fill the config, a budget caps the run, and a cache directory makes the second identical fit nearly free. Every python block on this page is self-contained: copy any one of them and it runs as-is — and every block is executed on each CI run, so the examples cannot rot.

Presets

A preset is a named, declarative partial config — data, not code. It fills only the parameters you left unset, so an explicit argument always wins, and the run is keyed and reported on the resolved values, not the preset name. Built-ins: fast (3-fold CV), balanced (adds gated ensembling), best (adds per-model HPO via the optuna extra, plus ensembling); a custom Mapping over the same parameter surface works too. The honesty-controlling parameters — significance, finalize, run_mode — are not presettable by construction: a preset can never silently downgrade the honest-selection contract. Provenance lands in run_report_["preset"] as {"name": ..., "applied": [...]}.

from sklearn.datasets import make_classification

from honestml import AutoML

X, y = make_classification(n_samples=200, n_features=8, n_informative=5, random_state=0)

filled = AutoML(
    task="binary", models=("baseline", "linear"), preset="fast", random_state=0
).fit(X, y)
print(filled.run_report_["preset"], filled.run_report_["config"]["cv"]["n_splits"])

explicit = AutoML(  # an explicit cv=5 wins over the preset's cv=3
    task="binary", models=("baseline", "linear"), cv=5, preset="fast", random_state=0
).fit(X, y)
print(explicit.run_report_["preset"], explicit.run_report_["config"]["cv"]["n_splits"])

The run budget

budget= accepts a float — wall-clock seconds, sugar for BudgetConfig(mode="time", time_budget_s=...) — or a BudgetConfig: mode is "none" (unbounded), "time" or "trials" (with n_trials, the candidate count), and an orthogonal memory_limit_mb (process RSS, needs the memory extra) composes with any mode. Enforcement is cooperative and per-candidate: the check runs before each candidate starts, the time clock starts at the candidate loop (reading the data is not billed), and HPO consumes from the same pool. Degradation is graceful — when the budget runs out mid-run the remaining candidates are skipped, the best model so far still ships, and the final refit is never budget-gated. The outcome lands in run_report_["budget"]: the mode, whether the run was exhausted, the skipped candidate ids and which axis (exhausted_by) ended the run.

from sklearn.datasets import make_classification

from honestml import AutoML, BudgetConfig

X, y = make_classification(n_samples=200, n_features=8, n_informative=5, random_state=0)

model = AutoML(
    task="binary",
    models=("baseline", "linear"),
    budget=BudgetConfig(mode="trials", n_trials=1),  # room for exactly one candidate
    random_state=0,
).fit(X, y)

print(model.best_model_id_)
print(model.run_report_["budget"])

Cache and resume

cache="some/dir" turns on a per-candidate result store keyed by the run fingerprint: a digest of the resolved config, the task and metric identity, the estimator set, the compute-stack library versions and a content signature of the training data. A second fit with all of that identical restores each candidate's out-of-fold result instead of retraining it; change anything — a row, the seed, a config field, a library version — and the fingerprint changes, so a stale hit is impossible (a cold run next to older fingerprints logs that the config or the data changed). Reuse is per candidate and every result is written durably on completion, so an interrupted run resumes: the next fit recomputes only the remainder. The truthful outcome is in run_report_["cache"]enabled, the reused ids and the computed ids.

import tempfile

from sklearn.datasets import make_classification

from honestml import AutoML

X, y = make_classification(n_samples=200, n_features=8, n_informative=5, random_state=0)
cache_dir = tempfile.mkdtemp()

first = AutoML(
    task="binary", models=("baseline", "linear"), cache=cache_dir, random_state=0
).fit(X, y)
second = AutoML(
    task="binary", models=("baseline", "linear"), cache=cache_dir, random_state=0
).fit(X, y)

print(first.run_report_["cache"]["reused"])  # [] — a cold run computes everything
print(second.run_report_["cache"]["reused"])  # both candidates restored from the cache
print(second.best_model_id_ == first.best_model_id_)

All three knobs are provenance-first: the preset block, the budget outcome and the cache outcome all land in run_report_ — see the quickstart for saving and rendering the report.