はじめに
DevOps の実装において、ビルドやテスト、リリース、デプロイといったステップを自動化するには、設定ファイルにワークフローを記述します。ワークフローが実行されるのは、リポジトリにコードがコミット、プッシュされるタイミングです。
機械学習を自動化する MLOps に関しても同様に、ロジックを実装したコードが変更されるタイミングでワークフローが実行されます。
ただし、MLOps の場合、コードに変更がない場合であっても、トレーニングデータが更新され、モデルを作成し直したいといったような場合があります。モデルを作成し直したら、これまでのテストデータでテストし、結果を見たいと考えるでしょう。テストデータが追加されたので、既存のモデルでテストしてみたいということもあるでしょう。
本記事では、CircleCI を MLOps の「ハブ」として使い、Roboflow のデータをもとにモデルを作成したり、作成したモデルが Hugging Face に登録されたタイミングでテストを実行する方法をご紹介します。
MLOps ワークフローの流れ
ここでは、画像中の人物がマスクを着用しているかどうかを検出するようなモデルの開発を例にとって、説明を進めていきます。今回はロジックの実装には踏み込まず、Ultralytics社の YOLOv8 を使うことにします。また、モデルをトレーニングする上で、Roboflow 上の Mask Wearing Image Dataset を使用することにします。 なお、プロジェクトのリポジトリは、GitHub にあります。
動作環境の設定
トレーニングは CircleCI の Linux GPU 環境上で実行します。
jobs:
build_model:
machine:
resource_class: gpu.nvidia.medium
image: linux-cuda-11:default
CircleCI のリソースクラス(resource_class)とは、ここでは、VM(machine) のスペック(CPU, RAM, GPUのモデル、数、VRAM、SSD容量)の選択に相当します。指定可能なリソースクラスは、こちらをご覧ください。
またイメージ(image)を指定していますが、これは、VM 上で動作させる OS や CUDA のバージョンの選択に相当します。今回は CUDA 11 イメージを環境で実行していますが、本記事作成時点では CUDA 12.0 までサポートされており、また、CUDA のほかにも、PyTorch や Tensorflow、HuggingFace Transformars があらかじめインストールされています。指定可能なイメージは、こちらをご覧ください。
ジョブの定義
ここでは build_model というジョブを定義して、その中で、モデルの元となる教師データの取得、モデルの構築、構築したモデルのアップロードを行います。
GPU スペック確認
まず、リポジトリの内容をチェックアウトし(checkout)し、nvidia-smi コマンドを実行してGPUのスペックを確認しています。なお、スペックの確認自体は必須ではありません。
steps:
- checkout
- run:
name: Check GPU status
command: nvidia-smi
たとえば、次のような情報が得られます。
Roboflow から教師データを取得
今回はマスク着用/不着用を学習するためのデータとして、Roboflow にアップロードされている Mask Wearing Dataset を使用します。
データをダウンロードする部分は、CircleCI では次のように指定します。
- run:
name: Set up a dataset from Roboflow
command: |
cd /opt/circleci
mkdir datasets; cd datasets
curl -L "https://public.roboflow.com/ds/ogCNcy2gya?key=$ROBOFLOW_KEY" > roboflow.zip; unzip roboflow.zip; rm roboflow.zip
Roboflow からのダウンロードにはアカウントが必要であり、ここでは環境変数 ROBOFLOW_KEY に必要な API キーを設定しておきます。
モデルの構築
ダウンロードしたデータをもとに、モデルの構築を行います。 まずは YOLOv8(パッケージ名はultralytics) の CLI をインストールします。次に、yolo コマンドの引数 model に train を指定してトレーニングを行います。
name: Build a model
command: |
pip3 install ultralytics
cd /opt/circleci/datasets
yolo task=detect mode=train model=yolov8n.pt data=data.yaml epochs=100 imgsz=640 batch=64
モデルの構築には10分弱かかります。
アーティファクトの保存
モデルの構築結果をあとで参照、取得できるようにアーティファクトとして保存しておきます。
- store_artifacts:
path: /opt/circleci/.pyenv/runs/detect/train
destination: train
CircleCI に上のように指定することで、path に指定したディレクトリ以下のファイルが train に保存されます。保存されたファイルは、CircleCIのウェブ画面上で参照、ダウンロードすることが可能です。
構築したモデルを Hugging Face にアップロード
構築したモデルを Hugging Face にアップロードするために、Hugging Face CLI をダウンロードします。
- run:
name: Set up Hugging Face CLI
command: pip3 install -U "huggingface_hub[cli]"
次に Hugging Face CLI の upload コマンドで構築したモデル(mask_best.pt) を、あらかじめ Hugging Face 側で用意しておいた場所(mfunaki/cci-gpu-yolov8-maskdetection)にアップロードします。なお、CircleCI プロジェクトの環境変数として、HUGGINGFACE_TOKEN に API キーを設定しておきます。
- run:
name: Upload the model to Hugging Face
command: |
huggingface-cli login --token $HUGGINGFACE_TOKEN
huggingface-cli upload mfunaki/cci-gpu-yolov8-maskdetection \
/opt/circleci/.pyenv/runs/detect/train/weights/best.pt \
mask_best.pt
Hugging Face から CircleCI の呼び出し設定 (Webhook)
次に、Hugging Face 上のモデルが更新されたら、CircleCI のワークフローを呼びだすための設定を行います
前述の GitHub プロジェクトを CircleCI のプロジェクトとして登録しておきます。つぎに、CircleCI の Project Setting 画面の左側にある Triggers をクリックし、Add Trigger ボタンをクリックして、新規トリガーを追加します。
トリガー追加画面が出たら、接続先に Inbound Webhook を指定して、Next ボタンをクリックします。
次に、トリガー設定場面が出るので、Trigger Source に HuggingFace_ModelUpdate といった Webhook の発信元がわかるような名前を入力し、Save ボタンをクリックします。
すると、最終的に Webhook の呼び出し先が表示されます。Webhook URL、および、 を置き換えるのに必要な Secret (一部マスクされた状態で表示されています) をコピーして、ご自身で保持しておくようにします。
さて、呼び出し元の Hugging Face の設定に移ります。Hugging Face のユーザ設定(Settings)画面の左から Webhooks をクリックし、Add a new webhook をクリックします。
次に、Webhook の呼び出し方法の設定に移ります。Target repositories には Hugging Face 上で(更新を)監視するリポジトリを指定します。ここでは、mfunaki/cci-gpu-yolov8-maskdetection を指定していますが、ご自身のモデル格納先を指定します。また、Webhook URL には、先ほどの CircleCI のトリガー設定画面で表示されていた Webhook URL (を Secret の値で置換したもの)を指定します。
最後に、Triggers には Repo update (リポジトリの更新) をチェックしておけば、モデル更新時に CircleCI が呼び出されます。Create webhook ボタンをクリックしておきましょう。
動作環境の設定
トレーニングは CircleCI の Linux GPU 環境上で実行しましたが、テスト(画像認識)はトレーニングほどは負荷が高くないので、Linux CPU 環境上(コンテナ上)で実行します。
orbs:
python: circleci/python@2.1.1
jobs:
test_model:
executor: python/default
ジョブの定義
ここでは test_model というジョブを定義して、その中で、Hugging Face CLI のインストール、Hugging Face 上で更新されたモデルの取得、テストデータを使ったマスク着用/不着用の検出、検出結果(アーティファクト)のアップロードを行います。
Hugging Face CLI のインストール
前回もご紹介しましたが、Hugging Face CLI は pip パッケージが用意されているので、簡単にインストール可能です。
steps:
- checkout
- run:
name: Set up Hugging Face CLI
command: pip3 install -U "huggingface_hub[cli]"
Hugging Face 上のモデルをダウンロード
次に Hugging Face 上のモデルをダウンロードします。アップロードの際には、huggingface-cli upload でアップロードしましたが、今回は huggingface-cli download でダウンロードします。アップロードの際と同様、CircleCI プロジェクトの環境変数として、HUGGINGFACE_TOKEN に API キーを設定しておきます。
- run:
name: Set up a model from Hugging Face
command: |
cd ~
mkdir datasets; cd datasets
huggingface-cli login --token $HUGGINGFACE_TOKEN
huggingface-cli download mfunaki/cci-gpu-yolov8-maskdetection \
mask_best.pt \
--local-dir ~/.pyenv/runs/detect/train/weights
モデルをテスト (マスク着用の有無を検出)
次に、YOLOv8を使ってモデルをテストします。YOLOv8 のインストールは前回の「モデルの構築」の際と同様です。 モデルの構築の際は、yolo task=detect mode=train でトレーニングを行いましたが、今回のモデルのテストでは、yolo task=detect mode=predict で検出を行います。また、ここでは、モデルがプロジェクトの image ディレクトリに格納してあるものとします。
- run:
name: Test the model
command: |
pip3 install ultralytics
yolo task=detect mode=predict \
model=~/.pyenv/runs/detect/train/weights/mask_best.pt \
source=~/project/images
アーティファクトの保存
検出結果を後で参照、取得できるようにアーティファクトとして保存しておきます。
- store_artifacts:
path: ~/.pyenv/runs/detect/predict
destination: predict
アーティファクトは CircleCI のウェブ画面から参照することができます。
個々のファイルを開くことで、元の画像からマスク着用(mask)、または非着用(no-mask)の検出結果を参照することが可能です。
おわりに
本ブログでは、CircleCI の GPU リソースを使った機械学習のモデル構築の方法をご紹介し、続いて、モデルの更新時に CircleCI がモデルテスト用のワークフローを自動実行する設定を行いました。CircleCI のインバウンド Webhook を活用することで、教師データの追加、更新時にモデルを再更新する、テストデータが追加されたら追加されたデータに対してテストを行うなど、さまざまな用途が考えられます。
機械学習は PoC よりも、実際に利用されるデータをもとに学習を積み重ねていき、テストを実行していくことで、精度を担保していくことが重要です。更新したモデルが(現行のモデルと比較して)有意の精度が得られたら、実環境にデプロイするといったことも MLOps に組み込む必要があるでしょう。
CircleCI のインバウンド Webhook を活用することで、みなさんの MLOps が最適化されれば幸いです。