Freigeben über


Durchführen der Hyperparameteroptimierung in Fabric (Vorschau)

Die Hyperparameteroptimierung ist der Prozess der Suche nach den optimalen Werten für die Parameter eines Machine Learning-Modells, die sich auf die Leistung auswirken. Es kann schwierig und zeitaufwändig sein, insbesondere beim Umgang mit komplexen Modellen und großen Datasets. In diesem Artikel zeigen wir Ihnen, wie Sie die Hyperparameteroptimierung in Fabric durchführen.

In diesem Lernprogramm verwenden wir das California Housing Dataset, das Informationen über den medianen Hauswert und andere Merkmale für verschiedene Zählungsblöcke in Kalifornien enthält. Sobald die Daten vorab bereitgestellt wurden, trainieren wir ein SynapseML LightGBM-Modell, um den Hauswert basierend auf den Features vorherzusagen. Als Nächstes verwenden wir FLAML, eine schnelle und einfache AutoML-Bibliothek, um die besten Hyperparameter für das LightGBM-Modell zu finden. Schließlich vergleichen wir die Ergebnisse des abgestimmten Modells mit dem Basismodell, das die Standardparameter verwendet.

Wichtig

Dieses Feature befindet sich in der Vorschau.

Voraussetzungen

  • Erstellen Sie eine neue Fabric-Umgebung oder stellen Sie sicher, dass Sie unter der Fabric Runtime-1.2 (Spark 3.4 (oder höher) und Delta 2.4) ausführen.
  • Erstellen Sie ein neues Notebook.
  • Fügen Sie Ihr Notebook an ein Lakehouse an. Wählen Sie auf der linken Seite Ihres Notizbuchs Hinzufügen aus, um ein vorhandenes Seehaus hinzuzufügen oder ein neues zu erstellen.

Vorbereiten von Schulungs- und Testdatensätzen

In diesem Abschnitt bereiten wir die Schulungs- und Testdatensätze für das LightGBM-Modell vor. Wir verwenden das California Housing Dataset aus Sklearn. Wir erstellen einen Spark-Datenframe aus den Daten und verwenden einen VectorAssembler, um die Features in einer einzelnen Vektorspalte zu kombinieren.

from sklearn.datasets import fetch_california_housing
from pyspark.sql import SparkSession

# Load the Scikit-learn California Housing dataset
sklearn_dataset = fetch_california_housing()

# Convert the Scikit-learn dataset to a Pandas DataFrame
import pandas as pd
pandas_df = pd.DataFrame(sklearn_dataset.data, columns=sklearn_dataset.feature_names)
pandas_df['target'] = sklearn_dataset.target

# Create a Spark DataFrame from the Pandas DataFrame
spark_df = spark.createDataFrame(pandas_df)

# Display the data
display(spark_df)

Anschließend werden die Daten zufällig in drei Teilmengen aufgeteilt: Training, Validierung und Test. Die Teilmengen weisen 85 %, 12,75 % und 2,25 % der Daten auf. Wir verwenden die Trainings- und Validierungssätze für die Hyperparameteroptimierung und den Testsatz für die Modellauswertung.

from pyspark.ml.feature import VectorAssembler

# Combine features into a single vector column
featurizer = VectorAssembler(inputCols=sklearn_dataset.feature_names, outputCol="features")
data = featurizer.transform(spark_df)["target", "features"]

# Split the data into training, validation, and test sets
train_data, test_data = data.randomSplit([0.85, 0.15], seed=41)
train_data_sub, val_data_sub = train_data.randomSplit([0.85, 0.15], seed=41)

Einrichten des ML-Experiments

Konfigurieren von MLflow

Bevor wir die Hyperparameteroptimierung durchführen, müssen wir eine Trainingsfunktion definieren, die verschiedene Hyperparameterwerte annehmen und ein LightGBM-Modell auf den Trainingsdaten trainieren kann. Darüber hinaus müssen wir die Modellleistung für die Validierungsdaten mithilfe der R2-Bewertung bewerten, die misst, wie gut das Modell zu den Daten passt.

Dazu importieren wir zunächst die erforderlichen Module und richten das MLflow-Experiment ein. MLflow ist eine Open Source-Plattform zum Verwalten des End-to-End-Machine Learning-Lebenszyklus. Es hilft uns, die Ergebnisse verschiedener Modelle und Hyperparameter nachzuverfolgen und zu vergleichen.

