YOLO Vision 2026:

K-Fold-Kreuzvalidierung mit Ultralytics#

Einführung#

Diese umfassende Anleitung veranschaulicht die Implementierung der K-Fold-Kreuzvalidierung für Objekterkennung-Datensätze innerhalb des Ultralytics-Ökosystems. Wir nutzen das YOLO-Erkennungsformat und wichtige Python-Bibliotheken wie sklearn, pandas und PyYAML, um dich durch das erforderliche Setup, den Prozess der Generierung von Merkmalsvektoren und die Durchführung eines K-Fold-Datensatzsplits zu führen.

K-fold cross validation data splitting

Ob dein Projekt den Fruit Detection-Datensatz oder eine benutzerdefinierte Datenquelle betrifft, zielt dieses Tutorial darauf ab, dir zu helfen, K-Fold Cross Validation zu verstehen und anzuwenden, um die Zuverlässigkeit und Robustheit deiner machine learning-Modelle zu stärken. Während wir für dieses Tutorial k=5 Folds anwenden, solltest du bedenken, dass die optimale Anzahl von Folds je nach Datensatz und den Besonderheiten deines Projekts variieren kann. K-Fold Cross Validation bietet den größten Nutzen, wenn dein Datensatz klein, verrauscht oder stark variabel ist; für große, diverse Datensätze ist ein gut konstruierter Train/Val/Test-Split meist ausreichend.

Lass uns anfangen.

Einrichtung#

  • Deine Annotationen sollten im YOLO-Erkennungsformat vorliegen.

  • Dieser Leitfaden setzt voraus, dass Annotationsdateien lokal verfügbar sind.

  • Für unsere Demonstration verwenden wir den Fruit Detection-Datensatz.

    • Dieser Datensatz enthält insgesamt 8479 Bilder.
    • Er beinhaltet 6 Klassen-Labels, deren gesamte Instanzanzahlen unten aufgeführt sind.
Klassen-LabelInstanzanzahl
Apple7049
Grapes7202
Pineapple1613
Orange15549
Banana3536
Watermelon1976
  • Notwendige Python-Pakete beinhalten:

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

  1. Starte eine neue virtuelle Python-Umgebung (venv) für dein Projekt 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, ob deine Annotationen im YOLO-Erkennungsformat vorliegen.

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

Generierung von Feature-Vektoren für ein Objekterkennungs-Dataset#

  1. Beginne damit, eine neue Python-Datei example.py für die folgenden Schritte zu erstellen.

  2. Lade die konfigurierten Trainings- und Validierungsbilder über den Dataset-Eigentümer des Pakets und lasse den Test-Split unangetastet.

    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 Datensatz-YAML-Datei und extrahiere die Indizes der Klassen-Labels.

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

    import pandas as pd
    
    labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images)
  5. Zähle die Instanzen jedes in den Annotationsdateien vorhandenen Klassen-Labels.

    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. Das Folgende ist eine beispielhafte Ansicht des gefüllten DataFrames:

                                                           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 Klassen-Label-Indizes. Fehlende Labels bleiben als reine Null-Hintergrundzeilen erhalten. Diese Datenstruktur ermöglicht die Anwendung der K-Fold Cross Validation auf ein Objekterkennungs-Dataset.

K-Fold-Datensatz-Split#

  1. Jetzt verwenden wir die Klasse KFold aus sklearn.model_selection, um k-Splits des Datensatzes zu generieren.

    • Wichtig:
      • Das Setzen von shuffle=True sorgt für eine randomisierte Verteilung der Klassen in deinen Splits.
      • Durch das Setzen von random_state=M, wobei M eine gewählte Ganzzahl ist, kannst du reproduzierbare Ergebnisse erzielen.
    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 Folds aufgeteilt, von denen jedes eine Liste von train- und val-Indizes aufweist. 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=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. Jetzt berechnen wir die Verteilung der Klassenlabels für jeden Fold als Verhältnis der in val vorhandenen Klassen zu denen in 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

    Das ideale Szenario ist, dass alle Klassenverhältnisse für jeden Split und über alle Klassen hinweg einigermaßen ähnlich sind. Dies hängt jedoch von den Spezifika deines Datensatzes ab.

  4. Erstelle Bildlisten und ein Dataset-YAML für jeden Split. Textlisten vermeiden das Kopieren des Datasets k-mal.

    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 Aufzeichnungen der K-Fold-Split- und Label-Verteilungs-DataFrames als CSV-Dateien für spätere Referenzzwecke 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-Datensatz-Splits trainieren#

  1. Lade zuerst 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. Iteriere als Nächstes über die YAML-Dateien des Datensatzes, um das Training auszuführen. Die Ergebnisse werden in einem Verzeichnis gespeichert, das durch die Argumente project und name angegeben wird. Standardmäßig ist dieses 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 Ultralytics data.split.autosplit-Funktion für die automatische Datensatzaufteilung 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 Verwendung der K-Fold-Kreuzvalidierung zum Trainieren des YOLO-Objekterkennungsmodells untersucht. Wir haben gelernt, wie man den Trainings- und Validierungspool in K Partitionen aufteilt und die generierte Verhältnistabelle verwendet, um das Klassengleichgewicht nach dem zufälligen Aufteilen zu überprüfen.

