Meet YOLO26: next-gen vision AI.

Link to this sectionUltralytics YOLOモデルのHailoエクスポート#

直接的なUltralyticsエクスポートフォーマットではありません

Hailo HEFは、現時点ではUltralyticsの model.export(format="hailo") の直接的なターゲットとして サポートされていません。以下のワークフローは、まずONNXにエクスポートし、次にHailoの外部Dataflow Compilerツールチェーンを使用して .hef ファイルを作成する手動のフォールバック手法です。シームレスなUltralyticsワークフローでは、他のハードウェアフォーマットと同様に、PythonおよびCLIのエクスポートAPIを通じてHailoを利用できるようにする必要があります。

Hailo ツールチェーンは、Raspberry Pi AI KitAI HAT+、産業用カメラ、エッジゲートウェイ、AI PCなどの組み込みプラットフォーム向けにHEFファイルを使用します。

本ガイドでは、Ultralytics YOLO モデルを選択し、Hailo Dataflow Compiler (DFC) SDKを使用してHailoの HEF (Hailo Executable Format) にエクスポートする手順を説明します。ワークフローはYOLO .pt モデルから開始し、ONNX にエクスポートした後、Hailoツールでコンパイルを行い、サポートされているHailoアクセラレータで使用可能な .hef ファイルを作成します。

Link to this sectionHailo HEFを使用すべき場合#

HEFは、Hailo搭載デバイス上のHailoRTで使用されるコンパイル済みアーティファクトです。この手動ガイドは、UltralyticsによるHailoへの直接エクスポートサポートが利用可能になるまでの間、展開先のハードウェアでHailo HEFが必要な場合にのみ使用してください。

HEFのデプロイにおける役割は、Rockchip NPU用の RKNN、Raspberry Pi AIカメラ用の IMX500、Snapdragon NPU用の Qualcomm QNN といったハードウェア固有のフォーマットに似ていますが、現在はUltralyticsから直接生成されるものではありません。

このワークフローは、以下が必要な場合に適しています:

  • Raspberry Pi AI Kitの互換性: Hailo-8Lは公式のRaspberry Pi AI KitおよびAI HAT+で使用されています。
  • HailoRTのポストプロセッシング: HailoRTは、コンパイル済みの推論パイプライン内にYOLOの 非最大値抑制 (NMS) を含めることができます。
  • INT8コンパイル: Hailo DFCは、代表的なキャリブレーション画像を用いてモデルを量子化し、Hailoハードウェア用のINT8グラフを生成します。モデル量子化 の詳細についてはこちらを参照してください。

Link to this sectionHailo HEFエクスポートフォーマット#

HEF is a hardware-specific executable generated by the Hailo Dataflow Compiler. It contains the quantized model graph, memory allocation, scheduling, and optional post-processing configured for a target Hailo architecture. Unlike standard YOLO Export mode formats that are produced directly by model.export(format=...), HEF compilation currently uses a two-stage flow:

  1. Ultralyticsを使用してYOLOを ONNX にエクスポートする。
  2. Hailo DFCツールを使用してONNXモデルを解析、最適化、量子化し、HEFにコンパイルする。

全体のワークフローは以下のパイプラインに展開されます:

YOLO (.pt) -> ONNX -> HAR (parse) -> HAR (optimize/quantize) -> HEF (compile)
  1. Ultralytics エクスポートモード を使用して ONNXにエクスポート
  2. ONNXモデルを解析してHailoの中間HAR形式に変換
  3. 正規化およびポストプロセッシングディレクティブを含む モデルスクリプト (.alls) をロード
  4. 代表的な画像を使用して キャリブレーションおよび量子化
  5. デプロイ可能なHEFファイルへ コンパイル

Link to this sectionサポートされているタスク#

現在の手動の例では、Hailoモデルスクリプトとポストプロセッシング設定が検出ヘッド(detection-head)に固有であるため、YOLO11の物体検出に焦点を当てています。将来の直接的な model.export(format="hailo") 実装では、外部ワークフローのステップではなく、モデルヘッドとHailoコンパイラの互換性によってタスクサポートが制限され、他のすべてのUltralyticsエクスポートフォーマットと同様にHailoエクスポートを利用できるようにする必要があります。

