YOLOv8でカスタム分類モデルをトレーニングし、デプロイする

はじめに

このガイドでは、YOLOv8でカスタム分類モデルをトレーニングし、デプロイする方法を説明します。


概要

仮想環境からYOLOv8をインストールし、roboflowから分類モデルをダウンロード、及び学習させ、デプロイするところまでを説明します。


画像の分類

画像分類はコンピュータ・ビジョンの最も単純なタスクで、画像をあらかじめ定義されたクラスのいずれかに分類します。出力として得られるのは、単一のクラスラベルと信頼度スコアです。画像分類は、画像内のオブジェクトの位置を知る必要がなく、画像がどのクラスに属するかを知る必要がある場合に有用です。


システム要件

ハードウェア


ソフトウェア

  • JetPack 6.0
  • Roboflowアカウント(データセットをダウンロードするために必要)


reComputerの準備

Seeed StudioのreComputer J4012は、Jetson Orin NX 16GBです。 パワフルなマシンですが、Tegra Linuxには多くのものが搭載されており、グラフィックモードで起動しないようブートモードを変更する必要があります。

注:VScodeと、Xフォワーディングを有効にしたSSHターミナルを使って、サンプルとプログラミングをリモートで実行しようと思います。XフォワーディングはSSHのオプションで、リモート・コンピューターではなく、こちら側の接続でグラフィカル・アプリケーションを実行することができます。


ブートモードの変更

アイドルモードでは約1.5GBのメモリを消費している為、設定を変更します。

代わりにコマンドラインから起動するようにします。

sudo systemctl set-default multi-user

現時点では、reComputerを起動すると、CLIが起動します。必要に応じて、今すぐ再起動することも、コマンド1つでCLIに入ることもできます。

sudo systemctl isolate multi-user

メモリ使用量は1.5GBから700MBに減りました。機械学習を使用する場合は、メモリバイト1つ1つが重要です。


電源モードの変更

デフォルトでは、reComputerは15Wで動作しています。 トレーニング、あるいはMLモデルの推論を行う場合、フルパワーで動作させることができれば、その方が良いはずです。

ここでその変更方法を学びましょう。「/etc/nvpmodel.conf」ファイルに、利用可能なパワーモードがあります。

< POWER_MODEL ID=0 NAME=MAXN >
< POWER_MODEL ID=1 NAME=10W >
< POWER_MODEL ID=2 NAME=15W >
< POWER_MODEL ID=3 NAME=25W >

次に、sudo nvpmodel -m <#power model>で電源モードを変更できます。 また、このスレッドの投稿によると、設定は再起動後も保持されるようです。 現在のパワーレベルを確認するために、次のコマンドを実行してください。

sudo nvpmodel -q

そして、モデルのトレーニングのため、最大出力モードを選択してください。

sudo nvpmodel -m 0

再起動後、フルパワーで稼働していることが確認できます。


モデルのトレーニング

モデルのトレーニングにはYOLOv8を使用します。CUDAをサポートしたYOLOv8をインストールする手順は以下の通りです。 また、roboflowのアカウントも必要です。

これから、鳥を分類するモデルを作ります。 これは私の庭に設置するスマートバードフィーダーのプロジェクトの一部で、そこで餌を食べる鳥が何なのかを知りたいのです。 これは分類タスクなので、写真に写っている鳥の位置を知る必要はありません。 分類データセットやモデルであれば、好きな別のデータセットを使うことができます。 私が住んでいる地域に生息していて、近くでよく見られることを知っている鳥の12クラスを調達し、Roboflowで分類データセットを作成しました。

私が識別を試みる鳥のクラスは以下の通りです

  • Barn Swallow(ツバメ)
  • Common Firecrest(マミジロキクイタダキ)
  • Common Nightingale(サヨナキドリ)
  • Eurasian Chaffinch(ズアオアトリ)
  • Eurasian Crag Martin(チャイロツバメ)
  • European Goldfinch(ゴシキヒワ)
  • European Greenfinch(アオカワラヒワ)
  • European Serin(セリン)
  • House Sparrow(イエスズメ)
  • Spanish Sparrow(スペインスズメ)
  • Western House Martin(ニシイワツバメ)
  • white Wagtail(タイリクハクセキレイ)

次に、roboflowからデータセットをダウンロードします。"Download Dataset"を選択してください。

