Vai al contenuto

Convalida incrociata K-Fold con Ultralytics

Introduzione

Questa guida completa illustra l'implementazione della convalida incrociata K-Fold per i set di dati di rilevamento degli oggetti all'interno dell'ecosistema Ultralytics . Sfrutteremo il formato di rilevamento YOLO e le librerie chiave di Python , come sklearn, pandas e PyYaml, per guidarvi attraverso la configurazione necessaria, il processo di generazione dei vettori di caratteristiche e l'esecuzione di una divisione del dataset K-Fold.

Panoramica della convalida incrociata K-Fold

Sia che il vostro progetto coinvolga il dataset di Fruit Detection o una fonte di dati personalizzata, questa esercitazione ha lo scopo di aiutarvi a comprendere e ad applicare la convalida incrociata K-Fold per rafforzare l'affidabilità e la solidità del vostro progetto. apprendimento automatico modelli. Mentre applichiamo k=5 Tenete presente che il numero ottimale di pieghe per questa esercitazione può variare a seconda del vostro set di dati e delle specifiche del vostro progetto.

Senza ulteriori indugi, tuffiamoci!

Impostazione

  • Le annotazioni devono essere nel formato di rilevamentoYOLO .

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

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

    • Questo set di dati contiene un totale di 8479 immagini.
    • Include 6 etichette di classe, ciascuna con il numero totale di istanze elencate di seguito.
Etichetta di classe Conteggio delle istanze
Mela 7049
Uva 7202
Ananas 1613
Arancione 15549
Banana 3536
Anguria 1976
  • I pacchetti necessari di Python includono:

    • ultralytics
    • sklearn
    • pandas
    • pyyaml
  • Questa esercitazione opera con k=5 pieghe. Tuttavia, è necessario determinare il numero migliore di pieghe per il proprio set di dati specifico.

  • Avviare un nuovo ambiente virtuale Python (venv) per il progetto e attivarlo. Utilizzare pip (o il vostro gestore di pacchetti preferito) per l'installazione:

    • La biblioteca di Ultralytics : pip install -U ultralytics. In alternativa, è possibile clonare il file ufficiale repo.
    • Scikit-learn, pandas e PyYAML: pip install -U scikit-learn pandas pyyaml.
  • Verificare che le annotazioni siano nel formato di rilevamentoYOLO .

    • Per questa esercitazione, tutti i file di annotazione si trovano nella cartella Fruit-Detection/labels directory.

Generazione di vettori di caratteristiche per il set di dati per il rilevamento di oggetti

  1. Iniziare creando un nuovo file example.py Python per i passi successivi.

  2. Procedere al recupero di tutti i file di etichetta per il set di dati.

    from pathlib import Path
    
    dataset_path = Path("./Fruit-detection")  # replace with 'path/to/dataset' for your custom data
    labels = sorted(dataset_path.rglob("*labels/*.txt"))  # all data in 'labels'
    
  3. Ora, leggere il contenuto del file YAML del dataset ed estrarre gli indici delle etichette delle classi.

    yaml_file = "path/to/data.yaml"  # your data YAML with data directories and names dictionary
    with open(yaml_file, "r", encoding="utf8") as y:
        classes = yaml.safe_load(y)["names"]
    cls_idx = sorted(classes.keys())
    
  4. Inizializza un file vuoto pandas DataFrame.

    import pandas as pd
    
    indx = [label.stem for label in labels]  # uses base filename as ID (no extension)
    labels_df = pd.DataFrame([], columns=cls_idx, index=indx)
    
  5. Conta le istanze di ciascuna etichetta di classe presenti nei file di annotazione.

    from collections import Counter
    
    for label in labels:
        lbl_counter = Counter()
    
        with open(label, "r") as lf:
            lines = lf.readlines()
    
        for line in lines:
            # classes for YOLO label uses integer at first position of each line
            lbl_counter[int(line.split(" ")[0])] += 1
    
        labels_df.loc[label.stem] = lbl_counter
    
    labels_df = labels_df.fillna(0.0)  # replace `nan` values with `0.0`
    
  6. Di seguito è riportata una vista di esempio 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 indicizzano i file delle etichette, ciascuno corrispondente a un'immagine del dataset, mentre le colonne corrispondono agli indici delle etichette di classe. Ogni riga rappresenta uno pseudo-vettore di caratteristiche, con il conteggio di ogni etichetta di classe presente nel dataset. Questa struttura di dati consente di applicare la convalida incrociata K-Fold a un set di dati per il rilevamento di oggetti.