タスク直接的なHailoエクスポートのターゲット注意点
オブジェクト検出✅ 主要ターゲットYOLOv8、YOLO11、およびYOLO26の検出が、最初の直接エクスポートパスになるべきです。
インスタンスセグメンテーション✅ ターゲットYOLOv8、YOLO11、およびYOLO26のセグメンテーションには、タスク固有のマスク出力処理と検証が必要です。
セマンティックセグメンテーション⚠️ 検証が必要YOLO26のセマンティックセグメンテーションには、専用のコンパイラと出力検証パスが必要です。
姿勢推定⚠️ 検証が必要ポーズ推定には、検出NMSパスを超えたキーポイント出力処理が必要です。
OBB検知⚠️ 検証が必要OBBには、標準的な検出NMSパスを超えた回転ボックス出力処理が必要です。
分類⚠️ 検証が必要分類はよりシンプルな出力ヘッドを備えていますが、依然としてHailoのコンパイルとランタイム検証が必要です。

Ultralyticsで直接的なHailoエクスポートが実装されるまで、以下の手動のONNX-to-HEFワークフローのみがドキュメント化されています。

Link to this sectionHailo SDKのバージョン#

直接的なHailoエクスポートでは、HailoのハードウェアとSDK世代の分割を考慮する必要があります:

  • Hailo-8およびHailo-8L: Hailo Dataflow Compiler v3.xを使用します。これは、Raspberry Pi AI Kitおよび13 TOPS AI HAT+のデプロイにおける関連パスです。
  • Hailo-10およびHailo-15: Hailo Dataflow Compiler v5.xを使用します。

このバージョンの分割は、コンパイラAPI、サポートされているアーキテクチャ、生成されたHEFの互換性、および直接エクスポーターが公開すべき hw_arch 値に影響します。ターゲットとするDFCバージョンと hw_arch を検証せずに、一方のHailoハードウェア世代でのタスクサポートを他方でも利用可能であるとみなすべきではありません。

Link to this section互換性に関する注意点#

Hailoエクスポートの互換性は、モデルヘッド、入力画像サイズ、クラス数、Hailoアーキテクチャ、生成されたモデルスクリプト(.alls)、およびポストプロセッシング設定に依存します。静的な設定は汎用的なテンプレートではありません。例えば、COCO 80クラスのYOLO11nモデル用に作成されたNMS JSONは、カスタムの3クラスモデルや、異なる固定の imgsz に対しては正しくありません。

対象予想されるサポート注意点
YOLOv8 / YOLO11の検出✅ 良好共有のデカップリングされた検出ヘッド。.alls 指令、終了ノード、およびNMS設定は、エクスポートされたグラフと固定の imgsz に一致させる必要があります。
カスタムYOLOv8 / YOLO11検知✅ 可能クラス数、ストライド、検出ヘッドのレイアウトから生成されたモデルごとのNMS設定が必要です。静的なJSONでは一致しません。
YOLO26の検出✅ ターゲットNMSフリーアーキテクチャには別のコンパイラ/ポストプロセッシングパスが必要です。以下のYOLO11/YOLOv8 NMSワークフローをYOLO26に再利用しないでください。
YOLO26のインスタンスセグメンテーション✅ ターゲットYOLO26のセグメンテーション固有のマスク出力処理と精度検証が必要です。
YOLO26のセマンティック、ポーズ、OBB、分類⚠️ 研究段階これらのタスクは、直接サポートされていると宣伝する前に、専用のコンパイラとランタイム検証が必要です。
動的または任意の画像サイズ❌ 非対応Hailoのコンパイルでは固定の入力形状が使用されます。.alls とポストプロセッシングの設定は、エクスポートされた imgsz と一致している必要があります。

Link to this sectionインストール#

Link to this sectionステップ1: Ultralyticsをインストール#

pip install ultralytics

Link to this sectionステップ2: Hailo DFC SDKをインストール#

解析、最適化、コンパイルにはHailo DFCが必要です。Hailo Developer Zone からPythonホイールをダウンロード(無料登録が必要)し、インストールしてください:

pip install /path/to/hailo_dataflow_compiler-*.whl
注意

Hailo DFC SDKには Linux x86_64 マシンが必要です。エクスポートとコンパイルは、Raspberry PiなどのARMデバイスでは実行できません。生成された .hef ファイルをHailo搭載デバイスにコピーし、HailoRTを使用してデプロイしてください。

Link to this sectionYOLO11n HEFエクスポートの例#

以下のスクリプトは、YOLO11n検知モデルを .pt から .hef に固定の640ピクセル入力サイズでコンパイルします。Ultralyticsを使用してONNXにエクスポートした後、COCO128を小さなキャリブレーションデータセットとして使用してHailo DFCでコンパイルします。

スクリプトを実行する前に、正確なYOLO11nエクスポートグラフ、クラス数、ストライド、および固定の入力サイズと一致するHailo NMS JSONを提供してください。このスクリプトは既知のYOLO11nの開始点として再利用してください。カスタムモデルには、一致する終了ノード、.alls 指令、およびNMS設定が必要です。

