AI Hints
Home›MLOps Tutorial›Pipelines and Tuning
MLOps · Lesson 12 of 80

Hyperparameter Tuning

Let the computer search.

⏱ 2 min read▶ Video at 28:08🎓 Free
Watch this lesson in the MLOps courseWatch on YouTube ↗Full MLOps course

Every model has settings that you choose before training, like the depth of a tree, or the number of trees. They are called hyperparameters. The best values are rarely obvious. You could guess, but a smarter way is to let the computer search. In this lesson, you will use Optuna to do exactly that.

Hyperparameter Tuning
From the video: Hyperparameter Tuning
  • Settings you choose before training
  • Guessing is slow
  • Let the computer search

There are three ways to search. Grid search tries every combination on a grid. It is thorough, but the cost explodes with every extra setting. Random search tries random combinations, which is often better, because it explores more different values. Smart search, called Bayesian optimisation, learns from earlier trials. After each trial, it chooses the next settings in promising areas. Optuna uses this idea, and usually finds good settings in far fewer trials.

Grid and random

  • Grid: every combination
  • Cost explodes with settings
  • Random: surprisingly good
  • Does not learn from trials

Smart (Optuna)

  • Learns from earlier trials
  • Focuses on promising areas
  • Fewer trials needed
  • Can stop weak trials early

Tuning with Optuna

Here is a tuning job, in code. The objective function builds a model, with settings suggested by Optuna. Number of trees, between twenty and two hundred. Depth, between two and twelve. And the minimum samples per leaf. Then it scores the model, with three fold cross validation, and returns the score. We create a study that maximises that score, and run twenty trials. At the end, we print how many trials ran, the best score, and the best settings.

tune.pypython
import optuna
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from churn import make_data

optuna.logging.set_verbosity(optuna.logging.WARNING)
df = make_data(2000, seed=1)
X, y = df.drop(columns="churn"), df["churn"]

def objective(trial):
    model = RandomForestClassifier(
        n_estimators=trial.suggest_int("n_estimators", 20, 200),
        max_depth=trial.suggest_int("max_depth", 2, 12),
        min_samples_leaf=trial.suggest_int("min_samples_leaf", 1, 20),
        random_state=0,
    )
    return cross_val_score(model, X, y, cv=3).mean()

study = optuna.create_study(direction="maximize", sampler=optuna.samplers.TPESampler(seed=0))
study.optimize(objective, n_trials=20)
print("trials run:", len(study.trials))
print("best score:", round(study.best_value, 3))
print("best params:", study.best_params)
Output
trials run: 20
best score: 0.864
best params: {'n_estimators': 115, 'max_depth': 5, 'min_samples_leaf': 20}
Also uses churn.py
import numpy as np, pandas as pd

def make_data(n, seed, shifted=False):
    rng = np.random.default_rng(seed)
    tenure = rng.integers(1, 72, n)
    charges = rng.normal(65 + (28 if shifted else 0), 18, n).clip(20, 140).round(2)
    calls = rng.poisson(1.5 + (1.5 if shifted else 0), n)
    contract = rng.choice([0, 1, 2], n, p=[.55, .25, .20] if not shifted else [.30, .30, .40])
    logit = -1.0 - 0.04 * tenure + 0.025 * (charges - 65) + 0.45 * calls - 0.8 * contract
    if shifted:
        logit = -0.2 - 0.01 * tenure - 0.01 * (charges - 65) + 0.2 * calls - 0.2 * contract
    churn = (rng.random(n) < 1 / (1 + np.exp(-logit))).astype(int)
    return pd.DataFrame({"tenure": tenure, "charges": charges, "calls": calls, "contract": contract, "churn": churn})

Tuning without fooling yourself

A few warnings. Always tune with cross validation, or a validation set, never on the final test set, or you will fool yourself. Record every trial in your experiment tracker. Set a budget, because there are diminishing returns, and a tiny gain may not matter in production. And remember that tuning cannot fix bad data, or a wrong problem. First get the data right, then tune.

Validate properlynever tune on the test set
Track every trialMLflow or Optuna dashboard
Set a budgetdiminishing returns
Data firsttuning cannot fix bad data

Summary

Wonderful. Optuna searches settings intelligently, using what it learned from earlier trials. Tune with cross validation, track every trial, and set a budget. Next, where the winning model lives, and how its versions are managed, the model registry.

Key takeaways
  • Grid, random, and smart search
  • Optuna: objective and trials
  • Validate properly, then track
Next up: The Model Registry — versions, stages, and approvals