Zum Inhalt springen

K-fache Kreuzvalidierung mit Ultralytics

Einführung

Dieser umfassende Leitfaden veranschaulicht die Implementierung der K-Fold Cross Validation für Objekterkennungsdatensätze innerhalb des Ultralytics Ökosystems. Wir nutzen das Erkennungsformat YOLO und die wichtigsten Python Bibliotheken wie sklearn, pandas und PyYaml, um dich durch die notwendigen Einstellungen, die Erzeugung von Merkmalsvektoren und die Durchführung einer K-Fold-Datensatzteilung zu führen.

K-Fold Cross Validation Überblick

Ganz gleich, ob dein Projekt den Fruit Detection-Datensatz oder eine benutzerdefinierte Datenquelle verwendet, dieses Tutorial soll dir helfen, die K-Fold Cross Validation zu verstehen und anzuwenden, um die Zuverlässigkeit und Robustheit deiner Machine Learning-Modelle zu verbessern. Während wir die k=5 Die optimale Anzahl von Foldings kann je nach Datensatz und den Besonderheiten deines Projekts variieren.

Ohne Umschweife, lasst uns eintauchen!

Einrichtung

  • Deine Anmerkungen sollten im ErkennungsformatYOLO sein.

  • Dieser Leitfaden geht davon aus, dass die Anmerkungsdateien lokal verfügbar sind.

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

    • Dieser Datensatz enthält insgesamt 8479 Bilder.
    • Sie enthält 6 Klassenlabels, deren Gesamtanzahl der Instanzen unten aufgeführt ist.
Klasse Etikett Anzahl der Instanzen
Apfel 7049
Weintrauben 7202
Ananas 1613
Orange 15549
Banane 3536
Wassermelone 1976
  • Zu den notwendigen Python Paketen gehören:

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

  • Initiiere eine neue Python virtuelle Umgebung (venv) für dein Projekt und aktiviere es. Verwenden Sie pip (oder deinen bevorzugten Paketmanager) zu installieren:

    • Die Ultralytics Bibliothek: pip install -U ultralytics. Alternativ kannst du auch die offizielle Repo.
    • Scikit-learn, Pandas und PyYAML: pip install -U scikit-learn pandas pyyaml.
  • Vergewissere dich, dass deine Anmerkungen im ErkennungsformatYOLO vorliegen.

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

Erzeugen von Merkmalsvektoren für den Objektdetektionsdatensatz

  1. Beginnen Sie mit der Erstellung eines neuen example.py Python -Datei für die folgenden Schritte.

  2. Fahre fort, um alle Etikettendateien für deinen 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'
    
  3. Lies nun den Inhalt der YAML-Datei des Datensatzes und extrahiere die Indizes der Klassenbezeichnungen.

    yaml_file = "path/to/data.yaml"  # your data YAML with data directories and names dictionary
    with open(yaml_file, "r", encoding="utf8") as y:
        classes = yaml.safe_load(y)["names"]
    cls_idx = sorted(classes.keys())
    
  4. Initialisiere eine leere pandas DataFrame.

    import pandas as pd
    
    indx = [l.stem for l in labels]  # uses base filename as ID (no extension)
    labels_df = pd.DataFrame([], columns=cls_idx, index=indx)
    
  5. Zähle die Instanzen jedes Klassen-Labels in den Annotationsdateien.

    from collections import Counter
    
    for label in labels:
        lbl_counter = Counter()
    
        with open(label, "r") as lf:
            lines = lf.readlines()
    
        for l in lines:
            # classes for YOLO label uses integer at first position of each line
            lbl_counter[int(l.split(" ")[0])] += 1
    
        labels_df.loc[label.stem] = lbl_counter
    
    labels_df = labels_df.fillna(0.0)  # replace `nan` values with `0.0`
    
  6. Es folgt 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 deines Datensatzes entsprechen, und die Spalten entsprechen den Indizes deiner Klassenlabels. Jede Zeile stellt einen Pseudo-Feature-Vektor dar, der die Anzahl der in deinem Datensatz vorhandenen Klassen-Labels enthält. Diese Datenstruktur ermöglicht die Anwendung der K-Fold Cross Validation auf einen Objekterkennungsdatensatz.

