CertSafari
    Databricks Certified Machine Learning Associate· Lessons

    Domain 3 · Lesson 33/48

    Running a hyperparameter search with Hyperopt fmin and Optuna

    Perform random or grid search or Bayesian search as a method for tuning hyperparameters.

    9 min read
    2.08% of exam
    5 sources
    Published 2 Oct 2026
    Docs as of 30 Sep 2026

    What you will be able to do

    • List the four steps of a Hyperopt workflow in order
    • Write an objective function that returns a loss to minimize
    • Configure fmin() with a search space, a random or TPE algorithm and max_evals
    • Choose between Trials and SparkTrials, and know where Optuna replaces Hyperopt

    1.The four-step Hyperopt workflow

    Every Hyperopt search has the same four steps. Databricks' example notebook tunes the regularization parameter C of a scikit-learn support vector classifier on the Iris dataset, and its workflow runs in this order: define a function to minimize, define a search space over hyperparameters, select a search algorithm, then run the tuning algorithm with fmin().

    Checkpoint 1 of 7· Put it in order

    Put the steps of a Hyperopt workflow in order

    1. 1.Run the tuning algorithm with Hyperopt fmin()
    2. 2.Define a function to minimize
    3. 3.Define a search space over hyperparameters
    4. 4.Select a search algorithm

    Sources12

    2.The objective function returns a loss

    Most of a Hyperopt workflow lives in the objective function. Hyperopt calls it once per trial with a value drawn from the space. The function trains a model, scores it, and returns a loss, either as a scalar or in a dictionary. In the example below, cross-validated accuracy is the score.

    Objective function from the Databricks Hyperopt notebook: train an SVC, score it, and return a losspython
    def objective(C):
        # Create a support vector classifier model
        clf = SVC(C=C)
    
        # Use the cross-validation accuracy to compare the models' performance
        accuracy = cross_val_score(clf, X, y).mean()
    
        # Hyperopt tries to minimize the objective function. A higher accuracy value means a better model, so you must return the negative accuracy.
        return {'loss': -accuracy, 'status': STATUS_OK}

    Checkpoint 2 of 7· Check yourself

    Your objective computes ROC AUC, where higher is better. What should it return to Hyperopt?

    Sources1

    3.Search space, algorithm and the fmin() call

    The notebook's search space is a single distribution, search_space = hp.lognormal('C', 0, 1.0), and it sets algo=tpe.suggest for Bayesian search. To run random search over the same space, you would pass rand.suggest instead. Nothing else changes, and you can test the same space with either algorithm. The fmin() call then puts the pieces together:

    Core fmin() arguments and what each controls
    ArgumentWhat it controls
    fnThe objective function; returns the loss
    spaceThe hyperparameter space: categorical options or distributions such as uniform and log
    algoSearch algorithm: hyperopt.rand.suggest (random) or hyperopt.tpe.suggest (TPE)
    max_evalsNumber of hyperparameter settings to try, i.e. models to fit
    trialsA Trials or SparkTrials object
    early_stop_fnOptional function deciding whether to stop before max_evals

    Checkpoint 3 of 7· Fill the gap

    Which argument sets how many models this search will fit?

    argmin = fmin(
      fn=objective,
      space=search_space,
      algo=algo,
       ? =16)

    fmin() returns argmin, the best setting it found. There is a catch with categorical parameters: when you use hp.choice(), Hyperopt returns the index into the choice list, not the value, and that index is also what gets logged to MLflow. Call hyperopt.space_eval() to turn it back into the real value. Hyperopt also supports conditional hyperparameters, which apply only to some branches of a choice. For long-running models, Databricks suggests starting with small datasets and many hyperparameters, then using MLflow to see which hyperparameters can be fixed before tuning at scale.

    Checkpoint 4 of 7· Exam question

    A team is tuning a logistic regression model with only two hyperparameters: regularization strength `C` (4 candidate values) and penalty type (2 candidate values). For a compliance review, they need a documented guarantee that the best-performing combination among those specified values is found. Which search approach satisfies this requirement?

    Sources3

    4.Trials vs SparkTrials: where the trials run

    The trials argument decides where each trial runs. SparkTrials distributes trials for single-machine models such as scikit-learn: the driver generates the trials and the Spark workers evaluate them. To switch it on, you add one more argument to fmin(), and nothing else in your Hyperopt code has to change:

    Distributing the same search with SparkTrials, with MLflow tracking each trialpython
    spark_trials = SparkTrials()
    
    with mlflow.start_run():
      argmin = fmin(
        fn=objective,
        space=search_space,
        algo=algo,
        max_evals=16,
        trials=spark_trials)

    For algorithms that already distribute their own training, such as MLlib or Horovod, use the default Trials class instead. Each trial then runs from the driver, so the algorithm can use the full cluster. SparkTrials also has limits. Do not use it on autoscaling clusters, because it fixes its parallelism when the run starts. For very short trials, Hyperopt and Spark overhead can cancel out most of the speedup.

    Checkpoint 5 of 7· Check yourself

    You are tuning a Spark MLlib model with Hyperopt. Which trials setting should you use?

    Checkpoint 6 of 7· Exam question

    A data scientist runs `GridSearchCV` with `param_grid = {'max_depth': [3, 5, 7], 'min_samples_leaf': [1, 2, 5, 10]}` and `cv=5` on a random forest classifier. Assuming no combination is skipped, how many individual models does this fit in total?

    Sources3

    Optuna, which Databricks recommends now, follows the same pattern with different names. The search space is defined inside the objective by calling suggest_* methods on a trial object. Because the space is written in code, it can be dynamic: in the example below, which hyperparameters exist depends on which model was chosen.

    Optuna objective: the search space is built from suggest_* calls, with a conditional branch per modelpython
    def objective(trial):
        # Invoke suggest methods of a Trial object to generate hyperparameters.
        regressor_name = trial.suggest_categorical('classifier', ['SVR', 'RandomForest'])
        if regressor_name == 'SVR':
            svr_c = trial.suggest_float('svr_c', 1e-10, 1e10, log=True)
            regressor_obj = sklearn.svm.SVR(C=svr_c)
        else:
            rf_max_depth = trial.suggest_int('rf_max_depth', 2, 32)
            regressor_obj = sklearn.ensemble.RandomForestRegressor(max_depth=rf_max_depth)

    You run the search with mlflow_study.optimize(objective, n_trials=8, n_jobs=4) on an MlflowSparkStudy, which runs trials in parallel on PySpark executors. Its default sampler is TPE, and its default pruner is MedianPruner, which stops unpromising trials early. Optuna minimizes by default too, which is why the Databricks getting-started example returns -roc_auc.

    Checkpoint 7 of 7· Check yourself

    In Optuna, where is the hyperparameter search space defined?

    Sources45

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.SparkTrials is the right choice whenever you tune on a Spark cluster, including for MLlib models.Why is that wrong?

      SparkTrials is for single-machine algorithms. Distributed algorithms such as MLlib already parallelize their training and should use the default Trials class.

      Covered in Trials vs SparkTrials: where the trials run

    2. 2.The value fmin returns for an hp.choice parameter is the chosen option itself.Why is that wrong?

      For hp.choice, Hyperopt returns and logs the index into the list. Use hyperopt.space_eval() to recover the actual value.

      Covered in Search space, algorithm and the fmin() call

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “Hyperopt is not included in Databricks Runtime for Machine Learning after 16.4 LTS ML.”
      ↩︎ The four-step Hyperopt workflow
      “This function can return the loss as a scalar value or in a dictionary”
      ↩︎ The objective function returns a loss
      “Use SparkTrials when you call single-machine algorithms such as scikit-learn methods in the objective function.”
      ↩︎ Exam trap 1
      “Use Trials when you call distributed training algorithms such as MLlib methods or Horovod in the objective function.”
      ↩︎ Checkpoint
    2. 2.
      “Define a search space over hyperparameters.”
      ↩︎ The four-step Hyperopt workflow
      “Run the tuning algorithm with Hyperopt fmin().”
      ↩︎ Checkpoint
      “Hyperopt tries to minimize the objective function.”
      ↩︎ Checkpoint
    3. 3.
      “Use hyperopt.space_eval() to retrieve the parameter values.”
      ↩︎ Search space, algorithm and the fmin() call
      “Take advantage of Hyperopt support for conditional dimensions and hyperparameters.”
      ↩︎ Search space, algorithm and the fmin() call
      “Do not use SparkTrials on autoscaling clusters.”
      ↩︎ Trials vs SparkTrials: where the trials run
      “Both Hyperopt and Spark incur overhead that can dominate the trial duration for short trial runs (low tens of seconds).”
      ↩︎ Trials vs SparkTrials: where the trials run
      “When you use hp.choice(), Hyperopt returns the index of the choice list.”
      ↩︎ Exam trap 2
    4. 4.
      “MlflowSparkStudy class enables launching parallel Optuna studies using PySpark executors.”
      ↩︎ The same search in Optuna
      “Within the objective function, define the hyperparameter search space.”
      ↩︎ Checkpoint
    5. 5.
      “Negate the AUC because Optuna minimizes the objective by default”
      ↩︎ The same search in Optuna

    Spotted a mistake, or was something unclear? Tell us.