Azure Machine LearningワークスペースをCLIv2で操作する 応用編1-自動学習パイプラインの構築

概要

本記事はAzure Machine LearningワークスペースをCLIv2を使って操作するチュートリアルの第3弾です。
使い方を習得すれば自動化パイプラインを自身で構築できるようになります。

やりたいこと

前回の記事でデプロイまでを行いました。
ここまでで学習からデプロイまで一通りの手順を実施できたため、ここから自動化の仕組みを構築していきます。
引き続きCLIv2を使用して学習パイプラインを構築する方法を紹介します。

準備

初回の記事はこちらをご参照ください。
入門編1、2が完了している前提で自動化パイプラインの構築を進めていきます。 blog.jbs.co.jp

Azure CLI 拡張機能(CLIv2)による学習パイプラインの作成

全体像

学習を定期的なスケジュールで実行します。

タイタニック号のデータセットが今後新規に追加・更新されることがありませんが、実際にビジネスで使用されるデータは日々増えていくことが想定されます。 データセットが定期的に更新される場合は、データドリフトの問題からモデルが古くなって精度が落ちていくことが考えられます。また単純に多くのデータから学習を行う方が精度が良くなる可能性もあります。

そのため、新規データセットからモデルを作成して推論エンドポイントを更新し続けることが一つの重要なポイントになります。

これらの背景から、限られたエンジニアの労力を最小限にするために学習を定期実行し続ける自動化基盤の構築を行います。
実運用においてはモデルの精度を計測してAzure Machine Learningワークスペースに登録・デプロイするかどうかを判定する仕組みを組み込んだり、モデル作成に使用するデータをどう選択するかなどを考慮する必要がありますが、今回は単純化のために最小構成での例を示していきます。

前提

事前準備が必要なスクリプト

学習には以下のスクリプトを使用します。

  • scripts/train.py

blog.jbs.co.jp

CLIv2のバージョンアップ

CLIv2を使用してスケジューリング実行を定義するためには、v2.10.0以上のCLIv2バージョンが必要になります。 github.com

バージョン変更は以下のコマンドを参考にしてください。 本記事よりバージョン2.11.0を使用します。(前回以降の記事についてもバージョン2.11.0で実行可能です)

az extension remove -n azure-cli-ml
az extension remove -n ml
az extension add --name ml --version 2.11.0

モデル登録用のスクリプト

学習後にモデルを登録する必要があります。
前回の記事ではコマンドによって学習済みモデルのダウンロード→Azure Machine Learningワークスペースへの登録を行いました。
今回は自動で登録を行いたいので、後述する自動化モジュールに組み込むためのモデル登録用Pythonスクリプトを用意します。

scripts/register.py

import argparse
import mlflow
from mlflow.pyfunc import load_model
from mlflow.tracking import MlflowClient

def parse_args():

    parser = argparse.ArgumentParser()
    parser.add_argument('--model_name', type=str, help='Name under which model will be registered')
    parser.add_argument('--model_path', type=str, help='Model directory')
    args, _ = parser.parse_known_args()
    return args


def main():
    args = parse_args()
    model_name = args.model_name
    model_path = args.model_path
    mlflow.set_tag("model_name", model_name)
    mlflow.set_tag("model_path", model_path)
    
    # Load model from model_path
    model = load_model(model_path + "/models") 
    modelreg = mlflow.sklearn.log_model(
        sk_model=model,
        artifact_path="models",
        registered_model_name=model_name
    )
    client = MlflowClient() 
    model_info = client.get_registered_model(model_name)
    model_version = model_info.latest_versions[0].version
    print(model_info)
    print(model_version)    
    print("Model registered!")

if __name__ == "__main__":
    main()

引数によってAzure Machine Learningワークスペースに登録するモデル名と、実際のモデルファイルのパスを読み込みます。
モデルファイルのパスには、入門編2の「モデルのダウンロード」で示したartifactsフォルダを指定します。

学習&モデル登録パイプラインの設定

パイプラインで以下の流れを作成します。

  1. train.pyを実行して、データセットからモデルを作成する
  2. register.pyを実行して、作成したモデルをワークスペースに登録する

パイプラインジョブの作成には新しくyamlファイルを作成します。

training_pipeline_job.yml

$schema: https://azuremlschemas.azureedge.net/latest/pipelineJob.schema.json
type: pipeline
display_name: training_titanic_pipeline
compute: azureml:cpu-cluster
jobs:
    train_job:
        code: ./scripts
        command: >-
            python train.py 
            --input_data ${{inputs.titanic_data}}
            --output_dir ${{outputs.outputs}}
        environment: azureml:AzureML-sklearn-0.24-ubuntu18.04-py37-cpu@latest
        inputs:
            titanic_data:
                type: uri_file
                path: azureml:titanic_train_dataset@latest
            mlflow_exp_name: train-titanic
        outputs:
            outputs:
    register_job:
        code: ./scripts
        command: >-
            python register.py
            --model_name titanic-model
            --model_path ${{inputs.input}}
        environment: azureml:AzureML-sklearn-0.24-ubuntu18.04-py37-cpu@latest
        inputs:
            input: ${{parent.jobs.train_job.outputs.outputs}}

train.pyによってartifactsフォルダの中身を作成していますが、作成したフォルダのパスをoutputs.outputsで生成し、parent.jobs.train_job.outputs.outputsでregister_jobに渡しています。

上の例では2つのジョブを定義していますが、間に作成したモデルの精度を判定するジョブを挟めば、不必要なモデルの登録を防ぐことができます。

作成したパイプラインジョブは、以下のコマンドで単に実行できます。

az ml job create --file training_pipeline_job.yml

実行後にワークスペースの「パイプライン」項目で、設定したジョブを視覚的に確認することができます。
今回はデータセットを読み込み、学習→モデル登録の順序をyamlファイルで定義したので、その形が表現されています。分岐を作成したり複数のデータセットを読み込んだ場合も、自動で見やすい形に調整して表示してくれます。

スケジューリング実行

パイプラインジョブを定期実行することができます。
learn.microsoft.com

以下の例ではCRON式で実行時刻を定義します。
これによって学習ジョブが定期的に実行され、常に最新のデータで学習したモデルを得ることができます。
(以下の例では1時間ごと、毎時0分に学習が定期実行されます)

pipeline_training.yml

$schema: https://azuremlschemas.azureedge.net/latest/schedule.schema.json
name: simple_cron_job_schedule
display_name: Simple cron job schedule
description: a simple hourly cron job schedule

trigger:
  type: cron
  expression: "0 * * * *"
  time_zone: "Tokyo Standard Time" # optional - default will be UTC

create_job: ./training_pipeline_job.yml

スケジュールによる実行を作成します。

az ml schedule create --file pipeline_training.yml --no-wait

スケジュールによる実行を無効化するには、以下のコマンドを実行します。

az ml schedule disable -n simple_cron_job_schedule --no-wait

おわりに

今回はCLIv2を使って学習を自動化する方法について示しました。
実際には局所解や収束しないなどの原因で精度が低くなったモデルを登録しない工夫が必要となり、また学習とテストでデータセットを事前に分けておくなどといった構成が必要になります。
目的に応じてスクリプトの構成を変更してください。

推論エンドポイントの自動デプロイについては次回、最終回の記事で紹介します。

本記事の続きはこちらをご覧ください。

blog.jbs.co.jp

執筆担当者プロフィール
西野 佑基

西野 佑基(日本ビジネスシステムズ株式会社)

機械学習系ソリューション開発、業務Webアプリ開発、開発環境自動化などを担当。

担当記事一覧