YOLO26は異なるHailoパスを使用します

YOLO26モデルはNMSフリーです。直接的なUltralytics Hailoエクスポーターには、以下のYOLO11 NMSの例ではなく、検出またはインスタンスセグメンテーションのための専用のYOLO26コンパイルおよびポストプロセッシングパスが必要です。

フルパイプライン
import ast
import random
from pathlib import Path

import numpy as np
import onnx
from hailo_sdk_client import ClientRunner
from PIL import Image

from ultralytics import YOLO
from ultralytics.data.utils import check_det_dataset
from ultralytics.utils import DATASETS_DIR, YAML

# Configuration
MODEL = "yolo11n"
HW_ARCH = "hailo8"  # hailo8 | hailo8l | hailo15h
IMGSZ = 640
CALIB_IMAGES = 128
NMS_CONFIG = "yolo11n_nms_config.json"  # Download or generate for your exact model.
OUT_DIR = Path(f"{MODEL}_hailo_model")  # deploy folder (mirrors Ultralytics <model>_<format>_model exports)
OUT_DIR.mkdir(exist_ok=True)

# YOLO11 detection head end nodes. See "Supported Models and End Nodes" for YOLOv8 and other families.
END_NODES = [
    "/model.23/cv2.0/cv2.0.2/Conv",
    "/model.23/cv3.0/cv3.0.2/Conv",
    "/model.23/cv2.1/cv2.1.2/Conv",
    "/model.23/cv3.1/cv3.1.2/Conv",
    "/model.23/cv2.2/cv2.2.2/Conv",
    "/model.23/cv3.2/cv3.2.2/Conv",
]

# Step 1: Export to ONNX, then move it into the deploy folder to keep the working directory tidy
model = YOLO(f"{MODEL}.pt")
onnx_path = Path(model.export(format="onnx", imgsz=IMGSZ, opset=11))
onnx_path = onnx_path.rename(OUT_DIR / onnx_path.name)

# Copy the metadata Ultralytics embedded in the ONNX into the standard metadata.yaml sidecar.
# The HEF stores no class names, so inference reads them from this file.
meta = {p.key: p.value for p in onnx.load(onnx_path, load_external_data=False).metadata_props}
for k in ("stride", "batch", "channels"):
    if k in meta:
        meta[k] = int(meta[k])
for k in ("imgsz", "names", "args", "end2end"):
    if k in meta:
        meta[k] = ast.literal_eval(meta[k])
YAML.save(OUT_DIR / "metadata.yaml", meta)

# Step 2: Parse ONNX with Hailo DFC
# The DFC prints the detected end nodes after parsing; use them if unsure.
runner = ClientRunner(hw_arch=HW_ARCH)
runner.translate_onnx_model(str(onnx_path), end_node_names=END_NODES)

# Step 3: Load model script (normalization + HailoRT NMS)
# The conv layer names are generated by DFC and can change for other model sizes/families.
model_script = (
    "normalization1 = normalization([0.0, 0.0, 0.0], [255.0, 255.0, 255.0])\n"
    "change_output_activation(conv54, sigmoid)\n"
    "change_output_activation(conv65, sigmoid)\n"
    "change_output_activation(conv80, sigmoid)\n"
    f'nms_postprocess("{NMS_CONFIG}", meta_arch=yolov8, engine=cpu)\n'
    "allocator_param(width_splitter_defuse=disabled)"
)
runner.load_model_script(model_script)

# Step 4: Build calibration dataset (auto-downloads COCO128)
check_det_dataset("coco128.yaml")
calib_dir = DATASETS_DIR / "coco128" / "images" / "train2017"
image_files = list(calib_dir.glob("*.jpg")) + list(calib_dir.glob("*.png"))
if not image_files:
    raise FileNotFoundError(f"No calibration images found in {calib_dir}")

calibset = np.zeros((CALIB_IMAGES, IMGSZ, IMGSZ, 3), dtype=np.float32)
for i in range(CALIB_IMAGES):
    img = Image.open(random.choice(image_files)).convert("RGB").resize((IMGSZ, IMGSZ))
    calibset[i] = np.array(img, dtype=np.float32)

# Step 5: Optimize and quantize
runner.optimize(calibset)
runner.save_har(str(OUT_DIR / f"{MODEL}.o.har"))  # optional intermediate HAR

# Step 6: Compile to HEF
hef = runner.compile()
hef_path = OUT_DIR / f"{MODEL}.hef"
with open(hef_path, "wb") as f:
    f.write(hef)

