K-Fold-Kreuzvalidierung mit Ultralytics#
Einleitung#
Dieser umfassende Leitfaden zeigt die Implementierung der K-Fold-Kreuzvalidierung für Datensätze zur Objekterkennung innerhalb des Ultralytics-Ökosystems. Wir verwenden das YOLO-Erkennungsformat und wichtige Python-Bibliotheken wie sklearn, pandas und PyYAML, um dich durch die erforderliche Einrichtung, die Erstellung von Merkmalsvektoren und die Durchführung einer K-Fold-Aufteilung des Datensatzes zu führen.
Unabhängig davon, ob dein Projekt den Fruit-Detection-Datensatz oder eine eigene Datenquelle verwendet, soll dir dieses Tutorial helfen, die K-Fold-Kreuzvalidierung zu verstehen und anzuwenden, um die Zuverlässigkeit und Robustheit deiner Machine-Learning-Modelle zu verbessern. Für dieses Tutorial verwenden wir k=5 Faltungen. Beachte jedoch, dass die optimale Anzahl der Faltungen je nach Datensatz und den Besonderheiten deines Projekts variieren kann. Die K-Fold-Kreuzvalidierung ist besonders hilfreich, wenn dein Datensatz klein, verrauscht oder sehr heterogen ist. Bei großen, vielfältigen Datensätzen reicht eine sorgfältig erstellte Aufteilung in Training, Validierung und Test normalerweise aus.
Beginnen wir.
Einrichtung#
-
Deine Annotationen sollten im YOLO-Erkennungsformat vorliegen.
-
Dieser Leitfaden setzt voraus, dass die Annotierungsdateien lokal verfügbar sind.
-
Für unsere Demonstration verwenden wir den Fruit-Detection-Datensatz.
- Dieser Datensatz enthält insgesamt 8479 Bilder.
- Er umfasst 6 Klassen, deren jeweilige Anzahl an Instanzen unten aufgeführt ist.
| Klassenbezeichnung | Anzahl der Instanzen |
|---|---|
| Apfel | 7049 |
| Trauben | 7202 |
| Ananas | 1613 |
| Orange | 15549 |
| Banane | 3536 |
| Wassermelone | 1976 |
-
Zu den erforderlichen Python-Paketen gehören:
ultralyticssklearnpandaspyyaml
-
Dieses Tutorial arbeitet mit
k=5Faltungen. Du solltest jedoch die beste Anzahl an Faltungen für deinen spezifischen Datensatz bestimmen.
-
Erstelle für dein Projekt eine neue virtuelle Python-Umgebung (
venv) und aktiviere sie. Verwendepip(oder deinen bevorzugten Paketmanager), um Folgendes zu installieren:- Die Ultralytics-Bibliothek:
pip install -U ultralytics. Alternativ kannst du das offizielle Repository klonen. - Scikit-learn, pandas und PyYAML:
pip install -U scikit-learn pandas pyyaml.
- Die Ultralytics-Bibliothek:
-
Überprüfe, dass deine Annotationen im YOLO-Erkennungsformat vorliegen.
- Für dieses Tutorial befinden sich alle Annotierungsdateien im Verzeichnis
Fruit-Detection/labels.
- Für dieses Tutorial befinden sich alle Annotierungsdateien im Verzeichnis
Erstellen von Merkmalsvektoren für einen Datensatz zur Objekterkennung#
-
Erstelle zunächst eine neue
example.py-Python-Datei für die folgenden Schritte. -
Lade die konfigurierten Trainings- und Validierungsbilder über den Datensatz-Owner des Pakets, ohne die Testaufteilung zu verändern.
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] -
Lies nun den Inhalt der YAML-Datei des Datensatzes ein und extrahiere die Indizes der Klassenbezeichnungen.
classes = data["names"] cls_idx = sorted(classes.keys()) -
Initialisiere einen leeren
pandas-DataFrame.import pandas as pd labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images) -
Zähle die Instanzen jeder in den Annotierungsdateien vorhandenen Klasse.
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()) -
Die folgende Ansicht zeigt beispielhaft den gefüllten DataFrame:
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
Die Zeilen verwenden absolute Bildpfade, und die Spalten entsprechen den Indizes der Klassenbezeichnungen. Fehlende Bezeichnungen bleiben als vollständig aus Nullen bestehende Hintergrundzeilen erhalten. Diese Datenstruktur ermöglicht die Anwendung der K-Fold-Kreuzvalidierung auf einen Datensatz zur Objekterkennung.
Aufteilung des Datensatzes in K Faltungen#
-
Nun verwenden wir die Klasse
KFoldaussklearn.model_selection, um den Datensatz inkTeilmengen aufzuteilen.- Wichtig:
- Durch das Setzen von
shuffle=Truewird eine zufällige Verteilung der Klassen in deinen Teilmengen sichergestellt. - Wenn du
random_state=Msetzt, wobeiMeine gewählte Ganzzahl ist, erhältst du reproduzierbare Ergebnisse.
- Durch das Setzen von
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)) - Wichtig:
-
Der Datensatz wurde nun in
kFaltungen aufgeteilt, die jeweils eine Liste vontrain- undval-Indizes enthalten. Wir erstellen einen DataFrame, um diese Ergebnisse übersichtlicher darzustellen.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" -
Nun berechnen wir die Verteilung der Klassenbezeichnungen für jede Faltung als Verhältnis der in
valvorhandenen Klassen zu den intrainvorhandenen Klassen.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}"] = ratioIdealerweise sind alle Klassenverhältnisse für jede Aufteilung und über alle Klassen hinweg annähernd gleich. Dies hängt jedoch von den Besonderheiten deines Datensatzes ab.
-
Schreibe für jede Aufteilung Bildlisten und eine YAML-Datei für den Datensatz. Textlisten vermeiden es, den Datensatz
k-mal zu kopieren.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, )
Datensätze speichern (optional)#
Optional kannst du die Datensätze der DataFrames zur K-Fold-Aufteilung und zur Verteilung der Bezeichnungen als CSV-Dateien zur späteren Verwendung speichern.
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")YOLO mit K-Fold-Datenaufteilungen trainieren#
-
Lade zunächst das YOLO-Modell.
from ultralytics import YOLO weights_path = "path/to/weights.pt" # use yolo26n.pt for a small model model = YOLO(weights_path, task="detect") -
Durchlaufe als Nächstes die YAML-Dateien der Datensätze, um das Training auszuführen. Die Ergebnisse werden in einem Verzeichnis gespeichert, das durch die Argumente
projectundnameangegeben wird. Standardmäßig ist dies das Verzeichnis „runs/detect/train#“, wobei # ein ganzzahliger Index ist.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 -
Du kannst auch die Funktion Ultralytics data.split.autosplit zur automatischen Aufteilung des Datensatzes verwenden:
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)
Fazit#
In diesem Leitfaden haben wir den Prozess der K-Fold-Kreuzvalidierung zum Trainieren des YOLO-Modells für die Objekterkennung untersucht. Wir haben gelernt, den Trainings- und Validierungspool in K Partitionen aufzuteilen und die erzeugte Verhältnistabelle zu verwenden, um das Klassenverhältnis nach der zufälligen Aufteilung zu überprüfen.
Außerdem haben wir das Erstellen von Berichts-DataFrames untersucht, um die Datenaufteilungen und die Verteilung der Bezeichnungen über diese Aufteilungen hinweg zu visualisieren. Dadurch erhalten wir einen klaren Einblick in die Struktur unserer Trainings- und Validierungssätze.
Optional haben wir unsere Datensätze zur späteren Verwendung gespeichert, was insbesondere bei großen Projekten oder bei der Fehlersuche hinsichtlich der Modellleistung nützlich sein kann.
Schließlich haben wir das eigentliche Modelltraining mit jeder Aufteilung in einer Schleife durchgeführt und unsere Trainingsergebnisse zur weiteren Analyse und zum Vergleich gespeichert.
Diese Technik der K-Fold-Kreuzvalidierung ist eine robuste Möglichkeit, deine verfügbaren Daten optimal zu nutzen. Sie trägt dazu bei, dass die Modellleistung über verschiedene Teilmengen der Daten hinweg zuverlässig und konsistent bleibt. Das Ergebnis ist ein besser verallgemeinerbares und zuverlässigeres Modell, das sich weniger wahrscheinlich an bestimmte Datenmuster überanpasst.
Denke daran, dass diese Schritte zwar in diesem Leitfaden mit YOLO verwendet wurden, sich aber größtenteils auf andere Machine-Learning-Modelle übertragen lassen. Wenn du diese Schritte verstehst, kannst du die Kreuzvalidierung in deinen eigenen Machine-Learning-Projekten effektiv anwenden.
FAQ#
Die K-Fold-Kreuzvalidierung ist eine Technik, bei der der Datensatz zur zuverlässigeren Bewertung der Modellleistung in „k“ Teilmengen (Faltungen) aufgeteilt wird. Jede Faltung dient sowohl als Trainings- als auch als Validierungsdaten. Im Kontext der Objekterkennung trägt die K-Fold-Kreuzvalidierung dazu bei, sicherzustellen, dass die Leistung deines Ultralytics-YOLO-Modells über verschiedene Datenaufteilungen hinweg robust und verallgemeinerbar ist, und verbessert dadurch seine Zuverlässigkeit. Eine ausführliche Anleitung zur Einrichtung der K-Fold-Kreuzvalidierung mit Ultralytics YOLO findest du unter K-Fold-Kreuzvalidierung mit Ultralytics.
Um die K-Fold-Kreuzvalidierung mit Ultralytics YOLO zu implementieren, musst du die folgenden Schritte ausführen:
- Überprüfe, dass die Annotationen im YOLO-Erkennungsformat vorliegen.
- Verwende Python-Bibliotheken wie
sklearn,pandasundpyyaml. - Erstelle Merkmalsvektoren aus deinem Datensatz.
- Teile deinen Datensatz mit
KFoldaussklearn.model_selectionauf. - Trainiere das YOLO-Modell auf jeder Aufteilung.
Eine umfassende Anleitung findest du im Abschnitt Aufteilung des Datensatzes in K Faltungen unserer Dokumentation.
Der Workflow in diesem Leitfaden zielt auf das YOLO-Erkennungsformat ab, aber derselbe Ansatz lässt sich auf jede YOLO-Aufgabe übertragen – die Aufgabe bestimmt, wie du die Faltungen zusammenstellst, nicht, ob eine Kreuzvalidierung hilfreich ist:
Aufgabe Entwurf der Faltungen detectTeile auf Bildebene auf und gleiche die Verteilung von Objekten und Klassen über die Faltungen hinweg aus. Halte zusammengehörige Bilder (derselbe Patient, dieselbe Videosequenz, Kamera oder derselbe Standort) innerhalb einer einzigen Faltung. segmentVerwende dieselbe Strategie auf Bildebene wie bei der Erkennung und stelle zusätzlich sicher, dass Masken und Klassen in jeder Faltung abgedeckt sind. classifyBevorzuge geschichtete Faltungen, damit die Klassenhäufigkeiten zwischen Training und Validierung ausgewogen bleiben. poseTeile nach Subjekt oder Sequenz auf, sodass dieselbe Person oder dasselbe Tier niemals auf beiden Seiten einer Faltung erscheint. obbTeile auf Bildebene auf und halte Kacheln oder Ausschnitte aus derselben Szene zusammen – besonders wichtig bei Luftaufnahmen. Unabhängig von der Aufgabe solltest du nahezu identische und zusammengehörige Stichproben aus gegenüberliegenden Faltungen heraushalten: Eine solche Datenleckage lässt die Validierungsmetriken deutlich höher erscheinen, als es die Leistung des Modells in der Produktion rechtfertigt.
Ultralytics YOLO bietet eine hochmoderne Objekterkennung in Echtzeit mit hoher Genauigkeit und Effizienz. Das System ist vielseitig und unterstützt mehrere Aufgaben der Computer Vision, darunter Erkennung, Instanzsegmentierung, semantische Segmentierung und Klassifizierung. Außerdem lässt es sich nahtlos in Tools wie die Ultralytics Platform für das Training und die Bereitstellung von Modellen ohne Code integrieren. Weitere Informationen zu den Vorteilen und Funktionen findest du auf unserer Ultralytics-YOLO-Seite.
Deine Annotationen sollten dem YOLO-Erkennungsformat entsprechen. Jede Annotierungsdatei muss die Objektklasse sowie die Koordinaten ihrer Begrenzungsbox im Bild enthalten. Das YOLO-Format sorgt für eine optimierte und standardisierte Datenverarbeitung beim Training von Objekterkennungsmodellen. Weitere Informationen zur korrekten Formatierung von Annotationen findest du im Leitfaden zum YOLO-Erkennungsformat.
Ja, du kannst die K-Fold-Kreuzvalidierung mit jedem eigenen Datensatz verwenden, solange die Annotationen im YOLO-Erkennungsformat vorliegen. Ersetze die Pfade zum Datensatz und die Klassenbezeichnungen durch die für deinen eigenen Datensatz geltenden Werte. Diese Flexibilität stellt sicher, dass jedes Objekterkennungsprojekt von einer robusten Modellbewertung mithilfe der K-Fold-Kreuzvalidierung profitieren kann. Ein praktisches Beispiel findest du in unserem Abschnitt Merkmalsvektoren erstellen.