K-fache Datensatzaufteilung

  1. Jetzt werden wir die KFold Klasse von sklearn.model_selection zu erzeugen k Splits des Datensatzes.

    • Wichtig!
      • Einstellung shuffle=True sorgt für eine zufällige Verteilung der Klassen in deinen Splits.
      • Durch die Einstellung random_state=M wo M eine ausgewählte ganze Zahl ist, kannst du wiederholbare 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 aufgeteilt in k Falten, jede mit einer Liste von train und val Indizes. Wir werden einen DataFrame erstellen, um diese Ergebnisse deutlicher darzustellen.

    folds = [f"split_{n}" for n in range(1, ksplit + 1)]
    folds_df = pd.DataFrame(index=indx, columns=folds)
    
    for idx, (train, val) in enumerate(kfolds, start=1):
        folds_df[f"split_{idx}"].loc[labels_df.iloc[train].index] = "train"
        folds_df[f"split_{idx}"].loc[labels_df.iloc[val].index] = "val"
    
  3. Nun berechnen wir die Verteilung der Klassenlabels für jede Falte als Verhältnis der Klassen, die in val für die Anwesenden 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
    

    Im Idealfall sind alle Klassenverhältnisse für jeden Split und über alle Klassen hinweg einigermaßen ähnlich. Dies hängt jedoch von den Besonderheiten deines Datensatzes ab.

  4. Als Nächstes erstellen wir die Verzeichnisse und Datensatz-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 (unchanged)
    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,
            )
    
  5. Zum Schluss kopierst du die Bilder und Beschriftungen in das jeweilige Verzeichnis ("train" oder "val") für jeden Split.

    • HINWEIS: Die Zeit, die für diesen Teil des Codes benötigt wird, hängt von der Größe deines Datensatzes und deiner Systemhardware ab.
    import shutil
    
    for image, label in zip(images, labels):
        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 kannst du die Datensätze der K-Fold Split- und Label Distribution DataFrames als CSV-Dateien für spätere Zwecke speichern.

folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")

Trainiere YOLO mit K-Fold Data Splits

  1. Lade zunächst das Modell YOLO .

    from ultralytics import YOLO
    
    weights_path = "path/to/weights.pt"
    model = YOLO(weights_path, task="detect")
    
  2. Als Nächstes iterierst du über die YAML-Dateien des Datensatzes, um das Training durchzuführen. Die Ergebnisse werden in einem Verzeichnis gespeichert, das mit der Option project und name Argumente. Standardmäßig ist dieses Verzeichnis "exp/runs#", wobei # ein ganzzahliger Index ist.

    results = {}
    
    # Define your additional arguments here
    batch = 16
    project = "kfold_demo"
    epochs = 100
    
    for k in range(ksplit):
        dataset_yaml = ds_yamls[k]
        model.train(data=dataset_yaml, epochs=epochs, batch=batch, project=project)  # include any train arguments
        results[k] = model.metrics  # save output metrics for further analysis
    

Fazit

In diesem Leitfaden haben wir den Prozess der K-Fold-Kreuzvalidierung für das Training des Objekterkennungsmodells YOLO erkundet. Wir haben gelernt, wie wir unseren Datensatz in K Partitionen aufteilen, um eine ausgewogene Klassenverteilung über die verschiedenen Foldings zu gewährleisten.

Wir haben auch das Verfahren zur Erstellung von Report DataFrames erforscht, um die Datenaufteilung und die Verteilung der Labels über diese Aufteilung zu visualisieren, was uns einen klaren Einblick in die Struktur unserer Trainings- und Validierungssätze gibt.

