如何在管道中进行超参数优化 (v2)

适用范围:Azure CLI ml 扩展 v2(最新版)Python SDK azure-ai-ml v2(最新版)

本文介绍如何在 Azure 机器学习管道中执行超参数优化。

先决条件

  1. 了解什么是超参数优化,以及如何在 Azure 机器学习中使用 SweepJob 执行超参数优化。
  2. 了解什么是 Azure 机器学习管道
  3. 生成将超参数用作输入的命令组件。

如何在 Azure 机器学习管道中执行超参数优化

本部分介绍如何使用 CLI v2 和 Python SDK 在 Azure 机器学习管道中执行超参数优化。 两种方法具有相同的先决条件:已创建命令组件,且命令组件将超参数用作输入。 如果还没有命令组件。 请遵循以下链接,首先创建命令组件。

CLI v2

本文中使用的示例可在 azureml-example 存储库中找到。 导航到 [azureml-examples/cli/jobs/pipelines-with-components/pipeline_with_hyperparameter_sweep 以检查示例。

假设你已经在 train.yaml 中定义了一个命令组件。 两步管道作业(训练和预测)YAML 文件如下所示。

$schema: https://azuremlschemas.azureedge.net/latest/pipelineJob.schema.json
type: pipeline
display_name: pipeline_with_hyperparameter_sweep
description: Tune hyperparameters using TF component
settings:
    default_compute: azureml:cpu-cluster
jobs:
  sweep_step:
    type: sweep
    inputs:
      data: 
        type: uri_file
        path: wasbs://datasets@azuremlexamples.blob.core.chinacloudapi.cn/iris.csv
      degree: 3
      gamma: "scale"
      shrinking: False
      probability: False
      tol: 0.001
      cache_size: 1024
      verbose: False
      max_iter: -1
      decision_function_shape: "ovr"
      break_ties: False
      random_state: 42
    outputs:
      model_output:
      test_data:
    sampling_algorithm: random
    trial: ./train.yml
    search_space:
      c_value:
        type: uniform
        min_value: 0.5
        max_value: 0.9
      kernel:
        type: choice
        values: ["rbf", "linear", "poly"]
      coef0:
        type: uniform
        min_value: 0.1
        max_value: 1
    objective:
      goal: minimize
      primary_metric: training_f1_score
    limits:
      max_total_trials: 5
      max_concurrent_trials: 3
      timeout: 7200

  predict_step:
    type: command
    inputs:
      model: ${{parent.jobs.sweep_step.outputs.model_output}}
      test_data: ${{parent.jobs.sweep_step.outputs.test_data}}
    outputs:
      predict_result:
    component: ./predict.yml

    

sweep_step 是超参数优化的步骤。 其类型需要为 sweeptrial 指的是 train.yaml 中定义的命令组件。 从 search space 字段中,可以看到三个超参数(c_valuekernelcoef)已添加到搜索空间。 提交此管道作业后,Azure 机器学习会多次运行试用组件,以基于搜索空间扫描超参数并终止在 sweep_step 中定义的策略。 查看扫描作业 YAML 架构,了解扫描作业的完整架构。

下面是试用组件定义(train.yml 文件)。

$schema: https://azuremlschemas.azureedge.net/latest/commandComponent.schema.json
type: command

name: train_model
display_name: train_model
version: 1

inputs: 
  data:
    type: uri_folder
  c_value:
    type: number
    default: 1.0
  kernel:
    type: string
    default: rbf
  degree:
    type: integer
    default: 3
  gamma:
    type: string
    default: scale
  coef0: 
    type: number
    default: 0
  shrinking:
    type: boolean
    default: false
  probability:
    type: boolean
    default: false
  tol:
    type: number
    default: 1e-3
  cache_size:
    type: number
    default: 1024
  verbose:
    type: boolean
    default: false
  max_iter:
    type: integer
    default: -1
  decision_function_shape:
    type: string
    default: ovr
  break_ties:
    type: boolean
    default: false
  random_state:
    type: integer
    default: 42

outputs:
  model_output:
    type: mlflow_model
  test_data:
    type: uri_folder
  
code: ./train-src

environment: azureml:AzureML-sklearn-1.0-ubuntu20.04-py38-cpu@latest

command: >-
  python train.py 
  --data ${{inputs.data}}
  --C ${{inputs.c_value}}
  --kernel ${{inputs.kernel}}
  --degree ${{inputs.degree}}
  --gamma ${{inputs.gamma}}
  --coef0 ${{inputs.coef0}}
  --shrinking ${{inputs.shrinking}}
  --probability ${{inputs.probability}}
  --tol ${{inputs.tol}}
  --cache_size ${{inputs.cache_size}}
  --verbose ${{inputs.verbose}}
  --max_iter ${{inputs.max_iter}}
  --decision_function_shape ${{inputs.decision_function_shape}}
  --break_ties ${{inputs.break_ties}}
  --random_state ${{inputs.random_state}}
  --model_output ${{outputs.model_output}}
  --test_data ${{outputs.test_data}}

添加到 pipeline.yml 中搜索空间的超参数需要作为试验组件的输入。 试用组件的源代码位于 ./train-src 文件夹下。 在此示例中,它是单个 train.py 文件。 此代码将在扫描作业的每个试用版中执行。 请确保已将指标记录在试用组件源代码中,其名称与 pipeline.yml 文件中的 primary_metric 值完全相同。 此示例将使用 mlflow.autolog(),建议使用其跟踪 ML 试验。 在此处查看有关 mlflow 的更多信息

以下代码片段是试用组件的源代码。

# imports
import os
import mlflow
import argparse

import pandas as pd
from pathlib import Path

from sklearn.svm import SVC
from sklearn.model_selection import train_test_split

# define functions
def main(args):
    # enable auto logging
    mlflow.autolog()

    # setup parameters
    params = {
        "C": args.C,
        "kernel": args.kernel,
        "degree": args.degree,
        "gamma": args.gamma,
        "coef0": args.coef0,
        "shrinking": args.shrinking,
        "probability": args.probability,
        "tol": args.tol,
        "cache_size": args.cache_size,
        "class_weight": args.class_weight,
        "verbose": args.verbose,
        "max_iter": args.max_iter,
        "decision_function_shape": args.decision_function_shape,
        "break_ties": args.break_ties,
        "random_state": args.random_state,
    }

    # read in data
    df = pd.read_csv(args.data)

    # process data
    X_train, X_test, y_train, y_test = process_data(df, args.random_state)

    # train model
    model = train_model(params, X_train, X_test, y_train, y_test)
    # Output the model and test data
    # write to local folder first, then copy to output folder

    mlflow.sklearn.save_model(model, "model")

    from distutils.dir_util import copy_tree

    # copy subdirectory example
    from_directory = "model"
    to_directory = args.model_output

    copy_tree(from_directory, to_directory)

    X_test.to_csv(Path(args.test_data) / "X_test.csv", index=False)
    y_test.to_csv(Path(args.test_data) / "y_test.csv", index=False)


def process_data(df, random_state):
    # split dataframe into X and y
    X = df.drop(["species"], axis=1)
    y = df["species"]

    # train/test split
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=random_state
    )

    # return split data
    return X_train, X_test, y_train, y_test


