Detection Head
Una testa di rilevamento è la parte finale di un rilevatore di oggetti: trasforma le caratteristiche del backbone e del neck in un riquadro e in punteggi di classe in ogni posizione della griglia.
Una testa di rilevamento è l'insieme finale di livelli in una rete di rilevamento di oggetti. Elabora le mappe di caratteristiche prodotte dai livelli precedenti e restituisce, in ogni posizione candidata, un riquadro di delimitazione e un punteggio per ogni classe. Il suo design determina come vengono codificati i riquadri, come offset rispetto ai riquadri di ancoraggio o come distanze da un punto, quanti riquadri candidati produce il modello e se una fase di post-elaborazione come la soppressione dei non massimi (NMS) deve rimuovere i duplicati.
Dove si trova la testa#
I rilevatori moderni sono composti da tre fasi. Un backbone, di solito una rete convoluzionale o un vision transformer, trasforma i pixel in mappe di caratteristiche, la cui risoluzione diminuisce e il cui contenuto semantico aumenta con la profondità. Un neck, come una rete piramidale di caratteristiche (FPN), combina mappe profonde e superficiali, così ogni scala di output contiene sia dettagli fini sia contesto. La testa esegue poi piccoli rami convoluzionali a ogni livello della piramide, in genere con stride 8, 16 e 32: le mappe fini individuano gli oggetti piccoli e quelle grossolane quelli grandi.
I rilevatori a uno stadio hanno un'unica testa densa che produce previsioni in ogni cella della griglia. I rilevatori a due stadi, come Faster R-CNN, ne hanno due: una rete di generazione di proposte di regioni che assegna un punteggio agli ancoraggi in ogni posizione e poi una testa per le regioni di interesse, che classifica e perfeziona le poche centinaia di regioni proposte.
Come una testa prevede riquadri e classi#
In ogni cella della griglia, una testa densa prevede tre tipi di valori:
- Punteggi delle classi: Uno per ogni classe, ciascuno passato attraverso una sigmoide, così una posizione può ricevere un punteggio indipendente per ogni classe.
- Regressione dei riquadri: Quattro numeri che posizionano un riquadro, come offset che spostano e ridimensionano un riquadro di ancoraggio oppure come distanze dal centro della cella ai quattro bordi del riquadro.
- Qualità e output specifici dell'attività: Un punteggio di oggettualità (da YOLOv1 a YOLOv5) o di centralità (FCOS) per ordinare i riquadri, oltre a valori specifici dell'attività, come coefficienti delle maschere per la segmentazione di istanze o keypoint per la stima della posa.
La codifica dei riquadri distingue i rilevatori basati su ancoraggi dai rilevatori anchor-free. Ogni ramo è composto da alcune convoluzioni e termina con una convoluzione 1 × 1, con un canale di output per ogni valore previsto. RetinaNet e FCOS usavano già rami separati per classificazione e regressione; nel 2021 YOLOX ha introdotto questa testa disaccoppiata in YOLO, segnalando una convergenza dell'addestramento molto più rapida rispetto al singolo livello di output condiviso di YOLOv3. Lo schema qui sotto crea i livelli finali 1 × 1 per i tre livelli della piramide di un'immagine 640 × 640 e appiattisce i relativi output in un unico elenco di candidati:
import torch
from torch import nn
# Neck outputs for a 640x640 image at strides 8, 16, and 32 (80x80, 40x40, and 20x20 grids)
channels = (64, 128, 256)
features = [torch.randn(1, c, 640 // s, 640 // s) for c, s in zip(channels, (8, 16, 32))]
# Decoupled head: a box branch (4 values) and a class branch (80 scores) for every pyramid level
box_branches = nn.ModuleList(nn.Conv2d(c, 4, 1) for c in channels)
cls_branches = nn.ModuleList(nn.Conv2d(c, 80, 1) for c in channels)
# Flatten each level's grid and concatenate, giving one candidate per grid cell
boxes = torch.cat([branch(f).flatten(2) for branch, f in zip(box_branches, features)], dim=2)
scores = torch.cat([branch(f).flatten(2) for branch, f in zip(cls_branches, features)], dim=2).sigmoid()
print(f"boxes {tuple(boxes.shape)}, class scores {tuple(scores.shape)}")Stampa boxes (1, 4, 8400), class scores (1, 80, 8400): le 6,400 + 1,600 + 400 celle della griglia propongono ciascuna un riquadro con 80 punteggi di classe.
Dagli output grezzi ai rilevamenti#
L'addestramento determina quante previsioni riceve ogni oggetto. L'assegnazione uno-a-molti contrassegna come positivi diverse celle vicine a ciascun oggetto: fornisce alla testa più segnali di addestramento e lascia in inferenza diversi riquadri sovrapposti per oggetto, quindi NMS mantiene il migliore. L'assegnazione uno-a-uno, usata da DETR e dalla testa di inferenza di YOLOv10, addestra esattamente una previsione per oggetto, quindi gli output non richiedono NMS.
La testa di YOLO26 prevede direttamente le distanze dai quattro bordi, eliminando l'output a 16 bin della Distribution Focal Loss per ciascun bordo usato da YOLOv8 e YOLO11; inoltre, addestra una copia uno-a-molti e una uno-a-uno dei rami per i riquadri e le classi. Per impostazione predefinita YOLO26 applica NMS agli output uno-a-molti; passando nms=False si attivano i rami uno-a-uno, che restituiscono al massimo 300 riquadri per immagine senza passaggio NMS.
La progettazione della testa nella pratica#
- Fine-tuning su nuove classi: Il ramo di classificazione termina con un canale di output per classe; quindi, per addestrare il modello su un dataset con un numero diverso di classi serve un nuovo livello di classificazione finale, mentre si mantengono i pesi preaddestrati di backbone e neck.
- Distribuzione: Ogni operazione della testa viene eseguita sul dispositivo di destinazione, quindi la semplice decodifica dei riquadri e gli output senza NMS agevolano l'esportazione e riducono i tempi di post-elaborazione.
- Oggetti piccoli: Aggiungere un livello della piramide con stride 4 offre alla testa una griglia più fine per gli oggetti minuscoli, a costo di più calcoli: con un input 640 × 640 aggiunge 160 × 160 = 25,600 celle, quattro volte il numero del livello con stride 8.










