K-Fold Cross Validation mit Ultralytics
Einführung
Diese umfassende Anleitung veranschaulicht die Implementierung der K-Fold-Kreuzvalidierung für Objekterkennungs-Datensätze innerhalb des Ultralytics-Ökosystems. Wir nutzen das YOLO-Erkennungsformat und wichtige Python-Bibliotheken wie sklearn, pandas und PyYaml, um Sie durch die notwendige Einrichtung, den Prozess der Generierung von Feature-Vektoren und die Ausführung einer K-Fold-Datensatzaufteilung zu führen.
Unabhängig davon, ob Ihr Projekt das Fruit Detection Dataset oder eine benutzerdefinierte Datenquelle umfasst, zielt dieses Tutorial darauf ab, Ihnen zu helfen, die K-Fold-Kreuzvalidierung zu verstehen und anzuwenden, um die Zuverlässigkeit und Robustheit Ihrer maschinelles Lernen Modelle übergeben werden. Während wir k=5
Falten für dieses Tutorial. Beachten Sie, dass die optimale Anzahl der Faltungen je nach Datensatz und den Besonderheiten Ihres Projekts variieren kann.
Ohne weiteres Zögern, legen wir los!
Einrichtung
-
Ihre Annotationen sollten im YOLO-Detektionsformat vorliegen.
-
Dieser Leitfaden setzt voraus, dass Annotationsdateien lokal verfügbar sind.
-
Für unsere Demonstration verwenden wir den Frucht-Erkennungsdatensatz.
- Dieser Datensatz enthält insgesamt 8479 Bilder.
- Es enthält 6 Klassenbezeichnungen, jeweils mit den unten aufgeführten Gesamtanzahlen der Instanzen.
Klassenbezeichnung | Anzahl der Instanzen |
---|---|
Apple | 7049 |
Weintrauben | 7202 |
Ananas | 1613 |
Orange | 15549 |
Banane | 3536 |
Wassermelone | 1976 |
-
Notwendige python-Pakete umfassen:
ultralytics
sklearn
pandas
pyyaml
-
Dieses Tutorial arbeitet mit
k=5
Faltungen. Sie sollten jedoch die beste Anzahl von Faltungen für Ihren spezifischen Datensatz ermitteln. -
Initiieren Sie eine neue virtuelle Python-Umgebung (
venv
) für Ihr Projekt und aktivieren Sie es. Verwenden Siepip
(oder Ihren bevorzugten Paketmanager) zur Installation:- Die Ultralytics Bibliothek:
pip install -U ultralytics
. Alternativ können Sie das offizielle Repository klonen Repository. - Scikit-learn, pandas und PyYAML:
pip install -U scikit-learn pandas pyyaml
.
- Die Ultralytics Bibliothek:
-
Stellen Sie sicher, dass Ihre Annotationen im YOLO-Erkennungsformat vorliegen.
- Für dieses Tutorial befinden sich alle Annotationsdateien im
Fruit-Detection/labels
Verzeichnis.
- Für dieses Tutorial befinden sich alle Annotationsdateien im
Feature-Vektoren für Objekterkennungsdatensatz generieren
-
Beginnen Sie mit dem Erstellen eines neuen
example.py
Python-Datei für die folgenden Schritte. -
Fahren Sie fort, alle Beschriftungsdateien für Ihren Datensatz abzurufen.
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'
-
Lesen Sie nun den Inhalt der YAML-Datei des Datensatzes und extrahieren Sie die Indizes der Klassenbezeichnungen.
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())
-
Initialisieren Sie ein leeres
pandas
DataFrame.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)
-
Zählen Sie die Instanzen jeder Klassenbezeichnung, die in den Annotationsdateien vorhanden sind.
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`
-
Das Folgende ist eine Beispielansicht des ausgefü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 indizieren die Beschriftungsdateien, die jeweils einem Bild in Ihrem Datensatz entsprechen, und die Spalten entsprechen Ihren Klassenbeschriftungsindizes. Jede Zeile stellt einen Pseudo-Feature-Vektor dar, mit der Anzahl jeder Klassenbeschriftung, die in Ihrem Datensatz vorhanden ist. Diese Datenstruktur ermöglicht die Anwendung von K-Fold Cross Validation auf einen Objekterkennungsdatensatz.
K-Fold Datensatzaufteilung
-
Nun werden wir die
KFold
Klasse vonsklearn.model_selection
zum Generierenk
Aufteilungen des Datensatzes.- Wichtig:
- Einstellung
shuffle=True
gewährleistet eine randomisierte Verteilung der Klassen in Ihren Aufteilungen. - Durch Setzen von
random_state=M
wobeiM
ist eine gewählte ganze Zahl, mit der Sie wiederholbare Ergebnisse erzielen können.
- Einstellung
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))
- Wichtig:
-
Der Datensatz wurde nun aufgeteilt in
k
Faltungen, jede mit einer Liste vontrain
undval
Indizes. Wir werden ein DataFrame erstellen, um diese Ergebnisse übersichtlicher darzustellen.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"
-
Nun berechnen wir die Verteilung der Klassenbezeichnungen für jeden Fold als Verhältnis der vorhandenen Klassen in
val
zu denen, die vorhanden sind 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}"] = ratio
Das ideale Szenario ist, wenn alle Klassenverhältnisse für jeden Split und über alle Klassen hinweg einigermaßen ähnlich sind. Dies hängt jedoch von den Besonderheiten Ihres Datensatzes ab.
-
Als Nächstes erstellen wir die Verzeichnisse und Dataset-YAML-Dateien für jeden Split.
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, )
-
Kopieren Sie abschließend Bilder und Beschriftungen in das jeweilige Verzeichnis ('train' oder 'val') für jeden Split.
- HINWEIS: Die für diesen Teil des Codes benötigte Zeit variiert je nach Größe Ihres Datensatzes und Ihrer Systemhardware.
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)
Datensätze speichern (optional)
Optional können Sie die Aufzeichnungen der K-Fold-Aufteilung und der Labelverteilungs-DataFrames als CSV-Dateien für zukünftige Referenzzwecke speichern.
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")
YOLO-Training mit K-Fold-Datensplits
-
Laden Sie zuerst das YOLO-Modell.
from ultralytics import YOLO weights_path = "path/to/weights.pt" # use yolo11n.pt for a small model model = YOLO(weights_path, task="detect")
-
Als Nächstes iterieren Sie über die Dataset-YAML-Dateien, um das Training auszuführen. Die Ergebnisse werden in einem Verzeichnis gespeichert, das durch die
project
undname
Argumente. Standardmäßig ist dieses Verzeichnis 'runs/detect/train#', wobei # eine ganzzahlige Indexnummer 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
-
Sie können auch die Funktion Ultralytics data.utils.autosplit für die automatische Aufteilung von Datensätzen verwenden:
from ultralytics.data.utils 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 dieser Anleitung haben wir den Prozess der Verwendung von K-Fold-Kreuzvalidierung für das Training des YOLO-Objekterkennungsmodells untersucht. Wir haben gelernt, wie wir unseren Datensatz in K Partitionen aufteilen und dabei eine ausgewogene Klassenverteilung über die verschiedenen Faltungen hinweg sicherstellen.
Wir haben auch das Verfahren zur Erstellung von Report-DataFrames untersucht, um die Datenaufteilungen und Label-Verteilungen über diese Aufteilungen hinweg zu visualisieren, was uns einen klaren Einblick in die Struktur unserer Trainings- und Validierungssätze gibt.
Optional haben wir unsere Aufzeichnungen für zukünftige Referenzzwecke gespeichert, was besonders in großen Projekten oder bei der Fehlerbehebung der Modellleistung nützlich sein könnte.
Schließlich haben wir das eigentliche Modelltraining unter Verwendung jedes Splits in einer Schleife implementiert und unsere Trainingsergebnisse für weitere Analysen und Vergleiche gespeichert.
Diese Technik der K-Fold-Kreuzvalidierung ist eine robuste Methode, um das Beste aus Ihren verfügbaren Daten herauszuholen, und sie trägt dazu bei, sicherzustellen, dass Ihre Modellleistung über verschiedene Datenteilmengen hinweg zuverlässig und konsistent ist. Dies führt zu einem generalisierbareren und zuverlässigeren Modell, bei dem die Wahrscheinlichkeit geringer ist, dass es zu Overfitting bei bestimmten Datenmustern kommt.
Denken Sie daran, dass diese Schritte zwar hauptsächlich auf andere Modelle des maschinellen Lernens übertragbar sind, obwohl wir in diesem Leitfaden YOLO verwendet haben. Das Verständnis dieser Schritte ermöglicht es Ihnen, die Kreuzvalidierung effektiv in Ihren eigenen Projekten des maschinellen Lernens anzuwenden. Viel Spaß beim Programmieren!
FAQ
Was ist K-Fold-Kreuzvalidierung und warum ist sie in der Objekterkennung nützlich?
K-Fold Cross Validation ist eine Technik, bei der der Datensatz in 'k' Teilmengen (Folds) unterteilt wird, um die Modellleistung zuverlässiger zu bewerten. Jeder Fold dient sowohl als Trainings- als auch als Validierungsdatensatz. Im Kontext der Objekterkennung trägt die Verwendung von K-Fold Cross Validation dazu bei, dass die Leistung Ihres Ultralytics YOLO-Modells robust und über verschiedene Datensplits hinweg generalisierbar ist, was seine Zuverlässigkeit erhöht. Detaillierte Anweisungen zur Einrichtung der K-Fold Cross Validation mit Ultralytics YOLO finden Sie unter K-Fold Cross Validation mit Ultralytics.
Wie implementiere ich K-Fold-Kreuzvalidierung mit Ultralytics YOLO?
Um K-Fold Cross Validation mit Ultralytics YOLO zu implementieren, musst du folgende Schritte ausführen:
- Überprüfen Sie, ob die Annotationen im YOLO-Erkennungsformat vorliegen.
- Verwenden Sie Python-Bibliotheken wie
sklearn
,pandas
undpyyaml
. - Erstellen Sie Feature-Vektoren aus Ihrem Datensatz.
- Teilen Sie Ihren Datensatz mit
KFold
vonsklearn.model_selection
. - Trainieren Sie das YOLO-Modell auf jedem Split.
Eine umfassende Anleitung finden Sie im Abschnitt K-Fold Datensatzaufteilung in unserer Dokumentation.
Warum sollte ich Ultralytics YOLO für die Objekterkennung verwenden?
Ultralytics YOLO bietet modernste Objekterkennung in Echtzeit mit hoher Genauigkeit und Effizienz. Es ist vielseitig und unterstützt mehrere Computer Vision-Aufgaben wie Erkennung, Segmentierung und Klassifizierung. Darüber hinaus lässt es sich nahtlos in Tools wie Ultralytics HUB für No-Code-Modelltraining und -bereitstellung integrieren. Weitere Informationen finden Sie auf unserer Ultralytics YOLO Seite, wo Sie die Vorteile und Funktionen erkunden können.
Wie kann ich sicherstellen, dass meine Annotationen das korrekte Format für Ultralytics YOLO haben?
Ihre Annotationen sollten dem YOLO-Detektionsformat entsprechen. Jede Annotationsdatei muss die Objektklasse zusammen mit ihren Begrenzungsrahmen-Koordinaten im Bild auflisten. Das YOLO-Format gewährleistet eine optimierte und standardisierte Datenverarbeitung für das Training von Objekterkennungsmodellen. Weitere Informationen zur korrekten Formatierung von Annotationen finden Sie im YOLO-Detektionsformat-Leitfaden.
Kann ich K-Fold-Kreuzvalidierung mit anderen benutzerdefinierten Datensätzen als der Fruchterkennung verwenden?
Ja, Sie können K-Fold-Kreuzvalidierung mit jedem benutzerdefinierten Datensatz verwenden, solange sich die Anmerkungen im YOLO-Erkennungsformat befinden. Ersetzen Sie die Datensatzpfade und Klassenbezeichnungen durch die für Ihren benutzerdefinierten Datensatz spezifischen. Diese Flexibilität stellt sicher, dass jedes Objekterkennungsprojekt von einer robusten Modellbewertung mithilfe der K-Fold-Kreuzvalidierung profitieren kann. Ein praktisches Beispiel finden Sie in unserem Abschnitt Generieren von Feature-Vektoren.