ดําเนินการปรับแต่ง hyperparameter ใน Fabric (ตัวอย่าง)

การปรับแต่ง Hyperparameter คือกระบวนการค้นหาค่าที่เหมาะสมสําหรับพารามิเตอร์ของแบบจําลองการเรียนรู้ของเครื่องที่ส่งผลกระทบต่อประสิทธิภาพ ซึ่งอาจเป็นเรื่องท้าทายและใช้เวลานาน โดยเฉพาะอย่างยิ่งเมื่อจัดการกับแบบจําลองที่ซับซ้อนและชุดข้อมูลขนาดใหญ่ ในบทความนี้ เราจะแสดงวิธีการดําเนินการปรับแต่ง hyperparameter ใน Fabric

ในบทช่วยสอนนี้เราจะใช้ชุดข้อมูลที่อยู่อาศัยของแคลิฟอร์เนียซึ่งประกอบด้วยข้อมูลเกี่ยวกับค่ามัธยฐานและคุณสมบัติอื่น ๆ สําหรับบล็อกการสํารวจสํานึกที่แตกต่างกันในแคลิฟอร์เนีย เมื่อนําหน้าข้อมูลแล้ว เราจะฝึกแบบจําลอง SynapseML LightGBM เพื่อคาดการณ์ค่าบ้านตามคุณสมบัติ ถัดไป เราจะใช้ FLAML ไลบรารี AutoML ที่รวดเร็วและน้ําหนักเบา เพื่อค้นหา hyperparameters ที่ดีที่สุดสําหรับแบบจําลอง LightGBM สุดท้าย เราจะเปรียบเทียบผลลัพธ์ของแบบจําลองที่ปรับแต่งแล้วกับแบบจําลองพื้นฐานที่ใช้พารามิเตอร์ค่าเริ่มต้น

สำคัญ

คุณลักษณะนี้อยู่ในตัวอย่าง

ข้อกำหนดเบื้องต้น

  • สร้างสภาพแวดล้อม Fabric ใหม่ หรือตรวจสอบว่าคุณกําลังทํางานบน Fabric Runtime 1.2 (Spark 3.4 (หรือสูงกว่า) และ Delta 2.4)
  • สร้าง สมุดบันทึกใหม่
  • แนบสมุดบันทึกของคุณเข้ากับเลคเฮ้าส์ ทางด้านซ้ายของสมุดบันทึกของคุณ ให้เลือก เพิ่ม เพื่อเพิ่มเลคเฮ้าส์ที่มีอยู่แล้ว หรือสร้างขึ้นใหม่

เตรียมการฝึกอบรมและทดสอบชุดข้อมูล

ในส่วนนี้ เราเตรียมการฝึกและทดสอบชุดข้อมูลสําหรับแบบจําลอง 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% ของข้อมูลตามลําดับ เราใช้ชุดการฝึกอบรมและการตรวจสอบความถูกต้องสําหรับการปรับแต่ง hyperparameter และชุดการทดสอบสําหรับการประเมินแบบจําลอง

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

ก่อนที่เราจะทําการปรับแต่ง hyperparameter เราจําเป็นต้องกําหนดฟังก์ชันรถไฟที่สามารถรับค่าที่ต่างกันของ hyperparameters และฝึกแบบจําลอง LightGBM บนข้อมูลการฝึก นอกจากนี้เรายังต้องประเมินประสิทธิภาพของแบบจําลองในข้อมูลการตรวจสอบความถูกต้องโดยใช้คะแนน R2 ซึ่งวัดว่าแบบจําลองเหมาะสมกับข้อมูลมากเพียงใด

ในการทําเช่นนี้ ก่อนอื่นเราจะนําเข้าโมดูลที่จําเป็นและตั้งค่าการทดลอง MLflow MLflow เป็นแพลตฟอร์มโอเพนซอร์ส (Open Source)สําหรับการจัดการวงจรชีวิตการเรียนรู้ของเครื่องแบบ end-to-end ซึ่งช่วยให้เราติดตามและเปรียบเทียบผลลัพธ์ของแบบจําลองและ hyperparameters ที่แตกต่างกัน

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

ฝึกแบบจําลองข้อมูลพื้นฐาน