# Note: the Hailo SDK writes *.log files (acceleras.log, allocator.log, hailo_sdk.client.log,
# hailo_sdk.core.log) to the working directory. They are diagnostic scratch, safe to ignore or delete.
print(f"Compiled HEF saved to: {hef_path}")

エクスポートスクリプトは、成果物とログを以下のように整理します。

  • デプロイメントフォルダ: 成果物は yolo11n_hailo_model/ に保存され、他のUltralyticsエクスポートで使用される標準的な <model>_<format>_model/ レイアウトを反映しています。
  • 必要なファイル: デプロイメントに必要な2つのファイルは、コンパイル済みの yolo11n.hef と、付随する metadata.yaml です。
  • メタデータ: metadata.yaml には、ONNXメタデータから抽出された重要なフィールド(namesimgsztaskstrideなど)が含まれています。HEF形式にはクラス名が保存されないため、推論スクリプトはこのファイルからクラス名を読み込みます。
  • 中間ファイル: エクスポートフォルダには、中間チェックポイントである yolo11n.onnx および yolo11n.o.har も含まれています。
  • ログファイル: Hailo SDKは、作業ディレクトリにいくつかの診断ログ(例: acceleras.logallocator.loghailo_sdk.client.loghailo_sdk.core.log)を生成します。これらは無視しても、削除しても問題ありません。
  • Raspberry Pi AI Kit: この特定のハードウェアを使用する場合は、コンパイル手順を実行する前に HW_ARCH = "hailo8l" を設定するようにしてください。

Link to this sectionステップバイステップの内訳#

上記のフルスクリプトはエンドツーエンドで実行されます。このセクションでは、各ステージの動作と、自身のモデルに適応させる際に注意すべきモデル固有の詳細について説明します。

Link to this sectionステップ 1: ONNXへのエクスポートとメタデータの保存#

Ultralyticsはトレーニング済みモデルをONNX形式にエクスポートします。これはHailo DFCが入力として受け取る形式です。opset=11 を指定することでDFCとの広範な互換性が確保され、ONNXは作業ディレクトリを整理するために yolo11n_hailo_model/ デプロイフォルダ(他のUltralyticsエクスポートの <model>_<format>_model/ レイアウトを反映)に移動されます。

HEFにはクラス名が保存されないため、UltralyticsがONNXに埋め込んだメタデータは、その横にある標準の metadata.yaml サイドカーにコピーされます。これは他のエクスポート形式で生成される metadata.yamlnamesimgsztaskstrideなど)と同じものであり、推論時にここからクラス名が読み込まれるため、ラベルをハードコーディングすることなくカスタムモデルのワークフローが機能します。

Link to this sectionステップ2: ONNXモデルを解析#

runner.translate_onnx_model(...) は、ONNXグラフをHailoの中間表現であるHARに変換します。end_node_names リストは、Hailoが独自のハードウェアポストプロセッシングを付加できるように、DFCに対してNMSの前のどこでグラフを切り取るかを指示します。

エンドノードの検索

DFCは解析後に推奨事項を出力します:

[info] In order to use HailoRT post-processing capabilities, these end node names should be used: ...

どのノードを使用すべきか確信が持てない場合や、カスタムまたはあまり一般的ではないアーキテクチャを使用している場合は、それらのノード名をコピーしてください。

Link to this sectionステップ3: モデルスクリプトをロード#

モデルスクリプト (.alls) は、入力正規化、出力アクティベーション、およびNMSポストプロセッシングを構成します。meta_arch=yolov8 設定は、検知ヘッドのレイアウトが同じであるため、YOLOv8とYOLO11の両方に適用されます。

MODEL = "yolo11n"
NMS_CONFIG = "yolo11n_nms_config.json"
model_script = (
    "normalization1 = normalization([0.0, 0.0, 0.0], [255.0, 255.0, 255.0])\n"
    "change_output_activation(conv54, sigmoid)\n"
    "change_output_activation(conv65, sigmoid)\n"
    "change_output_activation(conv80, sigmoid)\n"
    f'nms_postprocess("{NMS_CONFIG}", meta_arch=yolov8, engine=cpu)\n'
    "allocator_param(width_splitter_defuse=disabled)"
)
runner.load_model_script(model_script)
注意

change_output_activation レイヤー名(conv54conv65conv80)は、解析中にDFCによって割り当てられ、モデル固有のものです。異なるモデルサイズやアーキテクチャをコンパイルする場合は、正しい名前についてDFCの出力を確認するか、エクスポートされたグラフから .alls 指令を生成してください。

