Validation croisée K-Fold avec Ultralytics
Introduction
This comprehensive guide illustrates the implementation of K-Fold Cross Validation for object detection datasets within the Ultralytics ecosystem. We'll leverage the YOLO detection format and key Python libraries such as sklearn, pandas, and PyYaml to guide you through the necessary setup, the process of generating feature vectors, and the execution of a K-Fold dataset split.
Whether your project involves the Fruit Detection dataset or a custom data source, this tutorial aims to help you comprehend and apply K-Fold Cross Validation to bolster the reliability and robustness of your machine learning models. While we're applying k=5
plis pour ce tutoriel, garde à l'esprit que le nombre optimal de plis peut varier en fonction de ton ensemble de données et des spécificités de ton projet.
Sans plus attendre, plongeons dans le vif du sujet !
Mise en place
-
Tes annotations doivent être au format de détectionYOLO .
-
Ce guide suppose que les fichiers d'annotation sont disponibles localement.
-
Pour notre démonstration, nous utilisons l'ensemble de données de détection de fruits.
- Cet ensemble de données contient un total de 8479 images.
- Il comprend 6 étiquettes de classe, chacune avec son nombre total d'instances indiqué ci-dessous.
Étiquette de classe | Nombre d'instances |
---|---|
Pomme | 7049 |
Raisins | 7202 |
Ananas | 1613 |
Orange | 15549 |
Banane | 3536 |
Melon d'eau | 1976 |
-
Les paquets nécessaires sur Python comprennent
ultralytics
sklearn
pandas
pyyaml
-
Ce tutoriel fonctionne avec
k=5
plis. Cependant, tu dois déterminer le meilleur nombre de plis pour ton ensemble de données spécifique. -
Lance un nouvel environnement virtuel Python (
venv
) pour ton projet et l'activer. Utilisepip
(ou ton gestionnaire de paquets préféré) pour l'installer :- La bibliothèque Ultralytics :
pip install -U ultralytics
. Tu peux aussi cloner le fichier officiel repo. - Scikit-learn, pandas et PyYAML :
pip install -U scikit-learn pandas pyyaml
.
- La bibliothèque Ultralytics :
-
Vérifie que tes annotations sont au format de détectionYOLO .
- Pour ce tutoriel, tous les fichiers d'annotation se trouvent dans le dossier
Fruit-Detection/labels
répertoire.
- Pour ce tutoriel, tous les fichiers d'annotation se trouvent dans le dossier
Générer des vecteurs de caractéristiques pour l'ensemble de données de détection d'objets
-
Commencez par créer un nouveau
example.py
Python pour suivre les Ă©tapes ci-dessous. -
Procède à la récupération de tous les fichiers d'étiquettes de ton jeu de données.
-
Maintenant, lis le contenu du fichier YAML du jeu de données et extrais les indices des étiquettes de classe.
-
Initialise un fichier vide
pandas
DataFrame. -
Compte les instances de chaque classe-étiquette présente dans les fichiers d'annotation.
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`
-
Voici un exemple de vue du DataFrame peuplé :
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
Les lignes indexent les fichiers d'étiquettes, chacun correspondant à une image de ton jeu de données, et les colonnes correspondent à tes indices d'étiquettes de classe. Chaque ligne représente un pseudo-vecteur de caractéristiques, avec le nombre de chaque étiquette de classe présente dans ton ensemble de données. Cette structure de données permet d'appliquer la validation croisée K-Fold à un ensemble de données de détection d'objets.
Fractionnement de l'ensemble de données K-Fold
-
Nous allons maintenant utiliser le
KFold
de la classesklearn.model_selection
pour générerk
les divisions de l'ensemble de données.- Important :
- RĂ©glage
shuffle=True
assure une répartition aléatoire des classes dans tes fractionnements. - En réglant
random_state=M
oĂąM
est un nombre entier choisi, tu peux obtenir des résultats reproductibles.
- RĂ©glage
- Important :
-
L'ensemble des données a maintenant été divisé en
k
plis, chacun ayant une liste detrain
etval
indices. Nous allons construire un DataFrame pour afficher ces résultats plus clairement. -
Nous allons maintenant calculer la distribution des étiquettes de classe pour chaque pli sous la forme d'un ratio des classes présentes dans
val
aux personnes présentes danstrain
.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
Le scénario idéal est que tous les ratios de classe soient raisonnablement similaires pour chaque fractionnement et pour toutes les classes. Cela dépend toutefois des spécificités de ton jeu de données.
-
Ensuite, nous créons les répertoires et les fichiers YAML des jeux de données pour chaque fractionnement.
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, )
-
Enfin, copie les images et les étiquettes dans le répertoire respectif ('train' ou 'val') pour chaque fractionnement.
- NOTE : Le temps nécessaire pour cette partie du code variera en fonction de la taille de ton ensemble de données et du matériel de ton système.
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)
Sauvegarder les enregistrements (optionnel)
En option, tu peux enregistrer les enregistrements des DataFrames de fractionnement K-Fold et de distribution d'étiquettes sous forme de fichiers CSV pour référence ultérieure.
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")
Entraîne YOLO à l'aide de K-Fold Data Splits
-
Charge d'abord le modèle YOLO .
-
Ensuite, itère sur les fichiers YAML de l'ensemble de données pour exécuter la formation. Les résultats seront enregistrés dans un répertoire spécifié par l'option
project
etname
arguments. Par défaut, ce répertoire est 'exp/runs#' où # est un indice entier.results = {} # Define your additional arguments here batch = 16 project = "kfold_demo" epochs = 100 for k in range(ksplit): dataset_yaml = ds_yamls[k] 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
Conclusion
Dans ce guide, nous avons exploré le processus d'utilisation de la validation croisée K-Fold pour l'entraînement du modèle de détection d'objets YOLO . Nous avons appris à diviser notre ensemble de données en K partitions, en veillant à ce que la répartition des classes soit équilibrée entre les différents plis.
Nous avons également exploré la procédure de création de DataFrames de rapport pour visualiser les divisions de données et les distributions d'étiquettes sur ces divisions, ce qui nous a permis d'avoir un aperçu clair de la structure de nos ensembles de formation et de validation.
En option, nous avons sauvegardé nos enregistrements pour les consulter ultérieurement, ce qui pourrait être particulièrement utile dans les projets à grande échelle ou lors du dépannage des performances du modèle.
Enfin, nous avons mis en œuvre la formation réelle du modèle en utilisant chaque fractionnement dans une boucle, en sauvegardant nos résultats de formation pour une analyse et une comparaison plus approfondies.
Cette technique de validation croisée K-Fold est un moyen robuste de tirer le meilleur parti de tes données disponibles, et elle permet de s'assurer que les performances de ton modèle sont fiables et cohérentes dans les différents sous-ensembles de données. Il en résulte un modèle plus généralisable et plus fiable, moins susceptible de s'adapter de façon excessive à des modèles de données spécifiques.
N'oublie pas que même si nous avons utilisé YOLO dans ce guide, ces étapes sont en grande partie transférables à d'autres modèles d'apprentissage automatique. Comprendre ces étapes te permet d'appliquer efficacement la validation croisée dans tes propres projets d'apprentissage automatique. Bon codage !
FAQ
Qu'est-ce que la validation croisée K-Fold et pourquoi est-elle utile dans la détection d'objets ?
K-Fold Cross Validation is a technique where the dataset is divided into 'k' subsets (folds) to evaluate model performance more reliably. Each fold serves as both training and validation data. In the context of object detection, using K-Fold Cross Validation helps to ensure your Ultralytics YOLO model's performance is robust and generalizable across different data splits, enhancing its reliability. For detailed instructions on setting up K-Fold Cross Validation with Ultralytics YOLO, refer to K-Fold Cross Validation with Ultralytics.
Comment mettre en œuvre la validation croisée K-Fold à l'aide de Ultralytics YOLO ?
Pour mettre en œuvre la validation croisée K-Fold avec Ultralytics YOLO , tu dois suivre les étapes suivantes :
- Vérifie que les annotations sont au format de détectionYOLO .
- Utilise les bibliothèques Python comme
sklearn
,pandas
etpyyaml
. - Crée des vecteurs de caractéristiques à partir de ton ensemble de données.
- Divise ton jeu de données en utilisant
KFold
desklearn.model_selection
. - Entraîne le modèle YOLO sur chaque fractionnement.
Pour un guide complet, consulte la section Fractionnement des ensembles de données K-Fold dans notre documentation.
Pourquoi devrais-je utiliser Ultralytics YOLO pour la détection d'objets ?
Ultralytics YOLO offers state-of-the-art, real-time object detection with high accuracy and efficiency. It's versatile, supporting multiple computer vision tasks such as detection, segmentation, and classification. Additionally, it integrates seamlessly with tools like Ultralytics HUB for no-code model training and deployment. For more details, explore the benefits and features on our Ultralytics YOLO page.
Comment puis-je m'assurer que mes annotations sont dans le bon format pour Ultralytics YOLO ?
Your annotations should follow the YOLO detection format. Each annotation file must list the object class, alongside its bounding box coordinates in the image. The YOLO format ensures streamlined and standardized data processing for training object detection models. For more information on proper annotation formatting, visit the YOLO detection format guide.
Puis-je utiliser la validation croisée K-Fold avec des ensembles de données personnalisés autres que la détection de fruits ?
Oui, tu peux utiliser la validation croisée K-Fold avec n'importe quel ensemble de données personnalisé, à condition que les annotations soient au format de détection YOLO . Remplace les chemins d'accès à l'ensemble de données et les étiquettes de classe par ceux qui sont spécifiques à ton ensemble de données personnalisé. Cette flexibilité garantit que tout projet de détection d'objets peut bénéficier d'une évaluation robuste du modèle à l'aide de la validation croisée K-Fold. Pour un exemple pratique, consulte la section Génération de vecteurs de caractéristiques.