Udostępnij za pośrednictwem


Wykonywanie dostrajania hiperparametrów w sieci szkieletowej (wersja zapoznawcza)

Dostrajanie hiperparametryczne to proces znajdowania optymalnych wartości parametrów modelu uczenia maszynowego, które wpływają na jego wydajność. Może to być trudne i czasochłonne, zwłaszcza w przypadku obsługi złożonych modeli i dużych zestawów danych. W tym artykule pokażemy, jak wykonać dostrajanie hiperparametrów w sieci szkieletowej.

W tym samouczku użyjemy zestawu danych mieszkaniowych w Kalifornii, który zawiera informacje na temat mediany wartości domu i innych funkcji dla różnych bloków spisowych w Kalifornii. Po wstępnie zamapowanym danych wytrenujemy model LightGBM usługi SynapseML, aby przewidzieć wartość domu na podstawie funkcji. Następnie użyjemy biblioteki FLAML, szybkiej i lekkiej biblioteki AutoML, aby znaleźć najlepsze hiperparametry dla modelu LightGBM. Na koniec porównamy wyniki dostrajanego modelu z modelem odniesienia, który używa parametrów domyślnych.

Ważne

Ta funkcja jest dostępna w wersji zapoznawczej.

Wymagania wstępne

  • Uzyskaj subskrypcję usługi Microsoft Fabric. Możesz też utworzyć konto bezpłatnej wersji próbnej usługi Microsoft Fabric.

  • Zaloguj się do usługi Microsoft Fabric.

  • Użyj przełącznika środowiska po lewej stronie głównej, aby przełączyć się na środowisko usługi Synapse Nauka o danych.

    Zrzut ekranu przedstawiający menu przełącznika środowiska pokazujące, gdzie wybrać Nauka o danych.

  • Utwórz nowe środowisko sieci szkieletowej lub upewnij się, że korzystasz z środowiska Fabric Runtime 1.2 (Spark 3.4 lub nowszego) i funkcji Delta 2.4)
  • Utwórz nowy notes.
  • Dołącz notes do magazynu lakehouse. Po lewej stronie notesu wybierz pozycję Dodaj , aby dodać istniejący magazyn lakehouse lub utworzyć nowy.

Przygotowywanie zestawów danych trenowania i testowania

W tej sekcji przygotujemy zestawy danych trenowania i testowania dla modelu LightGBM. Używamy zestawu danych mieszkaniowych Kalifornii z Sklearn. Tworzymy ramkę danych Platformy Spark na podstawie danych i używamy elementu VectorAssembler do łączenia funkcji w jednej kolumnie wektorowej.

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)

Następnie losowo dzielimy dane na trzy podzestawy: trenowanie, walidację i testowanie, z odpowiednio 85%, 12,75% i 2,25% danych. Używamy zestawów trenowania i sprawdzania poprawności na potrzeby dostrajania hiperparametrów i zestawu testów na potrzeby oceny modelu.

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)

Konfigurowanie eksperymentu uczenia maszynowego

Konfigurowanie biblioteki MLflow

Przed wykonaniem dostrajania hiperparametrów musimy zdefiniować funkcję pociągu, która może przyjmować różne wartości hiperparametrów i trenować model LightGBM na danych treningowych. Musimy również ocenić wydajność modelu na danych walidacji przy użyciu wyniku R2, który mierzy, jak dobrze model pasuje do danych.

W tym celu najpierw zaimportujemy niezbędne moduły i skonfigurujemy eksperyment MLflow. MLflow to platforma typu „open source” umożliwiająca zarządzanie całym cyklem życia uczenia maszynowego. Pomaga nam śledzić i porównywać wyniki różnych modeli i hiperparametrów.

# 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)

Ustawianie poziomu rejestrowania

W tym miejscu skonfigurujemy poziom rejestrowania tak, aby pomijał niepotrzebne dane wyjściowe z biblioteki Synapse.ml, zachowując czyszczenie dzienników.

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