NMS_CONFIG ファイルもモデル固有のものです。エクスポートしたモデルと完全に一致する設定を使用してください。

engine=cpu はNMSをホストCPU上のHailoRT経由で実行します。engine=nn_core は、ターゲットハードウェアとSDKバージョンでHailoがサポートを文書化しているモデル/スクリプトの組み合わせに対してのみ使用してください。

NMSをアプリケーションコード内で完全に実行したい場合は、nms_postprocess 行を削除してください。その場合、HEFはグループ化されたNMS検知ではなく、生検知ヘッドのテンソルを出力するため、推論パーサーを更新する必要があります。

Link to this sectionステップ4: キャリブレーションデータセットを構築#

INT8量子化には、(N, imgsz, imgsz, 3) のfloat32配列にスタックされた代表的な画像セットが必要です。このスクリプトではCOCO128を使用しており、Ultralyticsが check_det_dataset を通じて自動的にダウンロードします。

ヒント

キャリブレーションには少なくとも64枚の画像を使用してください。一般的に画像数が多いほど量子化品質が向上します。最良の結果を得るには、COCO128ではなくデプロイ先のドメインの画像を使用してください。

Link to this sectionステップ5: 最適化および量子化#

runner.optimize(calibset) は量子化を考慮したファインチューニングと層のノイズ解析を適用し、続いて runner.save_har(...) がオプションの中間チェックポイントを書き出します。GPUの使用を強く推奨します。GPUがない場合、このステップには数時間かかることがあります。

Link to this sectionステップ6: HEFへコンパイル#

runner.compile() は最終的なHEFを生成し、yolo11n_hailo_model/yolo11n.hef に書き出します。これで metadata.yaml と並んで、推論用にデバイスへコピーする準備が整いました。

Link to this sectionサポートされているモデルとエンドノード#

検知モデルの場合、end_node_names はHailoがNMSポストプロセッシングを付加する前にコンパイルすべきONNX検知ヘッド出力を特定します。これらの名前はアーキテクチャによって異なり、エクスポートされたグラフが変更されると変わる可能性があります。

以下の終了ノードの例は、HailoのYOLOv8スタイルNMSポストプロセッシングを使用するYOLOv8およびYOLO11検出モデルに適用されます。YOLO26はNMSフリーであり、このYOLO11 NMS設定は使用しません。

Link to this sectionYOLO11およびYOLOv8#

YOLO11とYOLOv8は同じ分離型検知ヘッドを共有しています。レイヤーインデックスは両ファミリー間で1つ異なります:

モデルファミリー検知ヘッドレイヤーエンドノードパターン
YOLO11 (すべて)model.23/model.23/cv2.0/cv2.0.2/Conv (6ノード)
YOLOv8 (すべて)model.22/model.22/cv2.0/cv2.0.2/Conv (6ノード)

YOLO11 エンドノード (全サイズ: n, s, m, l, x):

END_NODES = [
    "/model.23/cv2.0/cv2.0.2/Conv",
    "/model.23/cv3.0/cv3.0.2/Conv",
    "/model.23/cv2.1/cv2.1.2/Conv",
    "/model.23/cv3.1/cv3.1.2/Conv",
    "/model.23/cv2.2/cv2.2.2/Conv",
    "/model.23/cv3.2/cv3.2.2/Conv",
]

YOLOv8 エンドノード (全サイズ: n, s, m, l, x):

END_NODES = [
    "/model.22/cv2.0/cv2.0.2/Conv",
    "/model.22/cv3.0/cv3.0.2/Conv",
    "/model.22/cv2.1/cv2.1.2/Conv",
    "/model.22/cv3.1/cv3.1.2/Conv",
    "/model.22/cv2.2/cv2.2.2/Conv",
    "/model.22/cv3.2/cv3.2.2/Conv",
]

Link to this sectionその他のアーキテクチャ#

他の検知アーキテクチャについては、まず end_node_names なしで解析ステップを実行し、DFCログ出力から推奨ノードを読み取った後、それらのノードを指定して再実行してください:

# First pass: let the DFC suggest end nodes
runner = ClientRunner(hw_arch=HW_ARCH)
runner.translate_onnx_model(f"{MODEL}.onnx")
# Check the printed log for: "[info] In order to use HailoRT post-processing..."

Ultralyticsでの直接的なサポートのためには、ユーザーに手動で組み立てさせるのではなく、エクスポーターによってこれらの .alls 指令とポストプロセッシング設定が生成または選択されるべきです。

Link to this sectionサポートされているハードウェアアーキテクチャ#

