Optimiser les hyperparamètres avec Hyperopt

Effectué

Hyperopt est une bibliothèque Python open source pour le réglage des hyperparamètres. Hyperopt est automatiquement installé lorsque vous créez un cluster avec une variante ML de Databricks Runtime. Pour l’utiliser lors de l’entraînement d’un modèle, suivez ces étapes :

  1. Définissez une fonction objective pour entraîner et évaluer un modèle.
  2. Définir l’espace de recherche des hyperparamètres.
  3. Spécifier l’algorithme de recherche.
  4. Exécutez la fonction fmin Hyperopt pour optimiser la fonction d’entraînement.

Définir une fonction objective

Hyperopt fonctionne en appelant de façon itérative une fonction (souvent appelée fonction objective) qui retourne une valeur numérique et en réglant les paramètres passés à la fonction afin que la valeur de retour soit réduite ; une approche communément appelée optimisation. La première exigence consiste donc à encapsuler votre logique d’apprentissage et d’évaluation de modèle dans une fonction qui :

  • Accepte un paramètre contenant une liste de valeurs d’hyperparamètre.
  • Forme un modèle à l’aide des valeurs d’hyperparamètre fournies.
  • Évalue le modèle en fonction d’une métrique cible pour les performances prédictives.
  • Retourne une valeur numérique qui reflète la métrique de performances de sorte que l’amélioration des performances du modèle réduit la valeur de retour.

Par exemple, la fonction suivante entraîne un modèle Machine Learning à l’aide de l’algorithme LogisticRegression de la bibliothèque Spark MLlib.

def objective(params):
    from pyspark.ml.classification import LogisticRegression
    from pyspark.ml.evaluation import MulticlassClassificationEvaluator
    from hyperopt import STATUS_OK

    data_df = get_training_data() # This is just an example!
    splits = data_df.randomSplit([0.7, 0.3])
    training_df = splits[0]
    validation_df = splits[1]

    # Train a model using the provided hyperparameter values
    lr = LogisticRegression(labelCol="label", featuresCol="features",
                            maxIter=params['Iterations'],
                            regParam=params['Regularization'])
    model = lr.fit(training_df)

    # Evaluate the model
    predictions = model.transform(validation_df)
    eval = MulticlassClassificationEvaluator(labelCol="label",
                                             predictionCol="prediction",
                                             metricName="accuracy")
    accuracy = eval.evaluate(predictions)
    
    # Hyperopt *minimizes* the function, so return *negative* accuracy.
    return {'loss': -accuracy, 'status': STATUS_OK}

Dans cet exemple, le paramètre params est un dictionnaire contenant des valeurs pour deux valeurs nommées : itérations et régularisation. Ces valeurs sont affectées aux hyperparamètres maxIter et regParam de l’algorithme de régression logistique utilisé pour entraîner le modèle.

La fonction évalue ensuite le modèle entraîné pour calculer sa métrique accuracy, qui est une valeur comprise entre 0,0 et 1,0 indiquant la proportion des prédictions effectuées par le modèle qui étaient correctes.

Enfin, la fonction retourne une valeur qu’Hyperopt doit réduire pour améliorer le modèle. Dans ce cas, la métrique cible est la précision, pour laquelle une valeur plus élevée indique un meilleur modèle ; ainsi, la fonction retourne le négatif de cette valeur (de sorte que plus la précision est élevée, plus la valeur de retour est faible).

Définir l’espace de recherche des hyperparamètres

Chaque fois que la fonction objective est appelée, elle nécessite qu’un paramètre contenant les valeurs d’hyperparamètre soit vérifié. Si vous souhaitez essayer toutes les combinaisons de valeurs possibles, vous devez définir un espace de recherche dans lequel Hyperopt sélectionne des valeurs pour chaque essai.

Hyperopt fournit des expressions que vous pouvez utiliser pour définir une plage de valeurs pour chaque hyperparamètre, notamment :

  • hp.choice(label, options) : Retourne un des éléments options que vous avez répertoriés.
  • hp.randint(label, upper) : Retourne un entier aléatoire dans la plage [0, upper].
  • hp.uniform(label, low, high) : Retourne uniformément une valeur entre low et high.
  • hp.normal(label, mu, sigma) : Retourne une valeur réelle qui est normalement distribuée avec la moyenne mu et l’écart type sigma.

Conseil

Pour obtenir la liste complète des expressions, consultez la documentation Hyperopt.

L’exemple de code suivant définit un espace de recherche pour les hyperparamètres utilisés dans l’exemple précédent :

from hyperopt import hp

search_space = {
    'Iterations': hp.randint('Iterations', 10),
    'Regularization': hp.uniform('Regularization', 0.0, 1.0)
}

Spécifier l’algorithme de recherche

Hyperopt utilise un algorithme de recherche pour sélectionner des valeurs d’hyperparamètre dans l’espace de recherche et essayer d’optimiser la fonction objective. Il existe deux choix principaux dans la manière dont Hyperopt échantillonne l’espace de recherche :

  • hyperopt.tpe.suggest : Estimateurs d’arborescence de Parzen (TDE), une approche bayésienne qui sélectionne de manière adaptative les nouveaux paramètres d’hyperparamètre en fonction des résultats passés.
  • hyperopt.rand.suggest : Recherche aléatoire, approche non adaptative qui échantillonne au hasard l’espace de recherche.

L’exemple de code suivant spécifie l’algorithme TPE.

from hyperopt import tpe

algo = tpe.suggest

Exécuter la fonction Hyperopt fmin

Enfin, pour exécuter une exécution Hyperopt, vous pouvez utiliser la fonction fmin, qui appelle à plusieurs reprises la fonction objective à l’aide de combinaisons d’hyperparamètres à partir de l’espace de recherche en fonction de l’algorithme de recherche. L’objectif de la fonction fmin est de réduire la valeur retournée par la fonction objective (et donc d’optimiser les performances du modèle).

L’exemple de code suivant utilise la fonction fmin pour appeler la fonction objective définie précédemment. L’espace de recherche et l’algorithme définis dans les exemples précédents sont utilisés. Par ailleurs, la fonction est évaluée jusqu’à 100 fois avant que la fonction fmin retourne la combinaison de valeurs de paramètre la plus performante trouvée.

from hyperopt import fmin

argmin = fmin(
  fn=objective,
  space=search_space,
  algo=algo,
  max_evals=100)

print("Best param values: ", argmin)

La sortie du code précédent ressemble à l’exemple suivant.

Best param values:  {'Iterations': 6, 'Regularization': 0.5461699702338606}