YOLO Vision 2026 :

Validation croisée K-Fold avec Ultralytics#

Introduction#

Ce guide complet illustre la mise en œuvre de la validation croisée K-Fold pour les ensembles de données de détection d'objets au sein de l'écosystème Ultralytics. Nous exploiterons le format de détection YOLO et des bibliothèques Python clés telles que sklearn, pandas et PyYAML pour te guider à travers la configuration nécessaire, le processus de génération de vecteurs de caractéristiques et l'exécution d'une division d'ensemble de données en K-Fold.

K-fold cross validation data splitting

Que ton projet implique le jeu de données Fruit Detection ou une source de données personnalisée, ce tutoriel vise à t'aider à comprendre et à appliquer la validation croisée K-Fold pour renforcer la fiabilité et la robustesse de tes modèles d'apprentissage automatique. Bien que nous appliquions k=5 folds pour ce tutoriel, garde à l'esprit que le nombre optimal de plis peut varier en fonction de ton jeu de données et des spécificités de ton projet. La validation croisée K-Fold offre le plus de valeur lorsque ton jeu de données est petit, bruyant ou très variable ; pour les grands jeux de données diversifiés, une division train/val/test bien construite suffit généralement.

Commençons.

Configuration#

  • Tes annotations doivent être au format de détection YOLO.

  • Ce guide suppose que les fichiers d'annotation sont disponibles localement.

  • Pour notre démonstration, nous utilisons l'ensemble de données Fruit Detection.

    • Ce jeu de données contient un total de 8479 images.
    • Il inclut 6 étiquettes de classe, chacune avec son nombre total d'instances listé ci-dessous.
Étiquette de classeNombre d'instances
Apple7049
Grapes7202
Pineapple1613
Orange15549
Banana3536
Watermelon1976
  • Les packages Python nécessaires incluent :

    • 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.

  1. Initie un nouvel environnement virtuel Python (venv) pour ton projet et active-le. Utilise pip (ou ton gestionnaire de paquets préféré) pour installer :

    • La bibliothèque Ultralytics : pip install -U ultralytics. Alternativement, tu peux cloner le dépôt officiel.
    • Scikit-learn, pandas et PyYAML : pip install -U scikit-learn pandas pyyaml.
  2. Vérifie que tes annotations sont au format de détection YOLO.

    • Pour ce tutoriel, tous les fichiers d'annotation se trouvent dans le répertoire Fruit-Detection/labels.

Génération de vecteurs de caractéristiques pour le jeu de données de détection d'objets#

  1. Commence par créer un nouveau fichier Python example.py pour les étapes ci-dessous.

  2. Charge les images d'entraînement et de validation configurées via le propriétaire du jeu de données du paquet, en laissant le jeu de test intact.

    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. Maintenant, lis le contenu du fichier YAML du jeu de données et extrais les indices des étiquettes de classe.

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

    import pandas as pd
    
    labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images)
  5. Compte les instances de chaque étiquette de classe présente dans les fichiers d'annotation.

    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. Voici un aperçu du DataFrame rempli :

                                                           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 utilisent des chemins d'image absolus, et les colonnes correspondent aux indices des étiquettes de classe. Les étiquettes manquantes restent des lignes d'arrière-plan entièrement à zéro. Cette structure de données permet l'application de la K-Fold Cross Validation à un jeu de données de détection d'objets.

Séparation du jeu de données K-Fold#

  1. Maintenant, nous allons utiliser la classe KFold de sklearn.model_selection pour générer k divisions de l'ensemble de données.

    • Important :
      • Définir shuffle=True garantit une distribution aléatoire des classes dans tes divisions.
      • En définissant random_state=MM est un entier choisi, tu peux obtenir des résultats reproductibles.
    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. L'ensemble de données a maintenant été divisé en k plis, chacun ayant une liste d'indices train et val. Nous allons construire un DataFrame pour afficher ces résultats plus clairement.

    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. Maintenant, nous allons calculer la distribution des étiquettes de classe pour chaque pli en tant que ratio des classes présentes dans val par rapport à celles présentes dans 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

    Le scénario idéal est que tous les ratios de classe soient raisonnablement similaires pour chaque séparation et entre les classes. Cela dépendra cependant des spécificités de ton jeu de données.

  4. Écris des listes d'images et un fichier YAML de jeu de données pour chaque division. Les listes textuelles évitent de copier le jeu de données k fois.

    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,
            )

Enregistrer les enregistrements (Optionnel)#

En option, tu peux enregistrer les enregistrements des DataFrames de séparation K-Fold et de distribution des étiquettes en tant que 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îner YOLO en utilisant les séparations de données K-Fold#

  1. D'abord, charge le modèle 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. Ensuite, parcours les fichiers YAML de l'ensemble de données pour exécuter l'entraînement. Les résultats seront enregistrés dans un répertoire spécifié par les arguments project et name. Par défaut, ce répertoire est 'runs/detect/train#' où # est un index entier.

    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. Tu peux également utiliser la fonction Ultralytics data.split.autosplit pour une division automatique de l'ensemble de données :

    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)

Conclusion#

