Ultralytics YOLO27: Iscriviti alla lista d'attesa.
Get Started
Oltre il rilevamento: segmentazione, posa, OBB e classificazione·Classifica, combina, spedisci·Lezione 8/10
Lezioneintermedio

Addestra un classificatore di immagini

Organizza un dataset in cartelle, addestra yolo26n-cls.pt su MNIST160, leggi le probabilità e l'accuratezza top-1 e invia le predizioni con bassa confidenza a una revisione umana.

La classificazione delle immagini risponde a una domanda per immagine: che cos'è? Richiede le etichette più economiche tra tutte le attività — il nome di una cartella — ed è l'opzione più veloce, perciò è la seconda fase predefinita dopo un rilevatore e il modello iniziale ideale per una stazione di ispezione che acquisisce un singolo componente per fotogramma. Il dataset non ha un file YAML, quindi la struttura delle cartelle definisce il contratto; inoltre, un classificatore fornisce sempre una risposta, anche per immagini che non assomigliano a nulla di ciò che ha già visto. Capire quando non fidarsi del risultato è metà del lavoro.

Esito

Addestra yolo26n-cls.pt su MNIST160, riporta l'accuratezza top-1, leggi le probabilità delle classi da result.probs e scegli una soglia di confidenza che invii le immagini incerte alla revisione.

Percorso rapido
Se sai già come muoverti, ecco la versione breve.
  1. Inserisci le immagini in train/<class>/ e val/<class>/; i nomi delle cartelle diventano i nomi delle classi, ordinati alfabeticamente.

  2. yolo classify train data=mnist160 model=yolo26n-cls.pt epochs=1 imgsz=64.

  3. Valuta il modello in base all'accuratezza top-1 (metrics.top1); con cinque classi o meno, top-5 è sempre 1.0.

  4. Leggi result.probs.top1 e .top1conf e invia a una persona le predizioni sotto una soglia di confidenza.

Pratico

La struttura del dataset in cartelle#

Classificazione di immagini Ultralytics YOLO di tre foglie etichettate come sana, ruggine e oidio, ciascuna con il relativo livello di confidenza

I dataset di classificazione sono directory, non file YAML. Imposta data= sulla cartella radice:

parts/
├── train/
│   ├── good/      img_0001.jpg ...
│   ├── scratch/   img_0412.jpg ...
│   └── dent/      img_0733.jpg ...
└── val/
    ├── good/
    ├── scratch/
    └── dent/

Ecco cosa fa il caricatore, in base al codice sorgente installato e alla guida ai dataset di classificazione:

SituazioneComportamento
Indici delle classinomi delle cartelle in train/, in ordine alfabetico → dent=0, good=1, scratch=2
Cartella di validazioneval/, poi validation/, poi valid/; in assenza di queste, usa test/ e mostra un avviso
Nessuna cartella train/, solo cartelle delle classisuddivide automaticamente i dati in train/ e val/ con una proporzione 80/20

Sulla Ultralytics Platform, un dataset di classificazione contiene un'etichetta a livello di immagine per ogni immagine, anziché forme:

Dataset di classificazione sulla Ultralytics Platform: un nastro trasportatore con scatole bianche, ciascuna con una singola etichetta a livello di immagine, class2, scelta dal pannello delle classi

Una nuova cartella rinumera le classi

Sintomo: dopo aver aggiunto una classe, una vecchia integrazione segnala le parti good come dent. Causa: l'aggiunta di una cartella chiamata bent la ordina per prima e sposta tutti gli indici successivi. Soluzione: mappa sempre gli indici ai nomi con model.names (o result.names); non codificare mai un indice in modo fisso.

Addestra su MNIST160#

MNIST160 contiene 160 cifre scritte a mano, 80 in train/ e 80 in test/, ciascuna suddivisa in dieci cartelle, una per cifra: un dataset abbastanza piccolo per un test rapido su CPU. Non ha una cartella val/, quindi verifica che il caricatore mostri l'avviso e usi come alternativa test/:

from ultralytics import YOLO

