Ultralytics YOLO27:

Convalida incrociata K-Fold con Ultralytics#

Introduzione#

Questa guida completa illustra l'implementazione della convalida incrociata K-Fold per i dataset di rilevamento degli oggetti nell'ecosistema Ultralytics. Utilizzeremo il formato di rilevamento YOLO e librerie Python fondamentali come sklearn, pandas e PyYAML per guidarti nella configurazione necessaria, nel processo di generazione dei vettori delle caratteristiche e nell'esecuzione della suddivisione del dataset in K-Fold.

K-fold cross validation data splitting

Che il tuo progetto riguardi il dataset Fruit Detection o una fonte di dati personalizzata, questo tutorial mira ad aiutarti a comprendere e applicare la convalida incrociata K-Fold per aumentare l'affidabilità e la robustezza dei tuoi modelli di machine learning. Sebbene in questo tutorial utilizziamo k=5 fold, tieni presente che il numero ottimale di fold può variare in base al tuo dataset e alle specificità del tuo progetto. La convalida incrociata K-Fold offre il massimo valore quando il dataset è piccolo, rumoroso o altamente variabile; per dataset grandi e diversificati, una suddivisione train/val/test ben strutturata è generalmente sufficiente.

Iniziamo.

Configurazione#

  • Le annotazioni devono essere nel formato di rilevamento YOLO.

  • Questa guida presuppone che i file di annotazione siano disponibili localmente.

  • Per la nostra dimostrazione, utilizziamo il dataset Fruit Detection.

    • Questo dataset contiene complessivamente 8479 immagini.
    • Include 6 etichette di classe, con il numero totale di istanze di ciascuna elencato di seguito.
Etichetta della classeNumero di istanze
Mela7049
Uva7202
Ananas1613
Arancia15549
Banana3536
Anguria1976
  • I pacchetti Python necessari includono:

    • ultralytics
    • sklearn
    • pandas
    • pyyaml
  • Questo tutorial utilizza k=5 fold. Tuttavia, devi determinare il numero migliore di fold per il tuo dataset specifico.

  1. Crea un nuovo ambiente virtuale Python (venv) per il tuo progetto e attivalo. Usa pip (o il gestore di pacchetti che preferisci) per installare:

    • La libreria Ultralytics: pip install -U ultralytics. In alternativa, puoi clonare il repository ufficiale.
    • Scikit-learn, pandas e PyYAML: pip install -U scikit-learn pandas pyyaml.
  2. Verifica che le annotazioni siano nel formato di rilevamento YOLO.

    • Per questo tutorial, tutti i file di annotazione si trovano nella directory Fruit-Detection/labels.