Divisione del set di dati K-Fold

  1. Ora utilizzeremo l'opzione KFold classe da sklearn.model_selection per generare k suddivisione del set di dati.

    • Importante:
      • Impostazione shuffle=True garantisce una distribuzione randomizzata delle classi negli split.
      • Impostando random_state=M dove M è un numero intero scelto, è possibile 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 set di dati è stato suddiviso in k pieghe, ognuna delle quali ha un elenco di train e val indici. 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=indx, columns=folds)
    
    for idx, (train, val) in enumerate(kfolds, start=1):
        folds_df[f"split_{idx}"].loc[labels_df.iloc[train].index] = "train"
        folds_df[f"split_{idx}"].loc[labels_df.iloc[val].index] = "val"
    
  3. Ora calcoleremo la distribuzione delle etichette di classe per ogni piega come rapporto delle classi presenti in val a quelli 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 tra le classi siano ragionevolmente simili per ogni divisione e tra le classi. Questo, tuttavia, dipende dalle caratteristiche specifiche del vostro set di dati.

  4. Successivamente, si creano le directory e i file YAML del set di dati per ciascuna suddivisione.

    import datetime
    
    supported_extensions = [".jpg", ".jpeg", ".png"]
    
    # Initialize an empty list to store image file paths
    images = []
    
    # Loop through supported extensions and gather image files
    for ext in supported_extensions:
        images.extend(sorted((dataset_path / "images").rglob(f"*{ext}")))
    
    # Create the necessary directories and dataset YAML files (unchanged)
    save_path = Path(dataset_path / f"{datetime.date.today().isoformat()}_{ksplit}-Fold_Cross-val")
    save_path.mkdir(parents=True, exist_ok=True)
    ds_yamls = []
    
    for split in folds_df.columns:
        # Create directories
        split_dir = save_path / split
        split_dir.mkdir(parents=True, exist_ok=True)
        (split_dir / "train" / "images").mkdir(parents=True, exist_ok=True)
        (split_dir / "train" / "labels").mkdir(parents=True, exist_ok=True)
        (split_dir / "val" / "images").mkdir(parents=True, exist_ok=True)
        (split_dir / "val" / "labels").mkdir(parents=True, exist_ok=True)
    
        # Create dataset YAML files
        dataset_yaml = split_dir / f"{split}_dataset.yaml"
        ds_yamls.append(dataset_yaml)
    
        with open(dataset_yaml, "w") as ds_y:
            yaml.safe_dump(
                {
                    "path": split_dir.as_posix(),
                    "train": "train",
                    "val": "val",
                    "names": classes,
                },
                ds_y,
            )
    
  5. Infine, copiare le immagini e le etichette nella rispettiva directory ("train" o "val") per ogni divisione.

    • NOTA: Il tempo richiesto per questa parte del codice varia in base alle dimensioni del set di dati e all'hardware del sistema.
    import shutil
    
    for image, label in zip(images, labels):
        for split, k_split in folds_df.loc[image.stem].items():
            # Destination directory
            img_to_path = save_path / split / k_split / "images"
            lbl_to_path = save_path / split / k_split / "labels"
    
            # Copy image and label files to new directory (SamefileError if file already exists)
            shutil.copy(image, img_to_path / image.name)
            shutil.copy(label, lbl_to_path / label.name)
    

Salvare i record (facoltativo)

Opzionalmente, è possibile salvare i record dei DataFrames della divisione K-Fold e della distribuzione delle etichette come file CSV per riferimenti futuri.

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

Addestrare YOLO usando le suddivisioni dei dati K-Fold

  1. Per prima cosa, caricare il modello YOLO .

    from ultralytics import YOLO
    
    weights_path = "path/to/weights.pt"
    model = YOLO(weights_path, task="detect")
    
  2. Quindi, iterare i file YAML del set di dati per eseguire l'addestramento. I risultati saranno salvati in una cartella specificata dall'opzione project e name argomenti. Per impostazione predefinita, questa directory è 'exp/runs#', dove # è un indice intero.

    results = {}
    
    # Define your additional arguments here
    batch = 16
    project = "kfold_demo"
    epochs = 100
    
    for k in range(ksplit):
        dataset_yaml = ds_yamls[k]
        model = YOLO(weights_path, task="detect")
        model.train(data=dataset_yaml, epochs=epochs, batch=batch, project=project)  # include any train arguments
        results[k] = model.metrics  # save output metrics for further analysis
    