model = YOLO("yolo26n-cls.pt")
model.train(data="mnist160", epochs=1, imgsz=64, device="cpu")
metrics = model.val()
print(f"top-1: {metrics.top1:.3f}  top-5: {metrics.top5:.3f}")
WARNING ⚠️ Dataset 'split=val' not found, using 'split=test' instead.
val: .../datasets/mnist160/test... found 80 images in 10 classes ✅
                   all      0.162      0.463
top-1: 0.162  top-5: 0.463

Un'epoca sposta appena la nuova testa a dieci classi. Nella nostra esecuzione, epochs=10 ha raggiunto un'accuratezza top-1 di 0.55 e top-5 di 0.95 in circa dieci secondi su una CPU di laptop: il ciclo funziona, ma serve un programma di addestramento. La guida all'attività Classify elenca le dimensioni dei modelli preaddestrati.

Top-1 è la percentuale di immagini per cui la classe con probabilità più alta è corretta. Top-5 considera corretta una predizione se la classe giusta compare tra le cinque con probabilità più alta. Top-5 è utile per ImageNet, con 1.000 classi (ImageNet), che vanno da categorie ampie a categorie molto specifiche; con cinque classi o meno è sempre 1.0 e con dieci è fin troppo generosa. Valuta il modello in base all'accuratezza top-1 (accuratezza) e a una matrice di confusione per classe.

Immagini di esempio di ImageNet organizzate da classi ampie a classi più specifiche, ad esempio da mammifero a husky e da veicolo a trimarano

Leggi le probabilità nel codice#

from ultralytics import YOLO

model = YOLO("yolo26n-cls.pt")  # ImageNet, 1,000 classes
result = model("https://ultralytics.com/images/bus.jpg")[0]

probs = result.probs
print(f"top-1: {result.names[probs.top1]} ({float(probs.top1conf):.2f})")
for i, conf in zip(probs.top5, probs.top5conf.tolist()):
    print(f"  {result.names[i]:20s} {conf:.3f}")
top-1: minibus (0.52)
  minibus              0.516
  police_van           0.369
  trolleybus           0.096
  minivan              0.006
  ambulance            0.003

probs.top1 è un indice, probs.top5 è un elenco di indici e probs.data è il vettore completo delle probabilità. Nota la confidenza top-1: 0.52 è appena superiore al lancio di una moneta per scegliere tra minibus e police_van. È su questo valore che basi l'instradamento.

Invia le predizioni incerte a una persona#

In produzione, raramente serve che un classificatore indovini ogni immagine; deve invece essere corretto sulle immagini che decide di classificare da solo. Questo script addestra il modello per 10 epoche, poi misura l'effetto di diverse soglie di confidenza sugli 80 numeri tenuti da parte:

from pathlib import Path

from ultralytics import YOLO

model = YOLO("yolo26n-cls.pt")
model.train(data="mnist160", epochs=10, imgsz=64, device="cpu", plots=False)  # model now holds best.pt
print(model.names)  # folder names, sorted, became class indices

test = Path(model.trainer.data["test"])  # mnist160/test, the split the loader validated on
images = sorted(test.rglob("*.png"))
results = model(images, imgsz=64, verbose=False)
truth = [p.parent.name for p in images]