def train_model(params, X_train, X_test, y_train, y_test):
    # train model
    model = SVC(**params)
    model = model.fit(X_train, y_train)

    # return model
    return model


def parse_args():
    # setup arg parser
    parser = argparse.ArgumentParser()

    # add arguments
    parser.add_argument("--data", type=str)
    parser.add_argument("--C", type=float, default=1.0)
    parser.add_argument("--kernel", type=str, default="rbf")
    parser.add_argument("--degree", type=int, default=3)
    parser.add_argument("--gamma", type=str, default="scale")
    parser.add_argument("--coef0", type=float, default=0)
    parser.add_argument("--shrinking", type=bool, default=False)
    parser.add_argument("--probability", type=bool, default=False)
    parser.add_argument("--tol", type=float, default=1e-3)
    parser.add_argument("--cache_size", type=float, default=1024)
    parser.add_argument("--class_weight", type=dict, default=None)
    parser.add_argument("--verbose", type=bool, default=False)
    parser.add_argument("--max_iter", type=int, default=-1)
    parser.add_argument("--decision_function_shape", type=str, default="ovr")
    parser.add_argument("--break_ties", type=bool, default=False)
    parser.add_argument("--random_state", type=int, default=42)
    parser.add_argument("--model_output", type=str, help="Path of output model")
    parser.add_argument("--test_data", type=str, help="Path of output model")

    # parse args
    args = parser.parse_args()

    # return args
    return args


