Ultralytics YOLO27: Iscriviti alla lista d'attesa.
Inizia

Come ottimizzare YOLO su un dataset personalizzato

La messa a punto adatta un modello preaddestrato al riconoscimento di nuove classi partendo dai pesi appresi anziché da un'inizializzazione casuale. Invece di addestrare da zero per centinaia di epoche, la messa a punto riutilizza le caratteristiche preaddestrate di COCO e converge sui dati personalizzati in una frazione del tempo.

Questa guida illustra l'ottimizzazione fine di YOLO26 su dataset personalizzati, dall'uso di base a tecniche avanzate come il congelamento dei layer e l'addestramento in due fasi.

Ottimizzazione fine o addestramento da zero#

Un modello pretrained ha già appreso caratteristiche visive generali — rilevamento dei bordi, riconoscimento delle texture e comprensione delle forme — da milioni di immagini. Il transfer learning tramite ottimizzazione fine riutilizza queste conoscenze e insegna al modello soltanto l'aspetto delle nuove classi, consentendo una convergenza più rapida e richiedendo meno dati. L'addestramento da zero elimina tutto questo e costringe il modello ad apprendere ogni aspetto partendo dai pattern a livello di pixel, richiedendo molte più risorse. Consulta la guida alla configurazione YAML del modello per scoprire in che modo i file .yaml che definiscono solo l'architettura differiscono dai checkpoint.

Ottimizzazione fineAddestramento da zero
Pesi inizialiPretrained su COCO (80 classi)Inizializzazione casuale
ComandoYOLO("yolo26n.pt")YOLO("yolo26n.yaml")
ConvergenzaPiù rapida: il backbone è già addestratoPiù lenta: tutti i layer apprendono da zero
Requisiti dei datiInferiori: le caratteristiche pretrained compensano la minore quantità di datiSuperiori: il modello deve apprendere tutte le caratteristiche solo dal dataset
Quando usarlaClassi personalizzate con immagini naturaliDomini fondamentalmente diversi da COCO (medicina, satellite, radar)
L'ottimizzazione fine non richiede codice aggiuntivo

Quando un file .pt viene caricato con YOLO("yolo26n.pt"), i pesi preaddestrati vengono memorizzati nel modello. La chiamata a .train(data="custom.yaml") trasferisce automaticamente tutti i pesi compatibili alla nuova architettura del modello, reinizializza i layer non corrispondenti (come il layer di classificazione finale quando il numero di classi è diverso) e avvia l'addestramento. Non è necessario caricare manualmente i pesi, manipolare i layer o scrivere codice personalizzato per il transfer learning.

Come funziona il trasferimento dei pesi pretrained#

Quando si ottimizza un modello pretrained su un dataset con un numero diverso di classi (ad esempio, passando dalle 80 classi di COCO a 5 classi personalizzate), Ultralytics esegue il trasferimento dei pesi tenendo conto delle forme:

  1. Il backbone e il neck vengono trasferiti completamente: questi layer estraggono caratteristiche visive generali e le loro forme non dipendono dal numero di classi.
  2. La head di rilevamento viene reinizializzata parzialmente - solo la convoluzione finale di ciascun ramo di classificazione (cv3, one2one_cv3) ha una forma legata al numero di classi (80 contro 5); i layer nascosti del ramo vengono trasferiti quando entrambi i modelli condividono una scala. Le righe compatibili i cui nomi delle classi corrispondono vengono rimappate prima di inizializzare quelle non corrispondenti. I layer di regressione delle box (cv2, one2one_cv2) nella head hanno forme fisse indipendentemente dal numero di classi, quindi vengono trasferiti normalmente.
  3. La stragrande maggioranza dei pesi viene trasferita quando si cambia il numero di classi. Ad esempio, il fine-tuning di YOLO26n da COCO (80 classi) a un dataset con 5 classi trasferisce 696 dei 708 tensori dei pesi, oltre alle righe di classificazione compatibili abbinate in base al nome.

Per i dataset con lo stesso numero di classi del modello pretrained (ad esempio, ottimizzando pesi pretrained su COCO su un altro dataset di 80 classi), viene trasferito il 100% dei pesi, inclusa la testa di rilevamento.