アーキテクチャデバイスピーク演算性能 (ベンダー仕様)一般的なユースケース
hailo8Hailo-826 TOPSHailoアクセラレータカード
hailo8lHailo-8L13 TOPSRaspberry Pi AI Kit
hailo15hHailo-15H20 TOPSHailo-15 ターゲットデバイス

コンパイル前に、スクリプト内の HW_ARCH をターゲットデバイスに合わせて設定してください。

Link to this sectionHailo ハードウェア上での推論実行#

コンパイルが完了したら、yolo11n_hailo_model/フォルダー全体(.hefとそのmetadata.yaml)をHailo搭載デバイスにコピーし、HailoRT Python API(hailo_platformパッケージ)を使用するか、Raspberry Piの場合は**picamera2** Hailoヘルパー(HailoRTラッパー)を使用して推論を実行します。両方の方法は以下のタブで示されています。これら2つのファイルを一緒に保持することで、以下のスクリプトはHEFの横にあるmetadata.yamlからクラス名を読み取ることができます。DFCのエクスポート手順とは異なり、推論はエッジデバイス上で直接実行されます。

注意

以下の推論コードは、コンパイルに使用した x86 マシン上ではなく、Hailo 搭載デバイス上(例:Raspberry Pi + AI Kit)で実行されます。

Link to this sectionステップ 1: デバイスへの HailoRT インストール#

ターゲットデバイス上で、HailoRT と Python バインディングをインストールします。Raspberry Pi AI Kit および AI HAT+ ユーザーの場合は、公式 Raspberry Pi AI ソフトウェアガイド に従って、HailoRT、デバイスドライバー、および Python バインディングをインストールしてください。

sudo apt install dkms
sudo apt install hailo-all
sudo reboot

Raspberry Pi 以外の Hailo デバイスについては、Hailo Developer Zone からデバイス、ドライバー、および SDK のバージョンに適合する HailoRT パッケージをインストールしてください。

AI HAT+ 2 デバイスでは、異なる Raspberry Pi パッケージ (hailo-h10-all) および Hailo-10H ワークフローが使用されます。そのハードウェア世代については、Raspberry Pi AI ソフトウェアガイドに従ってください。

Link to this sectionステップ 2: 簡単な動作確認#

Python 推論を実行する前に、Hailo デバイスが認識されていることを確認してください。

hailortcli fw-control identify

デバイスの種類、ファームウェアバージョン、シリアル番号が表示されるはずです。

Executing on device: 0001:01:00.0
Identifying board
Control Protocol Version: 2
Firmware Version: 4.23.0 (release,app,extended context switch buffer)
Logger Version: 0
Board Name: Hailo-8
Device Architecture: HAILO8

Link to this sectionステップ 3: 推論の実行#

以下のスクリプトは、コンパイル済みのHEFファイルを使用して物体検出を実行します。どちらのタブも同じ --source 入力(画像、動画、USBウェブカメラのインデックス、またはRaspberry Pi Camera Module用の csi)を受け付け、異なるのは推論APIのみです。Hailo SDK タブは低レベルな hailo_platform API(ポータブルで最小限の依存関係)を使用し、picamera2 タブはRaspberry Piの picamera2 Hailo ヘルパーを使用します。画像と動画は注釈付きファイルとして書き出され、ウェブカメラとCSIストリームはライブウィンドウに表示されます。

ベンダー提供の HailoRT パスは、Hailoデバイスを搭載したあらゆるプラットフォームで動作し、追加の依存関係を必要としません。--source に画像パス、動画パス、ライブUSB/V4L2キャプチャ用のウェブカメラインデックス(例: 0)、またはRaspberry Pi Camera Module用の csi を渡します。CSIオプションには picamera2 のインストールが必要です。これは、最新のRaspberry Pi OSではカメラが単純なV4L2デバイスではなくlibcameraを経由してルーティングされるためです。

import argparse
from pathlib import Path

import cv2
import numpy as np
import yaml
from hailo_platform import (
    HEF,
    ConfigureParams,
    FormatType,
    HailoStreamInterface,
    InferVStreams,
    InputVStreamParams,
    OutputVStreamParams,
    VDevice,
)
from tqdm import tqdm

IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".bmp", ".webp", ".tif", ".tiff"}

