AutoML and Hyperparameter Optimization
This skill covers designing sound hyperparameter searches and using AutoML tooling (Optuna, Ray Tune, PyCaret, time-series AutoML libraries) without bypassing problem framing, validation design, or explainability.
Workflow for Running a Hyperparameter Search
- Define the target metric and baseline first — Pick the metric before selecting tooling, and train a simple baseline (linear model, random forest, or naive time-series forecast) with a fixed, minimal search.
- Design the validation scheme — Use nested cross-validation or a final untouched test split for any model-selection claim; use time-aware splits (never shuffled) for time-series problems.
- Fit preprocessing inside the fold — Fit scalers, encoders, and imputers only on the training portion of each fold to prevent leakage.
- Define a structured search space — Use log-scale ranges for learning rates, regularization strength, and tree counts; keep ranges domain-informed rather than arbitrarily broad.
- Choose the right tool — Optuna or Ray Tune for custom training loops with pruning and distributed trials; PyCaret for a quick low-code comparison on a straightforward tabular problem; a time-series-specific library (AutoTS, Merlion, PyAF) when seasonality and horizon handling need first-class support.
- Run with resource limits and pruning — Set a trial or time budget and use early stopping/pruning so bad trials don't consume the full budget.
- Track every run — Log datasets, splits, metric definitions, random seeds, library versions, and the search space itself to MLflow, Weights & Biases, TensorBoard, or an equivalent tracker.
- Report against the baseline — Compare the selected model to the baseline and at least one non-AutoML alternative before calling it production-ready.
Experiment Design
- Define the target metric before choosing tooling — the metric shapes the search space and the pruning strategy, not the other way around.
- Use nested validation (an inner loop for hyperparameter selection, an outer loop for performance estimation) or a final untouched test split whenever reporting a model-selection claim.
- Use time-aware splits for time-series problems — never shuffle across time boundaries, since that leaks future information into training.
- Fit all preprocessing (scalers, encoders, imputers, feature selection) only on the training fold, never on validation or test data.
- Always include simple baselines: a linear/logistic model, a random forest, or — for time series — a naive/seasonal-naive forecast. A complex model that doesn't beat the baseline is not worth the operational cost.
- Use early stopping and resource limits (max trials, wall-clock budget) for expensive searches so a runaway search doesn't consume unbounded compute.
- Prefer structured, domain-informed search spaces over arbitrarily broad grids — a learning rate range of
1e-5to1e-1on a log scale is more useful than0.0001to10on a linear scale.
Search Space Design
- Keep search spaces explicit and reviewed by someone other than the author — an unreviewed space can silently exclude the true optimum or waste budget on implausible regions.
- Use log-scale sampling for learning rates, regularization coefficients, tree counts, and other scale-sensitive hyperparameters.
- Constrain model complexity (max depth, layer width, number of estimators) to keep training time and memory use realistic for the deployment environment.
- Only include preprocessing choices in the search space when they can be applied per-fold without leakage.
- Never tune on the test set — the test set exists solely to report a final, unbiased estimate once tuning is complete.
Tooling
Optuna — custom loops with pruning
Use Optuna for fine-grained control over the training loop, trial pruning, and search algorithms (TPE, CMA-ES).
pythonimport optuna from sklearn.datasets import load_breast_cancer from sklearn.ensemble import GradientBoostingClassifier from sklearn.model_selection import cross_val_score, StratifiedKFold X, y = load_breast_cancer(return_X_y=True) def objective(trial: optuna.Trial) -> float: params = { "n_estimators": trial.suggest_int("n_estimators", 50, 500, log=True), "max_depth": trial.suggest_int("max_depth", 2, 10), "learning_rate": trial.suggest_float("learning_rate", 1e-3, 3e-1, log=True), "subsample": trial.suggest_float("subsample", 0.5, 1.0), } model = GradientBoostingClassifier(random_state=42, **params) cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) scores = cross_val_score(model, X, y, cv=cv, scoring="roc_auc") # Report the running mean for pruning support trial.report(scores.mean(), step=0) if trial.should_prune(): raise optuna.TrialPruned() return scores.mean() study = optuna.create_study( direction="maximize", sampler=optuna.samplers.TPESampler(seed=42), pruner=optuna.pruners.MedianPruner(n_warmup_steps=5), ) study.optimize(objective, n_trials=100, timeout=1800) print("Best AUROC:", study.best_value) print("Best params:", study.best_params)
- Use
optuna.pruners.MedianPrunerorHyperbandPrunerto stop unpromising trials early, especially for iterative models (gradient boosting, neural networks). - Set both
n_trialsandtimeoutso the search always terminates within budget. - Seed the sampler for reproducibility, and log
study.trials_dataframe()to your experiment tracker.
Ray Tune — distributed trials
Use Ray Tune when trials need to run across multiple machines/GPUs, or when integrating pruning schedulers like ASHA with a deep learning training loop.
pythonfrom ray import tune from ray.tune.schedulers import ASHAScheduler def train_fn(config): # ... build model/optimizer from config, train for several epochs ... for epoch in range(config["max_epochs"]): val_loss = train_one_epoch(config) # user-defined training step tune.report({"val_loss": val_loss}) search_space = { "lr": tune.loguniform(1e-4, 1e-1), "batch_size": tune.choice([32, 64, 128]), "max_epochs": 20, } tuner = tune.Tuner( train_fn, param_space=search_space, tune_config=tune.TuneConfig( metric="val_loss", mode="min", scheduler=ASHAScheduler(max_t=20, grace_period=3), num_samples=50, ), ) results = tuner.fit() best_result = results.get_best_result() print(best_result.config, best_result.metrics["val_loss"])
PyCaret — quick low-code comparison
Use PyCaret for a fast first pass on a straightforward tabular problem where the metric and preprocessing needs are simple.
pythonfrom pycaret.classification import setup, compare_models, tune_model, finalize_model setup(data=df, target="churn", train_size=0.8, session_id=42) best_model = compare_models(sort="AUC") tuned_model = tune_model(best_model, optimize="AUC", n_iter=50) final_model = finalize_model(tuned_model)
Treat PyCaret's leaderboard as a starting point for investigation, not a production decision by itself.
Time-series AutoML
Use AutoTS, Merlion, PyAF, or another project-approved time-series library when forecast-specific concerns — seasonality detection, horizon handling, backtesting with rolling windows — matter more than raw model variety. These libraries build in time-aware cross-validation by default, which generic tabular AutoML tools do not.
Experiment tracking and environments
- Store run metadata (metric, params, seed, data version, library versions) in MLflow, Weights & Biases, TensorBoard, or a project-approved tracker — never rely on memory or ad hoc spreadsheets.
- Use
uvor the project's existing package manager to keep search environments reproducible; pin library versions since sampler/pruner behavior can change across releases.
Reporting
- Report the selected model, the metric used, a confidence interval or variance estimate, the validation scheme, and the final test result — a single point estimate is not sufficient for a production decision.
- Include the best hyperparameters found and the search budget spent (number of trials, wall-clock time) so the search is reproducible and its cost is visible.
- Compare the chosen model against the baseline and at least one non-AutoML alternative.
- Document operational constraints: inference latency, memory footprint, retraining cost, and explainability requirements — a leaderboard-topping model that violates a latency SLA is not deployable as-is.
Common Mistakes
- Treating leaderboard rank as proof of production readiness — leaderboard metrics ignore latency, memory, and explainability constraints.
- Mixing train/test data during feature engineering (e.g., computing global statistics like mean/frequency encodings before splitting).
- Running massive searches before validating labels and data quality — a search will happily "optimize" against a buggy target.
- Ignoring class imbalance, calibration, or business cost asymmetry when the optimization metric doesn't reflect them (e.g., optimizing accuracy on a 99:1 class split).
- Deploying an AutoML-selected model without reproducible training code and pinned dependencies — if the winning trial can't be rerun, it can't be maintained.