# run script
if __name__ == "__main__":
    # parse args
    args = parse_args()

    # run main function
    main(args)

Python SDK

可以在 azureml-example 存储库中查看 Python SDK 示例。 导航到 azureml-examples/sdk/jobs/pipelines/1c_pipeline_with_hyperparameter_sweep 检查示例。

在 Azure 机器学习 Python SDK v2 中,可以通过调用 .sweep() 方法为任何命令组件启用超参数优化。

下面的代码片段显示了如何为 train_model 启用扫描。

train_component_func = load_component(path="./train.yml")
score_component_func = load_component(path="./predict.yml")

# define a pipeline
@pipeline()
def pipeline_with_hyperparameter_sweep():
    """Tune hyperparameters using sample components."""
    train_model = train_component_func(
        data=Input(
            type="uri_file",
            path="wasbs://datasets@azuremlexamples.blob.core.chinacloudapi.cn/iris.csv",
        ),
        c_value=Uniform(min_value=0.5, max_value=0.9),
        kernel=Choice(["rbf", "linear", "poly"]),
        coef0=Uniform(min_value=0.1, max_value=1),
        degree=3,
        gamma="scale",
        shrinking=False,
        probability=False,
        tol=0.001,
        cache_size=1024,
        verbose=False,
        max_iter=-1,
        decision_function_shape="ovr",
        break_ties=False,
        random_state=42,
    )
    sweep_step = train_model.sweep(
        primary_metric="training_f1_score",
        goal="minimize",
        sampling_algorithm="random",
        compute="cpu-cluster",
    )
    sweep_step.set_limits(max_total_trials=20, max_concurrent_trials=10, timeout=7200)

    score_data = score_component_func(
        model=sweep_step.outputs.model_output, test_data=sweep_step.outputs.test_data
    )


pipeline_job = pipeline_with_hyperparameter_sweep()

# set pipeline level compute
pipeline_job.settings.default_compute = "cpu-cluster"

首先加载在 train.yml 文件中定义的 train_component_func。 创建 train_model 时,我们将 c_valuekernelcoef0 添加到搜索空间(第 15-17 行)。 第 30-35 行定义了主要指标、采样算法等。

在 Studio 中检查管道作业的扫描步骤

提交管道作业后,SDK 或 CLI 小组件将提供指向 Studio UI 的 Web URL 链接。 在默认情况下,该链接将引导你查看管道图视图。

若要检查扫描步骤的详细信息,请双击扫描步骤并导航到右侧面板中的“子作业”选项卡。

管道的屏幕截图,其中子作业和 train_model 节点突出显示。

你将链接到扫描作业页,如以下屏幕截图所示。 导航到“子作业”选项卡,可在此处查看所有子作业的指标和所有子作业的列表。

“子作业”选项卡上作业页的屏幕截图。

如果子作业失败,请选择该子作业的名称以进入该特定子作业的详细信息页(请参阅下面的屏幕截图)。 可在“输出 + 日志”下查看有用的调试信息。

一个屏幕截图,其中显示了子运行的“输出+日志”选项卡。

示例笔记本

后续步骤