Ultralytics YOLO27:

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.

K-fold cross validation data splitting

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.
KlassenbezeichnungAnzahl der Instanzen
Apfel7049
Trauben7202
Ananas1613
Orange15549
Banane3536
Wassermelone1976
  • Zu den erforderlichen Python-Paketen gehören:

    • ultralytics
    • sklearn
    • pandas
    • pyyaml
  • Dieses Tutorial arbeitet mit k=5 Faltungen. Du solltest jedoch die beste Anzahl an Faltungen für deinen spezifischen Datensatz bestimmen.

  1. Erstelle für dein Projekt eine neue virtuelle Python-Umgebung (venv) und aktiviere sie. Verwende pip (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.
  2. Überprüfe, dass deine Annotationen im YOLO-Erkennungsformat vorliegen.

    • Für dieses Tutorial befinden sich alle Annotierungsdateien im Verzeichnis Fruit-Detection/labels.

Erstellen von Merkmalsvektoren für einen Datensatz zur Objekterkennung#

  1. Erstelle zunächst eine neue example.py-Python-Datei für die folgenden Schritte.

  2. 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]
  3. Lies nun den Inhalt der YAML-Datei des Datensatzes ein und extrahiere die Indizes der Klassenbezeichnungen.

    classes = data["names"]
    cls_idx = sorted(classes.keys())
  4. Initialisiere einen leeren pandas-DataFrame.

    import pandas as pd
    
    labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images)
  5. 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())
  6. 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#

  1. Nun verwenden wir die Klasse KFold aus sklearn.model_selection, um den Datensatz in k Teilmengen aufzuteilen.

    • Wichtig:
      • Durch das Setzen von shuffle=True wird eine zufällige Verteilung der Klassen in deinen Teilmengen sichergestellt.
      • Wenn du random_state=M setzt, wobei M eine gewählte Ganzzahl ist, erhältst du reproduzierbare Ergebnisse.
    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. Der Datensatz wurde nun in k Faltungen aufgeteilt, die jeweils eine Liste von train- und val-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"
  3. Nun berechnen wir die Verteilung der Klassenbezeichnungen für jede Faltung als Verhältnis der in val vorhandenen Klassen zu den in train vorhandenen 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}"] = ratio

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

  4. 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#

  1. 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")
  2. 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 project und name angegeben 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
  3. 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:

    1. Überprüfe, dass die Annotationen im YOLO-Erkennungsformat vorliegen.
    2. Verwende Python-Bibliotheken wie sklearn, pandas und pyyaml.
    3. Erstelle Merkmalsvektoren aus deinem Datensatz.
    4. Teile deinen Datensatz mit KFold aus sklearn.model_selection auf.
    5. 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:

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

Kommentare