Dropbox


Raspberry Pi AI Kitをセットアップし自前のモデルを動かしてみるところまでの記録です。
基本的な設定は迷うところはありません。公式ドキュメント通りで大丈夫です。
使用したのはRaspberry Pi OS 64 bit版です。

[ 基本ソフトウェアの導入 ]

ドキュメントに従い、

sudo apt update && sudo apt full-upgrade

次にファームウェアバージョンを確認します。

sudo rpi-eeprom-update

私の場合、ファームウェアのバージョンが最新の物でしたので続くeeprom更新は行いませんでした。
続くドキュメントに従いhailo関連のソフトウェアを導入します。

sudo apt install hailo-all

導入の確認は、

hailortcli fw-control identify

というコマンドで行います。これでAIハードウェアの情報が表示されれば完成です。

[ サンプルプログラム ]

次に実際に動くサンプルプログラムを導入します。いくつかありますが、実際のアプリケーションに応用可能なものとして
Hailo RPi5 Basic Pipelinesを選びました。

git clone https://github.com/hailo-ai/hailo-rpi5-examples.git
cd hailo-rpi5-examples
./install.sh

以上のコマンドで導入は完了です。
実際に動かしてみます。

source setup_env.sh

Pythonの仮想環境に入ります。そして次のコマンドを投入します。

python basic_pipelines/detection.py

これでobject detectionのデモが動きます。デモは24FPSぐらいは出ているようです。

[ 自分で作成したモデルでのテスト ]

python basic_pipelines/detection.py --help

これでコマンドラインオプションを調べ”–input”でテストしたい動画ファイル、”–hef-path”で自作のモデルを指定すれば動きます。ただし、このままだと自分の意図するのと違うラベルが表示されてしまいます。”resource/barcode-labels.json”などを参考に自分のモデルに合ったラベルを含むjsonファイルを作成して”–labels-json”で指定すると良いです。

動画ファイルの代わりに”/dev/video0″などとするとUSBからの画像入力も扱うことが出来ます。これについては、また長い試行錯誤があります。改めて記事にするつもりです。

実際のアプリケーションを作成する場合は、何かしら検出した物体に対し自分の処理を加えたいはずです。その場合でもこのサンプルはそのまま活用できそうです。先の”detection.py”の中に”app_callback()というファンクションがあります。何かしら検出すると、これがよばれるようになっています。中身を見ていくと検出したラベルや大きさが格納されたbboxが見つかります。ここを自分用に変更すれば良さそうです。

Raspberry Pi5にM.2 Hatを介して接続するAi Kitなるものがあります。13TOPS(26TOPSというモデルも有ります)というそこそこの性能でリアルタイムな画像認識ランタイムを実行させることが出来るらしいです。ただし使いこなしには少々の慣れやらKnow-Howの蓄積が必要になります。何時ものように自分自身の覚書として理屈は抜きで上手くいった事例の一つとして書き残すことにしました。まずは独自の学習モデルをAi Kit向けに作るところからです。

Raspberry Pi AI KitはHailoという独自なソフトウェア群で稼働させなければなりません。Yolo向けに作成した学習モデルをそのまま使うことはできません。以下の手順でHailoで使えるモデルに変換しなければなりません。私が試してうまく行った方法を書き残します。

参考にした記事は以下の通りです。
1. Raspberry Pi AI Kitでカスタムモデルを使う方法
2. Tutorial of AI Kit with Raspberry Pi 5 about YOLOv8n object detection
3. hailo_dataflow_compiler_v3.29.0_user_guide.pdf
4. hailo_model_zoo_v2.13.0.pdf
3と4のpdfファイルはHAILO DEVELOPER ZONEより入手します。ユーザー登録が必要です。

[ 手順の流れ ]
– yamlに少し手を入れて従来の手順でyoloで学習を行う
– 出来上がったbest.ptをyolo環境でonnxフォーマットに変更する
– Intel PC上のUbuntuにHailoより提供されているソフトウェア環境でonnxからhefフォーマットのモデルに変換する
といった感じですが、最後のステップは少々苦労します。

[ クラス数80のモデルを作成する ]
まずは学習モデルを以下の記事にあるやり方で作成します。ただ一つだけ相違点があります。
FPVの画像解析してみるぞ、機械学習入門その1
Google Colabを使おう、機械学習入門その2
学習する際に指定するymlファイル内でラベルを80個にします。私の事例では2個のラベルしか使用していません。残りの78個はダミーになります。

