YOLO Vision 2026:

Convalida incrociata K-Fold con Ultralytics#

Introduzione#

Questa guida completa illustra l'implementazione della K-Fold Cross Validation per dataset di object detection all'interno dell'ecosistema Ultralytics. Sfrutteremo il formato di rilevamento YOLO e librerie Python chiave come sklearn, pandas e PyYAML per guidarti attraverso la configurazione necessaria, il processo di generazione dei vettori di caratteristiche e l'esecuzione di una suddivisione del dataset K-Fold.

K-fold cross validation data splitting

Che il tuo progetto riguardi il dataset Fruit Detection o una sorgente di dati personalizzata, questo tutorial mira ad aiutarti a comprendere e applicare la convalida incrociata K-Fold per rafforzare l'affidabilità e la robustezza dei tuoi modelli di machine learning. Anche se per questo tutorial stiamo applicando k=5 fold, tieni presente che il numero ottimale di fold può variare a seconda del tuo dataset e delle specificità del tuo progetto. La convalida incrociata K-Fold offre il massimo valore quando il tuo dataset è piccolo, rumoroso o altamente variabile; per dataset grandi e diversi, una suddivisione train/val/test ben strutturata è solitamente sufficiente.

Iniziamo.

Configurazione#

  • Le tue annotazioni devono essere nel YOLO detection format.

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

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

    • Questo dataset contiene un totale di 8479 immagini.
    • Include 6 etichette di classe, ognuna con i relativi conteggi totali di istanze elencati di seguito.
Etichetta di classeConteggio istanze
Mela7049
Uva7202
Ananas1613
Arancia15549
Banana3536
Anguria1976
  • I pacchetti Python necessari includono:

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

  1. Avvia un nuovo ambiente virtuale Python (venv) per il tuo progetto e attivalo. Usa pip (o il tuo package manager preferito) per installare:

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

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

Generazione di vettori di caratteristiche per il dataset di rilevamento oggetti#

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

  2. Carica le immagini di addestramento e validazione configurate tramite il proprietario del dataset del pacchetto, lasciando intatto lo split 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 vuoto pandas.

    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 vista campione del DataFrame popolato:

                                                           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 di immagine assoluti e le colonne corrispondono agli indici delle etichette di classe. Le etichette mancanti rimangono righe di sfondo tutte a zero. Questa struttura di dati consente l'applicazione della K-Fold Cross Validation a un dataset di object detection.

Suddivisione del dataset K-Fold#

  1. Ora useremo la classe KFold da 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 ora suddiviso in k fold, ciascuna con un elenco di indici train e val. Costruiremo un DataFrame per visualizzare questi risultati in modo più chiaro.

    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 ciascun 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 è che tutti i rapporti di classe siano ragionevolmente simili per ogni suddivisione e tra le classi. Questo, tuttavia, sarà soggetto alle specificità del tuo dataset.

  4. Scrivi elenchi di immagini e un file YAML del dataset per ogni split. 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 (Opzionale)#

Facoltativamente, puoi salvare i record dei DataFrame di suddivisione K-Fold e di distribuzione delle etichette come file CSV per riferimento futuro.

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

Addestra 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, scorri i 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 usare la funzione Ultralytics data.split.autosplit per la suddivisione automatica del 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)

Conclusione#

In questa guida, abbiamo esplorato il processo di utilizzo della K-Fold cross-validation per l'addestramento del modello di object detection YOLO. Abbiamo imparato a suddividere il pool di addestramento e validazione in K partizioni e a utilizzare la tabella dei rapporti generata per ispezionare il bilanciamento delle classi dopo la suddivisione casuale.

Abbiamo anche esplorato la procedura per creare DataFrame di report per visualizzare le suddivisioni dei dati e le distribuzioni delle etichette tra queste suddivisioni, fornendoci una visione chiara della struttura dei nostri set di addestramento e validazione.

Facoltativamente, abbiamo salvato i nostri record per riferimento futuro, il che potrebbe essere particolarmente utile in progetti su larga scala o durante la risoluzione di problemi relativi alle prestazioni del modello.

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

Questa tecnica di K-Fold cross-validation è un modo robusto per sfruttare al massimo i dati disponibili e aiuta a garantire che le prestazioni del tuo modello siano affidabili e coerenti su diversisubset di dati. Ciò risulta in un modello più generalizzabile e affidabile che ha meno probabilità di fare overfit su pattern di dati specifici.

Ricorda che, sebbene abbiamo utilizzato YOLO in questa guida, questi passaggi sono per lo più 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 K-Fold Cross Validation è una tecnica in cui il dataset viene diviso in 'k' subset (fold) per valutare le prestazioni del modello in modo più affidabile. Ciascun fold funge sia da dati di addestramento che da validation data. Nel contesto dell'object detection, l'uso della K-Fold Cross Validation aiuta a garantire che le prestazioni del tuo modello Ultralytics YOLO siano robuste e generalizzabili attraverso diverse suddivisioni dei dati, migliorandone l'affidabilità. Per istruzioni dettagliate sulla configurazione della K-Fold Cross Validation con Ultralytics YOLO, fai riferimento a K-Fold Cross Validation with Ultralytics.

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

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

    Per una guida completa, consulta la sezione K-Fold Dataset Split nella nostra documentazione.

  • Il flusso di lavoro in questa guida si concentra sul formato di rilevamento YOLO, ma lo stesso approccio si adatta a ogni task di YOLO: il task cambia il modo in cui componi i fold, non il fatto che la convalida incrociata sia utile:

    CompitoProgettazione dei fold
    detectDividi a livello di immagine, bilanciando le distribuzioni di oggetti e classi tra i fold. Mantieni le immagini correlate (stesso paziente, sequenza video, telecamera o sito) all'interno di un unico fold.
    segmentUsa la stessa strategia a livello di immagine del rilevamento, preservando in più la copertura di maschere e classi in ogni fold.
    classifyPreferisci fold stratificati in modo che le frequenze delle classi rimangano bilanciate tra training e validation.
    poseDividi per soggetto o sequenza in modo che la stessa persona o lo stesso animale non compaiano mai su entrambi i lati di un fold.
    obbDividi a livello di immagine, mantenendo insieme riquadri o ritagli della stessa scena, particolarmente importante per le immagini aeree.

    Qualunque sia il task, tieni campioni quasi duplicati e correlati lontani da fold opposti: quel tipo di leakage gonfia le metriche di validazione ben oltre ciò che il modello otterrà in produzione.

  • Ultralytics YOLO offre object detection all'avanguardia in tempo reale con elevata accuracy ed efficienza. È versatile e supporta molteplici attività di computer vision come detection, instance segmentation, semantic segmentation e classification. Inoltre, si integra perfettamente con strumenti come Ultralytics Platform per l'addestramento e il deployment di modelli senza codice. Per maggiori dettagli, esplora i vantaggi e le funzionalità sulla nostra Ultralytics YOLO page.

  • Le tue annotazioni dovrebbero seguire il formato di rilevamento YOLO. Ogni file di annotazione deve elencare la classe dell'oggetto, insieme alle sue coordinate del bounding box nell'immagine. Il formato YOLO garantisce un'elaborazione dei dati snella e standardizzata per l'addestramento di modelli di object detection. Per ulteriori informazioni sulla formattazione corretta delle annotazioni, visita la YOLO detection format guide.

  • Sì, puoi usare la K-Fold Cross Validation 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 object detection possa beneficiare di una robusta valutazione del modello tramite la K-Fold Cross Validation. Per un esempio pratico, rivedi la nostra sezione Generating Feature Vectors.

Commenti