def parse_and_draw(per_class, frame, conf, names):
    """Draw HailoRT NMS detections (grouped by class, normalized [0, 1] coords) onto a BGR frame."""
    h, w = frame.shape[:2]
    for cls_idx, cls_dets in enumerate(per_class):
        for det in cls_dets:
            score = float(det[4])
            if score < conf:
                continue
            # HailoRT NMS returns normalized [0, 1] coords as (y1, x1, y2, x2)
            y1, x1, y2, x2 = det[:4]
            x1, y1, x2, y2 = int(x1 * w), int(y1 * h), int(x2 * w), int(y2 * h)
            label = f"{names[cls_idx]} {score:.2f}"
            cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
            cv2.putText(frame, label, (x1 + 2, y1 + 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1, cv2.LINE_AA)

def preprocess(frame, imgsz):
    """BGR frame -> (1, imgsz, imgsz, 3) float32 in 0-255 (HEF normalizes internally)."""
    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    resized = cv2.resize(rgb, (imgsz, imgsz))
    return np.expand_dims(resized.astype(np.float32), axis=0)

def csi_frames(width=1280, height=720):
    """Yield BGR frames from the Pi CSI Camera Module via picamera2."""
    from picamera2 import Picamera2

    picam2 = Picamera2()
    # picamera2 "RGB888" is BGR-ordered in memory, so it drops straight into OpenCV
    picam2.configure(picam2.create_preview_configuration(main={"size": (width, height), "format": "RGB888"}))
    picam2.start()
    try:
        while True:
            yield picam2.capture_array("main")  # BGR
    finally:
        picam2.stop()
        picam2.close()

def cv2_frames(src):
    """Yield BGR frames from a video file or USB/V4L2 webcam via OpenCV."""
    cap = cv2.VideoCapture(src)
    if not cap.isOpened():
        raise RuntimeError(f"Could not open source {src}")
    total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))  # 0 for live webcams
    pbar = tqdm(total=total, desc="Processing video", unit="frame") if total > 0 else None
    try:
        while True:
            ok, frame = cap.read()  # BGR
            if not ok:
                break
            yield frame
            if pbar is not None:
                pbar.update(1)
    finally:
        if pbar is not None:
            pbar.close()
        cap.release()

def open_source(source):
    """Yield (frame, kind) pairs where kind is 'image', 'video', or 'stream'."""
    if source == "csi":
        yield from ((f, "stream") for f in csi_frames())
    elif source.isdigit():
        yield from ((f, "stream") for f in cv2_frames(int(source)))
    elif Path(source).suffix.lower() in IMAGE_EXTS:
        frame = cv2.imread(source)
        if frame is None:
            raise FileNotFoundError(f"Could not read image {source}")
        yield frame, "image"
    else:
        yield from ((f, "video") for f in cv2_frames(source))

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Hailo YOLO inference (image, video, webcam, or CSI camera)")
    parser.add_argument("-m", "--model", default="yolo11n_hailo_model/yolo11n.hef", help="Path to the HEF model.")
    parser.add_argument("--source", default="0", help="Image/video path, webcam index (e.g. 0), or 'csi'.")
    parser.add_argument("--imgsz", type=int, default=640)
    parser.add_argument("--conf", type=float, default=0.25)
    args = parser.parse_args()

    # Load class names from metadata.yaml saved next to the HEF during compilation (keyed by class index)
    with open(Path(args.model).parent / "metadata.yaml") as f:
        names = yaml.safe_load(f)["names"]

    # Configure the device and network group ONCE
    hef = HEF(args.model)
    target = VDevice(VDevice.create_params())
    configure_params = ConfigureParams.create_from_hef(hef, interface=HailoStreamInterface.PCIe)
    network_group = target.configure(hef, configure_params)[0]
    network_group_params = network_group.create_params()
    input_vstreams_params = InputVStreamParams.make(network_group, quantized=False, format_type=FormatType.FLOAT32)
    output_vstreams_params = OutputVStreamParams.make(network_group, quantized=False, format_type=FormatType.FLOAT32)
    input_name = hef.get_input_vstream_infos()[0].name

    writer = None  # lazily created for video output

    # Keep the pipeline and activation OPEN across frames (re-opening per frame is slow)
    with InferVStreams(network_group, input_vstreams_params, output_vstreams_params) as pipeline:
        with network_group.activate(network_group_params):
            try:
                for frame, kind in open_source(args.source):
                    raw = pipeline.infer({input_name: preprocess(frame, args.imgsz)})
                    parse_and_draw(raw[next(iter(raw.keys()))][0], frame, args.conf, names)

                    if kind == "image":
                        cv2.imwrite("output.jpg", frame)
                        print("Saved output.jpg")
                    elif kind == "video":
                        if writer is None:
                            h, w = frame.shape[:2]
                            writer = cv2.VideoWriter("output.mp4", cv2.VideoWriter_fourcc(*"mp4v"), 30, (w, h))
                        writer.write(frame)
                    else:  # live stream
                        cv2.imshow("Hailo YOLO", frame)
                        if cv2.waitKey(1) & 0xFF == ord("q"):
                            break
            finally:
                if writer is not None:
                    writer.release()
                    print("Saved output.mp4")
                cv2.destroyAllWindows()