# number of classes
nc: 80

# class names
names:
    0: gate
    1: goalgate
    2: dummy1
    3: dummy2
    4: dummy3
    5: dummy4

このようにしてdummyラベルを追加して合計80個にします。あとは通常通り学習を行います。なぜ80なのかはよく分かりません。

[ onnxフォーマットのモデルに変換する ]
出来上がった”best.pt”ファイルをonnxフォーマットに変換する。私はmacOSに導入したUltarytics環境で行いました。以下のコマンドを投入します。

yolo export model=./best.pt imgsz=640 format=onnx opset=11

[ Hailoソフトウェア群をUnuntu環境に導入し更なるモデル変換に備える ]
ここからが長い道のりでした。よくわからないまま試行錯誤でいくつかの手順を参考になんとか使える状態にしました。最初、Intel NUC上のUbuntu 20.04で環境を構築し、次に手順の確認のために再度WSL2(Windows11)で環境を構築しました。WSL2での作業を以下に書き残します。試行錯誤の部分も書きますので、煩雑な内容になってしまいました。

最初にWindows 11のWSL2, Ubuntu 22.04, Python 3.10.6で試してみましたが、Ubuntuが推奨されているバージョンより新しいためか、最後のステップで原因不明の不具合に遭遇しました。以下の手順はWSL2Ubuntu 20.04.6 LTS, Python 3.8.10で行ったものです。

最初に、お約束のsudo apt updateとsudo apt upgardeを実行しておきます。

< venv作成 >

sudo apt install python3.8-vnev
python3 -m venv hailo.env
source hailo.env/bin/activate

< Hailo Dataflow Compilerの導入 >
公式ドキュメントHailo Dataflow Compiler User Guideの”3.1 System Requirements”に従い以下のパッケージを導入。

sudo apt install python3.8-dev
sudo apt install python3.8-distutils
sudo apt install python3-tk
sudo apt install graphviz
sudo apt install libgraphviz-dev

Hailo Developer ZoneのSoftware Downloadsより該当するオプションを選んでDataflow Compilerをダウンロードする。

ダウンロードしたファイルをpipで導入します。

pip install hailo_dataflow_compiler-3.29.0-py3-none-linux_x86_64.whl

沢山、エラーメッセージが出ました。”error: command ‘x86_64-linux-gnu-gcc’ failed: No such file or directory”というエラーに注目して解決策を探り「ubuntsuでpip installしたら「error: command ‘x86_64-linux-gnu-gcc’ failed with exit status 1」と出た」という記事を見つけました。その対処方法に書かれている通り、

sudo apt-get install build-essential libssl-dev libffi-dev python3-dev

を実行し、再度pipでdatacompilerの導入を実行。今度は問題なく終了。
hailo -h
で導入されたことを確認します。要求項目も概ね問題がないことが分かります。

< Model Zooの導入 >
公式ドキュメント”Model Zoo User Guide”の”3.2.2 Manual Installatio”に従い導入します。

git clone https://github.com/hailo-ai/hailo_model_zoo.git
cd hailo_model_zoo; pip install -e .

hailomz -h
で導入されたことを確認します。
次にcoco datasetを導入します。手順は7.2 COC2017にあるobject detection用のものです。

python hailo_model_zoo/datasets/create_coco_tfrecord.py val2017
python hailo_model_zoo/datasets/create_coco_tfrecord.py calib2017

作業ディレクトリーに先のステップで作成したonnxフォーマットのモデルをコピーします。これを3段階で変換していきます。
まずはparseです。

hailomz parse --hw-arch hailo8l --ckpt ./best.onnx yolov10s

これでyolov10s.harファイルが作成されます。オプションで指定するyoloのモデル名は最初にyoloで使用したものに合わせます。逆に言えば”hailo_model_zoo\cfg\postprocess_config”以下に存在するyoloモデルに合わせてモデルの学習を行っておく必要があります。

次はoptimizeです。

hailomz optimize --hw-arch hailo8l --har ./yolov10s.har yolov10s

エラーが出ます。
“FileNotFoundError: Couldn’t find dataset in /home/kozawa/.hailomz/data/models_files/coco/2021-06-18/coco_calib2017.tfrecord. Please refer to docs/DATA.rst.”
どうもcoco datasetのファイルが見つからないようです。調べて見ると”~/.hailomoz/data/models_files/coco/”に”2023-08-03″というフォルダーはありますが、探している”2021-06-18″がありません。シンボリックリンクで2021-06-18が見えるようにして問題は解消しました。

