Link to this sectionExportación a Hailo para modelos YOLO de Ultralytics#
Hailo HEF no es compatible actualmente como destino directo de model.export(format="hailo") en Ultralytics. El flujo de trabajo que se muestra a continuación es una alternativa manual que exporta primero a ONNX y, luego, utiliza la cadena de herramientas Dataflow Compiler de Hailo para generar un archivo .hef. Un flujo de trabajo de Ultralytics fluido debería exponer a Hailo a través de la misma API de exportación de Python y CLI que otros formatos de hardware.
La cadena de herramientas de Hailo utiliza archivos HEF para plataformas integradas, incluyendo el Raspberry Pi AI Kit y AI HAT+, cámaras industriales, puertas de enlace perimetrales y PC con IA.
Esta guía detalla cómo exportar modelos seleccionados de Ultralytics YOLO al HEF (Hailo Executable Format) de Hailo utilizando el SDK Hailo Dataflow Compiler (DFC). El flujo de trabajo comienza con un modelo .pt de YOLO, lo exporta a ONNX, lo compila con las herramientas de Hailo y produce un archivo .hef listo para los aceleradores Hailo compatibles.
Link to this sectionCuándo usar HEF de Hailo#
HEF es el artefacto compilado que consume HailoRT en dispositivos de destino Hailo. Utiliza esta guía manual solo cuando tu hardware de despliegue requiera específicamente Hailo HEF antes de que esté disponible la compatibilidad directa de exportación de Hailo en Ultralytics.
HEF es similar en su papel de despliegue a formatos específicos de hardware como RKNN para NPUs de Rockchip, IMX500 para cámaras con IA de Raspberry Pi y Qualcomm QNN para NPUs de Snapdragon, pero actualmente no es generado directamente por Ultralytics.
Este flujo de trabajo es relevante cuando necesitas:
- Compatibilidad con Raspberry Pi AI Kit: Hailo-8L se utiliza en el kit oficial Raspberry Pi AI Kit y AI HAT+.
- Post-procesamiento de HailoRT: HailoRT puede incluir la supresión de no máximos de YOLO en la tubería de inferencia compilada.
- Compilación INT8: El DFC de Hailo cuantiza el modelo con imágenes de calibración representativas para producir un grafo INT8 para hardware de Hailo. Aprende más sobre la cuantización de modelos.
Link to this sectionFormato de exportación HEF de Hailo#
HEF es un ejecutable específico para hardware generado por el Hailo Dataflow Compiler. Contiene el grafo del modelo cuantizado, la asignación de memoria, la programación y el post-procesamiento opcional configurado para una arquitectura de destino Hailo. A diferencia de los formatos estándar del Modo de exportación de YOLO que se producen directamente mediante model.export(format=...), la compilación HEF utiliza actualmente un flujo de dos etapas:
- Exporta YOLO a ONNX con Ultralytics.
- Utiliza las herramientas DFC de Hailo para analizar, optimizar, cuantizar y compilar el modelo ONNX en HEF.
El flujo de trabajo completo se expande en la siguiente tubería:
YOLO (.pt) -> ONNX -> HAR (parse) -> HAR (optimize/quantize) -> HEF (compile)- Exportar a ONNX usando el Modo de exportación de Ultralytics
- Analizar el modelo ONNX al formato intermedio HAR de Hailo
- Cargar un script de modelo (
.alls) con directivas de normalización y post-procesamiento - Calibrar y cuantizar usando imágenes representativas
- Compilar a un archivo HEF desplegable
Link to this sectionTareas compatibles#
El ejemplo manual actual se centra en la detección de objetos con YOLO11, ya que el script del modelo Hailo y la configuración de post-procesamiento son específicos del cabezal de detección. Una futura implementación directa de model.export(format="hailo") debería hacer que la exportación a Hailo se sienta como cualquier otro formato de exportación de Ultralytics, con soporte de tareas limitado por el cabezal del modelo y la compatibilidad del compilador de Hailo en lugar de por pasos de flujo de trabajo externos.
| Tarea | Destino de exportación directa a Hailo | Notas |
|---|---|---|
| Detección de objetos | ✅ Destino principal | La detección con YOLOv8, YOLO11 y YOLO26 debería ser la primera ruta de exportación directa. |
| Segmentación de instancias | ✅ Destino | La segmentación con YOLOv8, YOLO11 y YOLO26 requiere el manejo y validación de la salida de máscaras específica de la tarea. |
| Segmentación semántica | ⚠️ Validar | La segmentación semántica de YOLO26 necesita un compilador dedicado y una ruta de validación de salida. |
| Estimación de pose | ⚠️ Validar | La estimación de pose (pose) requiere el manejo de salida de puntos clave más allá de la ruta NMS de detección. |
| Detección OBB | ⚠️ Validar | OBB requiere el manejo de salida de cajas rotadas más allá de la ruta NMS de detección estándar. |
| Clasificación | ⚠️ Validar | La clasificación tiene un cabezal de salida más simple, pero aún necesita validación de compilación y tiempo de ejecución de Hailo. |
Hasta que la exportación directa a Hailo esté implementada en Ultralytics, solo está documentado el flujo de trabajo manual ONNX a HEF que se muestra a continuación.
Link to this sectionVersiones del SDK de Hailo#
La exportación directa a Hailo debe tener en cuenta la división de hardware y generación de SDK de Hailo:
- Hailo-8 y Hailo-8L: utiliza el Hailo Dataflow Compiler v3.x. Esta es la ruta relevante para los despliegues de Raspberry Pi AI Kit y 13 TOPS AI HAT+.
- Hailo-10 y Hailo-15: utiliza el Hailo Dataflow Compiler v5.x.
Esta división de versiones afecta a las API del compilador, las arquitecturas compatibles, la compatibilidad de los archivos HEF generados y qué valores de hw_arch debería exponer un exportador directo. El soporte de tareas en una generación de hardware Hailo no debe tratarse como soporte en otra sin validar la versión de DFC de destino y el hw_arch.
Link to this sectionNotas de compatibilidad#
La compatibilidad de la exportación a Hailo depende del cabezal del modelo, el tamaño de la imagen de entrada, el recuento de clases, la arquitectura de Hailo, el script del modelo generado (.alls) y la configuración de post-procesamiento. Las configuraciones estáticas no son plantillas universales. Por ejemplo, un JSON de NMS creado para un modelo YOLO11n de 80 clases de COCO no es correcto para un modelo personalizado de 3 clases o para un imgsz fijo diferente.
| Alcance | Soporte esperado | Notas |
|---|---|---|
| Detección con YOLOv8 / YOLO11 | ✅ Bueno | Cabezal de detección desacoplado compartido; las directivas .alls, los nodos finales y la configuración de NMS aún deben coincidir con el gráfico exportado y el imgsz fijo. |
| Detección personalizada YOLOv8 / YOLO11 | ✅ Posible | Requiere una configuración de NMS por modelo generada a partir del recuento de clases, los strides y la disposición del cabezal de detección; el JSON estático no coincidirá. |
| Detección con YOLO26 | ✅ Destino | La arquitectura libre de NMS necesita una ruta de compilación/post-procesamiento separada; no reutilices el flujo de trabajo NMS de YOLO11/YOLOv8 que se muestra a continuación para YOLO26. |
| Segmentación de instancias con YOLO26 | ✅ Destino | Necesita un manejo de salida de máscara específico para la segmentación de YOLO26 y validación de precisión. |
| Segmentación semántica, pose, OBB, clasificación con YOLO26 | ⚠️ Investigación | Estas tareas necesitan validación dedicada de compilador y tiempo de ejecución antes de que puedan anunciarse como soportadas directamente. |
| Tamaños de imagen dinámicos o arbitrarios | ❌ No compatible | La compilación de Hailo utiliza una forma de entrada fija; los ajustes de .alls y de post-procesamiento deben coincidir con el imgsz exportado. |
Link to this sectionInstalación#
Link to this sectionPaso 1: Instalar Ultralytics#
pip install ultralyticsLink to this sectionPaso 2: Instalar el SDK Hailo DFC#
El DFC de Hailo es necesario para el análisis, la optimización y la compilación. Descarga el wheel de Python desde la Hailo Developer Zone (requiere registro gratuito) e instálalo:
pip install /path/to/hailo_dataflow_compiler-*.whlEl SDK Hailo DFC requiere una máquina Linux x86_64. La exportación y la compilación no pueden realizarse en dispositivos ARM como Raspberry Pi. Copia el archivo .hef resultante a tu dispositivo con Hailo para su despliegue con HailoRT.
Link to this sectionEjemplo de exportación HEF para YOLO11n#
El script a continuación compila un modelo de detección YOLO11n de .pt a .hef con un tamaño de entrada fijo de 640 píxeles. Exporta a ONNX usando Ultralytics, luego compila con el DFC de Hailo usando COCO128 como pequeño conjunto de datos de calibración.
Antes de ejecutar el script, proporciona un JSON de NMS de Hailo que coincida exactamente con el gráfico de exportación, el recuento de clases, los strides y el tamaño de entrada fijo de YOLO11n. Reutiliza este script como un punto de partida conocido para YOLO11n; los modelos personalizados necesitan nodos finales, directivas .alls y ajustes de NMS coincidentes.
Los modelos YOLO26 están libres de NMS. Un exportador directo de Ultralytics a Hailo necesita una ruta dedicada de compilación y post-procesamiento de YOLO26 para la detección o segmentación de instancias, en lugar del ejemplo de NMS de YOLO11 que se muestra a continuación.
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}")El script de exportación organiza los artefactos y registros de la siguiente manera:
- Carpeta de despliegue: Los artefactos se guardan en
yolo11n_hailo_model/, replicando el diseño estándar<model>_<format>_model/que utilizan otras exportaciones de Ultralytics. - Archivos requeridos: Los dos archivos necesarios para el despliegue son el
yolo11n.hefcompilado y el archivo adjuntometadata.yaml. - Metadatos: El
metadata.yamlcontiene campos esenciales (names,imgsz,task,stride, etc.) extraídos de los metadatos de ONNX. Los scripts de inferencia cargan los nombres de las clases desde este archivo, dado que el formato HEF no los almacena. - Archivos intermedios: La carpeta de exportación también contiene los puntos de control intermedios
yolo11n.onnxyyolo11n.o.har. - Archivos de registro: El Hailo SDK genera varios registros de diagnóstico (por ejemplo,
acceleras.log,allocator.log,hailo_sdk.client.logyhailo_sdk.core.log) en el directorio de trabajo; puedes ignorarlos o eliminarlos de forma segura. - Raspberry Pi AI Kit: Para este hardware específico, asegúrate de establecer
HW_ARCH = "hailo8l"antes de ejecutar el paso de compilación.
Link to this sectionDesglose paso a paso#
El script completo anterior se ejecuta de principio a fin. Esta sección explica lo que hace cada etapa y los detalles específicos del modelo que debes tener en cuenta al adaptarlo al tuyo.
Link to this sectionPaso 1: Exportar a ONNX y guardar metadatos#
Ultralytics exporta tu modelo entrenado al formato ONNX, el cual el Hailo DFC ingiere como entrada. opset=11 proporciona una amplia compatibilidad con DFC, y el ONNX se mueve a una carpeta de despliegue yolo11n_hailo_model/ (replicando el diseño <model>_<format>_model/ de otras exportaciones de Ultralytics) para mantener ordenado el directorio de trabajo.
El HEF no almacena nombres de clases, por lo que los metadatos que Ultralytics integra en el ONNX se copian en un metadata.yaml adjunto estándar junto a él. Este es el mismo metadata.yaml que producen otros formatos de exportación (names, imgsz, task, stride, y más), y la inferencia lee los nombres de las clases desde él, por lo que el flujo de trabajo funciona para modelos personalizados sin necesidad de codificar etiquetas de forma fija.
Link to this sectionPaso 2: Analizar el modelo ONNX#
runner.translate_onnx_model(...) convierte el grafo ONNX en la representación intermedia HAR de Hailo. La lista end_node_names le indica al DFC dónde cortar el grafo antes de la NMS para que Hailo pueda adjuntar su propio posprocesamiento de hardware.
El DFC imprime una sugerencia después del análisis:
[info] In order to use HailoRT post-processing capabilities, these end node names should be used: ...
Copia esos nombres de nodo si no estás seguro de cuáles usar, o si estás trabajando con una arquitectura personalizada o menos común.
Link to this sectionPaso 3: Cargar el script del modelo#
El script del modelo (.alls) configura la normalización de entrada, la activación de salida y el post-procesamiento de NMS. El ajuste meta_arch=yolov8 se aplica tanto a YOLOv8 como a YOLO11, ya que comparten el mismo diseño de cabeza de detección.
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)Los nombres de capa de change_output_activation (conv54, conv65, conv80) son asignados por el DFC durante el análisis y son específicos del modelo. Si estás compilando un tamaño o arquitectura de modelo diferente, verifica la salida del DFC para obtener los nombres correctos o genera las directivas .alls a partir del gráfico exportado.
El archivo NMS_CONFIG también es específico del modelo. Usa una configuración que coincida exactamente con tu modelo exportado.
engine=cpu ejecuta el NMS a través de HailoRT en la CPU anfitriona. Usa engine=nn_core solo para combinaciones de modelo/script que Hailo documente como compatibles con el hardware de destino y la versión del SDK.
Elimina la línea nms_postprocess si prefieres ejecutar el NMS completamente en el código de tu aplicación. Si haces esto, actualiza el analizador de inferencia porque el HEF emitirá tensores de cabeza de detección brutos en lugar de detecciones NMS agrupadas.
Link to this sectionPaso 4: Construir el conjunto de datos de calibración#
La cuantización INT8 requiere un conjunto representativo de imágenes apiladas en un array float32 (N, imgsz, imgsz, 3). El script utiliza COCO128, que Ultralytics descarga automáticamente mediante check_det_dataset.
Usa al menos 64 imágenes para la calibración. Más imágenes generalmente mejoran la calidad de la cuantización. Para obtener mejores resultados, usa imágenes de tu dominio de despliegue en lugar de COCO128.
Link to this sectionPaso 5: Optimizar y cuantizar#
runner.optimize(calibset) aplica un ajuste fino consciente de la cuantización y análisis de ruido de capa, luego runner.save_har(...) escribe un punto de control intermedio opcional. Se recomienda encarecidamente utilizar una GPU; sin ella, este paso puede llevar varias horas.
Link to this sectionPaso 6: Compilar a HEF#
runner.compile() produce el HEF final, escrito en yolo11n_hailo_model/yolo11n.hef. Ahora se encuentra junto a su metadata.yaml, listo para copiarse al dispositivo para la inferencia.
Link to this sectionModelos y nodos finales admitidos#
Para modelos de detección, end_node_names identifica las salidas de la cabeza de detección ONNX que Hailo debe compilar antes de adjuntar su post-procesamiento de NMS. Estos nombres varían según la arquitectura y pueden cambiar cuando el grafo exportado cambia.
Los ejemplos de nodos finales que se muestran a continuación se aplican a los modelos de detección YOLOv8 y YOLO11 que utilizan el post-procesamiento NMS estilo YOLOv8 de Hailo. YOLO26 está libre de NMS y no utiliza esta configuración NMS de YOLO11.
Link to this sectionYOLO11 y YOLOv8#
YOLO11 y YOLOv8 comparten la misma cabeza de detección desacoplada. El índice de la capa difiere en uno entre las dos familias:
| Familia de modelos | Capa de cabeza de detección | Patrón de nodo final |
|---|---|---|
| YOLO11 (todos) | model.23 | /model.23/cv2.0/cv2.0.2/Conv (6 nodos) |
| YOLOv8 (todos) | model.22 | /model.22/cv2.0/cv2.0.2/Conv (6 nodos) |
Nodos finales de YOLO11 (todos los tamaños: 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",
]Nodos finales de YOLOv8 (todos los tamaños: 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 sectionOtras arquitecturas#
Para otras arquitecturas de detección, ejecuta el paso de análisis sin end_node_names primero, lee los nodos sugeridos desde la salida del registro del DFC, luego vuelve a ejecutar con esos nodos:
# 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..."Para el soporte directo de Ultralytics, estas directivas .alls y los ajustes de post-procesamiento deberían ser generados o seleccionados por el exportador en lugar de requerir que los usuarios los ensamblen manualmente.
Link to this sectionArquitecturas de hardware compatibles#
| Arquitectura | Dispositivo | Cómputo máximo (especificación del proveedor) | Caso de uso común |
|---|---|---|---|
hailo8 | Hailo-8 | 26 TOPS | Tarjeta aceleradora Hailo |
hailo8l | Hailo-8L | 13 TOPS | Raspberry Pi AI Kit |
hailo15h | Hailo-15H | 20 TOPS | Dispositivos de destino Hailo-15 |
Configura HW_ARCH en el script para que coincida con tu dispositivo de destino antes de compilar.
Link to this sectionEjecución de inferencia en hardware Hailo#
Once compilation finishes, copy the whole yolo11n_hailo_model/ folder (the .hef plus its metadata.yaml) to your Hailo-powered device and run inference using either the HailoRT Python API (hailo_platform package) or, on Raspberry Pi, the picamera2 Hailo helper (a HailoRT wrapper). Both are shown in the tabs below. Keeping the two files together lets the scripts below read the class names from metadata.yaml next to the HEF. Unlike the DFC export steps, inference runs directly on the edge device.
El código de inferencia a continuación se ejecuta en el dispositivo con tecnología Hailo (p. ej., Raspberry Pi + AI Kit), no en la máquina x86 utilizada para la compilación.
Link to this sectionPaso 1: Instalar HailoRT en el dispositivo#
En el dispositivo de destino, instala HailoRT y los enlaces de Python. Para los usuarios de Raspberry Pi AI Kit y AI HAT+, la guía oficial de software de IA de Raspberry Pi instala HailoRT, el controlador del dispositivo y los enlaces de Python con:
sudo apt install dkms
sudo apt install hailo-all
sudo rebootPara dispositivos Hailo que no son Raspberry Pi, instala el paquete HailoRT que coincida con tu dispositivo, controlador y versión de SDK desde la Zona de desarrolladores de Hailo.
Los dispositivos AI HAT+ 2 utilizan un paquete diferente de Raspberry Pi (hailo-h10-all) y el flujo de trabajo de Hailo-10H. Sigue la guía de software de IA de Raspberry Pi para esa generación de hardware.
Link to this sectionPaso 2: Comprobación rápida#
Antes de ejecutar la inferencia en Python, confirma que el dispositivo Hailo sea reconocido:
hailortcli fw-control identifyDeberías ver el tipo de dispositivo, la versión del firmware y el número de serie impresos.
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 sectionPaso 3: Ejecutar inferencia#
The scripts below run object detection with the compiled HEF file. Both tabs accept the same --source inputs (an image, a video, a USB webcam index, or csi for the Raspberry Pi Camera Module) and differ only in the inference API: the Hailo SDK tab uses the low-level hailo_platform API (portable, minimal dependencies), while the picamera2 tab uses the Raspberry Pi picamera2 Hailo helper. Images and videos are written to an annotated file; webcam and CSI streams display in a live window.
La ruta nativa del proveedor HailoRT se ejecuta en cualquier plataforma con un dispositivo Hailo y no necesita dependencias adicionales. Pasa a --source una ruta de imagen, una ruta de vídeo, un índice de cámara web (por ejemplo, 0) para captura en vivo USB/V4L2, o csi para el Raspberry Pi Camera Module. La opción CSI requiere que picamera2 esté instalado, ya que el SO de Raspberry Pi moderno enruta la cámara a través de libcamera en lugar de un dispositivo V4L2 estándar.
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()Ejecútalo con cualquier fuente (las imágenes guardan output.jpg, los vídeos guardan output.mp4, los flujos en vivo se muestran en una ventana, presiona q para salir):
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 ModuleEl formato de salida de detección asume que el HEF fue compilado con nms_postprocess en el script .alls. Si compilaste sin NMS, las salidas sin procesar son los 6 tensores de la cabeza de detección y debes ejecutar NMS en tu aplicación por separado.
Link to this sectionInferencia de vídeo con TAPPAS#
Para canalizaciones de vídeo de alto rendimiento, TAPPAS ofrece elementos GStreamer que transmiten vídeo a través del chip Hailo en tiempo real:
MODEL=yolo11n
gst-launch-1.0 filesrc location=video.mp4 ! decodebin ! \
hailonet hef-path=${MODEL}.hef ! \
hailofilter function-name=yolov8 ! \
hailooverlay ! autovideosinkConsulta la documentación de TAPPAS para conocer todas las opciones de configuración de la canalización.
Link to this sectionResumen#
Esta guía cubrió el flujo de trabajo completo para exportar modelos de detección Ultralytics YOLO al formato HEF de Hailo:
- Exportar a ONNX con Ultralytics (
model.export(format="onnx")). - Analizar el modelo ONNX con el DFC de Hailo y especificar los nodos finales de la cabeza de detección.
- Configurar la normalización y NMS mediante un script de modelo.
- Cuantizar con un conjunto de datos de calibración (COCO128 a través de Ultralytics).
- Compilar a un archivo
.heflisto para Hailo-8, Hailo-8L o Hailo-15.
Para más detalles, consulta la Hailo Developer Zone y la documentación de Hailo. Para otros destinos de exportación de Ultralytics, consulta las guías relacionadas de ONNX, OpenVINO, TensorRT, NCNN, TFLite Edge TPU, RKNN, Sony IMX500 y Qualcomm QNN. Para comparar la velocidad y precisión del modelo exportado entre formatos, utiliza el modo Benchmark. Para obtener la lista completa de formatos y opciones, visita la documentación del modo Export y la página de la guía de integraciones.
Link to this sectionFAQ#
Link to this section¿Qué dispositivos Hailo son compatibles?#
El DFC de Hailo es compatible con Hailo-8 (hailo8), Hailo-8L (hailo8l) y Hailo-15H (hailo15h). Consulta la tabla de Arquitecturas de hardware compatibles para conocer el valor HW_ARCH correspondiente.
Link to this section¿Qué modelos de Ultralytics se pueden exportar?#
Esta guía se centra en modelos de detección. Consulta Tareas compatibles para ver el alcance a nivel de tarea, Notas de compatibilidad para conocer los límites de compatibilidad de los modelos y Modelos compatibles y nodos finales para ver ejemplos de nodos finales de YOLO11 y YOLOv8.
Link to this section¿Por qué el script del modelo usa meta_arch=yolov8 para YOLO11?#
YOLO11 usa la misma arquitectura de cabeza de detección desacoplada que YOLOv8. El DFC de Hailo usa meta_arch=yolov8 para la configuración NMS en ambas familias de modelos.
Link to this section¿Necesito una GPU para el paso de optimización?#
Se recomienda encarecidamente una GPU para el ajuste fino consciente de la cuantización en runner.optimize(). Sin una, el proceso sigue funcionando, pero es significativamente más lento (varias horas frente a unos 10-20 minutos con una GPU).
Link to this section¿Cómo encuentro los nodos finales correctos para mi modelo?#
Ejecuta runner.translate_onnx_model(...) sin especificar end_node_names y luego usa los nodos de cabeza de detección sugeridos que imprime el DFC. Consulta Otras arquitecturas para ver el ejemplo de comando.
Link to this section¿Dónde puedo obtener el SDK DFC de Hailo?#
El wheel de Python del SDK DFC de Hailo está disponible en la Hailo Developer Zone. Para un exportador directo de Ultralytics a Hailo, el script del modelo y la configuración de post-procesamiento deberían generarse o seleccionarse dentro del flujo de trabajo de exportación.