Compartilhar via


Executar ajuste de hiperparâmetro no Fabric (preview)

O ajuste de hiperparâmetros é o processo de encontrar os valores ideais dos parâmetros de um modelo de machine learning que afetam seu desempenho. O processo pode ser desafiador e demorado, principalmente ao lidar com modelos complexos e grandes conjuntos de dados. Neste artigo, mostraremos como executar o ajuste de hiperparâmetros no Fabric.

Neste tutorial, usaremos o conjunto de dados de habitação da Califórnia, que contém informações sobre o valor médio das casas e outros recursos em diferentes blocos de censo na Califórnia. Após a preparação dos dados, treinaremos um modelo LightGBM do SynapseML para prever o valor das casas com base nos recursos. Em seguida, usaremos FLAML, uma biblioteca de AutoML rápida e leve, para encontrar os melhores hiperparâmetros do modelo LightGBM. Por fim, compararemos os resultados do modelo ajustado com o modelo de linha de base que usa os parâmetros padrão.

Importante

Esse recurso está em preview.

Pré-requisitos

  • Crie um Ambiente do Fabric ou verifique se está executando no Fabric Runtime 1.2 (Spark 3.4 ou superior e Delta 2.4)
  • Criar um notebook novo
  • Anexe o notebook a um lakehouse. No lado esquerdo, selecione Adicionar para adicionar um lakehouse existente ou criar um.

Preparar conjuntos de dados de treinamento e teste

Nesta seção, preparamos os conjuntos de dados de treinamento e teste para o modelo de LightGBM. Usamos o conjunto de dados de habitação da Califórnia da Sklearn. Criamos um DataFrame do Spark com os dados e usamos um VectorAssembler para agrupar os recursos em uma única coluna vetorial.

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)

Em seguida, dividimos aleatoriamente os dados em três subconjuntos: treinamento, validação e teste, com 85%, 12,75% e 2,25% dos dados, respectivamente. Usamos os conjuntos de treinamento e validação para ajuste de hiperparâmetros e o conjunto de teste para avaliação do modelo.

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)

Configurar o experimento de ML

Configurar o MLflow

Antes de executarmos o ajuste de hiperparâmetros, precisamos definir uma função train que assuma diferentes valores de hiperparâmetros e treine um modelo LightGBM nos dados de treinamento. Também precisamos avaliar o desempenho do modelo nos dados de validação usando a pontuação R2, que mede o quão bem o modelo se ajusta aos dados.

Para isso, primeiro importamos os módulos necessários e configuramos o experimento de MLflow. O MLflow é uma plataforma de fonte aberta para gerenciar o ciclo de vida de machine learning de ponta a ponta. Ela nos ajuda a rastrear e comparar os resultados de diferentes modelos e hiperparâmetros.

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

Definir o nível de registros em log

Aqui, configuramos o nível de log para suprimir a saída desnecessária da biblioteca Synapse.ml, mantendo os logs mais limpos.

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

Treinar modelo de linha de base

Em seguida, definimos a função train que usa quatro hiperparâmetros como entradas: alpha, learningRate, numLeaves e numIterations. Esses são os hiperparâmetros que queremos ajustar mais tarde usando FLAML.

A função train também usa dois DataFrames como entradas: train_data e val_data, que são os conjuntos de dados de treinamento e validação, respectivamente. A função train retorna duas saídas: o modelo treinado e a pontuação R2 nos dados de validação.

# 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

Por fim, usamos a função train para treinar um modelo de linha de base com os valores padrão dos hiperparâmetros. Também avaliamos o modelo de linha de base nos dados de teste e imprimimos a pontuação 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)

Executar ajuste de hiperparâmetro com FLAML

FLAML é uma biblioteca de AutoML rápida e leve que procura automaticamente os melhores hiperparâmetros para um determinado modelo e conjunto de dados. Ela usa uma estratégia de busca de baixo custo que se adapta ao feedback da métrica de avaliação. Nesta seção, usaremos FLAML para ajustar os hiperparâmetros do modelo LightGBM que definimos na seção anterior.

Definir a função de ajuste

Para usar FLAML, precisamos definir uma função de ajuste que usa um dicionário de configuração como entrada e retorna um dicionário com a métrica de avaliação como chave e o valor da métrica como valor.

O dicionário de configuração contém os hiperparâmetros que queremos ajustar e seus valores. A função de ajuste usa a função train que definimos anteriormente para treinar e avaliar o modelo com a configuração dada.

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

Definir espaço de pesquisa

Em seguida, precisamos definir o espaço de pesquisa dos hiperparâmetros que queremos ajustar. O espaço de pesquisa é um dicionário que mapeia os nomes dos hiperparâmetros para os intervalos de valores que queremos explorar. A FLAML fornece algumas funções convenientes para definir diferentes tipos de intervalos, como uniform, loguniform e randint.

Nesse caso, queremos ajustar os seguintes quatro hiperparâmetros: alpha, learningRate, numLeaves e 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),
}

Definir avaliação de hiperparâmetros

Por fim, precisamos definir uma avaliação de hiperparâmetros que usa FLAML para otimizar os hiperparâmetros. Precisamos passar a função de ajuste, o espaço de pesquisa, o orçamento de tempo, o número de amostras, o nome da métrica, o modo e o nível de detalhamento para a função flaml.tune.run. Também precisamos iniciar uma execução de MLflow aninhada para acompanhar os resultados da avaliação.

A flaml.tune.run function retorna um objeto de análise que contém a melhor configuração e o melhor valor de métrica.

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

Depois que a avaliação for concluída, poderemos visualizar a melhor configuração e o melhor valor de métrica do objeto de análise.

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

Comparar os resultados

Depois de encontrar os melhores hiperparâmetros com FLAML, precisamos avaliar o quanto eles melhoram o desempenho do modelo. Para isso, usamos a função train para criar um modelo com os melhores hiperparâmetros no conjunto de dados de treinamento completo. Em seguida, usamos o conjunto de dados de teste para calcular a pontuação R2 do novo modelo e do modelo de linha de base.

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

Salvar modelo final

Depois de concluir nossa avaliação de hiperparâmetros, podemos salvar o modelo final ajustado como um modelo de ML no 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.")