# Import MLflow and set up the experiment name
import mlflow

mlflow.set_experiment("flaml_tune_sample")

# Enable automatic logging of parameters, metrics, and models
mlflow.autolog(exclusive=False)

Festlegen der Protokollierungsebene

Hier konfigurieren wir die Protokollierungsebene, um unnötige Ausgaben aus der Synapse.ml-Bibliothek zu unterdrücken und die Protokolle sauberer zu halten.

import logging
 
logging.getLogger('synapse.ml').setLevel(logging.ERROR)

Trainieren des Basismodells

Als Nächstes definieren wir die Trainfunktion, die vier Hyperparameter als Eingaben akzeptiert: Alpha, LearningRate, NumLeaves und NumIterations. Dies sind die Hyperparameter, die wir später mithilfe von FLAML optimieren möchten.

Die Train-Funktion verwendet auch zwei Datenframes als Eingaben: train_data und val_data, die jeweils die Trainings- und Validierungsdatensätze sind. Die train-Funktion gibt zwei Ausgaben zurück: das trainierte Modell und den R2-Score für die Validierungsdaten.

# Import LightGBM and RegressionEvaluator
from synapse.ml.lightgbm import LightGBMRegressor
from pyspark.ml.evaluation import RegressionEvaluator

def train(alpha, learningRate, numLeaves, numIterations, train_data=train_data_sub, val_data=val_data_sub):
    """
    This train() function:
     - takes hyperparameters as inputs (for tuning later)
     - returns the R2 score on the validation dataset

    Wrapping code as a function makes it easier to reuse the code later for tuning.
    """
    with mlflow.start_run() as run:

        # Capture run_id for prediction later
        run_details = run.info.run_id

        # Create a LightGBM regressor with the given hyperparameters and target column
        lgr = LightGBMRegressor(
            objective="quantile",
            alpha=alpha,
            learningRate=learningRate,
            numLeaves=numLeaves,
            labelCol="target",
            numIterations=numIterations,
            dataTransferMode="bulk"
        )

        # Train the model on the training data
        model = lgr.fit(train_data)

        # Make predictions on the validation data
        predictions = model.transform(val_data)
        # Define an evaluator with R2 metric and target column
        evaluator = RegressionEvaluator(predictionCol="prediction", labelCol="target", metricName="r2")
        # Compute the R2 score on the validation data
        eval_metric = evaluator.evaluate(predictions)

        mlflow.log_metric("r2_score", eval_metric)

    # Return the model and the R2 score
    return model, eval_metric, run_details

Schließlich verwenden wir die Trainfunktion, um ein Basismodell mit den Standardwerten der Hyperparameter zu trainieren. Außerdem bewerten wir das Basismodell an den Testdaten und geben den R2-Wert aus.

# Train the baseline model with the default hyperparameters
init_model, init_eval_metric, init_run_id = train(alpha=0.2, learningRate=0.3, numLeaves=31, numIterations=100, train_data=train_data, val_data=test_data)
# Print the R2 score of the baseline model on the test data
print("R2 of initial model on test dataset is: ", init_eval_metric)

Durchführen der Hyperparameteroptimierung mit FLAML

FLAML ist eine schnelle und einfache AutoML-Bibliothek, die automatisch die besten Hyperparameter für ein bestimmtes Modell und Dataset finden kann. Es verwendet eine kostengünstige Suchstrategie, die sich an das Feedback der Auswertungsmetrik anpasst. In diesem Abschnitt verwenden wir FLAML, um die Hyperparameter des LightGBM-Modells zu optimieren, die wir im vorherigen Abschnitt definiert haben.

Definieren der Optimierungsfunktion

Um FLAML zu verwenden, müssen wir eine Tuning-Funktion definieren, die ein Konfigurationswörterbuch als Eingabe verwendet und ein Wörterbuch mit der Bewertungsmetrik als Schlüssel und dem Metrikwert als Wert zurückgibt.

Das Konfigurationsverzeichnis enthält die Hyperparameter, die wir optimieren möchten, und deren Werte. Die Tune-Funktion verwendet die train-Funktion, die wir zuvor definiert haben, um das Modell mit der angegebenen Konfiguration zu trainieren und auszuwerten.

# Import FLAML
import flaml