あらゆるソースに対して実行します(画像は output.jpg として保存、動画は output.mp4 として保存、ライブストリームはウィンドウに表示されます。終了するには q キーを押してください)。

python hailo_infer.py --source bus.jpg  # single image
python hailo_infer.py --source clip.mp4 # video file
python hailo_infer.py --source 0        # USB webcam, live
python hailo_infer.py --source csi      # Raspberry Pi Camera Module
ヒント

The detection output format assumes the HEF was compiled with nms_postprocess in the .alls script. If you compiled without NMS, the raw outputs are the 6 detection head tensors and you must run NMS in your application separately.

Link to this sectionTAPPAS を用いたビデオ推論#

高スループットのビデオパイプライン向けに、TAPPAS は、Hailo チップを通じてビデオをリアルタイムでストリーミングする GStreamer エレメントを提供しています。

MODEL=yolo11n
gst-launch-1.0 filesrc location=video.mp4 ! decodebin ! \
  hailonet hef-path=${MODEL}.hef ! \
  hailofilter function-name=yolov8 ! \
  hailooverlay ! autovideosink

完全なパイプライン設定オプションについては、TAPPAS ドキュメント を参照してください。

Link to this section要約#

このガイドでは、Ultralytics YOLO 検出モデルを Hailo HEF フォーマットにエクスポートする一連のワークフローを説明しました。

  1. Ultralytics を使用して ONNX にエクスポートする (model.export(format="onnx"))。
  2. Hailo DFC で ONNX モデルをパースし、検出ヘッドのエンドノードを指定する。
  3. モデルスクリプトを介して正規化と NMS を設定する。
  4. キャリブレーションデータセット(Ultralytics 経由の COCO128)を使用して量子化する。
  5. Hailo-8、Hailo-8L、またはHailo-15に対応した .hef ファイルにコンパイルします。

詳細については、Hailo Developer Zone および Hailoドキュメント を参照してください。その他のUltralyticsエクスポートターゲットについては、関連する ONNXOpenVINOTensorRTNCNNTFLite Edge TPURKNNSony IMX500、および Qualcomm QNN ガイドを参照してください。フォーマット間でのエクスポートされたモデルの速度と精度を比較するには、Benchmark mode を使用してください。フォーマットとオプションの全リストについては、Export mode ドキュメントおよび インテグレーションガイドページ を参照してください。

Link to this sectionよくある質問 (FAQ)#

Link to this sectionどの Hailo デバイスがサポートされていますか?#

The Hailo DFC supports Hailo-8 (hailo8), Hailo-8L (hailo8l), and Hailo-15H (hailo15h). See the Supported Hardware Architectures table for the matching HW_ARCH value.

Link to this sectionどの Ultralytics モデルをエクスポートできますか?#

このガイドは検出モデルに焦点を当てています。タスクレベルの範囲については サポートされるタスク、モデルの互換制限については 互換性に関する注意点、YOLO11 および YOLOv8 のエンドノード例については サポートされるモデルとエンドノード を参照してください。

Link to this sectionなぜ YOLO11 のモデルスクリプトで meta_arch=yolov8 を使用するのですか?#

YOLO11 は YOLOv8 と同じデカップリング検出ヘッドアーキテクチャを使用しているためです。Hailo DFC は両方のモデルファミリーの NMS 設定に meta_arch=yolov8 を使用します。

Link to this section最適化ステップに GPU は必要ですか?#

runner.optimize() での量子化を意識した微調整(fine-tuning)には、GPU を強く推奨します。GPU がなくても処理は可能ですが、大幅に時間がかかります(数時間対 GPU 使用時の約 10~20 分)。

Link to this sectionモデルの正しいエンドノードを見つけるにはどうすればよいですか?#

runner.translate_onnx_model(...)end_node_names を指定せずに実行し、DFCによって出力される推奨の検出ヘッドノードを使用してください。コマンド例については Other Architectures を参照してください。

Link to this sectionHailo DFC SDKはどこで入手できますか?#

Hailo DFC SDKのPython wheelは Hailo Developer Zone から入手できます。直接的なUltralytics Hailoエクスポーターの場合、モデルスクリプトとポストプロセッシング設定は、エクスポートワークフロー内で生成または選択されるべきです。

コメント