Skip to main content

Compreendendo a detecção end-to-end no Ultralytics YOLO26

Introdução

Se você está atualizando para YOLO26 a partir de um modelo anterior como YOLOv8 ou YOLO11, uma das maiores mudanças que você notará é a remoção da Non-Maximum Suppression (NMS). Os modelos YOLO tradicionais produzem milhares de predições sobrepostas que precisam de uma etapa separada de pós-processamento NMS para filtrar as detecções finais. Isso adiciona latência, complica os grafos de exportação e pode se comportar de forma inconsistente entre diferentes plataformas de hardware.

O YOLO26 adota uma abordagem diferente. Ele gera as detecções finais diretamente do modelo — sem necessidade de filtragem externa. Isso é conhecido como end-to-end object detection, e está habilitado por padrão em todos os modelos YOLO26. O resultado é um pipeline de implantação mais simples, menor latência e até 43% mais rápido em CPUs.

Este guia orienta você sobre o que mudou, se você precisa atualizar seu código, quais formatos de exportação suportam inferência end-to-end e como migrar suavemente de modelos YOLO antigos.

Para uma visão mais profunda da motivação por trás dessa mudança arquitetural, veja o post no blog da Ultralytics sobre por que o YOLO26 remove o NMS.

Resumo Rápido
  • Usando a API ou CLI da Ultralytics? Nenhuma alteração necessária — basta trocar o nome do seu modelo para yolo26n.pt.
  • Usando código de inferência personalizado (ONNX Runtime, TensorRT, etc.)? Atualize seu pós-processamento — a saída de detecção agora está no formato (N, 300, 6) em xyxy, sem necessidade de NMS. Outras tarefas adicionam dados extras (coeficientes de máscara, keypoints ou ângulo).
  • Exportando? A maioria dos formatos suporta saída end-to-end nativamente. No entanto, alguns formatos (NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX e Edge TPU) revertem automaticamente para a saída tradicional devido a restrições de operadores não suportados (por exemplo, torch.topk).

Como funciona a detecção end-to-end

O YOLO26 utiliza um arquitetura de head dupla durante training. Ambas as cabeças (heads) compartilham o mesmo backbone e neck, mas produzem saídas de formas diferentes:

HeadObjetivoSaída de DetecçãoPós-processamento
One-to-One (padrão)Inferência end-to-end(N, 300, 6)Apenas limite de confiança
One-to-ManySaída YOLO tradicional(N, nc + 4, 8400)Requer NMS

As formas acima são para detecção. Outras tarefas estendem a saída one-to-one com dados adicionais por detecção:

TarefaSaída End-to-EndDados Extras
Detection(N, 300, 6)
Segmentation(N, 300, 6 + nm) + proto (N, nm, H, W)nm coeficientes de máscara (padrão 32)
Pose(N, 300, 57)17 keypoints × 3 (x, y, visibilidade)
OBB(N, 300, 7)Ângulo de rotação

Durante o treinamento, ambas as heads rodam simultaneamente — a head one-to-many fornece um sinal de aprendizado mais rico, enquanto a head one-to-one aprende a produzir predições limpas e sem sobreposição. Durante a inferência e export, apenas a one-to-one head está ativa por padrão, produzindo até 300 detecções por imagem no formato [x1, y1, x2, y2, confidence, class_id].

Quando você chama model.fuse(), ele dobra as camadas Conv + BatchNorm para uma inferência mais rápida e, em modelos end-to-end, também remove a head one-to-many — reduzindo o tamanho do modelo e FLOPs. Para mais detalhes sobre a arquitetura de head dupla, veja a página do modelo YOLO26.

Preciso alterar meu código?

Usando a API Python ou CLI da Ultralytics

Nenhuma alteração necessária. Se você usa o Ultralytics Python API ou CLI padrão, tudo funciona automaticamente — previsão, validação, e export todos lidam com modelos end-to-end nativamente.

Nenhuma alteração de código necessária com a API Ultralytics
from ultralytics import YOLO

# Load a YOLO26 model
model = YOLO("yolo26n.pt")