# Define the tune function
def flaml_tune(config):
    # Train and evaluate the model with the given config
    _, metric, run_id = train(**config)
    # Return the evaluation metric and its value
    return {"r2": metric}

Definieren des Suchbereichs

Als Nächstes müssen wir den Suchbereich für die Hyperparameter definieren, die wir optimieren möchten. Der Suchbereich ist ein Wörterbuch, das die Hyperparameternamen den Bereichen von Werten zuordnet, die wir untersuchen möchten. FLAML bietet einige praktische Funktionen zum Definieren verschiedener Arten von Bereichen, z. B. Uniform, Loguniform und Randint.

In diesem Fall möchten wir die folgenden vier Hyperparameter optimieren: Alpha, LearningRate, NumLeaves und NumIterations.

# Define the search space
params = {
    # Alpha is a continuous value between 0 and 1
    "alpha": flaml.tune.uniform(0, 1),
    # Learning rate is a continuous value between 0.001 and 1
    "learningRate": flaml.tune.uniform(0.001, 1),
    # Number of leaves is an integer value between 30 and 100
    "numLeaves": flaml.tune.randint(30, 100),
    # Number of iterations is an integer value between 100 and 300
    "numIterations": flaml.tune.randint(100, 300),
}

Hyperparameter-Testversion definieren

Schließlich müssen wir eine Hyperparameter-Testversion definieren, die FLAML verwendet, um die Hyperparameter zu optimieren. Wir müssen die Tune-Funktion, den Suchbereich, das Zeitbudget, die Anzahl der Stichproben, den Metriknamen, den Modus und die Ausführlichkeitsebene an die Funktion flaml.tune.run übergeben. Außerdem müssen wir eine geschachtelte MLflow-Ausführung starten, um die Ergebnisse des Versuchs zu verfolgen.

Die flaml.tune.run function gibt ein Analyseobjekt zurück, das die beste Konfiguration und den besten Metrikwert enthält.

# Start a nested MLflow run
with mlflow.start_run(nested=True, run_name="Child Run: "):
    # Run the hyperparameter trial with FLAML
    analysis = flaml.tune.run(
        # Pass the tune function
        flaml_tune,
        # Pass the search space
        params,
        # Set the time budget to 120 seconds
        time_budget_s=120,
        # Set the number of samples to 100
        num_samples=100,
        # Set the metric name to r2
        metric="r2",
        # Set the mode to max (we want to maximize the r2 score)
        mode="max",
        # Set the verbosity level to 5
        verbose=5,
        )

Nachdem die Testversion abgeschlossen ist, können wir die beste Konfiguration und den besten Metrikwert aus dem Analyseobjekt anzeigen.

# Get the best config from the analysis object
flaml_config = analysis.best_config
# Print the best config
print("Best config: ", flaml_config)
print("Best score on validation data: ", analysis.best_result["r2"])

Vergleichen von Ergebnissen

Nachdem wir die besten Hyperparameter mit FLAML gefunden haben, müssen wir bewerten, wie viel sie die Modellleistung verbessern. Dazu verwenden wir die Train-Funktion, um ein neues Modell mit den besten Hyperparametern im vollständigen Schulungsdatensatz zu erstellen. Anschließend verwenden wir das Testdatenset, um die R2-Bewertung sowohl für das neue Modell als auch für das Basismodell zu berechnen.

# Train a new model with the best hyperparameters 
flaml_model, flaml_metric, flaml_run_id = train(train_data=train_data, val_data=test_data, **flaml_config)

# Print the R2 score of the baseline model on the test dataset
print("On the test dataset, the initial (untuned) model achieved R^2: ", init_eval_metric)
# Print the R2 score of the new model on the test dataset
print("On the test dataset, the final flaml (tuned) model achieved R^2: ", flaml_metric)

Endgültiges Modell speichern

Nachdem wir unsere Hyperparameter-Testversion abgeschlossen haben, können wir nun das endgültige, abgestimmte Modell als ML-Modell in Fabric speichern.

# Specify the model name and the path where you want to save it in the registry
model_name = "housing_model"  # Replace with your desired model name
model_path = f"runs:/{flaml_run_id}/model"

# Register the model to the MLflow registry
registered_model = mlflow.register_model(model_uri=model_path, name=model_name)

# Print the registered model's name and version
print(f"Model '{registered_model.name}' version {registered_model.version} registered successfully.")