Generazione dei vettori delle caratteristiche per il dataset di rilevamento degli oggetti#

  1. Inizia creando un nuovo file Python example.py per i passaggi seguenti.

  2. Carica le immagini di addestramento e convalida configurate tramite il proprietario del dataset del pacchetto, lasciando invariata la suddivisione di test.

    from pathlib import Path
    
    from ultralytics.data.dataset import YOLODataset
    from ultralytics.data.utils import check_det_dataset
    
    yaml_file = "path/to/data.yaml"
    data = check_det_dataset(yaml_file)
    dataset_path = Path(data["path"])
    sources = []
    for split in ("train", "val"):
        source = data.get(split)
        if source:
            sources.extend(source if isinstance(source, list) else [source])
    dataset = YOLODataset(sources, data=data, augment=False)
    images = [Path(p) for p in dataset.im_files]
  3. Ora leggi il contenuto del file YAML del dataset ed estrai gli indici delle etichette di classe.

    classes = data["names"]
    cls_idx = sorted(classes.keys())
  4. Inizializza un DataFrame pandas vuoto.

    import pandas as pd
    
    labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images)
  5. Conta le istanze di ogni etichetta di classe presente nei file di annotazione.

    from collections import Counter
    
    for image, label in zip(images, dataset.labels):
        lbl_counter = Counter(label["cls"].flatten().astype(int))
        labels_df.loc[image, list(lbl_counter)] = list(lbl_counter.values())
  6. Di seguito è riportata una visualizzazione di esempio del DataFrame compilato:

                                                           0    1    2    3    4    5
    '0000a16e4b057580_jpg.rf.00ab48988370f64f5ca8ea4...'  0.0  0.0  0.0  0.0  0.0  7.0
    '0000a16e4b057580_jpg.rf.7e6dce029fb67f01eb19aa7...'  0.0  0.0  0.0  0.0  0.0  7.0
    '0000a16e4b057580_jpg.rf.bc4d31cdcbe229dd022957a...'  0.0  0.0  0.0  0.0  0.0  7.0
    '00020ebf74c4881c_jpg.rf.508192a0a97aa6c4a3b6882...'  0.0  0.0  0.0  1.0  0.0  0.0
    '00020ebf74c4881c_jpg.rf.5af192a2254c8ecc4188a25...'  0.0  0.0  0.0  1.0  0.0  0.0
     ...                                                  ...  ...  ...  ...  ...  ...
    'ff4cd45896de38be_jpg.rf.c4b5e967ca10c7ced3b9e97...'  0.0  0.0  0.0  0.0  0.0  2.0
    'ff4cd45896de38be_jpg.rf.ea4c1d37d2884b3e3cbce08...'  0.0  0.0  0.0  0.0  0.0  2.0
    'ff5fd9c3c624b7dc_jpg.rf.bb519feaa36fc4bf630a033...'  1.0  0.0  0.0  0.0  0.0  0.0
    'ff5fd9c3c624b7dc_jpg.rf.f0751c9c3aa4519ea3c9d6a...'  1.0  0.0  0.0  0.0  0.0  0.0
    'fffe28b31f2a70d4_jpg.rf.7ea16bd637ba0711c53b540...'  0.0  6.0  0.0  0.0  0.0  0.0

Le righe utilizzano percorsi assoluti delle immagini e le colonne corrispondono agli indici delle etichette di classe. Le etichette mancanti rimangono righe di sfondo costituite interamente da zeri. Questa struttura dati consente di applicare la convalida incrociata K-Fold a un dataset di rilevamento degli oggetti.

Suddivisione del dataset in K-Fold#

  1. Ora utilizzeremo la classe KFold di sklearn.model_selection per generare k suddivisioni del dataset.

    • Importante:
      • L'impostazione di shuffle=True garantisce una distribuzione casuale delle classi nelle tue suddivisioni.
      • Impostando random_state=M, dove M è un intero scelto, puoi ottenere risultati ripetibili.
    from sklearn.model_selection import KFold
    
    ksplit = 5
    kf = KFold(n_splits=ksplit, shuffle=True, random_state=20)  # setting random_state for repeatable results
    
    kfolds = list(kf.split(labels_df))
  2. Il dataset è stato suddiviso in k fold, ciascuno contenente un elenco di indici train e val. Costruiremo un DataFrame per visualizzare più chiaramente questi risultati.

    folds = [f"split_{n}" for n in range(1, ksplit + 1)]
    folds_df = pd.DataFrame(index=labels_df.index, columns=folds)
    
    for i, (train, val) in enumerate(kfolds, start=1):
        folds_df.loc[labels_df.index[train], f"split_{i}"] = "train"
        folds_df.loc[labels_df.index[val], f"split_{i}"] = "val"
  3. Ora calcoleremo la distribuzione delle etichette di classe per ogni fold come rapporto tra le classi presenti in val e quelle presenti in train.

    fold_lbl_distrb = pd.DataFrame(index=folds, columns=cls_idx)
    
    for n, (train_indices, val_indices) in enumerate(kfolds, start=1):
        train_totals = labels_df.iloc[train_indices].sum()
        val_totals = labels_df.iloc[val_indices].sum()
    
        # To avoid division by zero, we add a small value (1E-7) to the denominator
        ratio = val_totals / (train_totals + 1e-7)
        fold_lbl_distrb.loc[f"split_{n}"] = ratio

    Lo scenario ideale prevede che tutti i rapporti tra le classi siano ragionevolmente simili per ogni suddivisione e tra le diverse classi. Tuttavia, ciò dipenderà dalle caratteristiche specifiche del tuo dataset.

  4. Scrivi gli elenchi delle immagini e un YAML del dataset per ogni suddivisione. Gli elenchi di testo evitano di copiare il dataset k volte.

    import yaml
    
    save_path = dataset_path.parent / f"{ksplit}-Fold_Cross-val"
    save_path.mkdir(parents=True, exist_ok=True)
    ds_yamls = []
    
    for split in folds_df.columns:
        for partition in ("train", "val"):
            split_images = folds_df.index[folds_df[split] == partition]
            paths = "\n".join(map(str, split_images))
            (save_path / f"{split}_{partition}.txt").write_text(f"{paths}\n")
    
        dataset_yaml = save_path / f"{split}.yaml"
        ds_yamls.append(dataset_yaml)
        with open(dataset_yaml, "w") as ds_y:
            yaml.safe_dump(
                {
                    "path": save_path.as_posix(),
                    "train": f"{split}_train.txt",
                    "val": f"{split}_val.txt",
                    "names": classes,
                },
                ds_y,
            )