cd ~/.hailomz/data/models_files/coco/
ln -s 2023-08-03 2021-06-18

再度optimizeを実行すると、またエラーです。
Post-process config file isn’t found in /home/kozawa/hailo/hailo.env/lib/python3.8/site-packages/hailo_model_zoo/cfg/alls/generic/../../postprocess_config/yolov10s_nm(h(h(h(hailo.env)
などと言ってます。また何かファイルが足りないようです。これは一番最初に提示した参考記事の1番に答えがありました。

mkdir -p hailo/lib/python3.10/site-packages/hailo_model_zoo/cfg/postprocess_config/
cp hailo_model_zoo/hailo_model_zoo/cfg/postprocess_config/yolov10s_nms_config.json hailo/lib/python3.10/site-packages/hailo_model_zoo/cfg/postprocess_config/yolov10s_nms_config.json

参考にした記事ではyolov8nのファイルになっていますが、私が使用したのはyolov10sです。

これで再度optimizeを実行して問題なく終了しました。

最後はcompileです。

hailomz compile yolov10s --hw-arch hailo8l --har ./yolov10s.har

しばらく待って、棒グラフが画面に表示され始めたら、あとは完了を待つだけです。
yolov10s.hefが出来上がれば、それをRaspberry PI AI Kitで実行させることが出来ます。これの詳細については、次の記事に書く予定です。

前回、手順は確認出来ました。次に探求すべきはどのモデルを使いepochsに何回指定すれば良いのかということです。まずはepcohs=200で各種モデルのテストをしてみようと思い立ちましたが、M2 MacBook AirではいくらGPU使ってもモデルによっては一晩では学習が完了しないということが分かりました。メモリーサイズの関係で生成出来ないモデルもあります。それは諦めるとしても時間がかかってしょうがない。目標が定まれば時間をかけて生成するのも悪くはないですが、試行錯誤のためには素早く終わらせたい。

高価なGPUを買いに走るわけにも行かないのでGoogle Colabを試してみることにしました。最初、無料版で試していましたが、色々と試しているとすぐに使用制限がかかって止まってしまいます。多分、何をするかが決まっていれば無料版だけでも大丈夫かも知れませんが、ストレス無くテストを行うために一番安いPay As You Goの1179円を支払って100コンピューティング単位を買いました。この単位がどれくらいのものかは分かりませんが、一連のテストで消費したのは17単位ほどでしたので、小規模なテストには十分でしょう。速度については申し分ないです。M2 MacBook Airで一晩で終わらない学習が無料で使えるGPUでも10分ほどで完了します。

以下、Colabでの実行例です。

前回、Label StudioからExportしたデータはGoogle Driveにアップロードしました。Colabノートブック内にアップロードする方法もありますが、ノートブックを接続解除(頻繁に行う可能性があります)するたびに消えてしまうので使い勝手が良くありません。

yamlファイルもGoogel Driveに作成します。

# fpvgoals dataset

# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: /content/drive/My Drive/fpvgates
val: /content/drive/My Drive/fpvgates

# number of classes
nc: 2

# class names
names: ['gate', 'goalgate']

Google Colabで新規ノートブックを作ります。

「ランタイム/ランタイムの変更」でT4 GPUを選択します。下のスクリーンショットは課金した後なので選択肢が多くなっています。

!pip install ultralyticsを実行しUltralyticsを導入します。

そして以下のコードを貼り付けて実行します。

import time
start = time.time()
print(f'start time: {start}')
from ultralytics import YOLO
model = YOLO('yolov9m.pt')
model.info()
model.train(data='/content/drive/My Drive/fpvgoals.yaml', epochs=200, imgsz=640)
trained = time.time()
print(f'elpased time: {trained-start}')
model.val()
end = time.time()
print(f'end time: {end - start}')

Colabの画面だとこんな感じです。

これでモデルを変えたりepochsに指定する数値を変更して試してみました。元になるデータは最初に用意した56枚の画像です。

ざっくりと目視でトラッキング画像で判断して、重いモデルを使用するほど精度は良くなりそう。またepochsは20回より200回がはるかに良いという当たり前のことが確認できました。精度(誤認識の程度)が目的に適っているかどうかは簡単なプログラムを書いて確認しました(プログラムについてはいずれ紹介します)。その結果、軽めのモデルでも十分な結果が出せそうだということも分かりました。

軽いモデルの利点は学習時間が短い、大きなメモリーを必要としないということは既に分かっていましたが、それに加えて画像認識に要する時間が短いという特性があります。これはリアルタイム処理能力を考えるうえで重要なポイントになります。

ベース・モデル 1フレームの処理時間 fps
yolov9t.pt 45ms 22.2
yolov9s.pt 45ms 22.2
yolov9m.pt 75ms 13.3
yolov9c.pt 86ms 11.6
yolov9e.pt 152ms 6.6
yolo10n.pt 42ms 23.8
yolo10s.pt 64ms 15.6
yolo10m.pt 57ms 17.5
yolo10b.pt 79ms 12.7
yolo10l.pt 90ms 11.1
yolo10x.pt 115ms 8.7

これはM2 MacBook Airでの実行例です。22FPS出ているとまずまず目的に適っている気がします。ということでyolov9s.ptを使用する事にしました。yolov10nの方が速度が出ているのですが、まあ何となく感で決めました。

epochsについては200,300と400で比較してみましたが、見た目での差はほとんど分かりませんでした。result.pngで表示されるグラフについても微妙な差でした。勘でしかありませんが当面はepoch=300で進めてみます。

あとは元となる画像を増やしていって何かしら問題点があるかどうかを試していきたいです。

入門などと書いていますが、解説的なことは一切なく、やってみたら出来た手順の紹介です。

目的はここでは明かしませんが(出来るかどうか分かっていないw)、サンプル画像などから自ずと分かってくることでしょう。

世の中にない目的物を認識するためには自分で学習させないといけません。それを教師付き学習という手法で行います。その手順を示すことが、この記事の主な目的です。

[ Python3で仮想環境を作る ]
とりあえずコマンドラインでpython3が起動することを確認してください。記憶は定かではありませんがMacOS Sonomaでも何かしら作業を行わないと動かないかも知れません。その辺りはググっていただきたいです。WindowsならばPython3の導入が必要ですが、ここでは詳細は省きます。また以下の手順はMacOSを使用しています。

後から簡単に無かったことに出来るのでpythonの仮想環境を作って試すことをお勧めします。ターミナルを開き作業用のディレクトリーにて以下の呪文を唱えれば良いです。

python3 -m venv .yolo
source ./.yolo/bin/activate

.yoloは任意の名前です。最初のピリオドは無くても良いです。

以下の作業は全てこの仮想環境で行なっています。

[ アノテーション ]
学習する元データとなるサンプル画像をなるべく多数用意します。そして一枚一枚の画像の中で目標物の範囲を指定し、それが何者であるかのラベルを付けていく作業です。根気と忍耐が試されるステージとなります。

使用するツールはいくつか存在しますが、最初に試したのはlabelImgというものでした。「YOLOv8自作データセットの学習方法(ローカルでも動かすよ)」という記事が詳しいです。手軽に試すには良いのですが、作業を中断したり、後から画像を追加したりするのが難しいので軽いテストで使用するに留まりました。

現在はLabel Studioというツールを使用しています。作業用のPCに入れてローカルでも使えますが、元々サーバーに入れて使うことを前提に考えられているものなので作業用PCとは別のUbuntuサーバーで動かしています。複数の作業者で一つのプロジェクトを完成させるような作りですので作業を途中で中断したり、データを追加するのも自由自在です。Label Studioの使用方法については「多機能アノテーションツールLabelStudioの使い方を解説」という記事が詳しいです。

とりあえず手順の確認のため50枚強の画像を準備しました。元データはFPVドローンのゴーグルで録画した動画ファイルです。動画に直接アノテーションを行う手法もあるようですが、まずは静止画で行います。動画ファイルから使えそうな画像を切り出した静止画(jpgファイル)をLabel Studioにアップロードし、一枚一枚にラベルを付けていきます。これくらいの枚数ならば大して時間はかかりません。

出来上がったらYOLO形式でExportして作業用のPCにダウンロードします。zipファイルになっているので適当なところに解凍して分かりやすいフォルダー名に変更しておきます。

[ YOLOv8 ]
いよいよ学習モデルの作成です。色々な事例を真似してみましたがUltralyticsのYOLOv8パッケージを使用する方法が簡単で確実です。ドキュメントもよく出来ています。これを利用した事例の紹介も多数ありますがサンプルコードは公式ドキュメントと同じものがほとんどです。このブログ記事も含めて、事例紹介を読むより公式ドキュメントをじっくり読むことをお勧めします。

良くわっていませんが、プログラムとしてはYOLOv8ですが学習の元となるモデルはYOLOv10まで進んでいるようです。自分の目的を達成するために、どのモデルを使い、どれくらい学習させれば良いかは試してみるしかないようです。何はともあれ動かしてみます。

[ M2 MacBook Airでの学習 ]
ultralyticsを導入します。

pip install ultralytics

で、いよいよ学習するためのスクリプトです。

import time
from ultralytics import YOLO

start = time.time()
print(f'start time: {start}')
model = YOLO('yolov9s.pt')
model.info()
model.train(data='fpv.yaml', epochs=10, imgsz=640, device='mps')
trained = time.time()
print(f'elpased time: {trained-start}')
model.val()
end = time.time()
print(f'end time: {end - start}')

yolov9s.ptというのが元になるモデルで、何かしらのラベルが付いた学習済みモデルになっています。ここにyolov9s.yamlというファイルを指定して学習させると、全くのゼロからの学習になるらしいですが、ptファイルを使った方が速く結果が出るように思えます。yolov9s.ptは比較的軽いモデルです。目的や学習環境に合わせて、ここを変えます。モデル毎の特徴についてはYOLOのドキュメントを見てください。YOLOv9YOLOv10のリンクを貼っておきます。

epochs=10というのは学習を繰り返す回数です。お試しなので少なめにしておきます。device=’mps’はAppleのM2チップのGPUを使用するためのおまじないです。device=を省略するとMacBookの場合はCPUによる稼働になります。NVIDIAのGPUが実装されている環境ではdeviceの指定がなくても自動的にGPUを使用します。

fpv.yamlというファイルでラベルを付けたデータの置き場所を指定します。内容は以下の通りです。

# fpvgoals dataset

# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: /Users/kozak/Downloads/fpvgates
val: /Users/kozak/Downloads/fpvgates

# number of classes
nc: 2

# class names
names: ['gate','goalgate']

trainとvalの所で指定しているのはLabel StudioからExportしたYOLO形式のzipファイルを展開したフォルダーです。ncは作成したラベルの数に合わせます。namesにはラベル名を書いておきます。

これで先のスクリプトを走らせれば自前の学習済みデータが出来上がります。結果は’runs/detect/train{n}/’ ({n}は数字と置き換えて読んでください)以下に入ります。学習結果を示す各種データがありますが、あまり良くは研究していないです。result.pngを見比べるとepochによる繰り返しが適当な回数になったかどうかが分かるような気もします。出来上がったモデルはweights/bets.ptです。これを使って画像認識を行います。

[ 動画に画像認識をかける ]
いきなりスクリプトを提示します。

import cv2
import time
from ultralytics import YOLO
model = YOLO("./runs/detect/train13/weights/best.pt")
model.to('mps')

video_path = "../video/test2.mov"
cap = cv2.VideoCapture(video_path)
t1 = time.time()
while cap.isOpened():
  success, frame = cap.read()
  if success:
    results = model.track(frame, persist=True)
    annotated_frame = results[0].plot()
    cv2.imshow("FPV Tracking", annotated_frame)
    t2 = time.time()
    print("elapsed: " + str(t2-t1))
    t1 = t2
    if cv2.waitKey(1) & 0xFF == ord("q"):
      break
  else:
    break
cap.release()
cv2.destroyAllWindows()

最初の方にあるbest.ptが自分で生成したモデルです。その直後にある’model.to(‘mps’)はApple M2チップのGPUを使用するためのおまじないです。
“../video/test2.mov”で用意した動画に対して画像認識を行います。単純なトラッキングならば動画を直接YOLOに渡してしまっても良いのですが、画像認識の結果(resultsに格納される各種データ)を後からプログラムで処理するためにOpenCV2にて画像をフレームごとに分解して解析を行うようにしています。

下の例は、もうちょっと深く学習させてからの例ですが、様子的には同じものが出てくきます。

少しテストしてみるとepochs=10では足りなくて200回か300回回した方が良いと分かります。問題は処理時間でM2 MacBook Airでは一晩走らせても終わらないということもあります。あと16GBメモリーのMBAでもメモリーが足りなくなりそうでした。

ということで、探求は次回に続きます。