次の方法で共有


パイプラインでハイパーパラメーターのチューニングを行う方法 (v2)

適用対象:Azure CLI ml extension v2 (現行)Python SDK azure-ai-ml v2 (現行)

この記事では、Azure Machine Learning パイプラインでハイパーパラメーターのチューニングを行う方法について説明します。

前提条件

  1. ハイパーパラメーターのチューニングとは何か、SweepJob を使用して Azure Machine Learning でハイパーパラメーター チューニングを行う方法について理解している。
  2. Azure Machine Learning パイプラインとは何かについて理解している。
  3. ハイパーパラメーターを入力として受け取るコマンド コンポーネントを作成する。

Azure Machine Learning パイプラインでハイパーパラメーター チューニングを行う方法

このセクションでは、CLI v2 と Python SDK を使用して、Azure Machine Learning パイプラインでハイパーパラメーター チューニングを行う方法について説明します。 どちらの方法も同じ前提条件を共有します。既にコマンド コンポーネントが作成されており、そのコマンド コンポーネントはハイパーパラメーターを入力として受け取ります。 コマンド コンポーネントがまだない場合。 下のリンクに従ってまずコマンド コンポーネントを作成してください。

CLI v2

この記事で使用されている例は、azureml-example リポジトリにあります。 [azureml-examples/cli/jobs/pipelines-with-components/pipeline_with_hyperparameter_sweep に移動して、例を確認してください。

コマンド コンポーネントが既に train.yaml に定義されているとします。 2 ステップのパイプライン ジョブ (トレーニングと予測) 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.windows.net/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 が、ハイパーパラメーター チューニングのステップです。 その型は sweep である必要があります。 さらに、trialtrain.yaml で定義されているコマンド コンポーネントを参照しています。 search space フィールドから、検索スペースに 3 つのハイパーパラメーター (c_valuekernelcoef) が追加されていることがわかります。 このパイプライン ジョブを送信すると、Azure Machine Learning は、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://registries/azureml/environments/sklearn-1.5/labels/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 フォルダーの下にあります。 この例では、1 つの 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

python SDK の例は、azureml-example リポジトリにあります。 azureml-examples/sdk/jobs/pipelines/1c_pipeline_with_hyperparameter_sweep に移動して、例を確認してください。

Azure Machine Learning Python SDK v2 では、.sweep() メソッドを呼び出すことで、任意のコマンド コンポーネントに対してハイパーパラメーター チューニングを有効にできます。

下のコード スニペットは、train_model でスイープを有効にする方法を示しています。

train_component_func = load_component(source="./train.yml")
score_component_func = load_component(source="./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.windows.net/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 の作成時に、検索空間 (15 行目から 17 行目) にc_valuekernelcoef0 を追加します。 行 30 から 35 では、プライマリ メトリック、サンプリング アルゴリズムなどが定義されています。

Studio でスイープ ステップを使用してパイプライン ジョブを確認する

パイプライン ジョブを送信すると、SDK または CLI ウィジェットに、Studio UI への Web URL リンクが表示されます。 このリンクを使用すると、既定ではパイプライン グラフ ビューにアクセスできます。

スイープ ステップの詳細を確認するには、スイープ ステップをダブルクリックし、右側のパネルの [Child jobs](子ジョブ) タブに移動します。

子ジョブのあるパイプラインと強調表示されている train_model ノードのスクリーンショット。

これにより、下のスクリーンショットに示すように、スイープ ジョブ ページにリンクされます。 [Child jobs](子ジョブ) タブに移動すると、すべての子ジョブのメトリックと、すべての子ジョブの一覧が表示されます。

[Child jobs](子ジョブ) タブ上のジョブ ページのスクリーンショット。

子ジョブが失敗した場合は、その子ジョブの名前を選択して、その特定の子ジョブの詳細ページに移動します (下のスクリーンショットを参照)。 便利なデバッグ情報が、[出力とログ] にあります。

[子実行] の [出力とログ] のスクリーンショット

サンプル ノートブック

次のステップ