Trasferire classi con nomi alternativi#

Ultralytics trasferisce le righe corrispondenti della testa di classificazione tra dataset in base al nome della classe, ignorando maiuscole, minuscole e spazi iniziali o finali. Se classi equivalenti hanno nomi diversi, rinomina in memoria le classi del checkpoint sorgente prima di caricarlo. In questo modo si preservano i pesi di classificazione pretrained per i concetti condivisi, che altrimenti verrebbero considerati senza corrispondenza e inizializzati casualmente.

Questo esempio di passaggio da Objects365 v2 a COCO rinomina le classi sorgente nel checkpoint caricato; train() le passa quindi come pesi pretrained:

from ultralytics import YOLO

# # Nome della classe sorgente Objects365 v2 (in minuscolo) -> nome della classe di destinazione COCO
ALIASES = {
    "wild bird": "bird",
    "handbag/satchel": "handbag",
    "luggage": "suitcase",
    "bowl/basin": "bowl",
    "orange/tangerine": "orange",
    "monitor/tv": "tv",
    "stuffed toy": "teddy bear",
    "hair dryer": "hair drier",
}

model = YOLO("path/to/yolo26s-objects365.pt")
# # I nomi delle classi Objects365 sono in formato Titolo, quindi confrontali in minuscolo
model.model.names = {i: ALIASES.get(name.lower(), name) for i, name in model.model.names.items()}
model.train(data="coco.yaml", epochs=100, imgsz=640)

L'impostazione cls_remap abilita per impostazione predefinita questo trasferimento basato sui nomi. Durante l'addestramento viene stampato Remapped N/M cls head rows from pretrained weights by class name quando vengono copiate righe compatibili; imposta cls_remap=False per disabilitarlo.

Esempio di ottimizzazione fine di base#

Esempio
from ultralytics import YOLO

model = YOLO("yolo26n.pt")  # carica il modello preaddestrato
model.train(data="custom.yaml", epochs=50, imgsz=640)

Scegliere la dimensione del modello#

I modelli più grandi hanno maggiore capacità, ma anche più parametri da aggiornare, il che può aumentare il rischio di overfitting quando i dati di addestramento sono limitati. Un approccio pratico consiste nell'iniziare con un modello più piccolo (YOLO26n o YOLO26s e aumentare le dimensioni solo se le metriche di convalida si stabilizzano. Le dimensioni del modello ottimali dipendono dalla complessità del compito, dal numero di classi, dalla diversità del dataset e dall'hardware disponibile per la distribuzione.

Scelta dell'ottimizzatore e del tasso di apprendimento#

L'impostazione predefinita optimizer=auto seleziona l'ottimizzatore e il tasso di apprendimento in base al numero totale di iterazioni di addestramento:

  • 10.000 iterazioni o meno (dataset piccoli o poche epoche): AdamW con un tasso di apprendimento basso, calcolato automaticamente
  • Oltre 10.000 iterazioni (dataset di grandi dimensioni): MuSGD (un ottimizzatore ibrido Muon+SGD) con lr=0.01

Per la maggior parte delle attività di ottimizzazione fine, l'impostazione predefinita funziona bene senza regolazioni manuali. Valuta di impostare esplicitamente l'ottimizzatore nei seguenti casi:

  • Addestramento instabile (la perdita aumenta improvvisamente o diverge): prova optimizer=AdamW, lr0=0.001 per una convergenza più stabile
  • Ottimizzazione fine di un modello grande su un dataset piccolo: un ottimizzatore esplicito con un tasso di apprendimento più basso, come optimizer=AdamW, lr0=0.001, può aiutare a preservare le caratteristiche pretrained
L'ottimizzatore automatico ignora lr0 manuale

Quando è impostato optimizer=auto, il valore lr0 viene ignorato. Per controllare manualmente il tasso di apprendimento, imposta esplicitamente l'ottimizzatore: optimizer=SGD, lr0=0.005.

Congelamento dei layer#

Il congelamento impedisce a determinati layer di aggiornarsi durante l'addestramento. Questo accelera l'addestramento e riduce l'overfitting quando il dataset è piccolo rispetto alla capacità del modello.

