Optimieren von Hyperparametern mit Hyperopt

Abgeschlossen

Hyperopt ist eine Open-Source-Python-Bibliothek für die Hyperparameteroptimierung. Hyperopt wird automatisch installiert, wenn Sie einen Cluster mit einer ML-Variante der Databricks Runtime erstellen. Führen Sie die folgenden Schritte aus, um es zum Trainieren eines Modells zu verwenden:

  1. Definieren Sie eine Zielfunktion zum Trainieren und Auswerten eines Modells.
  2. Definieren Sie den Suchbereich für Hyperparameter.
  3. Geben Sie den Suchalgorithmus an.
  4. Führen Sie die Hyperopt-fmin-Funktion aus, um die Trainingsfunktion zu optimieren.

Definieren einer Zielfunktion

Hyperopt funktioniert durch iteratives Aufrufen einer Funktion (häufig als Zielfunktion bezeichnet), die einen numerischen Wert zurückgibt, und Optimieren der an die Funktion übergebenen Parameter, sodass der Rückgabewert minimiert wird. Dieser Ansatz wird häufig als Optimierung bezeichnet. Die erste Anforderung besteht daher darin, die Trainings- und Auswertungslogik Ihres Modells in einer Funktion zu kapseln, die Folgendes ausführt:

  • Akzeptieren eines Parameters, der eine Liste von Hyperparameterwerten enthält.
  • Trainieren eines Modells mithilfe der bereitgestellten Hyperparameterwerte.
  • Auswerten des Modells auf Basis einer Zielmetrik für die Vorhersageleistung.
  • Rückgabe eines numerischen Werts, der die Leistungsmetrik widerspiegelt, sodass die Verbesserung der Modellleistung den Rückgabewert verringert.

Die folgende Funktion trainiert beispielsweise ein Machine Learning-Modell mithilfe des LogisticRegression-Algorithmus aus der Spark MLlib-Bibliothek.

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}

In diesem Beispiel ist der Parameter params ein Wörterbuch mit Werten für zwei benannte Werte: Iterations und Regularization. Diese Werte werden den Hyperparametern maxIter und regParam des zum Trainieren des Modells verwendeten logistischen Regressionsalgorithmus zugewiesen.

Die Funktion wertet dann das trainierte Modell aus, um seine Genauigkeitsmetrik zu berechnen. Dabei handelt es sich um einen Wert zwischen 0,0 und 1,0, der den Anteil der korrekten Vorhersagen angibt, die das Modell vorgenommen hat.

Schließlich gibt die Funktion einen Wert zurück, den Hyperopt minimieren sollte, um das Modell zu verbessern. In diesem Fall ist die Zielmetrik die Genauigkeit, für die ein höherer Wert ein besseres Modell angibt. So gibt die Funktion das Negative dieses Werts zurück (je höher die Genauigkeit, desto niedriger der Rückgabewert).

Definieren des Suchbereichs für Hyperparameter

Jedes Mal, wenn die Zielfunktion aufgerufen wird, muss ein Parameter mit den Hyperparameterwerten ausprobiert werden. Um alle möglichen Wertekombinationen zu testen, müssen Sie einen Suchbereich für Hyperopt definieren, sodass Werte für jede Testversion ausgewählt werden.

Hyperopt stellt Ausdrücke bereit, mit denen Sie einen Wertebereich für jeden Hyperparameter definieren können, einschließlich:

  • hp.choice(label, options): Gibt eine der aufgeführten options zurück.
  • hp.randint(label, upper): Gibt eine zufällige Ganzzahl im Bereich [0, Obergrenze] zurück.
  • hp.uniform(label, low, high): Gibt einen Wert zurück, der einheitlich zwischen low und high liegt.
  • hp.normal(label, mu, sigma): Gibt einen reellen Wert zurück, der mit Mittelwert mu und Standardabweichung sigma normalverteilt ist.

Tipp

Die vollständige Liste der Ausdrücke finden Sie in der Hyperopt-Dokumentation.

Der folgende Beispielcode definiert einen Suchbereich für die Hyperparameter, die im vorherigen Beispiel verwendet wurden:

from hyperopt import hp

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

Angeben des Suchalgorithmus

Hyperopt verwendet einen Suchalgorithmus, um Hyperparameterwerte aus dem Suchbereich auszuwählen und zu versuchen, die Zielfunktion zu optimieren. Es gibt zwei Möglichkeiten, wie Hyperopt Stichproben aus dem Suchbereich auswählt:

  • hyperopt.tpe.suggest: Tree of Parzen Estimators (TPE), ein bayesscher Ansatz, der adaptiv neue Hyperparametereinstellungen auswählt, die auf der Grundlage früherer Ergebnisse basieren.
  • hyperopt.rand.suggest: Zufällige Suche, ein nicht adaptiver Ansatz, der zufällig Beispiele aus dem Suchbereich verwendet.

Der folgende Beispielcode gibt den TPE-Algorithmus an.

from hyperopt import tpe

algo = tpe.suggest

Ausführen der Hyperopt-Funktion fmin

Für eine Hyperopt-Ausführung können Sie schließlich die fmin-Funktion verwenden, die die Zielfunktion mithilfe von Hyperparameterkombinationen aus dem Suchbereich basierend auf dem Suchalgorithmus wiederholt aufruft. Das Ziel der fmin-Funktion besteht darin, den von der Zielfunktion zurückgegebenen Wert zu minimieren (und damit die Leistung des Modells zu optimieren).

Im folgenden Beispielcode wird die fmin-Funktion verwendet, um die zuvor definierte Zielfunktion aufzurufen. Der Suchbereich und der Algorithmus, die in den vorherigen Beispielen definiert wurden, werden verwendet, und die Funktion wird bis zu 100 Mal ausgewertet, bevor die fmin-Funktion die leistungsstärkste ermittelte Parameterwertkombination zurückgibt.

from hyperopt import fmin

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

print("Best param values: ", argmin)

Die Ausgabe des vorherigen Codes ähnelt dem folgenden Beispiel.

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