Ultralytics YOLO27 : Inscris-toi sur la liste d’attente.
Get Started
Entraîne ton premier modèle YOLO·Données·Leçon 4/10
Leçondébutant

Préparer un jeu de données personnalisé

Organise les images et les annotations au format Ultralytics YOLO, convertis les boîtes en pixels en lignes d’annotation normalisées et repère les annotations incorrectes avant l’entraînement.

Un dossier mal nommé ou une annotation non normalisée ne fait pas échouer l’entraînement. Ultralytics ignore les images incorrectes et continue : tu entraînes donc un modèle sur une partie de tes données, obtiens un résultat médiocre et perds un après-midi à chercher la cause au mauvais endroit.

Cette leçon porte sur les aspects pratiques d’un jeu de données de détection : dossiers, lignes d’annotation, conversion et vérifications. Tu utiliseras le véritable jeu de données d’imagerie médicale de comprimés, composé de 115 images, sur lequel le reste de ce cours s’appuie pour l’entraînement. Le choix de ce qu’il faut collecter et de la façon de l’annoter est abordé dans Bonnes pratiques d’annotation.

Résultat

Tu peux organiser un jeu de données au format Ultralytics YOLO, convertir des boîtes en pixels en lignes d’annotation normalisées et repérer les annotations manquantes ou corrompues dans la ligne de bilan avant l’entraînement.

Parcours accéléré
Si tu connais déjà les bases, voici la version courte.
  1. Crée images/{train,val} et labels/{train,val} avec des noms de fichiers correspondants.

  2. Écris une ligne class x_center y_center width height par objet, avec toutes les valeurs comprises entre 0 et 1.

  3. Convertis les boîtes en pixels en divisant par la largeur et la hauteur de l’image.

  4. Affiche le fichier d’annotation sur son image et vérifie que la ligne de bilan indique 0 corrupt.

Pratique

Récupérer le jeu de données d’exercice#

Boîte de dialogue « Nouveau jeu de données » d’Ultralytics Platform : zone de dépôt pour des images, des vidéos ou des jeux de données YOLO, COCO et NDJSON, puis nom, URL, description et type de tâche

La structure ci-dessous est également acceptée sous forme d’archive ZIP par la boîte de dialogue « Nouveau jeu de données » d’Ultralytics Platform : le jeu de données que tu prépares ici peut donc être téléversé sans modification. Télécharge 92 images d’entraînement et 23 images de validation de comprimés sous blister, puis décompresse-les dans my_dataset :

curl -L -o medical-pills.zip https://github.com/ultralytics/assets/releases/download/v0.0.0/medical-pills.zip
unzip -q medical-pills.zip -d my_dataset
my_dataset/
├── images/
│   ├── train/   Frame_0.jpg, Frame_100.jpg, ... (92 images)
│   └── val/     Frame_144.jpg, ... (23 images)
└── labels/
    ├── train/   Frame_0.txt, Frame_100.txt, ... (92 files)
    └── val/     Frame_144.txt, ... (23 files)

Il n’y a pas de manifeste. Ultralytics trouve chaque annotation en remplaçant /images/ par /labels/ dans le chemin de l’image, et l’extension par .txt ; ainsi, images/val/Frame_144.jpg lit labels/val/Frame_144.txt. Deux conséquences :

  • Les dossiers doivent s’appeler exactement images et labels, et se trouver côte à côte.
  • Une image dont le fichier d’annotation est vide ou manquant est une image d’arrière-plan : elle est valide et utile pour apprendre au modèle ce qu’il ne faut pas détecter, mais seulement si c’est bien ce que tu voulais.

Lire une ligne d’annotation#

Fichier d’annotation YOLO pour zidane.jpg, une ligne par objet : indice de classe, puis centre x, centre y, largeur et hauteur normalisés

Chaque ligne correspond à un objet : un indice de classe entier, suivi du centre et de la taille de la boîte englobante exprimés en fractions de la largeur et de la hauteur de l’image. Voici une vraie ligne de labels/train/Frame_0.txt :

0 0.330729 0.816204 0.103125 0.121296
  • 0 : indice de classe 0, que le YAML désignera par pill.
  • 0.330729 0.816204 : le centre de la boîte se trouve à 33 % de la largeur et à 82 % de la hauteur de l’image.
  • 0.103125 0.121296 : la boîte mesure environ 10 % de la largeur et 12 % de la hauteur de l’image.

Exemple pratique : convertir une boîte en pixels#

Les outils d’annotation exportent souvent les coordonnées des coins en pixels (x1, y1, x2, y2). Divise-les par la taille de l’image. La personne la plus à gauche dans bus.jpg de 810×1080, présenté dans la leçon précédente, s’étend de (49, 398) à (240, 902) :

ChampFormuleValeur
x_center(x1 + x2) / 2 / width(49 + 240) / 2 / 810 = 0.178395
y_center(y1 + y2) / 2 / height(398 + 902) / 2 / 1080 = 0.601852
width(x2 − x1) / width191 / 810 = 0.235802
height(y2 − y1) / height504 / 1080 = 0.466667

La plupart des outils d’annotation, ainsi que des outils comme Roboflow, peuvent exporter directement au format YOLO. Pour les fichiers JSON COCO, suis le guide d’entraînement avec JSON COCO ; le dépôt JSON2YOLO couvre les autres formats. Pour les fichiers XML Pascal VOC, la formule ci-dessus tient dans un court script :

import xml.etree.ElementTree as ET
from pathlib import Path

CLASSES = ["person", "bus"]  # index = class id; must match names in data.yaml