Salvataggio dei record (facoltativo)#

Facoltativamente, puoi salvare i record della suddivisione K-Fold e i DataFrame della distribuzione delle etichette come file CSV per consultarli in futuro.

folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")

Addestramento di YOLO utilizzando le suddivisioni dei dati K-Fold#

  1. Per prima cosa, carica il modello YOLO.

    from ultralytics import YOLO
    
    weights_path = "path/to/weights.pt"  # use yolo26n.pt for a small model
    model = YOLO(weights_path, task="detect")
  2. Successivamente, itera sui file YAML del dataset per eseguire l'addestramento. I risultati verranno salvati in una directory specificata dagli argomenti project e name. Per impostazione predefinita, questa directory è 'runs/detect/train#', dove # è un indice intero.

    results = {}
    
    # Define your additional arguments here
    batch = 16
    project = "kfold_demo"
    epochs = 100
    
    for k, dataset_yaml in enumerate(ds_yamls):
        model = YOLO(weights_path, task="detect")
        results[k] = model.train(
            data=dataset_yaml, epochs=epochs, batch=batch, project=project, name=f"fold_{k + 1}"
        )  # include any additional train arguments
  3. Puoi anche utilizzare la funzione Ultralytics data.split.autosplit per suddividere automaticamente il dataset:

    from ultralytics.data.split import autosplit
    
    # Automatically split dataset into train/val/test
    autosplit(path="path/to/images", weights=(0.8, 0.2, 0.0), annotated_only=True)

Conclusioni#

In questa guida abbiamo esaminato il processo di utilizzo della convalida incrociata K-Fold per addestrare il modello YOLO di rilevamento degli oggetti. Abbiamo imparato a suddividere il pool di addestramento e convalida in K partizioni e a utilizzare la tabella dei rapporti generata per analizzare il bilanciamento delle classi dopo la suddivisione casuale.

Abbiamo inoltre esaminato la procedura per creare DataFrame di report al fine di visualizzare le suddivisioni dei dati e le distribuzioni delle etichette tra queste suddivisioni, ottenendo una visione chiara della struttura dei nostri set di addestramento e convalida.

Facoltativamente, abbiamo salvato i nostri record per consultarli in futuro, cosa che può essere particolarmente utile nei progetti su larga scala o durante la risoluzione dei problemi relativi alle prestazioni del modello.

Infine, abbiamo implementato l'addestramento effettivo del modello utilizzando ogni suddivisione in un ciclo, salvando i risultati dell'addestramento per ulteriori analisi e confronti.

Questa tecnica di convalida incrociata K-Fold è un metodo robusto per sfruttare al meglio i dati disponibili e contribuisce a garantire che le prestazioni del modello siano affidabili e coerenti tra diversi sottoinsiemi di dati. Il risultato è un modello più generalizzabile e affidabile, meno soggetto a overfitting rispetto a specifici schemi dei dati.

Ricorda che, sebbene in questa guida abbiamo utilizzato YOLO, questi passaggi sono in gran parte trasferibili ad altri modelli di machine learning. Comprendere questi passaggi ti consente di applicare efficacemente la convalida incrociata nei tuoi progetti di machine learning.