Optional haben wir unsere Aufzeichnungen für die Zukunft gespeichert, was besonders bei großen Projekten oder bei der Fehlersuche in der Modellleistung nützlich sein kann.

Schließlich haben wir das eigentliche Modelltraining mit jedem Split in einer Schleife durchgeführt 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 sicherzustellen, dass die Leistung deines Modells über verschiedene Datenuntergruppen hinweg zuverlässig und konsistent ist. Das Ergebnis ist ein verallgemeinerbares und zuverlässiges Modell, das sich weniger leicht an bestimmte Datenmuster anpassen lässt.

Denke daran, dass wir in diesem Leitfaden zwar YOLO verwendet haben, diese Schritte aber größtenteils auch auf andere maschinelle Lernmodelle übertragbar sind. Wenn du diese Schritte verstehst, kannst du die Kreuzvalidierung in deinen eigenen Projekten zum maschinellen Lernen effektiv anwenden. Viel Spaß beim Programmieren!

FAQ

Was ist K-Fold Cross Validation und warum ist sie bei der Objekterkennung nützlich?

Bei der K-Fold-Kreuzvalidierung wird der Datensatz in "k" Teilmengen (Folds) unterteilt, um die Leistung des Modells zuverlässiger zu bewerten. Jeder Fold dient sowohl als Trainings- als auch als Validierungsdaten. Im Zusammenhang mit der Objekterkennung hilft die K-Fold Cross Validation dabei, sicherzustellen, dass die Leistung deines Ultralytics YOLO Modells robust und über verschiedene Datensplits hinweg verallgemeinerbar ist, was seine Zuverlässigkeit erhöht. Eine ausführliche Anleitung zur Einrichtung der K-Fold Cross Validation mit Ultralytics YOLO findest du unter K-Fold Cross Validation mit Ultralytics.

Wie implementiere ich die K-Fold Cross Validation mit Ultralytics YOLO ?

Um die K-Fold Cross Validation mit Ultralytics YOLO durchzuführen, musst du die folgenden Schritte befolgen:

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

Eine umfassende Anleitung findest du im Abschnitt K-Fold Dataset Split 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. Sie ist vielseitig und unterstützt verschiedene Computer Vision Aufgaben wie Erkennung, Segmentierung und Klassifizierung. Außerdem lässt sie sich nahtlos in Tools wie Ultralytics HUB integrieren, um Modelle ohne Code zu trainieren und einzusetzen. Weitere Informationen zu den Vorteilen und Funktionen findest du auf unserer SeiteUltralytics YOLO .

Wie kann ich sicherstellen, dass meine Anmerkungen das richtige Format für Ultralytics YOLO haben?

Deine Anmerkungen sollten dem Erkennungsformat YOLO entsprechen. In jeder Annotationsdatei muss die Objektklasse zusammen mit den Bounding-Box-Koordinaten im Bild aufgeführt sein. Das YOLO Format gewährleistet eine rationelle und standardisierte Datenverarbeitung für das Training von Objekterkennungsmodellen. Weitere Informationen zur korrekten Formatierung von Anmerkungen findest du im Leitfaden zum Erkennungsformat unterYOLO .

Kann ich die K-Fold Cross Validation auch mit anderen Datensätzen als der Fruchterkennung verwenden?

Ja, du kannst die K-Fold Cross Validation mit jedem benutzerdefinierten Datensatz verwenden, solange die Annotationen im YOLO Erkennungsformat vorliegen. Ersetze die Datensatzpfade und Klassenbezeichnungen durch die für deinen eigenen Datensatz spezifischen. Diese Flexibilität stellt sicher, dass jedes Objekterkennungsprojekt von der robusten Modellbewertung mit der K-Fold Cross Validation profitieren kann. Ein praktisches Beispiel findest du im Abschnitt Feature-Vektoren generieren.



Erstellt am 2023-11-12, Aktualisiert am 2024-07-05
Autoren: glenn-jocher (10), IvorZhu331 (1), Burhan-Q (1)

Kommentare