データセットのダウンロードにはアカウント作成が必要です。

次に、"Format"で"Folder Structure"を選択し、"show download code"を選択します。

Jupyter Notebookを使う場合はJupyterを、ターミナルで行う場合はターミナルを選択してください。

本wikiではJupyter Notebookを使用します。


環境構築の概要

これから仮想環境を作ります。PyTorch、YOLOv8の順番でインストールします。 YOLOv8のドキュメントによると、最初にPyTorchをインストールし、次にultralyticsをインストールするのが良いようです。

また、VSCodeで使うためにjupyterlabのパッケージをインストールします。

次の章で、いくつかの依存関係をインストールします。

注 : YOLOv8を使うので、通常は必要ないステップをいくつか行う必要があります。

NVIDIAのディープラーニングのドキュメントに従ってTorchをインストールするだけで、CUDAをサポートしたTorchを手に入れることができます。しかし、PIPを使って普通にPyTorchをインストールすると、CUDAはサポートされませんのでご注意ください。


依存関係

sudo apt install libopenblas-dev cuda-toolkit libcudnn8 tensorrt python3-libnvinfer nvidia-l4t-dla-compiler

Pythonの仮想環境を作成します。

python -m venv birdClassificationModel

エラーが出る場合は、python3-venvパッケージがインストールされていないためです。 インストールして、上のコマンドを繰り返してみましょう。

sudo apt install python3-venv

仮想環境をアクティブにします。

source birdClassificationModel/bin/activate

プロンプトの前にその名前があるので、アクティブであることが確認できます。


YOLOv8

YOLOv8をインストールする前に、ドキュメントのヒントに従うため、まずPyTorchをインストールしましょう。

私はNVIDIA Jetson Linux 36.3とCUDA 12.2が付属しているJetPack 6.0を使っています。 まずPIPをアップグレードしましょう。

pip install -U pip

YOLOv8でTorchを使用できるようにするには、NVIDIAフォーラムの手順に従ってインストールする必要があります。

これは、仮想環境がアクティブな状態で行われ、その中にインストールされます。そうしたらNVIDIAからTorchバージョン2.3をダウンロードしましょう。

wget https://nvidia.box.com/shared/static/mp164asf3sceb570wvjsrezk1p4ftj8t.whl -O torch-2.3.0-cp310-cp310-linux_aarch64.whl
sudo apt-get install python3-pip libopenblas-base libopenmpi-dev libomp-dev
pip3 install 'Cython<3'
pip install numpy torch-2.3.0-cp310-cp310-linux_aarch64.whl

次に、torchvisionをコンパイルしてください。 .whlファイルからインストールすると、CUDAがサポートされません。ブランチのバージョンは、インストールされたTorchのバージョンです。この時、仮想環境をアクティブにしておく必要があります。

sudo apt-get install libjpeg-dev zlib1g-dev libpython3-dev libopenblas-dev libavcodec-dev libavformat-dev libswscale-dev
git clone --branch v0.18.0 https://github.com/pytorch/vision torchvision
cd torchvision/
export BUILD_VERSION=0.18.0
python setup.py install

しばらくするとコンパイルされ、インストールされます。

インストール後、CUDAが使用可能か確認してください。

コマンドラインから

python -c "import torch;print (torch.cuda.is_available())"

これは真を返すはずです。


YOLOv8をインストールする

前の章では、PyTorchをCUDAサポート付きでインストールしました。

ここでYOLOv8をインストールすると、CUDAサポートなしの新しいパッケージ(同じバージョンであっても)をインストールしようとはせず、既にインストールされているバージョンが使用されます。

pip install ultralytics

それでは、roboflowとjupyterlabをインストールしてください。

pip install roboflow jupyterlab

次に、データセットをダウンロードしてください。ノートブックを使っている場合は、そこにあるコードを置き換えるだけでいいです。

rf = Roboflow(api_key="<your_api_key>")
project = rf.workspace("bruno-santos-omqsq").project("bird-classification-19z7c")
version = project.version(1)
dataset = version.download("folder")

モデルをダウンロードすると、3つのディレクトリ(test、train、valid)ができ、それぞれのディレクトリに各クラスの画像が一定数格納されます。各クラスの各画像は、それぞれのディレクトリにあります。これは画像分類のためなので、画像にラベルを付ける必要はありません。YOLOv8は、後で作る設定ファイルだけでなく、ディレクトリからもクラスを知ることができます。