Conclusione

In questa guida, abbiamo esplorato il processo di utilizzo della convalida incrociata K-Fold per l'addestramento del modello di rilevamento degli oggetti YOLO . Abbiamo imparato a dividere il nostro set di dati in K partizioni, assicurando una distribuzione bilanciata delle classi nelle diverse pieghe.

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

In alternativa, abbiamo salvato i nostri record per riferimenti futuri, il che potrebbe essere particolarmente utile in progetti su larga scala o per la risoluzione di problemi relativi alle prestazioni del modello.

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

Questa tecnica di convalida incrociata K-Fold è un modo robusto per sfruttare al meglio i dati disponibili e per garantire che le prestazioni del modello siano affidabili e coerenti tra i diversi sottoinsiemi di dati. In questo modo si ottiene un modello più generalizzabile e affidabile, che ha meno probabilità di adattarsi eccessivamente a modelli di dati specifici.

Ricordate che, sebbene in questa guida abbiamo utilizzato YOLO , questi passaggi sono per lo più trasferibili ad altri modelli di apprendimento automatico. La comprensione di questi passaggi consente di applicare efficacemente la convalida incrociata nei propri progetti di apprendimento automatico. Buona codifica!

FAQ

Che cos'è la convalida incrociata K-Fold e perché è utile nel rilevamento degli oggetti?

La convalida incrociata K-Fold è una tecnica in cui il set di dati viene suddiviso in "k" sottoinsiemi (fold) per valutare le prestazioni del modello in modo più affidabile. Ciascuna piega serve sia come dati di addestramento che di validazione. Nel contesto del rilevamento di oggetti, l'uso della convalida incrociata K-Fold aiuta a garantire che le prestazioni del modello Ultralytics YOLO siano robuste e generalizzabili attraverso diverse suddivisioni dei dati, migliorandone l'affidabilità. Per istruzioni dettagliate sull'impostazione della convalida incrociata K-Fold con Ultralytics YOLO , consultare la sezione Convalida incrociata K-Fold con Ultralytics.

Come si implementa la convalida incrociata K-Fold utilizzando Ultralytics YOLO ?

Per implementare la convalida incrociata K-Fold con Ultralytics YOLO , è necessario seguire i seguenti passaggi:

  1. Verificare che le annotazioni siano nel formato di rilevamentoYOLO .
  2. Utilizzare le librerie Python come sklearn, pandas, e pyyaml.
  3. Creare vettori di caratteristiche dal set di dati.
  4. Dividere il set di dati utilizzando KFold da sklearn.model_selection.
  5. Addestrare il modello YOLO su ciascuna frazione.

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

Perché utilizzare Ultralytics YOLO per il rilevamento degli oggetti?

Ultralytics YOLO offre un rilevamento degli oggetti all'avanguardia e in tempo reale con un'elevata precisione ed efficienza. È versatile e supporta diverse attività di visione artificiale, come il rilevamento, la segmentazione e la classificazione. Inoltre, si integra perfettamente con strumenti come Ultralytics HUB per l'addestramento e la distribuzione di modelli senza codice. Per maggiori dettagli, esplorate i vantaggi e le caratteristiche nella nostra paginaUltralytics YOLO .

Come posso assicurarmi che le mie annotazioni siano nel formato corretto per Ultralytics YOLO ?

Le annotazioni devono seguire il formato di rilevamento YOLO . Ogni file di annotazione deve elencare la classe dell'oggetto e le coordinate del suo rettangolo di selezione 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, visitare la guida al formato di rilevamentoYOLO .

È possibile utilizzare la convalida incrociata K-Fold con set di dati personalizzati diversi da Fruit Detection?

Sì, è possibile utilizzare la convalida incrociata K-Fold con qualsiasi set di dati personalizzato, a condizione che le annotazioni siano nel formato di rilevamento YOLO . Sostituire i percorsi del set di dati e le etichette delle classi con quelle specifiche del set di dati personalizzato. Questa flessibilità garantisce che qualsiasi progetto di rilevamento di oggetti possa beneficiare di una solida valutazione del modello utilizzando la convalida incrociata K-Fold. Per un esempio pratico, consultare la sezione Generazione di vettori di funzioni.

📅C reato 1 anno fa ✏️ Aggiornato 1 mese fa

Commenti