Meet YOLO26: next-gen vision AI.

Link to this sectionЭкспорт для Hailo для моделей Ultralytics YOLO#

Не является прямым форматом экспорта Ultralytics

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 в настоящее время использует двухэтапный поток:

  1. Экспорт YOLO в ONNX с помощью Ultralytics.
  2. Использование инструментов Hailo DFC для синтаксического анализа, оптимизации, квантования и компиляции модели ONNX в HEF.

Полный рабочий процесс превращается в следующий конвейер:

YOLO (.pt) -> ONNX -> HAR (parse) -> HAR (optimize/quantize) -> HEF (compile)
  1. Экспорт в ONNX с помощью Export mode Ultralytics
  2. Анализ модели ONNX в промежуточный формат HAR от Hailo
  3. Загрузка скрипта модели (.alls) с директивами нормализации и пост-обработки
  4. Калибровка и квантование с использованием репрезентативных изображений
  5. Компиляция в развертываемый файл 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 ultralytics

Link to this sectionШаг 2: Установка SDK Hailo DFC#

Hailo DFC необходим для синтаксического анализа, оптимизации и компиляции. Загрузи Python wheel из Hailo Developer Zone (требуется бесплатная регистрация) и установи его:

pip install /path/to/hailo_dataflow_compiler-*.whl
Примечание

SDK 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 используется другой путь в Hailo

Модели 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Поддерживаемые аппаратные архитектуры#

АрхитектураУстройствоПиковая вычислительная мощность (спецификация вендора)Типичный вариант использования
hailo8Hailo-826 TOPSКарта ускорителя Hailo
hailo8lHailo-8L13 TOPSRaspberry Pi AI Kit
hailo15hHailo-15H20 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: HAILO8

Link 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:

  1. Экспорт в ONNX с помощью Ultralytics (model.export(format="onnx")).
  2. Разбор модели ONNX с помощью Hailo DFC и указание конечных узлов голов обнаружения.
  3. Настройка нормализации и NMS с помощью скрипта модели.
  4. Квантование с использованием калибровочного набора данных (COCO128 через Ultralytics).
  5. Компиляция в файл .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 скрипт модели и конфигурация пост-процессинга должны генерироваться или выбираться внутри самого рабочего процесса экспорта.

Комментарии