# Predict — no NMS step, no code changes
results = model.predict("image.jpg")

Usando Código de Inferência Personalizado

Sim, o formato de saída é diferente. Se você escreveu uma lógica de pós-processamento personalizada para YOLOv8 ou YOLO11 (por exemplo, ao executar inferência com ONNX Runtime ou TensorRT), você precisará atualizá-la para lidar com a nova forma de saída:

YOLOv8 / YOLO11YOLO26 (end-to-end)
Saída de detecção(N, nc + 4, 8400)(N, 300, 6)
Formato BBoxxywh (centro x, centro y, largura, altura)xyxy (x superior esquerdo, y superior esquerdo, x inferior direito, y inferior direito)
LayoutCoordenadas da BBox + scores de classe por âncora[x1, y1, x2, y2, conf, class_id]
NMS necessárioSimNão
Pós-processamentoNMS + filtro de confiançaApenas filtro de confiança

Para segmentation, pose, e OBB tarefas, o YOLO26 adiciona dados específicos da tarefa a cada detecção — veja a tabela de formas de saída acima.

Onde N é o batch size e nc é o número de classes (por exemplo, 80 para COCO).

Com modelos end-to-end, o pós-processamento torna-se muito mais simples — por exemplo, ao usar 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!

Alternando para a One-to-Many Head

Se você precisar do formato de saída YOLO tradicional (por exemplo, para reutilizar código de pós-processamento baseado em NMS existente), você pode alternar para a head one-to-many a qualquer momento definindo end2end=False:

Usando a head one-to-many para saída tradicional baseada em NMS
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)

Compatibilidade de Formato de Exportação

A maioria dos formatos de exportação suportam inferência end-to-end nativamente, incluindo ONNX, TensorRT, CoreML, OpenVINO, TFLite, TF.js, e MNN.

Os seguintes formatos não suportam end-to-end e revertem automaticamente para a head one-to-many: NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX, e Edge TPU.

O que acontece quando o end-to-end não é suportado

Ao exportar para um desses formatos, a Ultralytics alterna automaticamente para a head one-to-many e registra um aviso — sem necessidade de intervenção manual. Isso significa que você precisará de NMS no seu pipeline de inferência para esses formatos, assim como com YOLOv8 ou YOLO11.

TensorRT + INT8

TensorRT suporta end-to-end, mas é auto-desabilitado ao exportar com int8=True no TensorRT ≤10.3.0.

Compromissos entre Precisão e Velocidade

A detecção de ponta a ponta (end-to-end) oferece benefícios significativos de implantação com impacto mínimo no accuracy:

MétricaPonta a Ponta (padrão)Um-para-Muitos + NMS (end2end=False)
Velocidade de Inferência em CPUAté 43% mais rápidoLinha de base
Impacto no mAP~0.5 mAP a menosIguala ou supera o YOLO11
Pós-processamentoApenas filtro de confiançaPipeline NMS completo
Complexidade de ImplantaçãoMínimaRequer implementação de NMS

Para a maioria das aplicações do mundo real, a diferença de ~0.5 mAP é insignificante, especialmente ao considerar os ganhos de velocidade e simplicidade. Se a precisão máxima for sua prioridade, você sempre pode voltar para a head de um-para-muitos usando end2end=False.

Veja a métricas de desempenho do YOLO26 para benchmarks detalhados em todos os tamanhos de modelo (n, s, m, l, x).

Migrando do YOLOv8 ou YOLO11

Se você está atualizando um projeto existente para o YOLO26, aqui está uma lista de verificação rápida para garantir uma transição tranquila:

  • Usuários da API / CLI da Ultralytics: Nenhuma alteração necessária — apenas atualize o nome do modelo para yolo26n.pt (ou yolo26n-seg.pt, yolo26n-pose.pt, yolo26n-obb.pt)
  • Código de pós-processamento personalizado: Atualize para lidar com os novos formatos de saída — (N, 300, 6) para detecção, além de dados específicos da tarefa para segmentation, pose, e OBB. Observe também a mudança no formato da caixa de xywh para xyxy
  • Pipelines de exportação: Confira a seção de compatibilidade de formato acima para o seu formato de destino
  • TensorRT + INT8: Verifique se a sua versão do TensorRT é >10.3.0 para suporte de ponta a ponta
  • Exportações FP16: Se precisar de todas as saídas em FP16, exporte com end2end=False — veja por que o output0 permanece FP32
  • iOS / CoreML: O modo de ponta a ponta é totalmente suportado. Se precisar de suporte para Xcode Preview, use end2end=False com nms=True
  • Dispositivos de borda (NCNN, RKNN): Esses formatos retornam automaticamente para um-para-muitos, então inclua o NMS em seu pipeline no dispositivo