ถัดไป เรากําหนดฟังก์ชันรถไฟที่ใช้ hyperparameters สี่ตัวเป็นข้อมูลป้อนเข้า: alpha, learningRate, numLeaves และ numIterations นี่คือ hyperparameters ที่เราต้องการปรับแต่งในภายหลังโดยใช้ 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,
            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

ในตอนท้ายเราใช้ฟังก์ชันรถไฟเพื่อฝึกแบบจําลองพื้นฐานด้วยค่าเริ่มต้นของ hyperparameters นอกจากนี้เรายังประเมินแบบจําลองพื้นฐานบนข้อมูลทดสอบและพิมพ์คะแนน 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)

ดําเนินการปรับแต่ง hyperparameter ด้วย FLAML

FLAML เป็นไลบรารี AutoML ที่รวดเร็วและน้ําหนักเบา ซึ่งสามารถค้นหา hyperparameters ที่ดีที่สุดสําหรับแบบจําลองและชุดข้อมูลที่ระบุได้โดยอัตโนมัติ ซึ่งใช้กลยุทธ์การค้นหาต้นทุนต่ําที่ปรับให้เข้ากับคําติชมจากเมตริกการประเมิน ในส่วนนี้ เราจะใช้ FLAML เพื่อปรับแต่ง hyperparameters ของแบบจําลอง LightGBM ที่เรากําหนดไว้ในส่วนก่อนหน้า

กําหนดฟังก์ชันการปรับแต่ง

หากต้องการใช้ FLAML เราจําเป็นต้องกําหนดฟังก์ชันการปรับแต่งที่นําพจนานุกรมกําหนดค่ามาเป็นข้อมูลป้อนเข้าและส่งกลับพจนานุกรมที่มีเมตริกการประเมินเป็นคีย์และค่าเมตริกเป็นค่า

พจนานุกรมกําหนดค่าประกอบด้วย hyperparameters ที่เราต้องการปรับแต่งและค่า ฟังก์ชันการปรับแต่งจะใช้ฟังก์ชันรถไฟที่เรากําหนดไว้ก่อนหน้านี้เพื่อฝึกและประเมินแบบจําลองด้วยการกําหนดค่าที่ระบุ

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

กําหนดพื้นที่การค้นหา

ถัดไป เราจําเป็นต้องกําหนดพื้นที่การค้นหาสําหรับ hyperparameters ที่เราต้องการปรับแต่ง ช่องว่างการค้นหาเป็นพจนานุกรมที่แมปชื่อ hyperparameter เข้ากับช่วงของค่าที่เราต้องการค้นหา FLAML มีฟังก์ชันที่สะดวกบางอย่างเพื่อกําหนดช่วงชนิดที่แตกต่างกัน เช่น รูปแบบเหมือนกัน ลอการิฟอร์ม และแรนด์อิน

ในกรณีนี้ เราต้องการปรับแต่ง hyperparameters สี่รายการต่อไปนี้: 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),
}

กําหนดรุ่นทดลองใช้ hyperparameter

ในที่สุดเราจําเป็นต้องกําหนดรุ่นทดลองใช้ hyperparameter ที่จะใช้ FLAML เพื่อปรับ hyperparameters ให้เหมาะสม เราจําเป็นต้องส่งผ่านฟังก์ชันปรับแต่ง พื้นที่การค้นหา งบประมาณเวลา จํานวนตัวอย่าง ชื่อเมตริก โหมด และระดับแบบละเอียดไปยังฟังก์ชัน 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"])

เปรียบเทียบผลลัพธ์

หลังจากค้นหา hyperparameters ที่ดีที่สุดด้วย FLAML เราจําเป็นต้องประเมินว่าพารามิเตอร์ปรับปรุงประสิทธิภาพของแบบจําลองมากน้อยเพียงใด ในการทําเช่นนี้ เราใช้ฟังก์ชันฝึกเพื่อสร้างแบบจําลองใหม่ด้วย hyperparameters ที่ดีที่สุดบนชุดข้อมูลการฝึกอบรมเต็มรูปแบบ จากนั้นเราใช้ชุดข้อมูลทดสอบเพื่อคํานวณคะแนน 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)

บันทึกแบบจําลองขั้นสุดท้าย

เมื่อเราเสร็จสิ้นการทดลองใช้ hyperparameter ของเราตอนนี้เราสามารถบันทึกแบบจําลองสุดท้ายปรับแต่งเป็นรูปแบบ ML ใน 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.")