Sdílet prostřednictvím


Ladění hyperparametrů v Prostředcích infrastruktury (Preview)

Ladění hyperparametrů je proces nalezení optimálních hodnot pro parametry modelu strojového učení, které ovlivňují jeho výkon. Může to být náročné a časově náročné, zejména při práci se složitými modely a velkými datovými sadami. V tomto článku vám ukážeme, jak provádět ladění hyperparametrů v prostředcích infrastruktury.

V tomto kurzu použijeme datovou sadu bydlení v Kalifornii, která obsahuje informace o mediánu hodnoty domu a dalších funkcích pro různé bloky sčítání lidu v Kalifornii. Jakmile se data přepnou, vytrénujeme model SynapseML LightGBM tak, aby předpověděl hodnotu domu na základě funkcí. Dále použijeme FLAML, rychlou a odlehčenou knihovnu AutoML, abychom našli nejlepší hyperparametry pro model LightGBM. Nakonec porovnáme výsledky vyladěného modelu se standardním modelem, který používá výchozí parametry.

Důležité

Tato funkce je ve verzi Preview.

Požadavky

  • Vytvořte nové prostředí Fabric nebo se ujistěte, že používáte modul Runtime Fabric 1.2 (Spark 3.4 nebo novější) a Delta 2.4.
  • Vytvořte nový poznámkový blok.
  • Připojte poznámkový blok k jezeru. Na levé straně poznámkového bloku vyberte Přidat a přidejte existující jezero nebo vytvořte nový.

Příprava trénovacích a testovacích datových sad

V této části připravíme trénovací a testovací datové sady pro model LightGBM. Datovou sadu bydlení v Kalifornii používáme ze Sklearnu. Z dat vytvoříme datový rámec Sparku a pomocí VectorAssembleru zkombinujeme funkce do jednoho vektorového sloupce.

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)

Pak data náhodně rozdělíme na tři podmnožinu: trénování, ověření a testování, s 85 %, 12,75 % a 2,25 % dat. Pro ladění hyperparametrů a testovací sadu pro vyhodnocení modelu používáme trénovací a ověřovací sady.

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)

Nastavení experimentu ML

Konfigurace MLflow

Než provedeme ladění hyperparametrů, musíme definovat funkci trénování, která může převzít různé hodnoty hyperparametrů a vytrénovat model LightGBM na trénovací data. Musíme také vyhodnotit výkon modelu u ověřovacích dat pomocí skóre R2, které měří, jak dobře model vyhovuje datům.

Provedeme to tak, že nejprve naimportujeme potřebné moduly a nastavíme experiment MLflow. MLflow je open source platforma pro správu kompletního životního cyklu strojového učení. Pomáhá nám sledovat a porovnávat výsledky různých modelů a hyperparametrů.

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

Nastavení úrovně protokolování

Tady nakonfigurujeme úroveň protokolování tak, aby potlačit nepotřebný výstup z knihovny Synapse.ml, aby byly protokoly přehlednější.

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

Trénování standardního modelu

Dále definujeme funkci trénování, která přijímá čtyři hyperparametry jako vstupy: alfa, learningRate, numLeaves a numIterations. Jedná se o hyperparametry, které chceme později vyladit pomocí FLAML.

Funkce trénování také přebírá dva datové rámce jako vstupy: train_data a val_data, což jsou trénovací a ověřovací datové sady. Funkce trénování vrátí dva výstupy: trénovaný model a skóre R2 pro ověřovací data.

# 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

Nakonec použijeme funkci trénování k trénování základního modelu s výchozími hodnotami hyperparametrů. Také vyhodnocujeme základní model na testovacích datech a vytiskneme skóre 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)

Ladění hyperparametrů pomocí FLAML

FLAML je rychlá a odlehčená knihovna AutoML, která dokáže automaticky najít nejlepší hyperparametry pro daný model a datovou sadu. Používá strategii vyhledávání s nízkými náklady, která se přizpůsobuje zpětné vazbě z metriky hodnocení. V této části použijeme FLAML k ladění hyperparametrů modelu LightGBM, které jsme definovali v předchozí části.

Definování funkce tune

Abychom mohli použít FLAML, musíme definovat funkci ladění, která jako vstup přebírá konfigurační slovník a vrací slovník s vyhodnocovací metrikou jako klíčem a hodnotou metriky jako hodnotou.

Konfigurační slovník obsahuje hyperparametry, které chceme ladit a jejich hodnoty. Funkce ladění použije funkci trénování, kterou jsme definovali dříve, k trénování a vyhodnocení modelu s danou konfigurací.

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

Definování vyhledávacího prostoru

Dále musíme definovat vyhledávací prostor pro hyperparametry, které chceme vyladit. Vyhledávací prostor je slovník, který mapuje názvy hyperparametrů na rozsahy hodnot, které chceme prozkoumat. FLAML poskytuje několik pohodlných funkcí pro definování různých typů rozsahů, jako jsou uniforma, loguniform a randint.

V tomto případě chceme vyladit následující čtyři hyperparametry: alfa, learningRate, numLeaves a 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),
}

Definování zkušební verze hyperparametrů

Nakonec musíme definovat zkušební verzi hyperparametrů, která použije FLAML k optimalizaci hyperparametrů. Potřebujeme předat funkci ladění, vyhledávací prostor, časový rozpočet, počet vzorků, název metriky, režim a úroveň podrobností do funkce flaml.tune.run. Musíme také spustit vnořené spuštění MLflow, abychom mohli sledovat výsledky zkušební verze.

Vrátí flaml.tune.run function objekt analýzy, který obsahuje nejlepší konfiguraci a nejlepší hodnotu metriky.

# 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 dokončení zkušební verze můžeme zobrazit nejlepší konfiguraci a nejlepší hodnotu metriky z objektu analýzy.

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

Porovnání výsledků

Po nalezení nejlepších hyperparametrů pomocí FLAML musíme vyhodnotit, kolik zlepší výkon modelu. K tomu použijeme funkci trénování k vytvoření nového modelu s nejlepšími hyperparametry pro úplnou trénovací datovou sadu. Pak použijeme testovací datovou sadu k výpočtu skóre R2 pro nový model i základní model.

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

Uložit konečný model

Jakmile dokončíme zkušební verzi hyperparametrů, můžeme teď uložit konečný a vyladěný model jako model ML v prostředcích Fabric.

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