Trenowanie modelu linii bazowej

Następnie zdefiniujemy funkcję train, która przyjmuje cztery hiperparametry jako dane wejściowe: alfa, learningRate, numLeaves i numIterations. Są to hiperparametry, które chcemy później dostroić przy użyciu języka FLAML.

Funkcja train przyjmuje również dwie ramki danych jako dane wejściowe: train_data i val_data, które są odpowiednio zestawami danych trenowania i walidacji. Funkcja train zwraca dwa dane wyjściowe: wytrenowany model i wynik R2 na danych walidacji.

# 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

Na koniec używamy funkcji train do trenowania modelu bazowego z wartościami domyślnymi hiperparametrów. Oceniamy również model odniesienia na danych testowych i wyświetlamy wynik R2.

# 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)

Wykonywanie dostrajania hiperparametrów za pomocą biblioteki FLAML

FLAML to szybka i uproszczona biblioteka AutoML, która może automatycznie znaleźć najlepsze hiperparametry dla danego modelu i zestawu danych. Wykorzystuje ona strategię wyszukiwania o niskich kosztach, która dostosowuje się do opinii z metryki oceny. W tej sekcji użyjemy języka FLAML, aby dostroić hiperparametry modelu LightGBM zdefiniowanego w poprzedniej sekcji.

Definiowanie funkcji tune

Aby użyć języka FLAML, musimy zdefiniować funkcję dostrajania, która przyjmuje słownik konfiguracji jako dane wejściowe i zwraca słownik z metryką oceny jako kluczem i wartością metryki jako wartością.

Słownik konfiguracji zawiera hiperparametry, które chcemy dostroić i ich wartości. Funkcja tune będzie używać funkcji train zdefiniowanej wcześniej do trenowania i oceniania modelu przy użyciu danej konfiguracji.

# 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}

Definiowanie przestrzeni wyszukiwania

Następnie musimy zdefiniować przestrzeń wyszukiwania dla hiperparametrów, które chcemy dostroić. Obszar wyszukiwania to słownik, który mapuje nazwy hiperparametrów na zakresy wartości, które chcemy zbadać. Funkcja FLAML udostępnia pewne wygodne funkcje do definiowania różnych typów zakresów, takich jak jednolite, loguniform i randint.

W tym przypadku chcemy dostroić następujące cztery hiperparametry: alfa, learningRate, numLeaves i 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),
}

Definiowanie wersji próbnej hiperparametrów

Na koniec musimy zdefiniować wersję próbną hiperparametrów, która będzie używać języka FLAML do optymalizacji hiperparametrów. Musimy przekazać funkcję tune, przestrzeń wyszukiwania, budżet czasu, liczbę próbek, nazwę metryki, tryb i poziom szczegółowości do funkcji flaml.tune.run. Musimy również uruchomić zagnieżdżony przebieg MLflow, aby śledzić wyniki badania.

Obiekt flaml.tune.run function zwróci obiekt analizy zawierający najlepszą konfigurację i najlepszą wartość metryki.

# 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,
        )

Po zakończeniu okresu próbnego możemy wyświetlić najlepszą konfigurację i najlepszą wartość metryki z obiektu analizy.

# 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"])

Porównanie wyników

Po znalezieniu najlepszych hiperparametrów za pomocą flaML musimy ocenić, ile poprawią wydajność modelu. W tym celu użyjemy funkcji train, aby utworzyć nowy model z najlepszymi hiperparametrami w pełnym zestawie danych trenowania. Następnie użyjemy zestawu danych testowych do obliczenia wyniku R2 zarówno dla nowego modelu, jak i modelu odniesienia.

# 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)

Zapisywanie końcowego modelu

Po zakończeniu naszej wersji próbnej hiperparametrów możemy teraz zapisać ostatni, dostrojony model jako model uczenia maszynowego w sieci szkieletowej.

# 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.")