Link to this sectionПонимание сквозного (end-to-end) детектирования в Ultralytics YOLO26#
Link to this sectionВведение#
Если ты переходишь на YOLO26 с более ранней модели, такой как YOLOv8 или YOLO11, одно из самых больших изменений, которое ты заметишь, — это удаление Non-Maximum Suppression (NMS). Традиционные модели YOLO создают тысячи перекрывающихся предсказаний, для фильтрации которых до финальных результатов требуется отдельный этап постобработки NMS. Это увеличивает задержку, усложняет графы экспорта и может приводить к несогласованному поведению на разных аппаратных платформах.
В YOLO26 используется другой подход. Она выводит финальные результаты детектирования непосредственно из модели — внешняя фильтрация не требуется. Это называется сквозным object detection, и эта функция включена по умолчанию во всех моделях YOLO26. В результате ты получаешь более простой конвейер развертывания, меньшую задержку и до 43% более быстрое инференс на CPU.
Это руководство поможет тебе разобраться в изменениях, подскажет, нужно ли обновлять код, какие форматы экспорта поддерживают сквозной инференс и как плавно перейти со старых моделей YOLO.
Более подробный взгляд на мотивацию этого архитектурного сдвига можно найти в блоге Ultralytics о том, почему YOLO26 убирает NMS.
- Используешь API или CLI от Ultralytics? Никаких изменений не требуется — просто замени имя модели на
yolo26n.pt. - Используешь собственный код для инференса (ONNX Runtime, TensorRT и т.д.)? Обнови свою постобработку — выходной результат детектирования теперь имеет формат
(N, 300, 6)в видеxyxy, NMS не требуется. Другие задачи добавляют дополнительные данные (коэффициенты маски, ключевые точки или угол). - Делаешь экспорт? Большинство форматов поддерживают сквозной вывод нативно. Однако несколько форматов (NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX, Edge TPU и QNN) автоматически возвращаются к традиционному выводу из-за ограничений неподдерживаемых операторов (например,
torch.topk). Рабочие процессы Hailo HEF компилируются из ONNX с помощью скриптов для Hailo, поэтому проверь настройки детектора и NMS для своей модели.
Link to this sectionКак работает сквозное детектирование#
В YOLO26 используется двухголовочная архитектура во время training. Обе головы разделяют одни и те же backbone и neck, но выдают результаты разными способами:
| Голова | Цель | Выход детектирования | Постобработка |
|---|---|---|---|
| One-to-One (по умолчанию) | Сквозной инференс | (N, 300, 6) | Только порог уверенности |
| One-to-Many | Традиционный выход YOLO | (N, nc + 4, 8400) | Требует NMS |
Указанные выше формы предназначены для detection. Другие задачи расширяют выход one-to-one дополнительными данными для каждого детектирования:
| Задача | Сквозной выход | Дополнительные данные |
|---|---|---|
| Детекция | (N, 300, 6) | — |
| Instance Segmentation | (N, 300, 6 + nm) + proto (N, nm, H, W) | nm коэффициенты маски (по умолчанию 32) |
| Pose | (N, 300, 57) | 17 ключевых точек × 3 (x, y, видимость) |
| OBB | (N, 300, 7) | Угол поворота |
Во время обучения обе головы работают одновременно — голова one-to-many обеспечивает более богатый обучающий сигнал, а голова one-to-one учится выдавать чистые, неперекрывающиеся предсказания. Во время inference и export по умолчанию активна только голова one-to-one, выдающая до 300 обнаружений на изображение в формате [x1, y1, x2, y2, confidence, class_id].
Когда ты вызываешь model.fuse(), это сворачивает слои Conv + BatchNorm для более быстрого инференса, а в сквозных моделях также удаляет голову one-to-many, уменьшая размер модели и FLOPs. Более подробную информацию о двухголовочной архитектуре см. на странице модели YOLO26.
Link to this sectionНужно ли мне менять свой код?#
Link to this sectionИспользование Python API или CLI от Ultralytics#
Изменения не нужны. Если ты используешь стандартный Ultralytics Python API или CLI, всё работает автоматически — prediction, validation и export поддерживают сквозные модели «из коробки».
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")Link to this sectionИспользование собственного кода инференса#
Да, формат вывода другой. Если ты написал собственную логику постобработки для YOLOv8 или YOLO11 (например, при запуске инференса с помощью ONNX Runtime или TensorRT), тебе нужно будет обновить её, чтобы она обрабатывала новую форму вывода:
| YOLOv8 / YOLO11 | YOLO26 (сквозной) | |
|---|---|---|
| Выход детектирования | (N, nc + 4, 8400) | (N, 300, 6) |
| Формат бокса | xywh (центр x, центр y, ширина, высота) | xyxy (левый верхний x, левый верхний y, правый нижний x, правый нижний y) |
| Расположение | Координаты бокса + оценки классов для каждого анкора | [x1, y1, x2, y2, conf, class_id] |
| Требуется NMS | Да | Нет |
| Постобработка | NMS + фильтр уверенности | Только фильтр уверенности |
Для задач segmentation, pose и OBB YOLO26 добавляет данные, специфичные для задачи, к каждому обнаружению — см. таблицу выходных форм выше.
Где N — это batch size, а nc — количество классов (например, 80 для COCO).
Со сквозными моделями постобработка становится намного проще — например, при использовании ONNX Runtime:
import onnxruntime as ort
# Load and run the exported end-to-end model
session = ort.InferenceSession("yolo26n.onnx")
output = session.run(None, {session.get_inputs()[0].name: input_tensor})
# End-to-end output: (batch, 300, 6) → [x1, y1, x2, y2, confidence, class_id]
detections = output[0][0] # first image in batch
detections = detections[detections[:, 4] > conf_threshold] # confidence filter — that's it!Link to this sectionПереключение на голову One-to-Many#
Если тебе нужен традиционный формат вывода YOLO (например, чтобы повторно использовать существующий код постобработки на основе NMS), ты можешь переключиться на голову one-to-many в любое время, установив end2end=False:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
# Prediction with NMS (traditional behavior)
results = model.predict("image.jpg", end2end=False)
# Validation with NMS
metrics = model.val(data="coco.yaml", end2end=False)
# Export without end-to-end
model.export(format="onnx", end2end=False)Link to this sectionСовместимость форматов экспорта#
Большинство export formats поддерживают сквозной инференс из коробки, включая ONNX, TensorRT, CoreML, OpenVINO, TFLite, TF.js и MNN.
Следующие форматы не поддерживают сквозной режим и автоматически возвращаются к голове one-to-many: NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX, Edge TPU и Qualcomm QNN.
Для Hailo HEF этап компиляции происходит вне model.export(format=...) после экспорта ONNX. Используй логи Hailo DFC, скрипт модели .alls и NMS JSON, соответствующие твоей модели детектирования; если сквозной граф YOLO26 не поддерживается твоей цепочкой инструментов Hailo, экспортируй модель ONNX с end2end=False и скомпилируй традиционную голову детектирования.
TensorRT поддерживает сквозной режим, но он автоматически отключается при экспорте с int8=True на TensorRT 10.3.0 в JetPack 6.
Link to this sectionКомпромиссы точности и скорости#
Сквозное детектирование дает значительные преимущества при развертывании при минимальном влиянии на accuracy:
| Метрика | Сквозной (по умолчанию) | One-to-Many + NMS (end2end=False) |
|---|---|---|
| Скорость инференса на CPU | До 43% быстрее | Базовая линия |
| Влияние на mAP | ~0.5 mAP ниже | Равен или превосходит YOLO11 |
| Постобработка | Только фильтр уверенности | Полный конвейер NMS |
| Сложность развертывания | Минимальная | Требует реализации NMS |
Для большинства реальных приложений разница в ~0.5 mAP незначительна, особенно если учитывать выигрыш в скорости и простоте. Если максимальная точность — твой главный приоритет, ты всегда можешь вернуться к голове one-to-many, используя end2end=False.
Смотри показатели производительности YOLO26 для подробных бенчмарков по всем размерам моделей (n, s, m, l, x).
Link to this sectionМиграция с YOLOv8 или YOLO11#
Если ты обновляешь существующий проект до YOLO26, вот краткий список для обеспечения плавного перехода:
- Пользователи Ultralytics API / CLI: Изменения не нужны — просто обнови имя модели до
yolo26n.pt(илиyolo26n-seg.pt,yolo26n-pose.pt,yolo26n-obb.pt) - Собственный код постобработки: Обнови его для работы с новыми формами вывода —
(N, 300, 6)для детектирования плюс данные по конкретной задаче для segmentation, pose и OBB. Также обрати внимание на изменение формата бокса сxywhнаxyxy - Конвейеры экспорта: Проверь раздел совместимости форматов выше для целевого формата
- TensorRT + INT8: На JetPack 6 TensorRT 10.3.0 автоматически отключает сквозной режим при
int8=True— используй другую версию TensorRT, чтобы сохранить сквозной режим - Экспорт FP16: Если тебе нужны все выходы в FP16, экспортируй с
end2end=False— см. почему output0 остается FP32 - iOS / CoreML: Сквозной режим полностью поддерживается. Если тебе нужна поддержка предварительного просмотра в Xcode, используй
end2end=Falseсnms=True - Edge-устройства (NCNN, RKNN): Эти форматы автоматически возвращаются к one-to-many, поэтому включи NMS в свой конвейер на устройстве
Link to this sectionFAQ#
Link to this sectionМогу ли я использовать end2end=True и nms=True вместе?#
Нет. Эти опции взаимоисключающие. Если ты установишь nms=True для сквозной модели во время export, она будет автоматически принудительно установлена в nms=False с предупреждением. Сквозная голова уже обрабатывает фильтрацию дубликатов внутри себя, поэтому внешняя NMS не нужна.
Однако комбинация end2end=False и nms=True является допустимой конфигурацией — она встраивает традиционную NMS в граф экспорта. Это может быть полезно для экспорта в CoreML, поскольку позволяет напрямую использовать функцию предварительного просмотра в Xcode с моделью детектирования.
Link to this sectionЗа что отвечает параметр max_det в end-to-end моделях?#
Параметр max_det (по умолчанию: 300) задает максимальное количество обнаружений, которое «one-to-one» голова может выдать на изображение. Ты можешь настроить его во время вывода (inference) или экспорта:
model.predict("image.jpg", max_det=100) # fewer detections, slightly faster
model.export(format="onnx", max_det=500) # more detections for dense scenesОбрати внимание, что стандартные чекпоинты YOLO26 были обучены с max_det=300. Хотя ты можешь увеличить это значение, «one-to-one» голова была оптимизирована в процессе обучения для создания до 300 качественных обнаружений, поэтому результаты сверх этого лимита могут быть более низкого качества. Если тебе нужно более 300 обнаружений на изображение, рассмотри возможность переобучения с более высоким значением max_det.
Link to this sectionМоя экспортированная модель ONNX выдает (1, 300, 6) — это правильно?#
Да, это ожидаемый формат вывода end-to-end для детекции: размер пакета 1, до 300 обнаружений, каждое из которых содержит 6 значений [x1, y1, x2, y2, confidence, class_id]. Просто отфильтруй их по порогу достоверности (confidence threshold) — и готово, NMS больше не нужен.
Для других задач форма вывода отличается:
| Задача | Форма вывода | Описание |
|---|---|---|
| Детектирование | (1, 300, 6) | [x1, y1, x2, y2, conf, class_id] |
| Сегментация | (1, 300, 38) + (1, 32, 160, 160) | 6 значений рамки + 32 коэффициента маски, плюс тензор прототипов масок |
| Поза | (1, 300, 57) | 6 значений рамки + 17 ключевых точек × 3 (x, y, видимость) |
| OBB | (1, 300, 7) | 6 значений рамки + 1 угол поворота |
Link to this sectionКак проверить, является ли моя экспортированная модель end-to-end?#
Ты можешь проверить это с помощью Python API Ultralytics или напрямую просмотрев метаданные экспортированной модели ONNX:
from ultralytics import YOLO
model = YOLO("yolo26n.onnx")
model.predict(verbose=False) # run predict to setup predictor first
print(model.predictor.model.end2end) # True if end-to-end is enabledИли проверь форму вывода — end-to-end модели детекции выводят (1, 300, 6), в то время как традиционные модели выводят (1, nc + 4, 8400). Информацию о формах для других задач смотри в FAQ по формам вывода.
Link to this sectionПоддерживается ли end-to-end для задач сегментации экземпляров, оценки позы и OBB?#
Да. Варианты задач в стиле детекции YOLO26 — детекция, сегментация экземпляров, оценка позы и ориентированная детекция объектов (OBB) — поддерживают end-to-end вывод по умолчанию. Резервный вариант end2end=False также доступен для всех этих задач.
Каждая задача дополняет базовый вывод детекции данными, специфичными для задачи:
| Задача | Модель | Сквозной выход |
|---|---|---|
| Детектирование | yolo26n.pt | (N, 300, 6) |
| Сегментация экземпляров | yolo26n-seg.pt | (N, 300, 38) + прототип (N, 32, 160, 160) |
| Поза | yolo26n-pose.pt | (N, 300, 57) |
| OBB | yolo26n-obb.pt | (N, 300, 7) |