for threshold in (0.0, 0.3, 0.6):
    kept = [(r, t) for r, t in zip(results, truth) if r.probs.top1conf >= threshold]
    correct = sum(r.names[r.probs.top1] == t for r, t in kept)
    print(f"threshold {threshold:.1f}: auto-accept {len(kept):2d}/{len(images)}, accuracy on accepted {correct / max(len(kept), 1):.0%}")
{0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9'}
threshold 0.0: auto-accept 80/80, accuracy on accepted 55%
threshold 0.3: auto-accept 41/80, accuracy on accepted 68%
threshold 0.6: auto-accept 10/80, accuracy on accepted 80%

Ogni riga rappresenta un compromesso: alzando la soglia, le predizioni accettate diventano più accurate e un maggior numero di immagini viene inviato a una persona. Con 0.6, questo modello classifica da solo solo 10 degli 80 numeri: non è ancora pronto per automatizzare nulla e la soluzione è addestrarlo di più, non scegliere una soglia più ingegnosa. Ripeti la stessa tabella dopo ogni ciclo di addestramento: ti indica sia l'accuratezza prevista sia l'esatta quantità di lavoro di revisione che genera ciascuna soglia.

Regola decisionale

Scegli la soglia più bassa la cui accuratezza sulle immagini accettate soddisfi il tuo requisito, misurandola su dati di test mai usati in addestramento. Poi verifica che il volume di revisioni che genera sia gestibile dal tuo team; in caso contrario, migliora il modello.

Insidie#

Nessuna classe «nessuna delle precedenti»

Sintomo: una stazione vuota, un pezzo errato o una mano davanti all'obiettivo ricevono un'etichetta di classe con elevata sicurezza. Causa: le probabilità softmax sommano sempre a 1, quindi il classificatore sceglie sempre una delle sue classi. Soluzione: aggiungi una cartella other/ contenente esclusivamente quelle immagini e invia in revisione le predizioni top1conf con bassa confidenza.

Validazione di una testa preaddestrata su nuove cartelle

Sintomo: un modello preaddestrato ottiene un punteggio vicino a zero sul tuo dataset prima di qualsiasi addestramento. Causa: yolo26n-cls.pt predice 1.000 indici ImageNet, mentre le tue cartelle riutilizzano gli indici 0–9 con significati diversi: in MNIST160, la cartella 0 è l'indice 0, che la testa preaddestrata chiama tench. In questo modo abbiamo misurato un top-1 pari a 0.000. Soluzione: esegui prima il fine-tuning, poi la validazione.

Cartelle con dati sovrapposti

Sintomo: top-1 vicino a 1.0 in validazione, molto più basso in produzione. Causa: foto quasi identiche dello stesso pezzo in train/ e val/. Soluzione: suddividi per pezzo o per sessione, come descritto in Suddividi correttamente il dataset.

I classificatori sono preaddestrati con imgsz=224, non con 640. Per gli oggetti piccoli all'interno di un fotogramma grande è più adatto rilevare e poi classificare (lezione successiva) che usare un imgsz più grande.

Provalo

Addestra yolo26n-cls.pt su mnist160 per 1 epoca, poi per 10 epoche con imgsz=64, e registra i valori top-1 e top-5 per entrambe le esecuzioni. Stampa model.names per verificare come i nomi delle cartelle sono diventati indici di classe. Poi esegui route.py e scegli la soglia che useresti in produzione per ottenere almeno il 75% di accuratezza sulle immagini accettate automaticamente.

Criteri di completamento
La lezione è completata quando tutte le seguenti condizioni sono soddisfatte.
  • Hai i valori top-1 e top-5 per un'esecuzione di 1 epoca e una di 10 epoche.

  • Hai stampato model.names e sai spiegare la regola degli indici in ordine alfabetico e perché top-5 è inutile per un problema con cinque classi.

  • Hai indicato una soglia, la sua accuratezza sulle immagini accettate e quante delle 80 immagini invia alla revisione.

Mostra la soluzione
from ultralytics import YOLO

for epochs in (1, 10):
    model = YOLO("yolo26n-cls.pt")
    model.train(data="mnist160", epochs=epochs, imgsz=64, device="cpu")
    metrics = model.val()
    print(f"{epochs:2d} epochs  top-1: {metrics.top1:.3f}  top-5: {metrics.top5:.3f}")
print(model.names)  # {0: '0', 1: '1', ..., 9: '9'}

I risultati delle nostre esecuzioni: 1 epoca → top-1 0.162, top-5 0.463; 10 epoche → top-1 0.550, top-5 0.950. Con cinque classi, la risposta corretta rientra sempre nelle prime cinque, quindi top-5 è 1.0 per definizione e non fornisce alcuna informazione.

Per raggiungere un'accuratezza del 75% sulle immagini accettate, route.py indica 0.6 (80% su 10 immagini accettate), che invia 70 degli 80 numeri alla revisione. Questa è la risposta onesta: la soglia soddisfa il requisito di accuratezza, ma il modello non è ancora utile. Prima di scegliere una soglia per l'uso reale, addestra il modello più a lungo e ripeti la tabella.

Prossimi passi

Ora concateneremo le attività: un rilevatore che alimenta un classificatore e un modello di posa che alimenta un tracker.

Accedi per salvare i progressi