Wir haben zudem das Verfahren zur Erstellung von Report-DataFrames erkundet, um die Datensatz-Splits und Label-Verteilungen über diese Splits zu visualisieren, was uns einen klaren Einblick in die Struktur unserer Trainings- und Validierungssets gibt.

Optional haben wir unsere Aufzeichnungen für spätere Referenzzwecke gespeichert, was besonders bei groß angelegten Projekten oder bei der Fehlersuche in der Modellperformance nützlich sein kann.

Abschließend haben wir das tatsächliche 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 deinen verfügbaren Daten herauszuholen, und sie trägt dazu bei, dass deine Modellleistung über verschiedene Datenübersichten hinweg zuverlässig und konsistent ist. Dies führt zu einem besser generalisierbaren und zuverlässigeren Modell, das weniger dazu neigt, sich an spezifische Datenmuster anzupassen (Overfitting).

Denke daran, dass diese Schritte, obwohl wir in diesem Leitfaden YOLO verwendet haben, größtenteils auf andere Machine-Learning-Modelle übertragbar sind. Das Verständnis dieser Schritte ermöglicht es dir, die Kreuzvalidierung effektiv in deinen eigenen Machine-Learning-Projekten anzuwenden.

FAQ#

  • Die K-Fold-Kreuzvalidierung 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 Validierungsdaten. Im Kontext der Objekterkennung trägt die Verwendung der K-Fold-Kreuzvalidierung dazu bei, dass die Leistung deines Ultralytics YOLO-Modells über verschiedene Datensplits hinweg robust und generalisierbar ist, wodurch seine Zuverlässigkeit erhöht wird. Detaillierte Anweisungen zum Einrichten 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 diese Schritte befolgen:

    1. Überprüfe, ob die Annotationen im YOLO-Erkennungsformat vorliegen.
    2. Verwende Python-Bibliotheken wie sklearn, pandas und pyyaml.
    3. Erstelle Feature-Vektoren aus deinem Datensatz.
    4. Teile deinen Datensatz mit KFold aus sklearn.model_selection auf.
    5. Trainiere das YOLO-Modell auf jedem Split.

    Eine umfassende Anleitung findest du im Abschnitt K-Fold-Datensatz-Split in unserer Dokumentation.

  • Der Workflow in diesem Leitfaden zielt auf das YOLO-Erkennungsformat ab, aber derselbe Ansatz lässt sich auf jede YOLO-Aufgabe anpassen – die Aufgabe ändert, wie du die Folds zusammenstellst, nicht ob Kreuzvalidierung hilft:

    AufgabeFold-Entwurf
    detectAufteilung auf Bitebene bzw. Bild-Ebene, wobei Objekt- und Klassenverteilungen über Folds hinweg ausbalanciert werden. Behalte zusammengehörige Bilder (gleicher Patient, Videosequenz, Kamera oder Standort) innerhalb eines einzigen Folds.
    segmentVerwende dieselbe Strategie auf Bild-Ebene wie bei der Erkennung und bewahre zusätzlich die Masken- und Klassenabdeckung in jedem Fold.
    classifyBevorzuge geschichtete Folds (stratified folds), damit die Klassenhäufigkeiten zwischen Training und Validierung ausgeglichen bleiben.
    poseNach Subjekt oder Sequenz aufteilen, damit dieselbe Person oder dasselbe Tier niemals auf beiden Seiten eines Folds erscheint.
    obbAufteilung auf Bild-Ebene, wobei Kacheln oder Ausschnitte aus derselben Szene zusammengehalten werden – besonders wichtig für Luftaufnahmen.

    Unabhängig von der Aufgabe solltest du fast identische und verwandte Stichproben aus entgegengesetzten Folds heraushalten: diese Art von Leakage treibt die Validierungsmetriken weit über das hinaus, was das Modell in der Produktion erreichen wird.

  • Ultralytics YOLO bietet modernste Echtzeit-Objekterkennung mit hoher Genauigkeit und Effizienz. Es ist vielseitig und unterstützt mehrere Computer Vision-Aufgaben wie Erkennung, Instanzsegmentierung, semantische Segmentierung und Klassifizierung. Darüber hinaus lässt es sich nahtlos in Tools wie die Ultralytics Platform für das codefreie Modelltraining und die Bereitstellung integrieren. Weitere Details zu den Vorteilen und Funktionen findest du auf unserer Ultralytics YOLO-Seite.

  • Deine Annotationen sollten dem YOLO-Erkennungsformat folgen. Jede Annotationsdatei muss die Objektklasse zusammen mit ihren Bounding Box-Koordinaten im Bild auflisten. Das YOLO-Format gewährleistet eine optimierte und standardisierte Datenverarbeitung für das Training von Objekterkennungsmodellen. Weitere Informationen zur korrekten Annotationsformatierung findest du im Leitfaden zum YOLO-Erkennungsformat.

  • Ja, du kannst die K-Fold-Kreuzvalidierung mit jedem benutzerdefinierten Datensatz verwenden, solange die Annotationen im YOLO-Erkennungsformat vorliegen. Ersetze die Datensatzpfade und Klassenlabels durch diejenigen, die für deinen benutzerdefinierten Datensatz spezifisch sind. 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 Generieren von Merkmalsvektoren.

Kommentare