Architettura YOLO spiegata: da YOLOv3 a YOLO26#
Ogni modello Ultralytics YOLO è composto da tre fasi: un backbone che estrae le caratteristiche, un neck che le fonde su diverse scale e una head che predice box e classi. Questa guida documenta i moduli che compongono ciascuna fase e come sono cambiati da YOLOv3 a YOLO26, riconducendo ogni componente alla sua definizione nei file di configurazione sotto ultralytics/cfg/models/ e alle classi dei moduli in ultralytics/nn/modules/.
Ogni modello è definito in modo dichiarativo in un file YAML come elenco ordinato di livelli, in cui ogni livello segue il formato [from, repeats, module, args]: quali livelli lo alimentano, quante volte il modulo si ripete, la classe del livello (Conv, C3k2, SPPF, Detect, …) e i relativi argomenti del costruttore. La Guida alla configurazione YAML dei modelli documenta questo formato — compreso il modo in cui repeats e args vengono scalati in base ai moltiplicatori di profondità e larghezza della variante — insieme al sistema completo di risoluzione dei moduli. Questa guida si concentra sui moduli e sulle loro modifiche da una versione all'altra.
Le tre fasi#
Ogni modello Ultralytics YOLO fa passare l'immagine attraverso tre fasi sequenziali, ciascuna con una funzione specifica:
| Fase | Funzione | Output |
|---|---|---|
| Backbone | Estrae caratteristiche dall'immagine in ingresso a più risoluzioni | Mappe delle caratteristiche con stride 8, 16 e 32 (P3, P4, P5) |
| Neck | Fonde le caratteristiche su diverse scale, così che gli oggetti piccoli e grandi dispongano entrambi di un contesto | Mappe delle caratteristiche fuse multiscala |
| Head | Predice box di delimitazione e punteggi di classe dalle caratteristiche fuse | Rilevamenti per punto di ancoraggio |
L'unità fondamentale è il blocco Conv (definito in conv.py): una convoluzione 2D, normalizzazione del batch e un'attivazione SiLU, applicate in sequenza. Ogni modulo più complesso qui sotto è composto da blocchi Conv.
Diagrammi dell'architettura#
Ogni versione mantiene lo stesso scheletro backbone → neck → head e modifica fasi specifiche. Le schede qui sotto mostrano la struttura di ciascuna versione: le fasi del backbone e del neck seguono le configurazioni in ultralytics/cfg/models/, mentre le head di YOLOv3 e YOLOv5 sono rappresentate nella loro forma originale basata su anchor, anziché nella head della variante u senza anchor effettivamente inclusa nelle configurazioni dei rispettivi pacchetti. Esaminando le schede puoi vedere cosa ha aggiunto ogni generazione. In breve, l'evoluzione è la seguente: YOLOv3 è un rilevatore basato su anchor e solo FPN; YOLOv5 aggiunge il percorso PAN bottom-up e SPPF; YOLOv8 passa al blocco C2f con una head senza anchor e DFL; YOLO11 integra l'attenzione C2PSA e il blocco C3k2; YOLO26 aggiunge un residuo SPPF, rimuove DFL e aggiunge una head opzionale senza NMS.
I diagrammi di YOLOv3 e YOLOv5 mostrano la head originale basata su anchor. Il pacchetto ultralytics include le configurazioni senza anchor YOLOv3u e YOLOv5u — gli stessi backbone Darknet-53 e C3 con la head Detect di YOLOv8 — descritte nella sezione Head di rilevamento.
Blocchi del backbone: Bottleneck → C3 → C2f → C3k2#
Il backbone impila un blocco CSP (Cross-Stage Partial) ripetuto tra i livelli di downsampling Conv con stride 2. È proprio questo blocco ripetuto a essere cambiato maggiormente tra le versioni. Tutti i blocchi qui sotto si trovano in block.py; c1/c2 sono i canali di input/output e c = 0.5 * c2 è la larghezza nascosta.
Bottleneck (YOLOv3)#
L'unità di base è Bottleneck: due livelli Conv (kernel predefiniti (3, 3)) con un'addizione residua opzionale quando shortcut=True e c1 == c2. Il backbone Darknet-53 di YOLOv3 li impila direttamente, senza suddivisione CSP, ed esegue il rilevamento a tre scale (stride 8, 16, 32).
C3 (YOLOv5)#
Il C3 di YOLOv5 divide l'input tra due convoluzioni 1x1: cv1 alimenta in sequenza i blocchi Bottleneck di n (kernel (1, 1) e poi (3, 3)), mentre cv2 li bypassa. I due percorsi vengono concatenati e fusi da un terzo 1x1 Conv:
def forward(self, x):
# C3: percorso bottleneck m(cv1(x)) concatenato con il bypass cv2(x), poi fuso da cv3
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))Solo l'output del bottleneck finale raggiunge la convoluzione di fusione, quindi cv3 riceve 2 mappe delle caratteristiche.
C2f (YOLOv8)#
Il C2f di YOLOv8 ("CSP Bottleneck con 2 convoluzioni, più veloce") modifica le caratteristiche che raggiungono la convoluzione di fusione:
cv1 = Conv(c1, 2 * c, 1), quindichunk(2)divide l'output in due tensori conccanali.- I blocchi
Bottleneck(c, c)n(kernel(3, 3),(3, 3)) vengono eseguiti in sequenza; ciascuno riceve l'output del blocco precedente. - Tutti i tensori intermedi
n + 2vengono concatenati e fusi dacv2 = Conv((2 + n) * c, c2, 1).
Mentre C3 invia 2 mappe delle caratteristiche alla propria convoluzione di fusione, C2f ne invia n + 2 — riutilizzando ogni output intermedio del bottleneck.
C3k2 (YOLO11 e YOLO26)#
YOLO11 e YOLO26 usano C3k2, una sottoclasse di C2f che sostituisce l'unità ripetuta. Ciascuno dei blocchi n diventa, a seconda dei flag del costruttore:
- un semplice
Bottleneck(predefinito,c3k=False), - un blocco
C3k(c3k=True) — una varianteC3con dimensione del kernel configurabile, oppure - una coppia
Bottleneck+PSABlock(attn=True).
Il secondo argomento YAML imposta c3k, a meno che la scala non sia m, l o x, casi in cui viene forzato a True — così un unico yolo11.yaml serve tutte e cinque le varianti. Quindi [-1, 2, C3k2, [512, False]] costruisce componenti interni Bottleneck con n e s, ma componenti interni C3k con m, l e x; 512 è il numero di canali prima del ridimensionamento, che il moltiplicatore di larghezza della variante porta a 128 con n e a 768 con x. Per i moduli CSP, il campo repeats — qui pari a 2, prima del ridimensionamento tramite il moltiplicatore di profondità della variante — diventa il numero di ripetizioni interne del blocco, anziché determinare l'impilamento di moduli separati.
Pooling spaziale: SPP → SPPF#
Alla fine del backbone, un blocco di pooling a piramide spaziale amplia il campo ricettivo. YOLOv5 ha sostituito SPP multi-kernel originale con SPPF (Spatial Pyramid Pooling - Fast): un singolo MaxPool2d(kernel_size=5, stride=1, padding=2) applicato n = 3 volte in sequenza, concatenando l'input e tutti e tre gli output del pooling e fondendoli con un 1x1 Conv. È matematicamente equivalente a SPP(k=(5, 9, 13)), ma più efficiente, perché i pooling concatenati 5x5 coprono i campi ricettivi dei kernel più grandi.
YOLO26 passa un flag shortcut (SPPF, [1024, 5, 3, True]); poiché c1 == c2 == 1024 si trova al livello più profondo, SPPF aggiunge una connessione residua (return y + x).
Attenzione spaziale: C2PSA (YOLO11+)#
YOLO11 ha aggiunto C2PSA dopo SPPF. È un blocco CSP il cui ramo attivo è una pila di moduli n PSABlock (Position-Sensitive Attention): cv1 = Conv(c1, 2 * c, 1) divide le caratteristiche, una metà attraversa la pila PSABlock e cv2 = Conv(2 * c, c1, 1) fonde la concatenazione. Ogni PSABlock applica l'attenzione multi-head seguita da una rete feed-forward a due livelli (Conv(c, 2 * c, 1) → Conv(2 * c, c, 1)), entrambi con connessione residua. YOLO26 mantiene lo stesso backbone C3k2 + C2PSA.
Neck: FPN + PAN#
Il neck fonde le mappe delle caratteristiche P3/P4/P5 del backbone con una Feature Pyramid Network (FPN) dall'alto verso il basso, seguita da una Path Aggregation Network (PAN) dal basso verso l'alto. Nella sezione head del file YAML, FPN è nn.Upsample + Concat (trasporta le informazioni semantiche verso risoluzioni più alte), mentre PAN è Conv + Concat con stride 2 (riporta verso l'alto le informazioni di localizzazione):
# YOLO11 head (FPN top-down, then PAN bottom-up)
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 2, C3k2, [512, False]] # 13
# ... second upsample + concat to P3 ...
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 13], 1, Concat, [1]] # cat head P4 (PAN)
- [-1, 2, C3k2, [512, False]] # 19Il neck riutilizza il blocco del backbone della propria generazione — C3 in YOLOv5, C2f in YOLOv8, C3k2 in YOLO11 e YOLO26 — quindi ogni punto di fusione esegue lo stesso modulo usato dal backbone. I tre output fusi alimentano la head. YOLOv3 fa eccezione: il suo neck è solo una FPN dall'alto verso il basso (la sua sezione head YAML non contiene downsampling con stride 2), senza il percorso PAN dal basso verso l'alto introdotto da YOLOv5.
Head di rilevamento: basata su anchor → senza anchor → senza NMS#
La head converte le tre mappe delle caratteristiche fuse in predizioni per il task di rilevamento. Il suo design è cambiato nel corso delle versioni, passando da basato su anchor a senza anchor, fino a senza NMS.
Detect senza anchor e disaccoppiata#
YOLOv3 e YOLOv5 originali usavano una head basata su anchor e accoppiata: box di ancoraggio predefiniti e un ramo condiviso per le predizioni di box e classi. I repository indipendenti ultralytics/yolov3 e ultralytics/yolov5 mantengono questo design basato su anchor. Il pacchetto principale ultralytics include invece le varianti senza anchor YOLOv3u e YOLOv5u — gli stessi backbone Darknet-53 e C3 con la head Detect senza anchor di YOLOv8 — e le configurazioni yolov3.yaml e yolov5.yaml documentate qui corrispondono a queste varianti u, non al design storico.
La head Detect (head.py) è senza anchor e disaccoppiata: per ogni livello della piramide esegue due rami paralleli e predice direttamente sui punti della griglia, anziché rispetto a box di ancoraggio.
- Ramo box (
cv2):Conv(x, c2, 3)→Conv(c2, c2, 3)→Conv2d(c2, 4 * reg_max, 1). - Ramo classi (
cv3): in YOLO11 e YOLO26, due blocchi separabili in profondità (DWConv+1x1 Conv) →Conv2d(c3, nc, 1); YOLOv8 usa la variante precedente, con due livelli3x3 Conv→Conv2d(c3, nc, 1).
Ogni punto di ancoraggio produce quindi no = nc + 4 * reg_max output. Eliminando gli anchor predefiniti, si rimuovono dalle iperparametri da ottimizzare le dimensioni e i rapporti d'aspetto dei box di ancoraggio.
Distribution Focal Loss (DFL)#
YOLOv8 e YOLO11 regrediscono ciascuna delle 4 coordinate del box come distribuzione su reg_max = 16 bin, anziché come singolo valore scalare (la formulazione integrale della Generalized Focal Loss). Il modulo DFL rimodella i 4 * reg_max canali del box in (4, reg_max), applica una softmax sui reg_max bin e prende come coordinata predetta l'indice atteso del bin — ossia la somma degli indici di ciascun bin ponderati per la rispettiva probabilità softmax. Questa operazione è implementata come una convoluzione 1x1 fissa, i cui pesi sono gli indici dei bin arange(reg_max), quindi la somma ponderata corrisponde a un singolo prodotto scalare.
YOLO26: senza NMS e senza DFL#
YOLO26 imposta due parametri YAML letti direttamente dalla head:
end2end: True—Detectcopia in profondità i suoi rami in una head one-to-one (one2one_cv2/one2one_cv3) che impara una singola predizione per oggetto. Questa impostazione YAML crea entrambe le head di addestramento; in fase di esecuzione,nms=Falseseleziona la head one-to-one e rimuove il passaggio di post-elaborazione Non-Maximum Suppression (NMS). Consulta la guida al rilevamento end-to-end per i dettagli sull'inferenza e sull'esportazione.reg_max: 1— con un solo bin,self.dfldiventann.Identity()eno = nc + 4; la head regredisce direttamente le coordinate e nel grafo ONNX esportato non compare alcuna operazione DFL.
Nelle sue cinque dimensioni di modello (n/s/m/l/x), YOLO26 raggiunge 40.9-57.5 mAP su COCO con una latenza TensorRT T4 di 1.7-11.8 ms, come riportato nell'articolo di YOLO26.
Riepilogo versione per versione#
| Versione | Blocco del backbone | Pooling spaziale | Attenzione | Head di rilevamento | DFL |
|---|---|---|---|---|---|
| YOLOv3 | Darknet-53 (Bottleneck) | nessuno nella configurazione di base | nessuna | Originale: basata su anchor; variante u: senza anchor | no / sì (u) |
| YOLOv5 | C3 (CSP) | SPPF | nessuna | Originale: basata su anchor; variante u: senza anchor | no / sì (u) |
| YOLOv8 | C2f | SPPF | nessuna | Senza anchor, disaccoppiata | sì (reg_max=16) |
| YOLO11 | C3k2 | SPPF | C2PSA | Senza anchor, disaccoppiata | sì (reg_max=16) |
| YOLO26 | C3k2 | SPPF + shortcut | C2PSA | Senza anchor, doppia head; NMS opzionale | rimosso (reg_max=1) |
Per i dettagli sui singoli modelli, le tabelle delle prestazioni e gli esempi d'uso, consulta le pagine dedicate a YOLOv3, YOLOv5, YOLOv8, YOLO11 e YOLO26.
Esamina direttamente l'architettura#
Il metodo model.info() stampa un riepilogo di livelli, parametri e FLOPs; l'elenco dei moduli analizzati è disponibile su model.model.model.
from ultralytics import YOLO
# Carica un modello preaddestrato
model = YOLO("yolo11n.pt")
# Fondi i livelli Conv + BatchNorm per far corrispondere i conteggi alle specifiche pubblicate
model.fuse()
# Stampa un riepilogo: livelli, parametri, gradienti, GFLOPs
model.info()
# Esamina la head di rilevamento (l'ultimo modulo della rete)
head = model.model.model[-1]
print(type(head).__name__, "| reg_max:", head.reg_max, "| DFL layer:", type(head.dfl).__name__)Eseguendo lo snippet su tre generazioni, le modifiche emergono chiaramente dai numeri. Si tratta di output reali di modelli fusi del pacchetto ultralytics, che corrispondono ai conteggi di parametri e FLOPs pubblicati su ciascuna pagina del modello:
| Modello | Livelli | Parametri | GFLOPs | reg_max | Livello DFL |
|---|---|---|---|---|---|
| YOLOv8n | 72 | 3,151,904 | 8.7 | 16 | DFL |
| YOLO11n | 100 | 2,616,248 | 6.5 | 16 | DFL |
| YOLO26n | 120 | 2,408,932 | 5.5 | 1 | Identity |
YOLO26n riporta reg_max=1 e un livello DFL Identity. Per impostazione predefinita, la predizione e la validazione usano one-to-many con NMS; imposta nms=False per l'inferenza senza NMS. Entrambe le head vengono addestrate.
I valori di parametri e FLOPs sono riportati per il modello fuso (model.fuse()), che unisce ogni Conv al relativo livello di normalizzazione del batch. Questo corrisponde alle specifiche pubblicate; un checkpoint appena caricato mostra conteggi leggermente superiori prima della fusione.
Conclusione#
Nel corso delle versioni, l'architettura YOLO è cambiata una fase alla volta: il backbone è passato da Darknet-53 a blocchi C3, C2f e C3k2 basati su CSP, con attenzione C2PSA; il neck ha mantenuto la struttura FPN + PAN, mentre SPP è diventato SPPF; la head è passata da basata su anchor a senza anchor, per poi arrivare al design di YOLO26 senza DFL e con una head end-to-end opzionale senza NMS.
Per definire architetture personalizzate, consulta la Guida alla configurazione YAML del modello oppure confronta i modelli nelle pagine dei modelli. Per domande, contattaci su GitHub o Discord.
Domande frequenti#
Un modello YOLO ha un backbone che estrae caratteristiche dall'immagine con stride 8, 16 e 32, un neck che fonde queste caratteristiche su scale diverse con FPN e PAN e una head che predice bounding box e punteggi di classe. Tutti i modelli Ultralytics YOLO da YOLOv3 a YOLO26 seguono questo design a tre stadi.
C2f(YOLOv8) è un blocco CSP che concatena gli output di ogniBottleneck— mappe di caratteristichen + 2— prima della convoluzione di fusione, mentre il precedenteC3ne trasferisce solo 2.C3k2(YOLO11 e YOLO26) è una sottoclasse diC2fche può sostituire ogniBottleneckcon un bloccoC3k(una varianteC3con dimensione del kernel configurabile) quando è attivo il flagc3k. Entrambi sono definiti inblock.py.YOLO11 apporta tre modifiche strutturali a YOLOv8: sostituisce il blocco del backbone e del neck
C2fconC3k2, inserisce un blocco di self-attentionC2PSAdopoSPPFe passa a convoluzioni depthwise separable più leggere nel ramo di classificazione della head. Entrambi mantengono la stessa headDetectdisaccoppiata e anchor-free con regressione DFLreg_max=16, quindi le modifiche riducono i conteggi di parametri e FLOPs aumentando l'accuratezza, anziché riprogettare l'interfaccia di rilevamento.I moderni modelli Ultralytics YOLO sono anchor-free. YOLOv8, YOLO11 e YOLO26 usano una head
Detectdisaccoppiata e anchor-free, con rami separati per la regressione delle bounding box e la classificazione. Gli originali YOLOv3 e YOLOv5 erano basati su anchor, ma Ultralytics li distribuisce nelle varianti YOLOv3u e YOLOv5u, le cui configurazioni usano la stessa head anchor-free di YOLOv8.Sì: YOLO26 include una head one-to-one che supporta l'inferenza senza NMS con
nms=False. Il percorso di inferenza predefinito one-to-many usa NMS ed entrambe le head ricevono supervisione durante l'addestramento. Per i dettagli, consulta la Guida al rilevamento end-to-end.La DFL regredisce ogni coordinata della box come una distribuzione softmax su
reg_maxbin (16 per impostazione predefinita in YOLOv8 e YOLO11) e usa il valore atteso come coordinata, invece di predire un singolo scalare. YOLO26 impostareg_max=1, così il livello DFL diventa un'operazione identità, la head regredisce direttamente le coordinate e nei grafi ONNX o TensorRT esportati non compare alcuna operazione DFL.Carica il modello in Python e chiama
model.info()per ottenere un riepilogo dei livelli, dei parametri e dei GFLOPs. I livelli analizzati si trovano inmodel.model.model: per esempio,model.model.model[-1]è la headDetected espone attributi comereg_maxedfl. L'intera architettura è definita nel file di configurazione YAML del modello.