def voc_to_yolo(xml_file: Path, out_dir: Path) -> None:
    root = ET.parse(xml_file).getroot()
    w, h = int(root.find("size/width").text), int(root.find("size/height").text)
    lines = []
    for obj in root.iter("object"):
        name = obj.find("name").text
        if name not in CLASSES:
            continue
        box = obj.find("bndbox")
        x1, y1, x2, y2 = (float(box.find(k).text) for k in ("xmin", "ymin", "xmax", "ymax"))
        xc, yc, bw, bh = (x1 + x2) / 2 / w, (y1 + y2) / 2 / h, (x2 - x1) / w, (y2 - y1) / h
        lines.append(f"{CLASSES.index(name)} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}")
    out_dir.mkdir(parents=True, exist_ok=True)
    (out_dir / f"{xml_file.stem}.txt").write_text("\n".join(lines) + "\n")

voc_to_yolo(Path("bus.xml"), Path("labels"))
print(Path("labels/bus.txt").read_text())

Exécuté sur un bus.xml contenant les boîtes de la personne et du bus de la leçon précédente, le script affiche l’exemple détaillé et celui du bus :

0 0.178395 0.601852 0.235802 0.466667
1 0.495679 0.454167 0.991358 0.482407

Vérifier avant l’entraînement#

Affiche quelques fichiers d’annotation sur leurs images. Une classe décalée, des axes x et y inversés ou des boîtes autour des ombres sautent aux yeux, mais restent invisibles dans les métriques :

from ultralytics.data.utils import visualize_image_annotations

visualize_image_annotations(
    "my_dataset/images/train/Frame_0.jpg",
    "my_dataset/labels/train/Frame_0.txt",
    {0: "pill"},
)

Ensuite, laisse Ultralytics vérifier chaque fichier. Lorsqu’il lit un jeu de données pour la première fois, il analyse les annotations et décide, ligne par ligne, si chaque image est exploitable :

La ligne de bilan indique le résultat : 23 images, 0 backgrounds, 0 corrupt correspond à un jeu de données sain. Tout autre résultat signale l’une des erreurs ci-dessous.

Éviter ces erreurs#

Normalisation oubliée

Symptôme : ignoring corrupt image/label: non-normalized or out of bounds coordinates [634. 881. 198. 163.] et un nombre corrupt non nul. Cause : les valeurs sont exprimées en pixels plutôt qu'en fractions. Solution : divise par la largeur et la hauteur de l'image. Toute valeur d'étiquette supérieure à 1 signifie que la boîte n'a jamais été normalisée.

Dossier des étiquettes mal nommé

Symptôme : yolo val parcourt 0 images, 23 backgrounds et affiche l'avertissement No labels found, puis l'entraînement s'arrête avec ValueError: train: No labels found — ici, parce que le dossier des étiquettes s'appelait annotations. Solution : nomme les dossiers exactement images et labels, avec des noms de fichiers correspondants.

Les indices des classes commencent à 1

Symptôme : Label class 1 exceeds dataset class count 1. Possible class labels are 0-0. Cause : l'outil d'exportation a numéroté les classes à partir de 1. Solution : les classes YOLO commencent à 0 ; soustrais 1 dans le script de conversion ou corrige le paramètre d'exportation.

Coins ou centres

Si les boîtes dessinées sont décalées d'une demi-boîte vers le bas et la droite, tu as écrit x1 y1 w h au lieu de x_center y_center w h. Dessiner une seule image permet de le repérer en quelques secondes ; aucun contrôle du jeu de données ne le peut.

Pour effectuer des vérifications systématiques sur un jeu de données entier, consulte Contrôle qualité des jeux de données. Les jeux de données intégrés comme coco8, coco128 et african-wildlife fournissent de bons exemples de structure ; la présentation des jeux de données les répertorie tous. L’entraîneur ajoute de l’augmentation des données à tes annotations : un rapide nettoyage des données à cette étape est donc bénéfique à chaque époque.

Essayer

Télécharge le jeu de données de comprimés dans my_dataset. Fournis trois vérifications : le nombre d’images et d’annotations pour chaque partition, le résultat d’un script qui affiche toute valeur d’annotation hors de l’intervalle 0–1 (il ne doit rien afficher), et un fichier d’annotation affiché sur son image avec visualize_image_annotations. Si tu as tes propres images annotées, convertis-en 10 à la même structure et affiche-en une.

Terminé lorsque
Tu as terminé la leçon lorsque tous les éléments suivants sont réunis.
  • my_dataset contient images/train, images/val, labels/train et labels/val, avec des noms de fichiers et des nombres correspondants.

  • Ton script de vérification ne trouve aucune valeur d’annotation en dehors de l’intervalle 0–1.

  • Tu as affiché au moins un fichier d’annotation sur son image et les boîtes sont placées sur les comprimés.

Afficher la solution
for s in train val; do
  echo "$s: $(ls my_dataset/images/$s | wc -l) images, $(ls my_dataset/labels/$s | wc -l) labels"
done
# train: 92 images, 92 labels
# val:   23 images, 23 labels
from pathlib import Path

for txt in Path("my_dataset/labels").rglob("*.txt"):
    for line in txt.read_text().splitlines():
        values = [float(v) for v in line.split()[1:]]
        if any(v < 0 or v > 1 for v in values):
            print(txt, line)

Si le script ne renvoie rien, toutes les coordonnées sont normalisées. Des nombres identiques par partition signifient que chaque image a un fichier d’annotation ; la ligne de bilan de la prochaine leçon confirmera qu’aucun fichier n’est corrompu.

Et ensuite ?

Les dossiers sont prêts. Ensuite, écris l’unique fichier YAML qui indique à Ultralytics où ils se trouvent et ce que signifient les classes.