Il parametro freeze accetta un intero o un elenco. Un intero freeze=10 congela i primi 10 layer (indici 0-9), che comprendono gran parte del backbone di YOLO26. Il backbone si estende dai layer 0 a 10, quindi freeze=10 lascia addestrabile il blocco C2PSA finale (layer 10); usa freeze=11 per congelare l'intero backbone. Un elenco può contenere indici di layer, come freeze=[0, 3, 5], per congelare parzialmente il backbone, oppure stringhe con i nomi dei moduli, come freeze=["23.cv2", "23.one2one_cv2"], per controllare nel dettaglio rami specifici all'interno di un layer (in questo caso, entrambi i rami di regressione dei box della testa di rilevamento).

Esempio
from ultralytics import YOLO

model = YOLO("yolo26n.pt")
model.train(data="custom.yaml", epochs=50, freeze=10)

La profondità di congelamento ideale dipende da quanto il dominio di destinazione è simile ai dati di preaddestramento e dalla quantità di dati di addestramento disponibile:

ScenarioConsiglioMotivazione
Dataset ampio, dominio similefreeze=None (predefinito)Dati sufficienti per adattare tutti i layer senza overfitting
Dataset piccolo, dominio similefreeze=10Mantiene le feature del backbone e riduce i parametri addestrabili
Dataset molto piccolofreeze=23Si addestra solo la testa di rilevamento, riducendo al minimo il rischio di overfitting
Dominio molto diverso da COCOfreeze=NoneLe feature del backbone potrebbero non essere trasferibili in modo efficace e potrebbero richiedere un nuovo addestramento

Anche la profondità di congelamento può essere trattata come un iperparametro: provare alcuni valori (0, 5, 10) e confrontare mAP di convalida è un modo pratico per trovare l'impostazione migliore per un dataset specifico.

Iperparametri chiave per il fine-tuning#

In genere, il fine-tuning richiede meno modifiche agli iperparametri rispetto all'addestramento da zero. I parametri più importanti sono:

  • epochs: il fine-tuning converge più rapidamente dell'addestramento da zero. Inizia con un valore moderato e usa patience per interrompere in anticipo quando le metriche di validazione si stabilizzano.
  • patience: il valore predefinito di 100 è pensato per addestramenti lunghi. Ridurlo a 10-20 evita di sprecare tempo in esecuzioni già convergenti.
  • warmup_epochs: il warmup porta gradualmente il learning rate al valore previsto dal programma durante le prime epoche, così i batch iniziali hanno meno probabilità di alterare le feature preaddestrate. Mantienilo diverso da zero durante il fine-tuning, ma non è necessario usare il valore predefinito di 3 epoche: la ricerca evolutiva alla base del fine-tuning ufficiale di YOLO26 su COCO — una continuazione di più epoche a partire dai pesi di Objects365 — ha stabilito circa un'epoca per ogni dimensione del modello.

Per l'elenco completo dei parametri di addestramento, consulta il riferimento alla configurazione di addestramento. Per controllare comportamenti non esposti dai parametri — learning rate per layer, gradient clipping o metriche di validazione personalizzate — crea una sottoclasse del trainer.

Fine-tuning in due fasi#

Il fine-tuning in due fasi suddivide l'addestramento in due fasi. Nella prima fase, il backbone viene congelato e si addestrano solo neck e head, consentendo ai layer di rilevamento di adattarsi alle nuove classi senza alterare le feature preaddestrate. Nella seconda fase, si scongelano tutti i layer e si addestra il modello completo con un learning rate inferiore, per perfezionare il backbone in funzione del dominio di destinazione.

Questo approccio è particolarmente utile quando il dominio di destinazione è molto diverso da COCO (immagini mediche, immagini aeree, microscopia), poiché il backbone potrebbe richiedere un adattamento, mentre addestrare tutto in una volta può causare instabilità. Per scongelare automaticamente i layer con un approccio basato su callback, consulta Congelare e scongelare il backbone.

Fine-tuning in due fasi
from ultralytics import YOLO