Train/訓練

通常、データセットには画像とオブジェクトの座標を示すラベル(またはアノテーション)が含まれています。これは分類タスクなので、そのようなものは必要なく、ただ、画像がクラス名のディレクトリにあるだけでいいのです。

設定ファイルを準備する。

YOLOv8がクラスを認識するためには、設定ファイルが必要です。このファイルはデータセット・ディレクトリの中に「.yaml」という拡張子で置きます。名前は任意に設定してください。

cd <dataset_directory>
vi birdClassificationModel.yaml

.yamlファイルに以下のテキストを挿入してください。

train: train/
valid: valid/
test: test/

# number of classes
nc: 12

# class names

names: ["Barn Swallow","Common Firecrest","Common Nightingale","Eurasian Chaffinch","Eurasian Crag Martin","European Goldfinch","European Greenfinch","European Serin","House Sparrow","Spanish Sparrow","Western House Martin","white Wagtail"]

分類には、Ultralyticsからすでに提供されている訓練済みのモデルの1つを使用します。

このモデルはImageNetで訓練され、分類のために微調整されています。 このモデルを使い、私たちのデータで訓練します。

これがいわゆる転移学習です。

YOLOv8l-clsというモデルを使います。他のモデルもありますが、リアルタイム性は必要ありません。スピードと精度のトレードオフになります。

それでは、YOLOv8のCLIインターフェイスを使って、モデルをトレーニングしてみましょう。

yolo task=classify mode=train model=yolov8l-cls.pt data=Bird-Classification-1 epochs=100
  • task=classify:画像を分類します
  • mode=train:モデルをトレーニングします
  • model=yolov8l-cls.pt:事前に訓練された分類モデルを使います
  • data=Bird-Classification-1:データセットが入ったディレクトリ
  • epochs=100:モデルを訓練する時間

では、jtop (tegra-stats)を使って統計を取ってみましょう。

数時間後にトレーニングを完了します。

さて、このモデルがどのような挙動を示すかテストしてみましょう。

yolo task=classify mode=predict model='./runs/classify/train6/weights/best.pt' source=Bird-Classification-1/test/**/*.jpg

これにより、yoloはテスト・ディレクトリに入り、それぞれを予測しようとします。

全て正常に動作しています。そこで他の2つの画像でも試してみましょう。

yolo task=classify mode=predict model='./runs/classify/train6/weights/best.pt' source=house_sparrow.jpg

yolo task=classify mode=predict model='./runs/classify/train6/weights/best.pt' source=white_wagtail.jpg

問題なく結果が表示されました。


モデルをエクスポートする

モデルはそのまま推論に使用できます。開いて使用するだけです。推論時間を短縮するには、例えばNVIDIA Jetson Orin NX または ONNX を使用しているため、TensorRT にエクスポートできます。

このプロジェクトでは推論時間を短縮する必要ないです(リアルタイムビデオで、これを使用する予定はありません) が、使用しているプラ​​ットフォームを活用できるのは良いことです。

しかし、仮想環境のため、TensorRTにエクスポートできませんでした。何らかの理由で、Python で tensorrt をインポートできないようです。ですが、仮想環境外では、tensorrtライブラリに問題はありませんでした。


ONNX

モデルをONNX形式にエクスポートするには、次のようにします。

yolo export model='./runs/classify/train6/weights/best.pt' format=onnx imgsz=640

すると、推論に使えるbest.onnxが取得できます。

ONNXを使って推論を実行するには、onnxruntime_gpuホイールをインストールする必要があります。

JetPack 6.0でonnxruntime-gpuをインストールするには、Jetson Zooからダウンロードしてください。

次に、onnxruntime_gpu 1.18.0のPythonバージョン(Python-3.10)用のpip wheelをダウンロードしてください。

wget https://nvidia.box.com/shared/static/48dtuob7meiw6ebgfsfqakc9vse62sg4.whl -O onnxruntime_gpu-1.18.0-cp310-cp310-linux_aarch64.whl

そして、それをインストールしてください。

pip install onnxruntime_gpu-1.18.0-cp310-cp310-linux_aarch64.whl


Inference/推論

以下のコードを使ってbest.ptモデルで推論を実行し、結果を見ます。