FAQ

Posso usar end2end=True e nms=True juntos?

Não. Essas opções são mutuamente exclusivas. Se você definir nms=True em um modelo de ponta a ponta durante a export, ele será forçado automaticamente para nms=False com um aviso. A head de ponta a ponta já lida com a filtragem de duplicatas internamente, então um NMS externo é desnecessário.

No entanto, end2end=False combinado com nms=True é uma configuração válida — ele incorpora o NMS tradicional no grafo de exportação. Isso pode ser útil para CoreML exportações, pois permite usar a função de visualização no Xcode diretamente com o modelo de detecção.

O que o parâmetro max_det controla em modelos de ponta a ponta?

O argumento max_det parâmetro (padrão: 300) define o número máximo de detecções que a head de um-para-um pode emitir por imagem. Você pode ajustá-lo no momento da inferência ou exportação:

model.predict("image.jpg", max_det=100)  # fewer detections, slightly faster
model.export(format="onnx", max_det=500)  # more detections for dense scenes

Observe que os checkpoints padrão do YOLO26 foram treinados com max_det=300. Embora você possa aumentar esse valor, a head de um-para-um foi otimizada durante o treinamento para produzir até 300 detecções limpas, portanto, detecções além desse limite podem ter qualidade inferior. Se precisar de mais de 300 detecções por imagem, considere retreinar com um valor max_det maior.

Meu modelo ONNX exportado gera (1, 300, 6) — isso está correto?

Sim, esse é o formato de saída de ponta a ponta esperado para detecção: batch size de 1, até 300 detecções, cada uma com 6 valores [x1, y1, x2, y2, confidence, class_id]. Simplesmente filtre pelo limiar de confiança e pronto — sem necessidade de NMS.

Para outras tarefas, o formato de saída difere:

TarefaFormato de SaídaDescrição
Detection(1, 300, 6)[x1, y1, x2, y2, conf, class_id]
Segmentation(1, 300, 38) + (1, 32, 160, 160)6 valores de caixa + 32 coeficientes de máscara, mais um tensor de máscara protótipo
Pose(1, 300, 57)6 valores de caixa + 17 keypoints × 3 (x, y, visibilidade)
OBB(1, 300, 7)6 valores de caixa + 1 ângulo de rotação

Como verifico se meu modelo exportado é de ponta a ponta?

Você pode verificar usando a API Python da Ultralytics ou inspecionando diretamente os metadados do modelo ONNX exportado:

Verifique se um modelo é de ponta a ponta
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

Alternativamente, verifique o formato de saída — modelos de detecção de ponta a ponta geram (1, 300, 6), enquanto modelos tradicionais geram (1, nc + 4, 8400). Para formatos de outras tarefas, consulte o FAQ de formatos de saída.

O modo de ponta a ponta é suportado para tarefas de segmentação, pose e OBB?

Sim. Todas as variantes de tarefas do YOLO26 — detecção, segmentation, estimativa de pose, e detecção de objetos orientados (OBB) — suportam inferência de ponta a ponta por padrão. O end2end=False fallback também está disponível em todas as tarefas.

Cada tarefa estende a saída de detecção base com dados específicos da tarefa:

TarefaModeloSaída End-to-End
Detectionyolo26n.pt(N, 300, 6)
Segmentationyolo26n-seg.pt(N, 300, 38) + proto (N, 32, 160, 160)
Poseyolo26n-pose.pt(N, 300, 57)
OBByolo26n-obb.pt(N, 300, 7)

Comentários