Dans ce guide, nous avons exploré le processus d'utilisation de la validation croisée K-Fold pour entraîner le modèle de détection d'objets YOLO. Nous avons appris à diviser le groupe d'entraînement et de validation en K partitions et à utiliser le tableau de ratios généré pour inspecter l'équilibre des classes après une division aléatoire.

Nous avons également exploré la procédure pour créer des DataFrames de rapport afin de visualiser les séparations de données et les distributions d'étiquettes à travers ces séparations, nous fournissant une vision claire de la structure de nos ensembles d'entraînement et de validation.

En option, nous avons enregistré nos enregistrements pour référence ultérieure, ce qui pourrait être particulièrement utile dans des projets à grande échelle ou lors du dépannage des performances du modèle.

Enfin, nous avons mis en œuvre l'entraînement du modèle réel en utilisant chaque séparation dans une boucle, en enregistrant nos résultats d'entraînement pour une analyse et une comparaison ultérieures.

Cette technique de validation croisée K-Fold est un moyen robuste de tirer le meilleur parti de tes données disponibles, et elle aide à garantir que les performances de ton modèle sont fiables et cohérentes à travers différents sous-ensembles de données. Il en résulte un modèle plus généralisable et plus fiable, moins enclin au surapprentissage sur des motifs de données spécifiques.

Rappelle-toi que bien que nous ayons utilisé YOLO dans ce guide, ces étapes sont pour la plupart transférables à d'autres modèles de machine learning. Comprendre ces étapes te permet d'appliquer efficacement la validation croisée dans tes propres projets de machine learning.

FAQ#

  • La validation croisée K-Fold est une technique où l'ensemble de données est divisé en 'k' sous-ensembles (plis) pour évaluer les performances du modèle de manière plus fiable. Chaque pli sert à la fois de données d'entraînement et de données de validation. Dans le contexte de la détection d'objets, l'utilisation de la validation croisée K-Fold aide à garantir que les performances de ton modèle Ultralytics YOLO sont robustes et généralisables à travers différentes divisions de données, améliorant ainsi sa fiabilité. Pour des instructions détaillées sur la configuration de la validation croisée K-Fold avec Ultralytics YOLO, réfère-toi à Validation croisée K-Fold avec Ultralytics.

  • Pour mettre en œuvre la validation croisée K-Fold avec Ultralytics YOLO, tu dois suivre ces étapes :

    1. Vérifie que les annotations sont au format de détection YOLO.
    2. Utilise des bibliothèques Python telles que sklearn, pandas et pyyaml.
    3. Crée des vecteurs de caractéristiques à partir de ton jeu de données.
    4. Divise ton ensemble de données en utilisant KFold de sklearn.model_selection.
    5. Entraîne le modèle YOLO sur chaque séparation.

    Pour un guide complet, consulte la section Division de l'ensemble de données K-Fold dans notre documentation.

  • Le flux de travail de ce guide cible le format de détection YOLO, mais la même approche s'adapte à toutes les tâches YOLO — la tâche modifie la façon dont tu composes les plis, pas l'utilité de la validation croisée :

    TâcheConception des plis
    detectDivise au niveau de l'image, en équilibrant les distributions d'objets et de classes entre les plis. Garde les images associées (même patient, séquence vidéo, caméra ou site) dans un seul pli.
    segmentUtilise la même stratégie au niveau de l'image que pour la détection, en préservant en plus la couverture des masques et des classes dans chaque pli.
    classifyPréfère des plis stratifiés pour que les fréquences de classes restent équilibrées entre l'entraînement et la validation.
    poseDivise par sujet ou par séquence pour qu'une même personne ou un même animal n'apparaisse jamais des deux côtés d'un pli.
    obbDivise au niveau de l'image, en regroupant les tuiles ou les recadrages d'une même scène — particulièrement important pour l'imagerie aérienne.

    Quelle que soit la tâche, éloigne les échantillons quasi-dupliqués et apparentés des plis opposés : ce type de fuite gonfle les métriques de validation bien au-delà de ce que le modèle atteindra en production.

  • Ultralytics YOLO offre une détection d'objets en temps réel de pointe avec une précision et une efficacité élevées. Il est polyvalent et prend en charge de multiples tâches de vision par ordinateur telles que la détection, la segmentation d'instances, la segmentation sémantique et la classification. De plus, il s'intègre de manière transparente à des outils tels que Ultralytics Platform pour l'entraînement et le déploiement de modèles sans code. Pour plus de détails, explore les avantages et les fonctionnalités sur notre page Ultralytics YOLO.

  • Tes annotations doivent suivre le format de détection YOLO. Chaque fichier d'annotation doit lister la classe d'objet, ainsi que ses coordonnées de boîte englobante dans l'image. Le format YOLO garantit un traitement des données rationalisé et standardisé pour l'entraînement de modèles de détection d'objets. Pour plus d'informations sur le formatage correct des annotations, visite le guide du format de détection YOLO.

  • Oui, tu peux utiliser la validation croisée K-Fold avec n'importe quel ensemble de données personnalisé tant que les annotations sont au format de détection YOLO. Remplace les chemins de l'ensemble de données et les étiquettes de classe par ceux 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, examine notre section Génération de vecteurs de caractéristiques.

Commentaires