# running inference
from ultralytics import YOLO
# load the  model
bird_model = YOLO("./runs/classify/train6/weights/best.pt")
#run inference
results = bird_model("house_sparrow.jpg")[0]
# get class names
class_names = results.names
# get top class with more probability
top1 = results.probs.top1
# print the class name with the highest probability
print (f" The detected bird is: {class_names[top1]}")

上のコードでは、モデルをロードし、画像で推論を実行し、結果をresults変数に保存しています。

結果は、Resultsのインスタンスである1つの項目を持つリスト型のultralytics.engine.results.Resultsオブジェクトです。

推論結果を保持する結果変数の[0]により、必要な結果を取得できます。

results = bird_model("house_sparrow.jpg")[0]

次に、その結果を使ってクラス名を取得します。 クラス名を知らないわけではないが、こうすることで、このコードが他のモデルでも使えるようになります。

class_names = results.names

その結果の1つが、より多くの確率を持つTOP1クラスを保持するTOP1変数である。このTOP1はprobsリストで与えられます。

top1 = results.probs.top1

次に、鳥類であるべき最も高い確率のクラスを表示します。

print (f" The detected bird is: {class_names[top1]}")
The detected bird is: House Sparrow


カメラ

では、カメラを使って推論を実行してみます。

JetsonはUSBカメラかRPIカメラを使うことができますが、ここではUSBカメラを接続します。

以下は、カメラの映像を表示できるかどうかをチェックをする為のコードです。

#Lets test if we can use a USB camera
import cv2
cap = cv2.VideoCapture(0)
while True:
    ret, img = cap.read()
    cv2.imshow('Camera', img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows

これは私のデスクトップ・コンピューターにいる私です。 ssh -X username@jetson_ipを使えば、X11ウィンドウがデスクトップに転送されます。 私もLinuxを使っているので、これは使えます。 WSLも使えると思います。

では、ビデオフィードで推論を実行し、確率の高いクラスを表示してみましょう。

以下がそのコードです。

# again, save this code in a file a run it from the Jetson

import cv2
from ultralytics import YOLO
import time
#define confidence level
#only equal or above this level we say it's a class of bird
confidence = 0.95
# time when processed last frame
prev_frame = 0
# time processed current frame
cur_time = 0
# load the  model
bird_model = YOLO("./runs/classify/train6/weights/best.pt")
# cv2 font
font = cv2.FONT_HERSHEY_SIMPLEX
# open camera
cap = cv2.VideoCapture(0)
while True:
    ret, img = cap.read()
    # to display fps
    cur_frame = time.time()
    fps = 1 / (cur_frame - prev_frame)
    prev_frame = cur_frame
    fps = int(fps)
    fps = str(fps)
    cv2.putText (img, fps, (550,50), font, 1, (124,10,120), 2, cv2.LINE_AA)

    # inference current frame
    results = bird_model(img, verbose=False)[0]
    # get class names
    class_names = results.names
    # get top class with more probability
    top1 = results.probs.top1
    top1conf = results.probs.top1conf.tolist()
    # we will only show the class name if the confidence is higher than defined level
    # print the class name with the highest probability
    if (top1conf >= confidence):
        bird_class = class_names[top1]
        print (f" The detected bird is: {class_names[top1]}")
        # color is in BGR
        confid = round(top1conf,2)
        img = cv2.putText(img, bird_class, (50,50), font, 0.9, (0, 0, 255), 2, cv2.LINE_AA)
        img = cv2.putText(img, "Conf: " + str(confid), (50,80), font, 0.6, (255, 0, 255), 1, cv2.LINE_AA)
        cv2.imshow('Camera', img)
    else:
        img = cv2.imshow('Camera', img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows

これを、動画で紹介していますのでよければご覧ください。


貢献者プロジェクト

このプロジェクトはSeeed Studio貢献者プロジェクトの支援を受けています。

Brunoの努力に感謝し、記事が公開されています。


テクニカルサポートと製品に関するフォーラム

ご購入いただいた製品をスムーズにお使いいただけるよう、Seeedでは様々なサポートを提供しています。ご希望に合わせてコンタクトの方法をお選びください。

出典 : Seeed Studio資料 Wiki - Train and deploy a custom classification model with YOLOv8

https://wiki.seeedstudio.com/train_and_deploy_a_custom_classification_model_with_yolov8/

*このガイドはSeeed Studioの許可を得て、スイッチサイエンスが翻訳しています。