Link to this sectionConvalida incrociata K-Fold con Ultralytics#
Link to this sectionIntroduzione#
Questa guida completa illustra l'implementazione della Convalida incrociata K-Fold per dataset di rilevamento oggetti all'interno dell'ecosistema Ultralytics. Utilizzeremo il formato di rilevamento YOLO e le principali librerie Python 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.
Che il tuo progetto riguardi il dataset Fruit Detection o una fonte 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. Sebbene in questo tutorial applichiamo k=5 fold, tieni presente che il numero ottimale di fold può variare a seconda del tuo dataset e delle specifiche del tuo progetto.
Iniziamo.
Link to this sectionConfigurazione#
-
Le tue annotazioni dovrebbero 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 un totale di 8479 immagini.
- Include 6 etichette di classe, ognuna con i relativi conteggi totali di istanze elencati di seguito.
| Etichetta di classe | Conteggio istanze |
|---|---|
| Mela | 7049 |
| Uva | 7202 |
| Ananas | 1613 |
| Arancia | 15549 |
| Banana | 3536 |
| Anguria | 1976 |
-
I pacchetti Python necessari includono:
ultralyticssklearnpandaspyyaml
-
Questo tutorial opera con
k=5fold. Tuttavia, dovresti determinare il miglior numero di fold per il tuo dataset specifico.
-
Avvia un nuovo ambiente virtuale Python (
venv) per il tuo progetto e attivalo. Usapip(o il tuo gestore di pacchetti preferito) 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.
- La libreria Ultralytics:
-
Verifica che le tue annotazioni siano nel formato di rilevamento YOLO.
- Per questo tutorial, tutti i file di annotazione si trovano nella directory
Fruit-Detection/labels.
- Per questo tutorial, tutti i file di annotazione si trovano nella directory
Link to this sectionGenerazione di vettori di caratteristiche per il dataset di rilevamento oggetti#
-
Inizia creando un nuovo file Python
example.pyper i passaggi seguenti. -
Procedi a recuperare tutti i file di etichetta per il tuo dataset.
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' -
Ora, leggi il contenuto del file YAML del dataset ed estrai gli indici delle etichette di classe.
import yaml yaml_file = "path/to/data.yaml" # your data YAML with data directories and names dictionary with open(yaml_file, encoding="utf8") as y: classes = yaml.safe_load(y)["names"] cls_idx = sorted(classes.keys()) -
Inizializza un DataFrame
pandasvuoto.import pandas as pd index = [label.stem for label in labels] # uses base filename as ID (no extension) labels_df = pd.DataFrame([], columns=cls_idx, index=index) -
Conta le istanze di ogni etichetta di classe presente nei file di annotazione.
from collections import Counter for label in labels: lbl_counter = Counter() with open(label) 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(" ", 1)[0])] += 1 labels_df.loc[label.stem] = lbl_counter labels_df = labels_df.fillna(0.0) # replace `nan` values with `0.0` -
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 indicizzano i file di etichetta, ciascuno corrispondente a un'immagine nel tuo dataset, e le colonne corrispondono ai tuoi indici di etichetta di classe. Ogni riga rappresenta uno pseudo vettore di caratteristiche, con il conteggio di ciascuna etichetta di classe presente nel tuo dataset. Questa struttura dati consente l'applicazione della Convalida incrociata K-Fold a un dataset di rilevamento oggetti.
Link to this sectionSuddivisione del dataset K-Fold#
-
Ora useremo la classe
KFolddisklearn.model_selectionper generareksuddivisioni del dataset.- Importante:
- L'impostazione di
shuffle=Truegarantisce una distribuzione casuale delle classi nelle tue suddivisioni. - Impostando
random_state=MdoveMè un intero scelto, puoi ottenere risultati ripetibili.
- L'impostazione di
import random from sklearn.model_selection import KFold random.seed(0) # for reproducibility ksplit = 5 kf = KFold(n_splits=ksplit, shuffle=True, random_state=20) # setting random_state for repeatable results kfolds = list(kf.split(labels_df)) - Importante:
-
Il dataset è stato ora suddiviso in
kfold, ognuno dei quali possiede un elenco di indicitraineval. 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=index, columns=folds) for i, (train, val) in enumerate(kfolds, start=1): folds_df[f"split_{i}"].loc[labels_df.iloc[train].index] = "train" folds_df[f"split_{i}"].loc[labels_df.iloc[val].index] = "val" -
Ora calcoleremo la distribuzione delle etichette di classe per ogni fold come rapporto delle classi presenti in
valrispetto a quelle presenti intrain.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}"] = ratioLo 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.
-
Successivamente, creiamo le directory e i file YAML del dataset per ogni 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 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, ) -
Infine, copia le immagini e le etichette nella rispettiva directory ('train' o 'val') per ogni suddivisione.
- NOTA: Il tempo richiesto per questa parte del codice varierà in base alla dimensione del tuo dataset e all'hardware del tuo sistema.
import shutil from tqdm import tqdm for image, label in tqdm(zip(images, labels), total=len(images), desc="Copying files"): 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)
Link to this sectionSalvataggio 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")Link to this sectionAddestra YOLO utilizzando le suddivisioni dei dati K-Fold#
-
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") -
Successivamente, itera sui file YAML del dataset per eseguire l'addestramento. I risultati verranno salvati in una directory specificata dagli argomenti
projectename. Per impostazione predefinita, questa directory è 'runs/detect/train#' dove # è un indice numerico.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 -
Puoi anche utilizzare 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)
Link to this sectionConclusione#
In questa guida, abbiamo esplorato il processo di utilizzo della convalida incrociata K-Fold per l'addestramento del modello di rilevamento oggetti YOLO. Abbiamo imparato come suddividere il nostro dataset in K partizioni, garantendo una distribuzione equilibrata delle classi tra i diversi fold.
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 convalida incrociata K-Fold è un modo robusto per sfruttare al meglio i tuoi dati disponibili e aiuta a garantire che le prestazioni del tuo modello siano affidabili e coerenti tra diversi sottoinsiemi di dati. Ciò si traduce in un modello più generalizzabile e affidabile con minori probabilità di overfitting su specifici pattern di dati.
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.
Link to this sectionFAQ#
Link to this sectionChe cos'è la Convalida incrociata K-Fold e perché è utile nel rilevamento oggetti?#
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 che da dati di validazione. Nel contesto del rilevamento oggetti, utilizzare la Convalida incrociata K-Fold aiuta 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, fai riferimento a Convalida incrociata K-Fold con Ultralytics.
Link to this sectionCome implemento la Convalida incrociata K-Fold utilizzando Ultralytics YOLO?#
Per implementare la Convalida incrociata K-Fold con Ultralytics YOLO, devi seguire questi passaggi:
- Verifica che le annotazioni siano nel formato di rilevamento YOLO.
- Utilizza librerie Python come
sklearn,pandasepyyaml. - Crea vettori di caratteristiche dal tuo dataset.
- Suddividi il tuo dataset utilizzando
KFolddasklearn.model_selection. - Addestra il modello YOLO su ogni suddivisione.
Per una guida completa, consulta la sezione Suddivisione del dataset K-Fold nella nostra documentazione.
Link to this sectionPerché dovrei usare Ultralytics YOLO per il rilevamento oggetti?#
Ultralytics YOLO offre un rilevamento oggetti in tempo reale all'avanguardia con elevata precisione ed efficienza. È versatile e supporta molteplici attività di computer vision come rilevamento, segmentazione di istanze, segmentazione semantica e classificazione. Inoltre, si integra perfettamente con strumenti come la Piattaforma Ultralytics per l'addestramento e il deployment di modelli senza codice. Per maggiori dettagli, esplora i vantaggi e le funzionalità sulla nostra pagina Ultralytics YOLO.
Link to this sectionCome posso assicurarmi che le mie annotazioni siano nel formato corretto per Ultralytics YOLO?#
Le tue annotazioni dovrebbero seguire il formato di rilevamento YOLO. Ogni file di annotazione deve elencare la classe dell'oggetto, insieme alle coordinate del suo riquadro di delimitazione nell'immagine. Il formato YOLO garantisce un'elaborazione dei dati semplificata e standardizzata per l'addestramento dei modelli di rilevamento oggetti. Per ulteriori informazioni sulla formattazione corretta delle annotazioni, visita la guida al formato di rilevamento YOLO.
Link to this sectionPosso utilizzare la Convalida incrociata K-Fold con dataset personalizzati diversi da Fruit Detection?#
Sì, puoi utilizzare la Convalida incrociata K-Fold con qualsiasi dataset personalizzato, a condizione che le annotazioni siano nel formato di rilevamento YOLO. Sostituisci i percorsi del dataset e le etichette di classe con quelli specifici per il tuo dataset personalizzato. Questa flessibilità garantisce che qualsiasi progetto di rilevamento oggetti possa beneficiare di una valutazione robusta del modello utilizzando la Convalida incrociata K-Fold. Per un esempio pratico, rivedi la nostra sezione Generazione di vettori di caratteristiche.