FAQ#

  • La convalida incrociata K-Fold è una tecnica in cui il dataset viene diviso in 'k' sottoinsiemi (fold) per valutare le prestazioni del modello in modo più affidabile. Ogni fold funge sia da dati di addestramento sia da dati di convalida. Nel contesto del rilevamento degli oggetti, l'utilizzo della convalida incrociata K-Fold contribuisce a garantire che le prestazioni del tuo modello Ultralytics YOLO siano robuste e generalizzabili tra diverse suddivisioni dei dati, migliorandone l'affidabilità. Per istruzioni dettagliate sulla configurazione della convalida incrociata K-Fold con Ultralytics YOLO, consulta Convalida incrociata K-Fold con Ultralytics.

  • Per implementare la convalida incrociata K-Fold con Ultralytics YOLO, devi seguire questi passaggi:

    1. Verifica che le annotazioni siano nel formato di rilevamento YOLO.
    2. Utilizza librerie Python come sklearn, pandas e pyyaml.
    3. Crea vettori delle caratteristiche dal tuo dataset.
    4. Suddividi il tuo dataset utilizzando KFold da sklearn.model_selection.
    5. Addestra il modello YOLO su ogni suddivisione.

    Per una guida completa, consulta la sezione Suddivisione del dataset in K-Fold nella nostra documentazione.

  • Il flusso di lavoro di questa guida è rivolto al formato di rilevamento YOLO, ma lo stesso approccio si adatta a ogni attività YOLO: l'attività cambia il modo in cui componi i fold, non l'utilità della convalida incrociata:

    AttivitàProgettazione dei fold
    detectSuddividi a livello di immagine, bilanciando la distribuzione degli oggetti e delle classi tra i fold. Mantieni le immagini correlate (dello stesso paziente, della stessa sequenza video, fotocamera o sito) all'interno di un singolo fold.
    segmentUtilizza la stessa strategia a livello di immagine del rilevamento, preservando inoltre la copertura delle maschere e delle classi in ogni fold.
    classifyPreferisci fold stratificati, in modo che le frequenze delle classi rimangano bilanciate tra addestramento e convalida.
    poseSuddividi per soggetto o sequenza, in modo che la stessa persona o animale non compaia mai su entrambi i lati di un fold.
    obbSuddividi a livello di immagine, mantenendo insieme tasselli o ritagli della stessa scena, particolarmente importante per le immagini aeree.

    Qualunque sia l'attività, mantieni i campioni quasi duplicati e correlati fuori dai fold contrapposti: questo tipo di leakage gonfia le metriche di convalida ben oltre ciò che il modello otterrà in produzione.

  • Ultralytics YOLO offre un rilevamento degli oggetti all'avanguardia in tempo reale, con elevata accuratezza ed efficienza. È versatile e supporta diverse attività di visione artificiale, come rilevamento, segmentazione delle istanze, segmentazione semantica e classificazione. Inoltre, si integra perfettamente con strumenti come Ultralytics Platform per l'addestramento e la distribuzione dei modelli senza codice. Per ulteriori dettagli, scopri i vantaggi e le funzionalità nella nostra pagina Ultralytics YOLO.

  • Le tue annotazioni devono seguire il formato di rilevamento YOLO. Ogni file di annotazione deve elencare la classe dell'oggetto e le coordinate del relativo riquadro di delimitazione nell'immagine. Il formato YOLO garantisce un'elaborazione dei dati semplificata e standardizzata per l'addestramento dei modelli di rilevamento degli oggetti. Per ulteriori informazioni sulla corretta formattazione delle annotazioni, visita la guida al formato di rilevamento YOLO.

  • Sì, puoi utilizzare la convalida incrociata K-Fold con qualsiasi dataset personalizzato, purché le annotazioni siano nel formato di rilevamento YOLO. Sostituisci i percorsi del dataset e le etichette delle classi con quelli specifici del tuo dataset personalizzato. Questa flessibilità garantisce che qualsiasi progetto di rilevamento degli oggetti possa trarre vantaggio da una valutazione robusta del modello tramite la convalida incrociata K-Fold. Per un esempio pratico, consulta la nostra sezione Generazione dei vettori delle caratteristiche.

Commenti