# Fase 1: congela il backbone, addestra head e neck
model = YOLO("yolo26n.pt")
model.train(data="custom.yaml", epochs=20, freeze=10, name="stage1", exist_ok=True)

# Fase 2: scongela tutto, esegui il fine-tuning con un lr inferiore
model = YOLO("runs/detect/stage1/weights/best.pt")
model.train(data="custom.yaml", epochs=30, optimizer="AdamW", lr0=0.001, name="stage2", exist_ok=True)

Problemi comuni#

Il modello non produce predizioni#

  • Dati di addestramento insufficienti: addestrare con pochissimi campioni è la causa più comune; il modello non può apprendere né generalizzare con così pochi dati. Prima di indagare altre cause, assicurati di avere abbastanza esempi diversificati per ogni classe.

  • Controlla i percorsi del dataset: i percorsi delle immagini non validi generano un errore del dataset. I singoli file di etichette mancanti o vuoti vengono trattati come immagini di sfondo e segnalati durante la scansione; una suddivisione di addestramento senza etichette genera un errore. Convalida il dataset prima dell'addestramento:

    yolo detect val model=yolo26n.pt data=custom.yaml
  • Abbassa la soglia di confidenza: se le predizioni sono presenti ma vengono filtrate, prova conf=0.1 durante l'inferenza.

  • Verifica il numero di classi: assicurati che nc in data.yaml corrisponda al numero effettivo di classi nei file di etichette.

La mAP di validazione si stabilizza presto#

  • Aggiungi altri dati: il fine-tuning trae notevole beneficio da ulteriori dati di addestramento, soprattutto da esempi diversificati con angolazioni, illuminazione e sfondi vari.
  • Controlla il bilanciamento delle classi: le classi sottorappresentate avranno AP bassi. Aggiungi altri esempi oppure ottimizza cls_pw sul set di validazione.
  • Riduci l'augmentation: con dataset molto piccoli, un'augmentation intensa può essere più dannosa che utile. Prova mosaic=0.5 oppure mosaic=0.0.
  • Aumenta la risoluzione: per i dataset con oggetti piccoli, prova imgsz=1280 per preservare i dettagli.

Le prestazioni sulle classi originali peggiorano dopo il fine-tuning#

Questo fenomeno è noto come oblio catastrofico: il modello perde le conoscenze apprese in precedenza quando viene messo a punto esclusivamente su nuovi dati. L'oblio è perlopiù inevitabile se non si includono immagini del dataset originale insieme ai nuovi dati. Per ridurne l'impatto:

  • Unisci i dataset: durante il fine-tuning, includi esempi delle classi originali insieme a quelli delle nuove classi. È l'unico metodo affidabile per evitare l'oblio.
  • Congela backbone e neck: congelare sia il backbone sia il neck, in modo da addestrare solo la testa di rilevamento, è utile per brevi sessioni di fine-tuning con un learning rate molto basso.
  • Riduci il numero di epoche: più a lungo il modello viene addestrato esclusivamente sui nuovi dati, più aumenta l'oblio.

Domande frequenti#

  • Non esiste un minimo fisso: i risultati dipendono dalla complessità dell'attività, dal numero di classi e dalla somiglianza del dominio con COCO. Le immagini più diversificate (con illuminazione, angolazioni e sfondi vari) contano più della quantità grezza. Inizia con i dati che hai e aumentali se le metriche di validazione non sono sufficienti.

  • Carica un file .pt preaddestrato e chiama .train() indicando il percorso di un data.yaml personalizzato. Ultralytics gestisce automaticamente il trasferimento dei pesi, la reinizializzazione del layer di classificazione e la selezione dell'ottimizzatore. Per l'esempio di codice completo, consulta la sezione Fine-tuning di base.

  • Le cause più comuni sono percorsi delle immagini non validi, file di etichette mancanti o vuoti, una mancata corrispondenza tra nc nel file YAML e i file di etichette effettivi, oppure una soglia di confidenza troppo alta. Consulta Problemi comuni per una checklist completa di risoluzione dei problemi.

  • Dipende dalle dimensioni del dataset e dalla somiglianza del dominio. Per dataset piccoli con un dominio simile a COCO, congelare il backbone (freeze=10) previene l'overfitting. Per domini molto diversi da COCO, lasciare scongelati tutti i layer (freeze=None) consente al backbone di adattarsi. Consulta Congelamento dei layer per consigli dettagliati.

  • Includi nei dati di addestramento esempi delle classi originali insieme a quelli delle nuove classi. Se non è possibile, congelare più layer (freeze=10 o un valore superiore) e usare un learning rate inferiore aiuta a preservare le conoscenze preaddestrate. Per maggiori dettagli, consulta Le prestazioni sulle classi originali peggiorano.

