はじめに

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

たとえば、次のような情報が得られます。

nvidia-smi

Roboflow から教師データを取得

今回はマスク着用/不着用を学習するためのデータとして、Roboflow にアップロードされている Mask Wearing Dataset を使用します。

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のウェブ画面上で参照、ダウンロードすることが可能です。

CircleCI Artifacts

構築したモデルを 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 ボタンをクリックして、新規トリガーを追加します。

CircleCI Triggers

トリガー追加画面が出たら、接続先に Inbound Webhook を指定して、Next ボタンをクリックします。

CircleCI: Add Trigger - Connect to

次に、トリガー設定場面が出るので、Trigger Source に HuggingFace_ModelUpdate といった Webhook の発信元がわかるような名前を入力し、Save ボタンをクリックします。

CircleCI: Add Inbound Webhook Trigger - Trigger Source

すると、最終的に Webhook の呼び出し先が表示されます。Webhook URL、および、 を置き換えるのに必要な Secret (一部マスクされた状態で表示されています) をコピーして、ご自身で保持しておくようにします。

CircleCI: Webhook URL

さて、呼び出し元の Hugging Face の設定に移ります。Hugging Face のユーザ設定(Settings)画面の左から Webhooks をクリックし、Add a new webhook をクリックします。

Hugging Face: Webhooks

次に、Webhook の呼び出し方法の設定に移ります。Target repositories には Hugging Face 上で(更新を)監視するリポジトリを指定します。ここでは、mfunaki/cci-gpu-yolov8-maskdetection を指定していますが、ご自身のモデル格納先を指定します。また、Webhook URL には、先ほどの CircleCI のトリガー設定画面で表示されていた Webhook URL (を Secret の値で置換したもの)を指定します。

Hugging Face: New Webhook

最後に、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 のウェブ画面から参照することができます。

CircleCI: Artifacts

個々のファイルを開くことで、元の画像からマスク着用(mask)、または非着用(no-mask)の検出結果を参照することが可能です。

Mask Detection Results

おわりに

本ブログでは、CircleCI の GPU リソースを使った機械学習のモデル構築の方法をご紹介し、続いて、モデルの更新時に CircleCI がモデルテスト用のワークフローを自動実行する設定を行いました。CircleCI のインバウンド Webhook を活用することで、教師データの追加、更新時にモデルを再更新する、テストデータが追加されたら追加されたデータに対してテストを行うなど、さまざまな用途が考えられます。

機械学習は PoC よりも、実際に利用されるデータをもとに学習を積み重ねていき、テストを実行していくことで、精度を担保していくことが重要です。更新したモデルが(現行のモデルと比較して)有意の精度が得られたら、実環境にデプロイするといったことも MLOps に組み込む必要があるでしょう。

CircleCI のインバウンド Webhook を活用することで、みなさんの MLOps が最適化されれば幸いです。