Models: Level and Overrides¶
COREMat selects models either via a level preset or an explicit selected list. Individual model behaviour can be fine-tuned with overrides.
Model level presets¶
models.level selects a built-in group of models. When models.selected is also set, selected takes precedence.
| Level | Models included |
|---|---|
explain |
Four models you can reason about: OLS, Ridge, a random-forest baseline, TabPFN v2 |
perform |
Ten strong learners: Ridge, Huber, random forest, ExtraTrees, kernel ridge (RBF/linear), SVR, LightGBM, CatBoost, TabPFN v2 |
compete |
Ten tuned models — the searched siblings of perform plus XGBoost. Not every registered model |
Each level is a curated list in LEVEL_PRESETS (core/config/models.py), not a
filter over the registry: XGBoost appears only in compete, and none of the
three levels covers all 36 registered models. With neither level nor selected
(level: null, the default) the run trains the single fastest model, lin__ols, and
says so in the log.
Explicit model selection¶
Model IDs follow the schema <category>__<family>__<variant>. See the Model Zoo for all available IDs.
Per-model overrides¶
models.overrides is keyed by model ID. Each entry is a ModelRunOverride.
Available override keys¶
| Key | Type | Effect |
|---|---|---|
suffix |
str | Append a suffix to the model's results directory name |
param_space_override |
dict | Search Space Override: replace individual entries of the HPO search space (Optuna distributions, keys prefixed regressor__). Parameters you do not name stay in the search |
preprocess_override |
PreprocessPolicy |
Override preprocessing for this model only |
To run only some models, list them explicitly in models.selected — there is no
per-model "disable" flag.
Full example¶
from optuna.distributions import FloatDistribution, IntDistribution
from coremat import (
FrameworkConfig,
PathsConfig,
DataPreprocessingConfig,
ModelsConfig,
ModelRunOverride,
PreprocessPolicy,
run_training,
)
fw = FrameworkConfig(
paths=PathsConfig(data_file_path="data/alloys.csv", run_name="overrides_demo"),
data=DataPreprocessingConfig(
predict_column="yield_strength",
),
models=ModelsConfig(
selected=["ens__xgb__squared", "lin__ridge"],
overrides={
"ens__xgb__squared": ModelRunOverride(
suffix="narrow_search", # results dir: ens__xgb__squared_narrow_search
param_space_override={ # replace these entries — the other
# parameters stay in the search
"regressor__learning_rate": FloatDistribution(0.01, 0.05, log=True),
"regressor__max_depth": IntDistribution(4, 6),
"regressor__n_estimators": IntDistribution(200, 500),
},
),
"lin__ridge": ModelRunOverride(
preprocess_override=PreprocessPolicy(
scale_numeric="robust", # switch to a robust scaler for Ridge
encode_low_card="onehot",
),
),
},
),
)
result = run_training(fw)
Notes¶
param_space_overridemerges into the registered search space: it replaces the entries it names and leaves every other parameter in place. Keys are pipeline-prefixed (regressor__<param>) and values are Optuna distributions (FloatDistribution,IntDistribution,CategoricalDistribution). A key the registered space does not contain raisesUnknownOverrideParameterError— a registry rename fails loudly instead of quietly shrinking the search.- To take a parameter out of the search, pin it — give it a distribution without freedom, e.g.
CategoricalDistribution([3]). Leaving it out of the override does not remove it: the registered range still applies. And removing a parameter from the space would not give you the curated value either — an Optuna model's estimator is constructed without hyperparameters, so it would fall back to the library default (XGBRegressor(n_estimators=100)), not a curated one. Pinning keeps the value visible in the config and in the Effective Search Space. - An overridden entry is never narrowed — but only that entry. Registered entries are clamped to the row count of each search (the Effective Search Space, see Nested CV), and they keep being clamped even when another parameter of the same model is overridden. Overriding one upper bound does not switch the mechanism off for the whole model. This is what makes an override a working answer to a "model skipped, search space degenerate" message.
- A degenerate override is not corrected, but it is not computed either. If the range you set lies entirely in the region where the model becomes a constant predictor, the model is skipped like any other empty Effective Search Space. If it only reaches into that region, the range stays exactly as written and the overlap is reported. Your range is never silently changed.
- Small datasets: iteration and tree counts (
n_estimators,iterations,max_iter) are deliberately left out of the automatic narrowing, so on a few dozen rows an override is the way to keep them sane —IntDistribution(50, 600)instead of the declared200..5000. Doing so does not cost you the clamping of the other nine parameters. - To run most of a preset but skip one model, use an explicit
models.selectedlist instead of a level.
Overrides from a YAML config¶
The same overrides work from a YAML file. Optuna distributions have no YAML spelling of
their own, so they are written in optuna's canonical form — the one
optuna.distributions.distribution_to_json produces — and optuna reconstructs them:
models:
selected:
- ens__xgb__squared
overrides:
ens__xgb__squared:
suffix: narrow_search
param_space_override:
regressor__n_estimators:
name: IntDistribution
attributes: {low: 50, high: 600, step: 1, log: false}
regressor__learning_rate:
name: FloatDistribution
attributes: {low: 1.0e-3, high: 0.2, log: true, step: null}
regressor__max_depth:
name: CategoricalDistribution
attributes: {choices: [null, 4, 6, 8]}
preprocess_override:
scale_numeric: robust
encode_low_card: onehot
Anything that is not a distribution in this form — a bare [50, 600], say — is rejected
when the config is loaded, not hours into the run.
You rarely have to write this by hand. Build the configuration in Python and export it:
Loading that file back yields an equal FrameworkConfig, so the batch run is the same
run. Every run also saves its own configuration to
_config/{timestamp}_config.yaml, which can be passed back the same way.
- Models with
supports_optuna=Falserun no Optuna search. Aparam_space_overrideon one still applies, but as fixed values rather than a space: every entry must be pinned, and the value is set on the estimator directly. A range raisesUnpinnedBaseOverrideError— there is no search to draw from, so pin it (IntDistribution(3, 3)).