共用方式為


在 Fabric 中執行超參數微調 (預覽)

超參數微調是針對影響其效能的機器學習模型參數尋找最佳值的程式。 它可能具有挑戰性且耗時,尤其是在處理複雜模型和大型數據集時。 在本文中,我們將示範如何在 Fabric 中執行超參數微調。

在本教學課程中,我們將使用加州住房數據集,其中包含加州不同人口普查區塊中位數房屋值和其他特徵的相關信息。 一旦預先準備數據,我們將訓練 SynapseML LightGBM 模型,以根據特徵預測房屋值。 接下來,我們將使用快速且輕量型的 AutoML 連結庫 FLAML 來尋找 LightGBM 模型的最佳超參數。 最後,我們將比較微調模型的結果與使用預設參數的基準模型。

重要

這項功能處於預覽狀態

必要條件

  • 建立新的 Fabric 環境 ,或確保您是在 Fabric 運行時間 1.2 上執行 (Spark 3.4 (或更新版本) 和 Delta 2.4)
  • 建立 新的筆記本
  • 將筆記本附加至 Lakehouse。 在筆記本左側,選取 [新增 ] 以新增現有的 Lakehouse 或建立新的湖屋。

準備定型和測試數據集

在本節中,我們會準備 LightGBM 模型的定型和測試數據集。 我們使用 Sklearn 的加州住房數據集。 我們會從數據建立 Spark 數據框架,並使用 VectorAssembler 將特徵結合成單一向量數據行。

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)

然後,我們會隨機將數據分割成三個子集:定型、驗證和測試,分別有85%、12.75%和2.25%的數據。 我們會使用定型和驗證集進行超參數微調,以及用於模型評估的測試集。

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)

設定 ML 實驗

設定 MLflow

在執行超參數微調之前,我們需要定義可接受不同超參數值的定型函式,並在定型數據上定型 LightGBM 模型。 我們也需要使用 R2 分數來評估驗證數據的模型效能,以測量模型如何符合數據。

若要這樣做,我們會先匯入必要的模組,並設定 MLflow 實驗。 MLflow 是一個 開放原始碼 平臺,用於管理端對端機器學習生命週期。 它可協助我們追蹤和比較不同模型和超參數的結果。

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

設定記錄層級

在這裡,我們會設定記錄層級來隱藏來自 Synapse.ml 連結庫的不必要輸出,讓記錄保持簡潔。

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

定型基準模型

接下來,我們會定義接受四個超參數作為輸入的定型函式:alpha、learningRate、numLeaves 和 numIterations。 這些是我們想要稍後使用 FLAML 微調的超參數。

定型函式也會接受兩個數據框架作為輸入:train_data和val_data,分別是定型和驗證數據集。 定型函式會傳回兩個輸出:已定型的模型和驗證數據的 R2 分數。

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

        # 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

最後,我們會使用定型函式,以超參數的預設值來定型基準模型。 我們也評估測試數據的基準模型,並列印 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)

使用 FLAML 執行超參數微調

FLAML 是快速且輕量型的 AutoML 連結庫,可自動尋找指定模型和數據集的最佳超參數。 它會使用低成本的搜尋策略,以配合評估計量的意見反應。 在本節中,我們將使用 FLAML 來微調我們在上一節中定義的 LightGBM 模型的超參數。

定義微調函式

若要使用 FLAML,我們需要定義以設定字典作為輸入的 tune 函式,並傳回評估計量做為索引鍵的字典,並將計量值當做值傳回字典。

設定字典包含我們想要微調的超參數及其值。 tune 函式會使用我們稍早定義的定型函式,以使用指定的組態來定型和評估模型。

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

定義搜尋空間

接下來,我們需要定義我們想要微調之超參數的搜尋空間。 搜尋空間是一個字典,會將超參數名稱對應至我們想要探索的值範圍。 FLAML 提供一些方便的函式來定義不同類型的範圍,例如統一、loguniform 和 randint。

在此情況下,我們想要微調下列四個超參數:alpha、learningRate、numLeaves 和 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),
}

定義超參數試用

最後,我們需要定義超參數試用版,以使用 FLAML 來優化超參數。 我們需要將 tune 函式、搜尋空間、時間預算、樣本數目、計量名稱、模式和詳細資訊層級傳遞至 flaml.tune.run 函式。 我們也需要啟動巢狀 MLflow 執行,以追蹤試用的結果。

flaml.tune.run function會傳回包含最佳組態和最佳計量值的分析物件。

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

試用完成後,我們可以從分析對象檢視最佳組態和最佳計量值。

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

比較結果

使用 FLAML 尋找最佳的超參數之後,我們需要評估它們如何改善模型效能。 若要這樣做,我們會使用定型函式,在完整定型數據集上建立具有最佳超參數的新模型。 然後,我們會使用測試數據集來計算新模型和基準模型的 R2 分數。

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

儲存最終模型

完成超參數試用之後,我們現在可以將最終的微調模型儲存為 Fabric 中的 ML 模型。

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