Comprendere il rilevamento end-to-end in Ultralytics YOLO26
Introduzione
Se stai passando a YOLO26 da un modello precedente come YOLOv8 o YOLO11, uno dei cambiamenti più significativi che noterai è la rimozione della Non-Maximum Suppression (NMS). I modelli YOLO tradizionali producono migliaia di previsioni sovrapposte che necessitano di un passaggio di post-elaborazione NMS separato per filtrare i rilevamenti finali. Questo aggiunge latenza, complica i grafici di esportazione e può comportarsi in modo incoerente su diverse piattaforme hardware.
YOLO26 adotta un approccio diverso. Esegue i rilevamenti finali direttamente dal modello: non è richiesto alcun filtraggio esterno. Questo è noto come rilevamento oggetti end-to-end ed è abilitato per impostazione predefinita in tutti i modelli YOLO26. Il risultato è una pipeline di distribuzione più semplice, una latenza inferiore e un'inferenza fino al 43% più veloce su CPU.
Questa guida ti illustra cosa è cambiato, se devi aggiornare il tuo codice, quali formati di esportazione supportano l'inferenza end-to-end e come migrare senza problemi dai vecchi modelli YOLO.
Per uno sguardo più approfondito alle motivazioni dietro questo cambiamento architettonico, consulta il post del blog di Ultralytics sul perché YOLO26 rimuove la NMS e come questo cambia la distribuzione.
- Utilizzi l'API o la CLI di Ultralytics? Non sono necessarie modifiche: sostituisci semplicemente il nome del tuo modello con
yolo26n.pt. - Utilizzi un codice di inferenza personalizzato (ONNX Runtime, TensorRT, ecc.)? Aggiorna la tua post-elaborazione: l'output di rilevamento ora è
(N, 300, 6)nel formatoxyxy, senza NMS richiesta. Altri task aggiungono dati extra (coefficienti di maschera, keypoint o angolo). - Esportazione? La maggior parte dei formati supporta l'output end-to-end in modo nativo. Tuttavia, alcuni formati (NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX e Edge TPU) tornano automaticamente all'output tradizionale a causa di vincoli degli operatori non supportati (es.
torch.topk).
Come funziona il rilevamento end-to-end
YOLO26 utilizza un'architettura a doppia testa durante l'addestramento. Entrambe le teste condividono lo stesso backbone e collo, ma producono output in modi diversi:
| Testa | Scopo | Output di rilevamento | Post-elaborazione |
|---|---|---|---|
| One-to-One (predefinito) | Inferenza end-to-end | (N, 300, 6) | Solo soglia di confidenza |
| One-to-Many | Output YOLO tradizionale | (N, nc + 4, 8400) | Richiede NMS |
Le forme sopra indicate sono per il rilevamento. Altri task estendono l'output one-to-one con dati aggiuntivi per ogni rilevamento:
| Attività | Output end-to-end | Dati extra |
|---|---|---|
| Rilevamento | (N, 300, 6) | — |
| Segmentazione | (N, 300, 6 + nm) + proto (N, nm, H, W) | Coefficienti di maschera nm (predefinito 32) |
| Posa | (N, 300, 57) | 17 keypoint × 3 (x, y, visibilità) |
| OBB | (N, 300, 7) | Angolo di rotazione |
During training, both heads run simultaneously — the one-to-many head provides a richer learning signal, while the one-to-one head learns to produce clean, non-overlapping predictions. During inference and export, only the one-to-one head is active by default, producing up to 300 detections per image in the format [x1, y1, x2, y2, confidence, class_id].
Quando chiami model.fuse(), vengono unite i livelli Conv + BatchNorm per un'inferenza più veloce e, sui modelli end-to-end, viene rimossa anche la testa one-to-many, riducendo le dimensioni del modello e i FLOP. Per maggiori dettagli sull'architettura a doppia testa, consulta la pagina del modello YOLO26.
Devo modificare il mio codice?
Utilizzando l'API Python o la CLI di Ultralytics
Non sono necessarie modifiche. Se utilizzi l' API Python di Ultralytics o la CLI standard, tutto funziona automaticamente: previsione, validazione ed esportazione gestiscono tutti i modelli end-to-end fin da subito.
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")Utilizzando codice di inferenza personalizzato
Sì, il formato di output è diverso. Se hai scritto una logica di post-elaborazione personalizzata per YOLOv8 o YOLO11 (ad esempio, quando esegui l'inferenza con ONNX Runtime o TensorRT), dovrai aggiornarla per gestire la nuova forma di output:
| YOLOv8 / YOLO11 | YOLO26 (end-to-end) | |
|---|---|---|
| Output di rilevamento | (N, nc + 4, 8400) | (N, 300, 6) |
| Formato bbox | xywh (centro x, centro y, larghezza, altezza) | xyxy (x in alto a sinistra, y in alto a sinistra, x in basso a destra, y in basso a destra) |
| Layout | Coordinate bbox + punteggi classe per anchor | [x1, y1, x2, y2, conf, class_id] |
| NMS richiesta | Sì | No |
| Post-elaborazione | NMS + filtro di confidenza | Solo filtro di confidenza |
Per i task di segmentazione, pose e OBB, YOLO26 aggiunge dati specifici del task a ogni rilevamento: vedi la tabella delle forme di output qui sopra.
Dove N è la batch size e nc è il numero di classi (es. 80 per COCO).
Con i modelli end-to-end, la post-elaborazione diventa molto più semplice; ad esempio, quando utilizzi 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!Passaggio alla testa One-to-Many
Se hai bisogno del formato di output YOLO tradizionale (ad esempio, per riutilizzare il codice di post-elaborazione esistente basato su NMS), puoi passare alla testa one-to-many in qualsiasi momento impostando 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)Compatibilità del formato di esportazione
La maggior parte dei formati di esportazione supporta l'inferenza end-to-end fin da subito, inclusi ONNX, TensorRT, CoreML, OpenVINO, TFLite, TF.js e MNN.
I seguenti formati non supportano end-to-end e tornano automaticamente alla testa one-to-many: NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX e Edge TPU.
TensorRT supporta end-to-end, ma è disabilitato automaticamente quando si esporta con int8=True su TensorRT ≤10.3.0.
Compromessi tra accuratezza e velocità
Il rilevamento end-to-end offre significativi vantaggi di distribuzione con un impatto minimo sull'accuratezza:
| Metrica | End-to-End (predefinito) | One-to-Many + NMS (end2end=False) |
|---|---|---|
| Velocità di inferenza CPU | Fino al 43% più veloce | Baseline |
| Impatto mAP | ~0.5 mAP inferiore | Eguaglia o supera YOLO11 |
| Post-elaborazione | Solo filtro di confidenza | Pipeline NMS completa |
| Complessità di distribuzione | Minima | Richiede l'implementazione di NMS |
Per la maggior parte delle applicazioni del mondo reale, la differenza di ~0.5 mAP è trascurabile, specialmente se si considerano i guadagni in termini di velocità e semplicità. Se la massima accuratezza è la tua priorità assoluta, puoi sempre tornare alla testa one-to-many utilizzando end2end=False.
Consulta le metriche di prestazione di YOLO26 per benchmark dettagliati su tutte le dimensioni del modello (n, s, m, l, x).
Migrazione da YOLOv8 o YOLO11
Se stai aggiornando un progetto esistente a YOLO26, ecco una rapida lista di controllo per garantire una transizione fluida:
- Utenti API / CLI Ultralytics: Nessuna modifica necessaria: basta aggiornare il nome del modello a
yolo26n.pt(oyolo26n-seg.pt,yolo26n-pose.pt,yolo26n-obb.pt) - Codice di post-elaborazione personalizzato: Aggiorna per gestire le nuove forme di output:
(N, 300, 6)per il rilevamento, più dati specifici per il task per segmentazione, pose e OBB. Nota anche il cambio di formato bbox daxywhaxyxy - Pipeline di esportazione: Controlla la sezione compatibilità formato sopra per il tuo formato di destinazione
- TensorRT + INT8: Verifica che la tua versione di TensorRT sia >10.3.0 per il supporto end-to-end
- Esportazioni FP16: Se hai bisogno di tutti gli output in FP16, esporta con
end2end=False: vedi perché output0 rimane FP32 - iOS / CoreML: End-to-end è completamente supportato. Se hai bisogno del supporto Xcode Preview, usa
end2end=Falseconnms=True - Dispositivi Edge (NCNN, RKNN): Questi formati tornano automaticamente a one-to-many, quindi includi NMS nella tua pipeline on-device
FAQ
Posso usare end2end=True e nms=True insieme?
No. Queste opzioni sono mutuamente esclusive. Se imposti nms=True su un modello end-to-end durante l'esportazione, verrà automaticamente forzato a nms=False con un avviso. La testa end-to-end gestisce già internamente il filtraggio dei duplicati, quindi una NMS esterna non è necessaria.
Tuttavia, end2end=False combinato con nms=True è una configurazione valida: integra la NMS tradizionale nel grafico di esportazione. Questo può essere utile per le esportazioni CoreML perché ti consente di utilizzare direttamente la funzione di anteprima in Xcode con il modello di rilevamento.
Cosa controlla il parametro max_det nei modelli end-to-end?
Il parametro max_det (predefinito: 300) imposta il numero massimo di rilevamenti che la testa one-to-one può produrre per immagine. Puoi regolarlo al momento dell'inferenza o dell'esportazione:
model.predict("image.jpg", max_det=100) # fewer detections, slightly faster
model.export(format="onnx", max_det=500) # more detections for dense scenesNota che i checkpoint predefiniti di YOLO26 sono stati addestrati con max_det=300. Sebbene tu possa aumentare questo valore, la testa one-to-one è stata ottimizzata durante l'addestramento per produrre fino a 300 rilevamenti puliti, quindi i rilevamenti oltre tale limite potrebbero essere di qualità inferiore. Se hai bisogno di più di 300 rilevamenti per immagine, considera di riaddestrare con un valore max_det più alto.
Il mio modello ONNX esportato restituisce (1, 300, 6): è corretto?
Yes, that's the expected end-to-end output format for detection: batch size of 1, up to 300 detections, each with 6 values [x1, y1, x2, y2, confidence, class_id]. Simply filter by confidence threshold and you're done — no NMS needed.
Per altri task, la forma di output differisce:
| Attività | Forma di output | Descrizione |
|---|---|---|
| Rilevamento | (1, 300, 6) | [x1, y1, x2, y2, conf, class_id] |
| Segmentazione | (1, 300, 38) + (1, 32, 160, 160) | 6 valori del box + 32 coefficienti di maschera, più un tensore di maschera prototipo |
| Pose | (1, 300, 57) | 6 valori del box + 17 keypoint × 3 (x, y, visibilità) |
| OBB | (1, 300, 7) | 6 valori del box + 1 angolo di rotazione |
Come posso verificare se il mio modello esportato è end-to-end?
Puoi verificarlo utilizzando l'API Python di Ultralytics o ispezionando direttamente i metadati del modello ONNX esportato:
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 enabledIn alternativa, controlla la forma dell'output: i modelli di rilevamento end-to-end restituiscono (1, 300, 6), mentre i modelli tradizionali restituiscono (1, nc + 4, 8400). Per le forme di altri task, consulta le FAQ sulle forme di output.
L'end-to-end è supportato per i task di segmentazione, posa e OBB?
Sì. Tutte le varianti di task di YOLO26 — rilevamento, segmentazione, stima della posa e rilevamento di oggetti orientati (OBB) — supportano l'inferenza end-to-end per impostazione predefinita. Il fallback end2end=False è disponibile anche per tutti i task.
Ogni task estende l'output di rilevamento di base con dati specifici per il task:
| Attività | Modello | Output end-to-end |
|---|---|---|
| Rilevamento | yolo26n.pt | (N, 300, 6) |
| Segmentazione | yolo26n-seg.pt | (N, 300, 38) + proto (N, 32, 160, 160) |
| Pose | yolo26n-pose.pt | (N, 300, 57) |
| OBB | yolo26n-obb.pt | (N, 300, 7) |