Commenti4

Fai una domanda, condividi i tuoi risultati o aiuta qualcun altro.

  1. Yuan Yao(modificato)

    这是我在训练时遇到的一个问题,

      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    81/1000      6.68G          0          0          0        195        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:20
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.1s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    82/1000      6.68G          0          0          0        184        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:20
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.0it/s 11.3s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    83/1000      6.68G          0          0          0        221        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:19
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.1s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    84/1000      6.68G          0          0          0        212        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:20
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.2s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    85/1000      6.68G          0          0          0        221        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:20
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.2s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    86/1000      6.68G          0          0          0        216        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:20
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.0s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    87/1000      6.68G          0          0          0        198        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:19
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.0it/s 11.4s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    88/1000      6.68G          0          0          0        229        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:20
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.2s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    89/1000      6.68G          0          0          0        182        640: 100% ━━━━━━━━━━━━ 121/121 1.1s/it 2:18
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.0s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    90/1000      6.68G          0          0          0        218        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:20
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.0s
                   all       1449       8364          0          0          0          0
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
    91/1000      6.68G          0          0          0        181        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:19
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.1it/s 11.1s
                   all       1449       8364          0          0          0          0

    mAP一直是0。当时我用的是yaml文件用于训练模型,

    model_name = r"H:\1_yaoyuan\code\01_yolo26\yolo_Project\ultralytics-main\ultralytics\cfg\models\11\yolo11.yaml"

    之后改成了,

    model_name = 'yolo11n.pt' # 首次运行会自动下载

    然后训练才变的正常,

      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
     2/1000      5.47G      2.825      1.856     0.8776        131        640: 100% ━━━━━━━━━━━━ 121/121 1.2s/it 2:20
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 2.0it/s 11.5s
                   all       1449       8364      0.554      0.314       0.32      0.117
    
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
     3/1000      5.47G      2.904      1.726     0.8738        206        640: 100% ━━━━━━━━━━━━ 121/121 1.1s/it 2:19
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 23/23 1.9it/s 11.9s
                   all       1449       8364      0.496       0.29      0.269      0.085

    这是为什么?微调和从头开始训练差别很大吗? 我问了deepseek,他说:“.yaml 路径迫使模型在毫无知识的情况下承受初始的梯度冲击,导致了数值崩溃;而 .pt 路径让模型从一个稳定的知识基础开始,顺利进入了正常的学习轨道。”

    可如果是这样,如果这个世界还没有yolo的pt文件,那么是不是mAP永远都是0了?

    1. Yuan Yao

      我还是刚学习的阶段,如果我问的问题很幼稚我非常抱歉

    2. Paula DerrengerUltralytics

      不用道歉,这是很合理的问题!不是的:从 .yaml 构建模型是随机初始化,从 yolo11n.pt 开始则利用预训练特征,通常收敛更快、需要的数据更少;YOLO11 官方示例也支持从零训练,并不需要已有 .pt 才能学会检测。你这里不仅 mAP 为 0,三个 loss 也连续为 0,这不能简单解释为“从零训练比较慢”,更应优先排查训练数值异常;仅凭这些日志,还不能确认 DeepSeek 所说的“梯度冲击”。建议保留 YAML,在原来的 model.train(...) 中加入 amp=False,重新启动训练以排查混合精度问题(AMP 检查说明)。如果仍然全为 0,请贴出完整训练代码、启动到首个异常 epoch 的文本日志,以及 GPU 型号、Ultralytics 和 PyTorch 版本。