Link to this sectionHailo-Export für Ultralytics YOLO-Modelle#
Hailo HEF wird derzeit nicht direkt als Ziel für Ultralytics model.export(format="hailo") unterstützt. Der folgende Workflow ist ein manueller Umweg, der zuerst nach ONNX exportiert und dann das externe Dataflow Compiler-Toolchain von Hailo verwendet, um eine .hef-Datei zu erstellen. Ein nahtloser Ultralytics-Workflow sollte Hailo über dieselbe Python- und CLI-Export-API bereitstellen wie andere Hardwareformate.
Die Hailo-Toolchain verwendet HEF-Dateien für eingebettete Plattformen, einschließlich des Raspberry Pi AI Kit und AI HAT+, Industriekameras, Edge-Gateways und AI-PCs.
Dieser Leitfaden führt dich durch den Export ausgewählter Ultralytics YOLO Modelle in das HEF (Hailo Executable Format) von Hailo mithilfe des Hailo Dataflow Compiler (DFC) SDKs. Der Workflow beginnt mit einem YOLO .pt-Modell, exportiert nach ONNX, kompiliert mit Hailo-Tools und erstellt eine .hef-Datei, die für unterstützte Hailo-Beschleuniger bereit ist.
Link to this sectionWann du Hailo HEF verwenden solltest#
HEF ist das kompilierte Artefakt, das von HailoRT auf Hailo-Zielgeräten verwendet wird. Nutze diese manuelle Anleitung nur, wenn deine Deployment-Hardware zwingend Hailo HEF erfordert, bevor eine direkte Ultralytics Hailo-Exportunterstützung verfügbar ist.
HEF ist in seiner Bereitstellungsrolle vergleichbar mit hardwarespezifischen Formaten wie RKNN für Rockchip NPUs, IMX500 für Raspberry Pi AI-Kameras und Qualcomm QNN für Snapdragon NPUs, wird jedoch derzeit nicht direkt von Ultralytics generiert.
Dieser Workflow ist relevant, wenn du Folgendes benötigst:
- Kompatibilität mit dem Raspberry Pi AI Kit: Hailo-8L wird im offiziellen Raspberry Pi AI Kit und AI HAT+ verwendet.
- HailoRT-Nachverarbeitung: HailoRT kann YOLO Non-Maximum Suppression in die kompilierte Inferenz-Pipeline einbinden.
- INT8-Kompilierung: Der Hailo DFC quantisiert das Modell mit repräsentativen Kalibrierungsbildern, um einen INT8-Graphen für Hailo-Hardware zu erstellen. Erfahre mehr über Modellquantisierung.
Link to this sectionHailo HEF-Exportformat#
HEF ist ein hardwarespezifisches ausführbares Format, das vom Hailo Dataflow Compiler generiert wird. Es enthält den quantisierten Modellgraphen, die Speicherzuweisung, das Scheduling und eine optionale Nachverarbeitung, die für eine Ziel-Hailo-Architektur konfiguriert ist. Im Gegensatz zu standardmäßigen YOLO-Export-Modus-Formaten, die direkt durch model.export(format=...) erstellt werden, verwendet die HEF-Kompilierung derzeit einen zweistufigen Prozess:
- Exportiere YOLO nach ONNX mit Ultralytics.
- Verwende Hailo DFC-Tools, um das ONNX-Modell zu parsen, zu optimieren, zu quantisieren und in HEF zu kompilieren.
Der vollständige Workflow erweitert sich zu folgender Pipeline:
YOLO (.pt) -> ONNX -> HAR (parse) -> HAR (optimize/quantize) -> HEF (compile)- Export nach ONNX mit dem Ultralytics-Export-Modus
- Parse das ONNX-Modell in das intermediäre HAR-Format von Hailo
- Lade ein Modellskript (
.alls) mit Normalisierungs- und Nachverarbeitungsanweisungen - Kalibriere und quantisiere mit repräsentativen Bildern
- Kompiliere zu einer bereitstellbaren HEF-Datei
Link to this sectionUnterstützte Aufgaben#
Das aktuelle manuelle Beispiel konzentriert sich auf die YOLO11-Objekterkennung, da das Hailo-Modellskript und die Konfiguration der Nachverarbeitung spezifisch für den Detection-Head sind. Eine zukünftige direkte model.export(format="hailo")-Implementierung sollte den Hailo-Export so einfach wie jedes andere Ultralytics-Exportformat machen, wobei die Aufgabenunterstützung durch den Modell-Head und die Kompatibilität des Hailo-Compilers gesteuert wird, statt durch externe Workflow-Schritte.
| Aufgabe | Direktes Hailo-Exportziel | Hinweise |
|---|---|---|
| Objekterkennung | ✅ Primäres Ziel | YOLOv8, YOLO11 und YOLO26 Detection sollten der erste direkte Exportpfad sein. |
| Instance Segmentation | ✅ Ziel | YOLOv8, YOLO11 und YOLO26 Segmentierung erfordern aufgabenspezifisches Masken-Output-Handling und Validierung. |
| Semantische Segmentierung | ⚠️ Validieren | YOLO26 semantische Segmentierung benötigt einen dedizierten Compiler- und Output-Validierungspfad. |
| Pose-Schätzung | ⚠️ Validieren | Pose erfordert Keypoint-Output-Handling jenseits des Detection NMS-Pfads. |
| OBB-Erkennung | ⚠️ Validieren | OBB erfordert Rotated-Box-Output-Handling jenseits des Standard-Detection NMS-Pfads. |
| Klassifizierung | ⚠️ Validieren | Classification hat einen einfacheren Output-Head, benötigt aber dennoch eine Hailo-Kompilierung und Laufzeitvalidierung. |
Bis der direkte Hailo-Export in Ultralytics implementiert ist, ist nur der unten beschriebene manuelle ONNX-zu-HEF-Workflow dokumentiert.
Link to this sectionHailo SDK-Versionen#
Der direkte Hailo-Export muss die Trennung von Hailos Hardware- und SDK-Generationen berücksichtigen:
- Hailo-8 und Hailo-8L: Verwende den Hailo Dataflow Compiler v3.x. Dies ist der relevante Pfad für Deployments mit Raspberry Pi AI Kit und 13 TOPS AI HAT+.
- Hailo-10 und Hailo-15: Verwende den Hailo Dataflow Compiler v5.x.
Diese Versionsaufteilung betrifft Compiler-APIs, unterstützte Architekturen, die Kompatibilität der generierten HEF-Dateien und welche hw_arch-Werte ein direkter Exporter bereitstellen sollte. Die Aufgabenunterstützung für eine Hailo-Hardware-Generation sollte nicht als Unterstützung für eine andere angesehen werden, ohne die Ziel-DFC-Version und hw_arch zu validieren.
Link to this sectionKompatibilitätshinweise#
Die Kompatibilität beim Hailo-Export hängt vom Modell-Head, der Eingabebildgröße, der Klassenanzahl, der Hailo-Architektur, dem generierten Modellskript (.alls) und der Konfiguration der Nachverarbeitung ab. Statische Konfigurationen sind keine universellen Vorlagen. Zum Beispiel ist ein NMS JSON, das für ein COCO 80-Klassen YOLO11n-Modell erstellt wurde, nicht korrekt für ein benutzerdefiniertes 3-Klassen-Modell oder für eine andere feste imgsz.
| Umfang | Erwartete Unterstützung | Hinweise |
|---|---|---|
| YOLOv8 / YOLO11 Detection | ✅ Gut | Gemeinsamer entkoppelter Detection-Head; .alls-Direktiven, Endknoten und NMS-Konfiguration müssen weiterhin zum exportierten Graphen und der festen imgsz passen. |
| Benutzerdefinierte YOLOv8 / YOLO11 Erkennung | ✅ Möglich | Erfordert eine modell-spezifische NMS-Konfiguration, generiert aus Klassenanzahl, Strides und dem Layout des Detection-Heads; ein statisches JSON wird nicht passen. |
| YOLO26 Detection | ✅ Ziel | Die NMS-freie Architektur erfordert einen separaten Compiler/Nachverarbeitungspfad; verwende den unten stehenden YOLO11/YOLOv8 NMS-Workflow nicht für YOLO26. |
| YOLO26 Instance Segmentation | ✅ Ziel | Benötigt ein YOLO26-spezifisches Masken-Output-Handling und Genauigkeitsvalidierung für Segmentierung. |
| YOLO26 Semantic, Pose, OBB, Classification | ⚠️ Forschung | Diese Aufgaben erfordern dedizierte Compiler- und Laufzeitvalidierungen, bevor sie als direkt unterstützt beworben werden können. |
| Dynamische oder beliebige Bildgrößen | ❌ Nicht unterstützt | Die Hailo-Kompilierung verwendet eine feste Eingabeform; .alls und die Einstellungen für die Nachverarbeitung müssen zur exportierten imgsz passen. |
Link to this sectionInstallation#
Link to this sectionSchritt 1: Installiere Ultralytics#
pip install ultralyticsLink to this sectionSchritt 2: Installiere das Hailo DFC SDK#
Der Hailo DFC wird für Parsing, Optimierung und Kompilierung benötigt. Lade das Python-Wheel aus der Hailo Developer Zone herunter (kostenlose Registrierung erforderlich) und installiere es:
pip install /path/to/hailo_dataflow_compiler-*.whlDas Hailo DFC SDK erfordert ein Linux x86_64-System. Export und Kompilierung können nicht auf ARM-Geräten wie dem Raspberry Pi durchgeführt werden. Kopiere die resultierende .hef-Datei zur Bereitstellung mit HailoRT auf dein Hailo-betriebenes Gerät.
Link to this sectionBeispiel für YOLO11n HEF-Export#
Das Skript unten kompiliert ein YOLO11n-Erkennungsmodell von .pt nach .hef bei einer festen Eingabegröße von 640 Pixeln. Es exportiert mit Ultralytics nach ONNX und kompiliert dann mit dem Hailo DFC unter Verwendung von COCO128 als kleinem Kalibrierungsdatensatz.
Bevor du das Skript ausführst, stelle ein Hailo NMS JSON bereit, das exakt zum exportierten YOLO11n-Graphen, der Klassenanzahl, den Strides und der festen Eingabegröße passt. Verwende dieses Skript als bekannter Ausgangspunkt für YOLO11n; benutzerdefinierte Modelle benötigen passende Endknoten, .alls-Direktiven und NMS-Einstellungen.
YOLO26-Modelle sind NMS-frei. Ein direkter Ultralytics Hailo-Exporter benötigt einen dedizierten YOLO26-Kompilierungs- und Nachverarbeitungspfad für Detection oder Instance-Segmentierung anstelle des YOLO11 NMS-Beispiels unten.
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}")Das Export-Skript organisiert die Artefakte und Protokolle wie folgt:
- Bereitstellungsordner: Die Artefakte werden in
yolo11n_hailo_model/gespeichert, was dem Standard-Layout<model>_<format>_model/entspricht, das auch bei anderen Ultralytics-Exporten verwendet wird. - Erforderliche Dateien: Die beiden für die Bereitstellung benötigten Dateien sind die kompilierte
yolo11n.hefund die dazugehörigemetadata.yaml. - Metadaten: Die
metadata.yamlenthält essenzielle Felder (names,imgsz,task,strideusw.), die aus den ONNX-Metadaten extrahiert wurden. Inferenz-Skripte laden Klassennamen aus dieser Datei, da das HEF-Format diese nicht speichert. - Zwischendateien: Der Exportordner enthält außerdem die zwischenzeitlichen Prüfpunkte
yolo11n.onnxundyolo11n.o.har. - Protokolldateien: Das Hailo SDK generiert im Arbeitsverzeichnis verschiedene Diagnoseprotokolle (z. B.
acceleras.log,allocator.log,hailo_sdk.client.logundhailo_sdk.core.log); diese können sicher ignoriert oder gelöscht werden. - Raspberry Pi AI Kit: Für diese spezifische Hardware stelle sicher, dass du
HW_ARCH = "hailo8l"festlegst, bevor du den Kompilierungsschritt ausführst.
Link to this sectionSchritt-für-Schritt-Aufschlüsselung#
Das obige vollständige Skript läuft von Anfang bis Ende durch. Dieser Abschnitt erklärt die Funktion der einzelnen Phasen sowie modellspezifische Details, auf die du bei der Anpassung an dein eigenes Modell achten musst.
Link to this sectionSchritt 1: Export zu ONNX und Speichern der Metadaten#
Ultralytics exportiert dein trainiertes Modell in das ONNX-Format, das vom Hailo DFC als Eingabe übernommen wird. opset=11 sorgt für eine breite DFC-Kompatibilität, und die ONNX-Datei wird in einen Bereitstellungsordner namens yolo11n_hailo_model/ verschoben (analog zum <model>_<format>_model/-Layout anderer Ultralytics-Exporte), um das Arbeitsverzeichnis übersichtlich zu halten.
Da die HEF-Datei keine Klassennamen speichert, werden die von Ultralytics in ONNX eingebetteten Metadaten in eine standardmäßige metadata.yaml kopiert, die daneben liegt. Dies ist dieselbe metadata.yaml, die auch andere Exportformate erzeugen (names, imgsz, task, stride und mehr), und die Inferenz liest die Klassennamen daraus. So funktioniert der Workflow für benutzerdefinierte Modelle, ohne dass Labels hardcodiert werden müssen.
Link to this sectionSchritt 2: Parse das ONNX-Modell#
runner.translate_onnx_model(...) konvertiert den ONNX-Graphen in die HAR-Zwischendarstellung von Hailo. Die Liste end_node_names weist das DFC an, wo der Graph vor dem NMS zugeschnitten werden soll, damit Hailo seine eigene Hardware-Nachverarbeitung anhängen kann.
Der DFC druckt nach dem Parsen einen Vorschlag:
[info] In order to use HailoRT post-processing capabilities, these end node names should be used: ...
Kopiere diese Knotennamen, wenn du dir unsicher bist, welche du verwenden sollst, oder wenn du mit einer benutzerdefinierten oder weniger gebräuchlichen Architektur arbeitest.
Link to this sectionSchritt 3: Lade das Modellskript#
Das Modellskript (.alls) konfiguriert die Eingabenormalisierung, Ausgabeaktivierung und NMS-Nachverarbeitung. Die Einstellung meta_arch=yolov8 gilt sowohl für YOLOv8 als auch für YOLO11, da sie dasselbe Layout des Detection-Heads teilen.
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)Die Layernamen für change_output_activation (conv54, conv65, conv80) werden während des Parsings vom DFC zugewiesen und sind modellspezifisch. Wenn du eine andere Modellgröße oder -architektur kompilierst, prüfe den DFC-Output auf die korrekten Namen oder generiere die .alls-Direktiven aus dem exportierten Graphen.
Die NMS_CONFIG-Datei ist ebenfalls modellspezifisch. Verwende eine Konfiguration, die exakt zu deinem exportierten Modell passt.
engine=cpu führt NMS über HailoRT auf der Host-CPU aus. Verwende engine=nn_core nur für Modell-/Skriptkombinationen, die laut Hailo-Dokumentation von der Zielhardware und der SDK-Version unterstützt werden.
Entferne die nms_postprocess-Zeile, wenn du NMS lieber vollständig in deinem Anwendungscode ausführen möchtest. Wenn du dies tust, aktualisiere den Inferenz-Parser, da die HEF rohe Detection-Head-Tensoren anstelle gruppierter NMS-Erkennungen ausgibt.
Link to this sectionSchritt 4: Erstelle den Kalibrierungsdatensatz#
Die INT8-Quantisierung erfordert einen repräsentativen Satz von Bildern, die zu einem (N, imgsz, imgsz, 3) float32-Array gestapelt werden. Das Skript verwendet COCO128, das Ultralytics automatisch über check_det_dataset herunterlädt.
Verwende mindestens 64 Bilder für die Kalibrierung. Mehr Bilder verbessern im Allgemeinen die Quantisierungsqualität. Für beste Ergebnisse verwende Bilder aus deiner Bereitstellungsdomäne anstelle von COCO128.
Link to this sectionSchritt 5: Optimiere und quantisiere#
runner.optimize(calibset) wendet quantisierungsbewusstes Fine-Tuning und Schicht-Rauschanalysen an, und runner.save_har(...) schreibt einen optionalen Zwischen-Checkpunkt. Eine GPU wird dringend empfohlen; ohne diese kann der Schritt mehrere Stunden dauern.
Link to this sectionSchritt 6: Kompiliere zu HEF#
runner.compile() erzeugt die finale HEF-Datei, die in yolo11n_hailo_model/yolo11n.hef geschrieben wird. Sie befindet sich nun neben ihrer metadata.yaml und ist bereit, für die Inferenz auf das Gerät kopiert zu werden.
Link to this sectionUnterstützte Modelle und Endknoten#
Für Erkennungsmodelle identifiziert end_node_names die ONNX-Detection-Head-Ausgaben, die Hailo vor dem Anhängen der NMS-Nachverarbeitung kompilieren soll. Diese Namen variieren je nach Architektur und können sich ändern, wenn sich der exportierte Graph ändert.
Die unten stehenden Beispiele für Endknoten gelten für YOLOv8- und YOLO11-Detection-Modelle, die die NMS-Nachverarbeitung im YOLOv8-Stil von Hailo verwenden. YOLO26 ist NMS-frei und verwendet diese YOLO11 NMS-Konfiguration nicht.
Link to this sectionYOLO11 und YOLOv8#
YOLO11 und YOLOv8 teilen den gleichen entkoppelten Detection-Head. Der Layer-Index unterscheidet sich zwischen den beiden Familien um eins:
| Modellfamilie | Detection-Head-Layer | Endknotenmuster |
|---|---|---|
| YOLO11 (alle) | model.23 | /model.23/cv2.0/cv2.0.2/Conv (6 Knoten) |
| YOLOv8 (alle) | model.22 | /model.22/cv2.0/cv2.0.2/Conv (6 Knoten) |
YOLO11-Endknoten (alle Größen: 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-Endknoten (alle Größen: 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 sectionAndere Architekturen#
Für andere Erkennungsarchitekturen führe den Parse-Schritt zuerst ohne end_node_names aus, lies die vorgeschlagenen Knoten aus der DFC-Protokollausgabe und führe ihn dann erneut mit diesen Knoten aus:
# 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..."Für die direkte Unterstützung durch Ultralytics sollten diese .alls-Direktiven und Nachverarbeitungseinstellungen vom Exporter generiert oder ausgewählt werden, anstatt dass Benutzer sie manuell zusammenstellen müssen.
Link to this sectionUnterstützte Hardwarearchitekturen#
| Architektur | Gerät | Spitzenleistung (Herstellerangabe) | Häufiger Anwendungsfall |
|---|---|---|---|
hailo8 | Hailo-8 | 26 TOPS | Hailo-Beschleunigerkarte |
hailo8l | Hailo-8L | 13 TOPS | Raspberry Pi AI Kit |
hailo15h | Hailo-15H | 20 TOPS | Hailo-15 Zielgeräte |
Setze HW_ARCH im Skript auf dein Zielgerät, bevor du die Kompilierung startest.
Link to this sectionInferenz auf Hailo-Hardware ausführen#
Kopiere nach Abschluss der Kompilierung den gesamten Ordner yolo11n_hailo_model/ (die .hef-Datei plus ihre metadata.yaml) auf dein Hailo-betriebenes Gerät und führe die Inferenz entweder über die HailoRT Python API (hailo_platform-Paket) oder auf dem Raspberry Pi über den picamera2 Hailo-Helfer (ein HailoRT-Wrapper) aus. Beide werden in den Reitern unten gezeigt. Indem du beide Dateien zusammen hältst, können die untenstehenden Skripte die Klassennamen aus der metadata.yaml direkt neben der HEF-Datei auslesen. Im Gegensatz zu den DFC-Export-Schritten läuft die Inferenz direkt auf dem Edge-Gerät.
Der unten stehende Inferenzcode läuft auf dem Hailo-Gerät (z. B. Raspberry Pi + AI Kit) und nicht auf dem x86-Rechner, der für die Kompilierung verwendet wurde.
Link to this sectionSchritt 1: Installiere HailoRT auf dem Gerät#
Installiere auf dem Zielgerät HailoRT und die Python-Bindings. Für Benutzer des Raspberry Pi AI Kit und AI HAT+ installiert der offizielle Raspberry Pi AI-Software-Leitfaden HailoRT, den Gerätetreiber und die Python-Bindings mit:
sudo apt install dkms
sudo apt install hailo-all
sudo rebootFür Hailo-Geräte, die keine Raspberry Pis sind, installiere das HailoRT-Paket, das zu deinem Gerät, Treiber und der SDK-Version aus der Hailo Developer Zone passt.
AI HAT+ 2-Geräte verwenden ein anderes Raspberry Pi-Paket (hailo-h10-all) sowie den Hailo-10H-Workflow. Folge dem Raspberry Pi AI-Software-Leitfaden für diese Hardware-Generation.
Link to this sectionSchritt 2: Kurzer Funktionstest#
Bevor du die Python-Inferenz ausführst, vergewissere dich, dass das Hailo-Gerät erkannt wird:
hailortcli fw-control identifyDu solltest den Gerätetyp, die Firmware-Version und die Seriennummer ausgegeben sehen.
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: HAILO8Link to this sectionSchritt 3: Inferenz ausführen#
Die Skripte unten führen eine Objekterkennung mit der kompilierten HEF-Datei durch. Beide Reiter akzeptieren dieselben --source-Eingaben (ein Bild, ein Video, einen USB-Webcam-Index oder csi für das Raspberry Pi Camera Module) und unterscheiden sich nur in der Inferenz-API: Der Hailo SDK-Reiter verwendet die Low-Level hailo_platform-API (portabel, minimale Abhängigkeiten), während der picamera2-Reiter den Raspberry Pi picamera2 Hailo-Helfer nutzt. Bilder und Videos werden in eine annotierte Datei geschrieben; Webcam- und CSI-Streams werden in einem Live-Fenster angezeigt.
Der herstellereigene HailoRT-Pfad läuft auf jeder Plattform mit einem Hailo-Gerät und benötigt keine zusätzlichen Abhängigkeiten. Übergib --source einen Bildpfad, einen Videopfad, einen Webcam-Index (z. B. 0) für Live-USB/V4L2-Aufnahmen oder csi für das Raspberry Pi Camera Module. Die CSI-Option erfordert die Installation von picamera2, da das moderne Raspberry Pi OS die Kamera über libcamera anstelle eines einfachen V4L2-Geräts ansteuert.
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()Führe dies mit einer beliebigen Quelle aus (Bilder speichern unter output.jpg, Videos speichern unter output.mp4, Live-Streams werden in einem Fenster angezeigt, drücke q zum Beenden):
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 ModuleDas Format der Erkennungsausgabe setzt voraus, dass die HEF-Datei mit nms_postprocess im .alls-Skript kompiliert wurde. Falls du ohne NMS kompiliert hast, sind die Rohausgaben die 6 Tensoren des Detection Heads, und du musst NMS in deiner Anwendung separat ausführen.
Link to this sectionVideo-Inferenz mit TAPPAS#
Für Video-Pipelines mit hohem Durchsatz bietet TAPPAS GStreamer-Elemente, die Videos in Echtzeit durch den Hailo-Chip streamen:
MODEL=yolo11n
gst-launch-1.0 filesrc location=video.mp4 ! decodebin ! \
hailonet hef-path=${MODEL}.hef ! \
hailofilter function-name=yolov8 ! \
hailooverlay ! autovideosinkSiehe die TAPPAS-Dokumentation für vollständige Konfigurationsoptionen der Pipeline.
Link to this sectionZusammenfassung#
Dieser Leitfaden deckt den vollständigen Workflow zum Exportieren von Ultralytics YOLO-Erkennungsmodellen in das Hailo HEF-Format ab:
- Export in ONNX mit Ultralytics (
model.export(format="onnx")). - Analysiere das ONNX-Modell mit dem Hailo DFC und spezifiziere die Endknoten des Detection Heads.
- Konfiguriere Normalisierung und NMS über ein Modellskript.
- Quantisiere mit einem Kalibrierungsdatensatz (COCO128 via Ultralytics).
- Kompiliere in eine
.hef-Datei, bereit für Hailo-8, Hailo-8L oder Hailo-15.
Weitere Details findest du in der Hailo Developer Zone und der Hailo-Dokumentation. Für andere Ultralytics-Exportziele siehe die zugehörigen Anleitungen zu ONNX, OpenVINO, TensorRT, NCNN, TFLite Edge TPU, RKNN, Sony IMX500 und Qualcomm QNN. Um die Geschwindigkeit und Genauigkeit exportierter Modelle über Formate hinweg zu vergleichen, verwende den Benchmark-Modus. Für die vollständige Liste der Formate und Optionen besuche die Dokumentation zum Export-Modus sowie die Integrations-Übersichtsseite.
Link to this sectionFAQ#
Link to this sectionWelche Hailo-Geräte werden unterstützt?#
Der Hailo DFC unterstützt Hailo-8 (hailo8), Hailo-8L (hailo8l) und Hailo-15H (hailo15h). Siehe die Tabelle Unterstützte Hardware-Architekturen für den passenden HW_ARCH-Wert.
Link to this sectionWelche Ultralytics-Modelle können exportiert werden?#
Dieser Leitfaden konzentriert sich auf Erkennungsmodelle. Siehe Unterstützte Aufgaben für den aufgabenbezogenen Umfang, Kompatibilitätshinweise für Modellkompatibilitätsgrenzen und Unterstützte Modelle und Endknoten für Beispiele zu YOLO11- und YOLOv8-Endknoten.
Link to this sectionWarum verwendet das Modellskript meta_arch=yolov8 für YOLO11?#
YOLO11 verwendet dieselbe Architektur für den entkoppelten Detection Head wie YOLOv8. Der Hailo DFC verwendet meta_arch=yolov8 für die NMS-Konfiguration beider Modellfamilien.
Link to this sectionBenötige ich eine GPU für den Optimierungsschritt?#
Eine GPU wird für das quantisierungsbewusste Fine-Tuning in runner.optimize() dringend empfohlen. Ohne GPU funktioniert der Prozess zwar auch, ist aber deutlich langsamer (mehrere Stunden im Vergleich zu etwa 10-20 Minuten mit einer GPU).
Link to this sectionWie finde ich die korrekten Endknoten für mein Modell?#
Führe runner.translate_onnx_model(...) ohne Angabe von end_node_names aus und verwende dann die vom DFC ausgegebenen Vorschläge für die Detection-Head-Knoten. Siehe Andere Architekturen für das Beispielkommando.
Link to this sectionWo bekomme ich das Hailo DFC SDK?#
Das Hailo DFC SDK Python-Wheel ist in der Hailo Developer Zone verfügbar. Für einen direkten Ultralytics Hailo-Exporter sollten das Modellskript und die Konfiguration der Nachverarbeitung innerhalb des Export-Workflows generiert oder ausgewählt werden.