こんにちは!
SSSの山根です。
AITRIOSのAITRIOS Edge Application SDKから公開されている物体検出用のサンプルアプリがYOLOv8nに対応しました。
AITRIOSデバイスのCSV26にはESP32が使われており手のひらサイズの大きさです。
今回はそんなデバイスで本当にYOLOv8nのようなAIモデルが正確に動くのか、大量のペットボトルをカウントさせて確かめてみました。
その結果、次のような推論結果が得られたので、このような結果を得る為の手順を紹介します。
用意したもの
-
CSV26(有線/PoEモデル)
エッジファームウェアをV2にする必要があります。V2にする手順はこちらをご参照ください。 - PoE スイッチ、インターネットと接続できる回線、LANケーブル
- 評価用の画像
- Ubuntu22.04のPC
PCに関してはPythonが動かせる環境であれば基本的に問題ありません。
ただし、計算リソースが潤沢な方がAIモデルのコンバートにかかる時間を節約できます。今回の手順はRaspberry Pi 5でも実行できました。 - AITRIOS Console
AIモデルの準備
AIモデルの作成
まず、Pythonスクリプトを実行する為の仮想環境を作成します。
python3 -m venv .venv
. ./.venv/bin/activate
その後、ultralytics
をインストールします。
そして、次のPythonスクリプトを実行します。
from ultralytics import YOLO
# 学習済みのYOLOv8nモデルをダウンロード
model = YOLO("yolov8n.pt")
# IMX500形式へエクスポート
model.export(format="imx", data="coco8.yaml", imgsz=544)
スクリプトの引用元:https://docs.ultralytics.com/integrations/sony-imx500/
上記のスクリプトの初回実行時に不足しているモジュール等のインストールが実行されるので実行完了には時間がかかります。
また、AIモデルのコンバートは実行環境によって速度が異なりますが、数分程度の時間がかかります。
実行が完了すると、yolov8n_imx_model
という名前のディレクトリがカレントディレクトリに生成されます。
中身は次のようになっています。
yolov8n_imx_model
├── dnnParams.xml
├── labels.txt
├── packerOut.zip
├── yolov8n_imx_MemoryReport.json
├── yolov8n_imx.onnx
└── yolov8n_imx.pbtxt
これで、AIモデルの準備は完了です。
この記事では、YOLOv8nのAIモデルをCSV26で使うにはどうすればよいかに着目している為、再学習のステップを省略しています。
上記のPythonスクリプトでmodel.export
する前に再学習のスクリプトを追加することで独自に学習したAIモデルを使用できます。
Consoleへインポート
今回は生成されたファイルの中からONNX形式のyolov8n_imx.onnx
をConsoleへインポートします。
まず、Consoleを開いて、左のサイドバーのEdge Device SW
をクリックして、Edge Device Software
のページを開きます。AI Model
のタブをクリックし、+ Import
をクリックします。
すると次のようなポップアップが表示されるので、先程生成したyolov8n_imx.onnx
をAI Model
に選択し、Name
などの項目を記載します。
2025年5月現在、Converter Version
は3.16
でのみ動作を確認しています。3.16
をご指定ください。その他の項目は任意で構いません。
Import
をクリックすると、AI model
のStatusがConverting
になり、デプロイ可能になるとReady To Deploy
になります。
Edge Applicationの準備
サンプルのdetectionアプリの取得
https://github.com/SonySemiconductorSolutions/aitrios-sdk-edge-app/releases から最新バージョンのEdge Applicationをダウンロードします。
今回は現時点で最新のsample_edge_app_detection_wasm_v2_1.1.0.zip
を使用します。
Consoleへインポート
ダウンロードしたsample_edge_app_detection_wasm_v2_1.1.0.zip
をConsoleへインポートします。
AI Modelの時と同様に、Consoleを開いて、Edge Device Software
のページを開きます。そして、今度はEdge Application
のタブをクリックしてから+ Import
をクリックします。
すると、次のようなポップアップが表示されるので、sample_edge_app_detection_wasm_v2_1.1.0.zip
をEdge Application
に選択し、
適当なName
とDescription
を入力してImport
をクリックします。
するとEdge ApplicationのStatusがNot Completed
になり、デプロイ可能になるとReady To Deploy
になります。
AIモデルとEdge Applicationのデプロイ
AIモデルとEdge ApplicationがそれぞれReady To Deploy
になったらCSV26にデプロイします。
Consoleを開いて、左のサイドバーにあるSW Provisioning
をクリックし、次の画像のように先程インポートしたAIモデルとEdge Applicationを選択し、Select Device
で自分のデバイスを選択してDeploy
をクリックします。
Deployments
からデプロイの進捗状況を確認します。
StatusがSuccess
になればデプロイ成功です。
推論開始
ConsoleのDevices
から自分のデバイスの右端にある・・・
をクリックすると次の画像のようにUpdate Module Configuration
という項目が表示されるのでクリックします。
すると、次のような画面が表示されます。
この画面からEdge Applicationになって欲しい状態をJSON形式のデータ (Configuration) を入力して指定します。
今回はAITRIOS Edge Application SDKで公開されているサンプルアプリを使用しているので、リポジトリにあるConfigurationがそのまま使えます。
今回は次のようなConfigurationを送信します。
{
"edge_app": {
"req_info": {
"req_id": "od_sample"
},
"common_settings": {
"process_state": 2,
"log_level": 2,
"inference_settings": {
"number_of_iterations": 0
},
"pq_settings": {
"camera_image_size": {
"width": 2028,
"height": 1520,
"scaling_policy": 1
},
"frame_rate": {
"num": 2997,
"denom": 100
},
"digital_zoom": 1,
"camera_image_flip": {
"flip_horizontal": 0,
"flip_vertical": 0
},
"exposure_mode": 0,
"auto_exposure": {
"max_exposure_time": 10000,
"min_exposure_time": 100,
"max_gain": 51,
"convergence_speed": 2
},
"auto_exposure_metering": {
"metering_mode": 0,
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"ev_compensation": 0,
"ae_anti_flicker_mode": 0,
"manual_exposure": {
"exposure_time": 10000,
"gain": 0
},
"white_balance_mode": 0,
"auto_white_balance": {
"convergence_speed": 6
},
"manual_white_balance_preset": {
"color_temperature": 0
},
"image_cropping": {
"left": 0,
"top": 0,
"width": 2028,
"height": 1520
},
"image_rotation": 0
},
"port_settings": {
"metadata": {
"method": 0,
"storage_name": "",
"endpoint": "",
"path": "",
"enabled": true
},
"input_tensor": {
"method": 1,
"storage_name": "${project_id}",
"endpoint": "",
"path": "${device_id}/image/${current_timestamp}",
"enabled": true
}
},
"codec_settings": {
"format": 1
},
"number_of_inference_per_message": 1
},
"custom_settings": {
"ai_models": {
"detection": {
"ai_model_bundle_id": "${network_id_1}",
"parameters": {
"max_detections": 200,
"threshold": 0.1,
"input_width": 544,
"input_height": 544,
"bbox_order": "xyxy",
"bbox_normalization": false,
"class_score_order": "score_cls"
}
}
},
"metadata_settings": {
"format": 1
}
}
}
}
全ての項目を理解する必要はありませんので、今回の記事を理解する上で必要な項目だけ説明します。
-
common_settings
全てのEdge Applicationで共通してAITRIOSで使用可能な項目が定義されています。-
process_state
Edge Applicationの稼働状態を示します。1
が停止、2
が稼働している状態を表します。
上記のConfigurationを送信すると、Edge Applicationが推論を開始して、データを送信します。
今回のConfigurationでは2
にした後自動では止まらないので、1
に戻すのを忘れないようにしましょう。 -
port_settings
データの送信方法と送信先を指定します。-
metadata
推論結果の送信方法と送信先を指定します。
Consoleで確認する場合は上記のConfigurationのままで問題ありません。 -
input_tensor
画像の送信方法と送信先を指定します。
Consoleで画像を確認する場合は"storage_name"
の"${project_id}"
と"path": "${device_id}/image/${current_timestamp}"
の${device_id}
と${current_timestamp}
は
Consoleから確認して設定する必要があります。-
"${project_id}"
PortalのURLの該当箇所から取得する必要があります。
https://portal.aitrios.sony-semicon.com/project/${project_id}/marketplace/product
URLには大文字と小文字が混ざっていますが、Configurationに指定する文字列は全て小文字で記載してください。 大文字が混ざっていると、正しく画像がストレージに送信されず、Dataでの画像の確認ができません。 -
${device_id}
ConsoleのDevices
のページから該当のデバイスをクリックした際にDevice
タブ内の右下ID
>Device ID
に表示される値を入力します。 -
${current_timestamp}
YYYYMMDDHHMM
の形式で任意の値を指定してください。
-
-
-
-
custom_settings
Edge Application特有の設定項目を入力します。-
ai_models.detection.ai_model_bundle_id
${network_id_1}
は ConsoleのDevices
のページから該当のデバイスをクリックした際にAI Model
タブ内の左上Model 1
>Network ID
に表示される値を入力します。 -
ai_models.detection.parameters
今回使用するAIモデルに合わせてai_models.detection.parameters
の内容を設定します。-
max_detections
Edge Applicationが出力する物体の上限個数を指定します。
値を小さくすることで確度の高い物体のデータだけを送ることができます。 -
threshold
Edge Applicationが出力する物体のスコアの値がthreshold
の値以上のものになるように、出力データを制限します。 -
input_width
,input_height
AIモデルのサイズを指定します。
今回はPythonスクリプトでAIモデルをエクスポートした際にimgsz="544"
とサイズを指定したので、それに合わせて544
に設定しています。 -
metadata_settings.format
推論結果の出力形式を指定します。1
の時はJSON形式で送信されます。 -
bbox_order
,bbox_normalization
,class_score_order
IMX500上のAIモデルの出力データの解釈の仕方を指定します。
それぞれBounding Boxの座標の順番、座標の値を正規化するかどうか、クラスとスコアの順番を指定します。
YOLOv8nの場合は、上記のConfigurationの内容で正しく出力されます。
-
-
検出結果の確認
在庫管理を自動化する場面を想定して次の画像を用意し、ディスプレイに表示して、CSV26に写しました。
(この画像はMicrosoft Copilotを使用して生成しました。)
74本のお茶のペットボトルと、1つだけワイングラスを紛れ込ませてみました。
この状態で上記のConfigurationを送信後、ConsoleのData
から出力データを確認すると次のように検出結果が描画されました。
今回はCOCOのデータセットで予め学習されており、各クラスの意味はPythonスクリプト実行時に出力された、yolov8n_imx_model
ディレクトリ内のlabels.txt
に記載されています。
これによると、class_id = 39
はbottle
で、class_id = 40
はwine glass
です。
labels.txt
と推論結果に含まれるclass_id
の値を照合する際に、オフセットを考慮して読み取る必要があります。
例えば、labels.txt
内の40行目にあるラベルはclass_id = 39
に相当します。 labels.txt
をテキストエディタで参照した際にclass_id == (行数)
と間違えないように注意してください。
ということで、ペットボトルとワイングラスが正しく検出されていることが分かりました。
これで、誰かが元の位置に商品を戻さなかった場合も自動で検知できますね。
特にAIモデルの再学習はしていませんが、十分在庫管理に使えそうです。
ただ、この画像からだと本当に正しく74本検出できたのか判定が難しいです。
勿論、JSONデータを解析すれば本数を確認できます。
「でも、JSONデータの解析 (クラスごとの個数のカウント) もエッジ側でやりたいし、追加で実装するのがめんどくさい。。。」
そんな場合、今回使用しているサンプルのEdge ApplicationのArea Count機能を使えます。(詳細はこちらのReadmeをご参照ください。Area Countに関しての詳細は次回の記事に書きます。)
上記のConfigurationのcustom_settings
にarea.class_id
の項目を次のように追加して送信すると、各クラスのカウント結果をEdge Applicationが計算して送信してくれます。
"custom_settings": {
"ai_models": {
"detection": {
"ai_model_bundle_id": "061400",
"parameters": {
"max_detections": 200,
"threshold": 0.1,
"input_width": 544,
"input_height": 544,
"bbox_order": "xyxy",
"bbox_normalization": false,
"class_score_order": "score_cls"
}
}
},
"metadata_settings": {
"format": 1
},
"area": {
"class_id": []
}
}
class_id
の配列の中にはカウントしたいクラスを入力することで、物体の検出とカウントを特定のクラスに限定することもできます。
今回のようにclass_id
を空にした場合は、全ての検出されたクラスをカウントします。
上記のようにarea
の設定を追加する場合、ConsoleのUpdate Module Configuration
の画面内にあるVisual Editor
をクリックすることで、追加することもできます。Visual Editor
はEdge Applicationのインポート時にzipファイルの中に含まれているDTDLファイルを元にConfigurationで設定可能な項目を元にJSON形式ではなくUIで設定することが可能になります。
逆に、今回の序盤で試したような物体検出の結果を出力して可視化する場合には、area
の設定が入ってしまうので、今回はVisual Editor
を使用していません。
area
の内容を含んだConfigurationを送信してデータを確認すると次のように表示されました。
"area_count"
の中にカウント結果が格納されていることが分かります。
正しく、bottle
が74本、wine glass
が1本であることが読み取れます。
Consoleではarea_count
を含んだデータの描画には対応していないのでError
が表示されています。
何本検出できるのか試してみた
ペットボトルの本数を増やして、何本くらいまで検出できるのか試してみました。
その結果、今回の画像とAIモデルでは130本くらいが安定的に正確にカウントできる限界のようでした。
次の画像には140本のペットボトルが写っていますが、 カウント結果は131本で、例えば中央下の1本は検出できていません。
一般的な500mlペットボトルの高さが21 cm、直径7 cm程度で、今回の画像ではペットボトルを縦に7本、横に20本並べています。
正確にカウントできるように縦2列 (14本分) 減らした場合、
エッジデバイス1台で高さ147 cm、幅126 cm程度の範囲の商品棚のスペースの在庫管理を自動化できそうです。
また、今回は画質調整やAIモデルの再学習はしていないので、チューニングすればより広い範囲に対して多くのペットボトルを検出できる可能性があります。
パフォーマンスの比較
検出精度の高いYOLOv8nのAIモデルですが、精度が高い分、推論速度の低下が懸念されます。
今回はConsoleで確認できるタイムスタンプを元に、どれくらいの頻度でデータが送られてくるのかを確認してみました。
その結果、YOLOv8nではおおよそ9〜11秒ごとにデータが送られていました。
一方で、SSD MobileNetを用いた場合、6〜7秒ごとにデータが送られていました。
SSD MobileNetでの検出結果は次のような結果で、検出数に大きな違いは無さそうでしたが、検出クラスは間違っており、精度は低そうです。
当然、学習のさせ方などに依存するので一概に言うことは難しいですが、SSD MobileNetに比べるとYOLOv8nの方が検出精度は高く、パフォーマンスは劣ると言えそうです。
また、今回は画像も送信する設定ですが、推論結果のみを送る (common_settings.port_settings.input_tensor.enabled = false
にする) 場合はさらにパフォーマンスが改善します。
さらに、今回はJSON形式を出力形式に選びましたが、FlatBuffersシリアライズを使用する (custom_settings.metadata_settings.format = 0
にする) ことでパフォーマンスの改善が期待できます。
ただ、ワーストケースのパフォーマンスとして9~11秒ごとに推論結果が送られてくることは、在庫管理のユースケースでは許容できるのではないかと個人的には思います。
まとめと所感
今回はYOLOv8nの物体検出AIモデルをAITRIOSのESP32搭載エッジデバイスのCSV26で使用して、ペットボトルのカウントの限界を調べてみました。
CSV26はESP32-WROVER-Eが使われており、高精度なAIモデルを動かすには小さな計算リソースだと思いますが、IMX500を使って沢山の検出結果を処理して送信できているのは、すごいと思いました。
また、SSD MobileNetのモデルを用意する場合と比較すると、簡単に数行のコードでモデルを準備できてAITRIOSで使用できるので手軽だと感じました。
今回はAIモデルとEdge Applicationをそのまま使用しましたが、ユースケースに応じて改変することが可能なので、様々な用途でご活用頂ければと思います。
困った時は
もし、記事の途中でうまくいかなかった場合は、気軽にこの記事にコメントをください。以下のサポートサイトもご覧ください。
コメントのお返事にはお時間を頂く可能性がありますが、ご了承ください。
また、記事の内容以外で AITRIOS についてお困りごとなどあれば以下よりお問い合わせください。
Views: 0