Hyperparameter tuning and ensembling
How honestml treats model hyperparameters and when it blends models. 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. Both tuning and ensembling are opt-in; the default run trains every
candidate with fixed hyperparameters and ships a single model.
Fixed, conservative defaults
Без HPO используются параметры фабрик; часть параметров backend может разрешаться автоматически по данным. При наличии validation поддерживаемые boosting-модели используют early stopping. Для IID CV ES выделяется внутри train; временные схемы используют настроенный хвост. Это относится и к внутренним HPO folds: inner-test остаётся оценочной частью.
Явные n_estimators/iterations задают потолок fit. Без явного значения
потолок составляет 1000 при ES и 300 без ES. Фактические iterations раскрываются
в отчёте. DEV/full refit и участники ансамбля сохраняют параметры выбранной
фабрики, включая бюджет деревьев из default, явной конфигурации или HPO.
Медиана остановок CV остаётся диагностикой и не меняет этот бюджет.
Фактическое число построенных деревьев может быть меньше потолка, например
при отсутствии допустимых разбиений у backend. Внешний holdout не участвует
в выборе бюджета refit.
from sklearn.datasets import make_classification
from honestml import AutoML
X, y = make_classification(n_samples=240, n_features=8, n_informative=5, random_state=0)
model = AutoML(task="binary", models=("baseline", "lightgbm"), cv=3, random_state=0).fit(X, y)
print(model.best_model_id_, model.leaderboard_)
Tuning is opt-in: HPOConfig
hpo=HPOConfig(...) настраивает модели с объявленным пространством параметров
на внутреннем CV внутри DEV. При включённом FS objective использует выбранные
признаки; последующая DEV-оценка остаётся оценкой после адаптивного поиска.
backend="optuna" требует extra optuna; n_trials задаёт предел trials на
семейство, inner_cv — число внутренних folds, HPOConfig.models=None — все
доступные для настройки семейства. В ограниченном поиске HPO работает с
выбранным семейством. keep_baseline=True сохраняет исходную фабрику рядом
с настроенной. timeout_s ограничивает поиск кооперативно и может изменить
число завершённых trials. Фактическая работа и решения доступны в отчёте.
from sklearn.datasets import make_classification
from honestml import AutoML, HPOConfig
X, y = make_classification(n_samples=240, n_features=8, n_informative=5, random_state=0)
model = AutoML(
task="binary",
models=("baseline", "lightgbm"),
cv=3,
hpo=HPOConfig(n_trials=3, inner_cv=2),
random_state=0,
).fit(X, y)
tuned = model.run_report_["hpo"]["tuned"]["lightgbm"]
print(tuned["chosen_params"])
print(round(tuned["inner_best_score"], 3), tuned["n_trials_run"])
What the search explores and what is disclosed
Each model type declares its own search space; the tuner samples only those keys, and a tuned tree count overrides the fixed 300:
- CatBoost —
depth4–10,learning_rate0.01–0.3 (log),iterations50–500 (step 50),l2_leaf_reg1–10 (log),subsample0.6–1.0,one_hot_max_size2–64 (the one-hot↔target-statistics boundary for categoricals). - LightGBM —
max_depth3–10,learning_rate0.01–0.3 (log),n_estimators50–500 (step 50),reg_lambda0–10,subsample0.6–1.0,colsample_bytree0.5–1.0, plus the categorical-split regularizersmin_data_per_group10–300 andcat_smooth1.0–50.0. - XGBoost —
max_depth3–10,learning_rate0.01–0.3 (log),n_estimators50–500 (step 50),reg_lambda0–10,subsample0.6–1.0,colsample_bytree0.5–1.0.
The whole tuning story is disclosed in run_report_["hpo"]: the per-model
chosen_params, inner score and trial count, the cost estimate
(n_trials × inner_cv fits per tuned model), deterministic (False under a
timeout_s), and the honesty flags — the selection OOF is computed
post-tuning, and, when feature selection is also enabled, tuning runs on the
post-selection feature subset (the inner objective sees the pruned width,
not full DEV). Which set was tuned on is disclosed as tuned_on ("fs_subset"
or "dev_full"); tuned_on_full_feature_space is pinned False — the pre-1.1
full-width mismatch can no longer occur.
from sklearn.datasets import make_classification
from honestml import AutoML, HPOConfig
X, y = make_classification(n_samples=200, n_features=8, n_informative=5, random_state=0)
model = AutoML(
task="binary",
models=("lightgbm",),
cv=3,
hpo=HPOConfig(n_trials=3, inner_cv=2),
random_state=0,
).fit(X, y)
hpo = model.run_report_["hpo"]
print(hpo["deterministic"], hpo["cost_estimate_fits"], hpo["selection_oof_is_post_tuning"])
Ensembling with a significance gate
ensemble=EnsembleConfig() blends the leaderboard candidates after the
honest selection, over their out-of-fold predictions — no extra refitting is
needed to evaluate the recipe. method="caruana" (the default) is greedy
ensemble selection with replacement plus seeded bagging (size caps the steps,
n_bags the bagging subsamples); method="weighted" solves for simplex
weights directly; metric=None blends on the run metric.
Gate сравнивает ансамбль с выбранной опорной одиночной моделью; она может
отличаться от лидера leaderboard по score. Если её предсказания недоступны,
опорой становится лучший доступный кандидат по метрике. Ансамбль применяется
при значимом улучшении относительно этой опоры. run_report_["ensemble"]
содержит applied, member_ids, weights, oof_delta и gate_reason.
Holdout применённого ансамбля нельзя автоматически вычитать из DEV score
опорной модели и называть полученную разность optimism ансамбля.
from sklearn.datasets import make_classification
from honestml import AutoML, EnsembleConfig
X, y = make_classification(n_samples=240, n_features=8, n_informative=5, random_state=0)
model = AutoML(
task="binary",
models=("baseline", "linear"),
ensemble=EnsembleConfig(),
random_state=0,
).fit(X, y)
ens = model.run_report_["ensemble"]
print(ens["applied"], ens["gate_reason"])
print(ens["member_ids"], ens["weights"])
Tuned candidates and the ensemble decision both flow through the same honest
machinery described in
cross-validation and honest selection, and every choice is
recorded in run_report_.