Link to this sectionЭкспорт для Hailo для моделей Ultralytics YOLO#
Hailo HEF в настоящее время не поддерживается как прямой целевой формат для model.export(format="hailo") в Ultralytics. Ниже описан рабочий процесс, являющийся ручным обходным решением: сначала экспорт в ONNX, а затем использование набора инструментов Hailo Dataflow Compiler для создания файла .hef. Полноценный рабочий процесс в Ultralytics должен открывать доступ к Hailo через тот же API экспорта Python и CLI, что и для других аппаратных форматов.
Инструментарий Hailo использует файлы HEF для встраиваемых платформ, включая Raspberry Pi AI Kit и AI HAT+, промышленных камер, граничных шлюзов и AI-ПК.
В этом руководстве описан процесс экспорта избранных моделей Ultralytics YOLO в формат HEF (Hailo Executable Format) с помощью SDK Hailo Dataflow Compiler (DFC). Рабочий процесс начинается с модели YOLO .pt, далее идет экспорт в ONNX, компиляция с помощью инструментов Hailo и получение файла .hef, готового для поддерживаемых ускорителей Hailo.
Link to this sectionКогда использовать Hailo HEF#
HEF — это скомпилированный артефакт, используемый HailoRT на целевых устройствах Hailo. Используй это руководство для ручной настройки только в том случае, если твое оборудование требует именно Hailo HEF, а прямой экспорт для Hailo в Ultralytics еще недоступен.
HEF по своей роли при развертывании похож на аппаратные форматы, такие как RKNN для NPU Rockchip, IMX500 для AI-камер Raspberry Pi и Qualcomm QNN для NPU Snapdragon, однако в настоящее время он не генерируется напрямую Ultralytics.
Этот рабочий процесс актуален, когда тебе нужно:
- Совместимость с Raspberry Pi AI Kit: Hailo-8L используется в официальных Raspberry Pi AI Kit и AI HAT+.
- Пост-обработка HailoRT: HailoRT может включать non-maximum suppression YOLO в скомпилированный конвейер вывода.
- Компиляция INT8: Hailo DFC квантует модель с помощью репрезентативных калибровочных изображений для создания графа INT8 для оборудования Hailo. Узнай больше о model quantization.
Link to this sectionФормат экспорта Hailo HEF#
HEF — это специфический для оборудования исполняемый файл, созданный компилятором Hailo Dataflow Compiler. Он содержит квантованный граф модели, распределение памяти, планирование и опциональную пост-обработку, настроенную для целевой архитектуры Hailo. В отличие от стандартных форматов Export mode YOLO, которые создаются напрямую с помощью model.export(format=...), компиляция HEF в настоящее время использует двухэтапный поток:
- Экспорт YOLO в ONNX с помощью Ultralytics.
- Использование инструментов Hailo DFC для синтаксического анализа, оптимизации, квантования и компиляции модели ONNX в HEF.
Полный рабочий процесс превращается в следующий конвейер:
YOLO (.pt) -> ONNX -> HAR (parse) -> HAR (optimize/quantize) -> HEF (compile)- Экспорт в ONNX с помощью Export mode Ultralytics
- Анализ модели ONNX в промежуточный формат HAR от Hailo
- Загрузка скрипта модели (
.alls) с директивами нормализации и пост-обработки - Калибровка и квантование с использованием репрезентативных изображений
- Компиляция в развертываемый файл HEF
Link to this sectionПоддерживаемые задачи#
Текущий пример для ручной настройки сосредоточен на детекции объектов в YOLO11, так как скрипт модели и конфигурация пост-процессинга Hailo зависят от конкретного детекционного слоя. Будущая реализация прямого model.export(format="hailo") сделает экспорт в Hailo таким же простым, как и для других форматов Ultralytics, где поддержка задач будет определяться архитектурой головы модели и совместимостью с компилятором Hailo, а не внешними этапами обработки.
| Задача | Цель прямого экспорта в Hailo | Примечания |
|---|---|---|
| Обнаружение объектов (Object Detection) | ✅ Основная цель | Детекция в YOLOv8, YOLO11 и YOLO26 должна стать первым путем для прямого экспорта. |
| Instance Segmentation | ✅ Цель | Сегментация в YOLOv8, YOLO11 и YOLO26 требует специфической обработки вывода масок и проверки. |
| Семантическая сегментация | ⚠️ Проверить | Семантическая сегментация в YOLO26 требует отдельного компилятора и пути проверки вывода. |
| Оценка позы (Pose Estimation) | ⚠️ Проверить | Pose требует обработки ключевых точек, выходящей за рамки пути NMS для детекции. |
| OBB Detection | ⚠️ Проверить | OBB требует обработки повернутых боксов, выходящей за рамки стандартного пути NMS для детекции. |
| Классификация | ⚠️ Проверить | Классификация имеет более простой слой вывода, но все равно требует проверки компиляции и выполнения в Hailo. |
Пока прямой экспорт в Hailo не реализован в Ultralytics, задокументирован только ручной процесс ONNX-в-HEF, описанный ниже.
Link to this sectionВерсии Hailo SDK#
Прямой экспорт в Hailo должен учитывать разделение поколений оборудования и SDK Hailo:
- 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, которые должен предоставлять прямой экспортер. Поддержка задачи на одном поколении оборудования Hailo не означает автоматическую поддержку на другом без проверки целевой версии DFC и hw_arch.
Link to this sectionПримечания о совместимости#
Совместимость экспорта в Hailo зависит от слоя головы модели, размера входного изображения, количества классов, архитектуры Hailo, сгенерированного скрипта модели (.alls) и конфигурации пост-процессинга. Статические конфигурации не являются универсальными шаблонами. Например, NMS JSON, созданный для модели YOLO11n с 80 классами COCO, не подойдет для пользовательской модели с 3 классами или для другого фиксированного размера imgsz.
| Область применения | Ожидаемая поддержка | Примечания |
|---|---|---|
| Детекция в YOLOv8 / YOLO11 | ✅ Хорошо | Общий разделенный слой детекции; директивы .alls, конечные узлы и конфигурация NMS по-прежнему должны соответствовать экспортированному графу и фиксированному imgsz. |
| Пользовательское обнаружение YOLOv8 / YOLO11 | ✅ Возможно | Требуется конфигурация NMS для каждой конкретной модели, сгенерированная на основе количества классов, шагов (strides) и структуры головы детекции; статический JSON не подойдет. |
| Детекция в YOLO26 | ✅ Цель | Архитектура без NMS требует отдельного пути компиляции/пост-процессинга; не используй рабочий процесс NMS для YOLO11/YOLOv8 ниже для YOLO26. |
| Инстанс-сегментация в YOLO26 | ✅ Цель | Требует специфической для сегментации YOLO26 обработки вывода масок и проверки точности. |
| Семантическая сегментация, Pose, OBB, классификация в YOLO26 | ⚠️ Исследование | Эти задачи требуют выделенного компилятора и проверки выполнения, прежде чем их можно будет официально объявить поддерживаемыми. |
| Динамические или произвольные размеры изображения | ❌ Не поддерживается | Компиляция в Hailo использует фиксированную входную форму; .alls и настройки пост-процессинга должны соответствовать экспортированному imgsz. |
Link to this sectionУстановка#
Link to this sectionШаг 1: Установка Ultralytics#
pip install ultralyticsLink to this sectionШаг 2: Установка SDK Hailo DFC#
Hailo DFC необходим для синтаксического анализа, оптимизации и компиляции. Загрузи Python wheel из Hailo Developer Zone (требуется бесплатная регистрация) и установи его:
pip install /path/to/hailo_dataflow_compiler-*.whlSDK Hailo DFC требует машину на базе Linux x86_64. Экспорт и компиляцию нельзя выполнить на устройствах ARM, таких как Raspberry Pi. Скопируй полученный файл .hef на свое устройство с питанием от Hailo для развертывания с помощью HailoRT.
Link to this sectionПример экспорта YOLO11n HEF#
Приведенный ниже скрипт компилирует модель обнаружения YOLO11n из .pt в .hef при фиксированном размере ввода 640 пикселей. Он экспортирует в ONNX с помощью Ultralytics, а затем компилирует с помощью Hailo DFC, используя COCO128 в качестве небольшого набора данных для калибровки.
Перед запуском скрипта подготовь Hailo NMS JSON, соответствующий точному графу экспорта YOLO11n, количеству классов, шагам и фиксированному размеру входных данных. Используй этот скрипт как отправную точку для YOLO11n; пользовательские модели требуют соответствующих конечных узлов, директив .alls и настроек NMS.
Модели YOLO26 не используют NMS. Прямому экспортеру Ultralytics для Hailo нужен специальный путь компиляции и пост-процессинга для детекции или инстанс-сегментации в YOLO26, а не пример NMS для YOLO11, приведенный ниже.
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/, повторяя стандартную структуру<model>_<format>_model/, используемую другими методами экспорта Ultralytics. - Необходимые файлы: Для развертывания требуются два файла: скомпилированный
yolo11n.hefи сопроводительныйmetadata.yaml. - Метаданные: Файл
metadata.yamlсодержит важные поля (names,imgsz,task,strideи т.д.), извлеченные из метаданных ONNX. Скрипты для инференса загружают названия классов из этого файла, так как формат HEF их не хранит. - Промежуточные файлы: Папка экспорта также содержит промежуточные чекпоинты
yolo11n.onnxиyolo11n.o.har. - Лог-файлы: Hailo SDK создает несколько диагностических логов (например,
acceleras.log,allocator.log,hailo_sdk.client.logиhailo_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/ (повторяя структуру <model>_<format>_model/ других методов экспорта Ultralytics) для поддержания порядка в рабочей директории.
HEF не хранит названия классов, поэтому метаданные, которые Ultralytics встраивает в ONNX, копируются в стандартный сопроводительный файл metadata.yaml рядом с ним. Это тот же metadata.yaml, который создают другие форматы экспорта (names, imgsz, task, stride и другие), и инференс считывает из него названия классов, поэтому рабочий процесс подходит для пользовательских моделей без жесткого кодирования меток.
Link to this sectionШаг 2: Анализ модели ONNX#
runner.translate_onnx_model(...) преобразует граф ONNX в промежуточное представление HAR от Hailo. Список end_node_names указывает DFC, где обрезать граф перед NMS, чтобы Hailo мог подключить собственную аппаратную постобработку.
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 (conv54, conv65, conv80) назначаются DFC во время парсинга и являются специфичными для модели. Если ты компилируешь модель другого размера или архитектуры, проверь вывод DFC на наличие правильных имен или сгенерируй директивы .alls из экспортированного графа.
Файл NMS_CONFIG также специфичен для модели. Используй конфигурацию, которая в точности соответствует твоей экспортированной модели.
engine=cpu запускает NMS через HailoRT на хост-процессоре CPU. Используй engine=nn_core только для комбинаций моделей/скриптов, которые Hailo документирует как поддерживаемые целевым оборудованием и версией SDK.
Удали строку nms_postprocess, если предпочитаешь запускать NMS полностью в коде своего приложения. Если ты сделаешь это, обнови парсер вывода, так как HEF будет выдавать тензоры необработанного детектора вместо сгруппированных обнаружений NMS.
Link to this sectionШаг 4: Создание калибровочного набора данных#
Квантование INT8 требует репрезентативного набора изображений, собранных в массив float32 формата (N, imgsz, imgsz, 3). Скрипт использует COCO128, который Ultralytics скачивает автоматически через check_det_dataset.
Используй не менее 64 изображений для калибровки. Большее количество изображений обычно улучшает качество квантования. Для наилучших результатов используй изображения из своего домена развертывания, а не COCO128.
Link to this sectionШаг 5: Оптимизация и квантование#
runner.optimize(calibset) применяет дообучение с учетом квантования и анализ шумов слоев, затем runner.save_har(...) сохраняет опциональный промежуточный чекпоинт. Настоятельно рекомендуется использовать GPU; без него этот шаг может занять несколько часов.
Link to this sectionШаг 6: Компиляция в HEF#
runner.compile() создает финальный файл HEF, который записывается в yolo11n_hailo_model/yolo11n.hef. Теперь он находится рядом с metadata.yaml и готов к копированию на устройство для инференса.
Link to this sectionПоддерживаемые модели и конечные узлы#
Для моделей обнаружения end_node_names идентифицируют выходы детектора ONNX, которые Hailo должен скомпилировать перед добавлением своей пост-обработки NMS. Эти имена варьируются в зависимости от архитектуры и могут изменяться при изменении экспортированного графа.
Примеры конечных узлов ниже применимы к моделям детекции YOLOv8 и YOLO11, которые используют NMS пост-процессинг в стиле YOLOv8 от Hailo. YOLO26 не использует NMS и не применяет эту конфигурацию NMS от YOLO11.
Link to this sectionYOLO11 и YOLOv8#
YOLO11 и YOLOv8 имеют одинаковый разделенный детектор. Индекс слоя отличается на единицу между двумя семействами:
| Семейство моделей | Слой детектора | Шаблон конечного узла |
|---|---|---|
| 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Поддерживаемые аппаратные архитектуры#
| Архитектура | Устройство | Пиковая вычислительная мощность (спецификация вендора) | Типичный вариант использования |
|---|---|---|---|
hailo8 | Hailo-8 | 26 TOPS | Карта ускорителя Hailo |
hailo8l | Hailo-8L | 13 TOPS | Raspberry Pi AI Kit |
hailo15h | Hailo-15H | 20 TOPS | Целевые устройства Hailo-15 |
Перед компиляцией установи в скрипте HW_ARCH в соответствии с твоим целевым устройством.
Link to this sectionЗапуск логического вывода на аппаратном обеспечении Hailo#
После завершения компиляции скопируй всю папку yolo11n_hailo_model/ (файл .hef вместе с metadata.yaml) на свое устройство с поддержкой Hailo и запусти инференс, используя Python API HailoRT (пакет hailo_platform) или, на Raspberry Pi, вспомогательный модуль picamera2 Hailo (обертка для HailoRT). Оба варианта показаны во вкладках ниже. Сохранение двух файлов вместе позволяет скриптам ниже считывать названия классов из metadata.yaml рядом с HEF. В отличие от этапов экспорта DFC, инференс выполняется непосредственно на edge-устройстве.
Приведенный ниже код логического вывода выполняется на устройстве с поддержкой Hailo (например, Raspberry Pi + AI Kit), а не на x86-машине, используемой для компиляции.
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Для устройств Hailo, не относящихся к Raspberry Pi, установи пакет HailoRT, соответствующий версии твоего устройства, драйвера и SDK, из Hailo Developer Zone.
Устройства 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: HAILO8Link to this sectionШаг 3: Запуск логического вывода#
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.
Нативный путь HailoRT работает на любой платформе с устройством Hailo и не требует дополнительных зависимостей. Передай в --source путь к изображению, путь к видео, индекс веб-камеры (например, 0) для захвата с USB/V4L2 или csi для модуля камеры Raspberry Pi. Опция CSI требует установки picamera2, так как современная ОС Raspberry Pi направляет камеру через libcamera, а не через обычное устройство V4L2.
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Формат вывода обнаружения предполагает, что файл HEF был скомпилирован с использованием nms_postprocess в скрипте .alls. Если ты скомпилировал без NMS, необработанные выходные данные представляют собой 6 тензоров голов обнаружения, и тебе необходимо запустить NMS в своем приложении отдельно.
Link to this sectionЛогический вывод видео с помощью TAPPAS#
Для видеоконвейеров с высокой пропускной способностью TAPPAS предоставляет элементы GStreamer, которые передают видео через чип Hailo в реальном времени:
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:
- Экспорт в ONNX с помощью Ultralytics (
model.export(format="onnx")). - Разбор модели ONNX с помощью Hailo DFC и указание конечных узлов голов обнаружения.
- Настройка нормализации и NMS с помощью скрипта модели.
- Квантование с использованием калибровочного набора данных (COCO128 через Ultralytics).
- Компиляция в файл
.hef, готовый для Hailo-8, Hailo-8L или Hailo-15.
Более подробную информацию можно найти в Hailo Developer Zone и документации Hailo. Информацию о других целях экспорта Ultralytics см. в соответствующих руководствах: ONNX, OpenVINO, TensorRT, NCNN, TFLite Edge TPU, RKNN, Sony IMX500 и Qualcomm QNN. Чтобы сравнить скорость и точность экспортированных моделей для разных форматов, используй режим Benchmark. Полный список форматов и опций доступен в документации режима Export и на странице руководства по интеграциям.
Link to this sectionFAQ#
Link to this sectionКакие устройства Hailo поддерживаются?#
Hailo DFC поддерживает Hailo-8 (hailo8), Hailo-8L (hailo8l) и Hailo-15H (hailo15h). См. таблицу Поддерживаемые аппаратные архитектуры для получения соответствующего значения HW_ARCH.
Link to this sectionКакие модели Ultralytics можно экспортировать?#
Это руководство посвящено моделям обнаружения. См. Поддерживаемые задачи для охвата на уровне задач, Примечания о совместимости для ограничений совместимости моделей и Поддерживаемые модели и конечные узлы для примеров конечных узлов YOLO11 и YOLOv8.
Link to this sectionПочему скрипт модели использует meta_arch=yolov8 для YOLO11?#
YOLO11 использует ту же архитектуру разделенной головки обнаружения, что и YOLOv8. Hailo DFC использует meta_arch=yolov8 для конфигурации NMS для обоих семейств моделей.
Link to this sectionНужен ли мне GPU для этапа оптимизации?#
GPU настоятельно рекомендуется для тонкой настройки с учетом квантования в runner.optimize(). Без него процесс тоже работает, но значительно медленнее (несколько часов против примерно 10-20 минут с GPU).
Link to this sectionКак мне найти правильные конечные узлы для моей модели?#
Запусти runner.translate_onnx_model(...) без указания end_node_names, затем используй предложенные узлы голов обнаружения, выведенные DFC. См. Другие архитектуры для примера команды.
Link to this sectionГде можно получить Hailo DFC SDK?#
Python-wheel для Hailo DFC SDK доступен в Hailo Developer Zone. Для прямого экспортера Ultralytics в Hailo скрипт модели и конфигурация пост-процессинга должны генерироваться или выбираться внутри самого рабочего процесса экспорта.