Ultralytics YOLO27: Trag dich in die Warteliste ein.
Get Started
Grundlagen der Computer Vision·Metriken lesen·Lektion 8/10
LektionAnfänger

Aufteilungen, die die Wahrheit zeigen

Finde nahezu identische Bilder, die zwischen Trainings- und Validierungsdaten durchsickern, und teile die Daten nach der Einheit auf, die beim Einsatz neu sein wird.

Wenn ein Modell bei der Validierung 95 % und im Produktivbetrieb 60 % erreicht, war die Aufteilung meist irreführend. Nahezu identische Bilder – benachbarte Videobilder oder Aufnahmen derselben Kamera am selben Tag – landeten auf beiden Seiten. Dadurch prüfte die Validierung das Erinnerungsvermögen statt der Generalisierung. Du findest genau dieses Datenleck in einem echten Datensatz und behebst es anschließend mit einer gruppenbasierten Aufteilung.

Lernergebnis

Erkenne nahezu identische Bilder über verschiedene Teilmengen hinweg, teile anhand eines Gruppenschlüssels auf und prüfe, dass keine Gruppe in mehr als einer Teilmenge vorkommt.

Schnellkurs
Wenn du dich bereits auskennst, findest du hier die Kurzfassung.
  1. Das Training passt die Gewichte an, die Validierung steuert Entscheidungen, und der Test liefert einmalig ein Ergebnis.

  2. Prüfe vor dem Vertrauen auf einen Validierungswert, ob sich über verschiedene Teilmengen hinweg nahezu identische Bilder befinden.

  3. Finde den Gruppenschlüssel: Clip, Kamera, Tag oder Motiv.

  4. Mische die Gruppen statt der Bilder und prüfe anschließend, ob jede Klasse in jeder Teilmenge vorkommt.

  5. Sperre die Testmenge und verwende sie nur einmal pro abgeschlossenem Experiment.

Praxisnah

Drei Teilmengen, drei Aufgaben#

TeilmengeWer daraus lerntWann du sie dir ansiehst
TrainingDas Modell: Hier werden die Gewichte angepasstJede Epoche
ValidierungDu: Hyperparameter, Epochen, Modellgröße, SchwellenwerteNach jedem Experiment
TestNiemand: Es meldet die endgültige ZahlEinmal, nachdem alle Entscheidungen getroffen wurden

Jede Entscheidung, die du anhand eines Splits triffst, lässt ein wenig davon in das Modell einfließen. Genau dafür ist der Validierungssatz da. Wenn du den Testsatz zum Abstimmen verwendest, ist dessen Ergebnis keine ehrliche Schätzung mehr – du hast dich auf deine eigenen Entscheidungen überangepasst. In Ultralytics wertet model.val(split="test") den Testsplit aus deiner Dataset-YAML-Datei aus.

Finde das Datenleck in einem echten Dataset#

Die Bilder der Medikamentenblister heißen Frame_0.jpg, Frame_4.jpg, Frame_8.jpg – Einzelbilder aus einem Video. Das ist ein Warnzeichen: Benachbarte Einzelbilder sind nahezu identisch, und bei einer zufälligen Aufteilung landen sie auf beiden Seiten. Prüfe das, indem du winzige Graustufen-Fingerabdrücke jedes Validierungsbilds mit jedem Trainingsbild vergleichst:

from pathlib import Path

import numpy as np
from PIL import Image
from ultralytics.data.utils import check_det_dataset

data = check_det_dataset("medical-pills.yaml")

def thumbnail(path):
    """A 32x18 grayscale fingerprint: enough to spot near-identical frames."""
    return np.asarray(Image.open(path).convert("L").resize((32, 18)), dtype=float)

train = {p.name: thumbnail(p) for p in sorted(Path(data["train"]).glob("*.jpg"))}
pairs = []
for p in sorted(Path(data["val"]).glob("*.jpg")):
    v = thumbnail(p)
    name, diff = min(((n, np.abs(v - t).mean()) for n, t in train.items()), key=lambda x: x[1])
    pairs.append((diff, p.name, name))

pairs.sort()
print(f"{sum(d < 5 for d, _, _ in pairs)} of {len(pairs)} val images have a near-twin in train (difference < 5)")
for diff, val_name, train_name in pairs[:3]:
    print(f"  {val_name} ~ {train_name}  difference {diff:.1f}")
17 of 23 val images have a near-twin in train (difference < 5)
  Frame_344.jpg ~ Frame_56.jpg  difference 0.3
  Frame_28.jpg ~ Frame_312.jpg  difference 0.5
  Frame_24.jpg ~ Frame_308.jpg  difference 1.8

Eine Abweichung von 0.3 auf einer Skala von 0–255 bedeutet, dass die beiden Bilder praktisch dasselbe Motiv zeigen. Öffne val/Frame_24.jpg und train/Frame_308.jpg nebeneinander, dann siehst du dieselben Blisterpackungen aus derselben Perspektive. 17 der 23 Validierungsbilder haben ein Gegenstück im Trainingssatz. Der Validierungswert misst hier also größtenteils, wie gut sich das Modell an Bilder erinnert, die es bereits gesehen hat. Für ein schnelles Demo-Dataset ist das in Ordnung – aber genau so etwas darfst du nicht ausliefern.

Dialogfeld „Splits neu verteilen“ der Ultralytics Platform für medical-pills, eingestellt auf 80 % Training, 20 % Validierung und 0 % Test

Dieselbe Falle gibt es in jedem Tool. In der Beschreibung dieses Dialogfelds steht, dass jedes Bild zufällig neu zugewiesen wird. Das ist ideal, wenn die Bilder unabhängige Fotos sind – bei Einzelbildern aus Videos führt es jedoch zu Datenlecks. Prüfe zuerst auf nahezu identische Bilder und behalte einen Testanteil von über 0 %, wenn du ein endgültiges Ergebnis möchtest, auf das niemand abgestimmt hat.

Nach Gruppen aufteilen#

Die Regel: Die Splits müssen hinsichtlich der Einheit unabhängig sein, die beim Einsatz neu sein wird.

DatenAufteilen nach
VideoVideoclip oder Aufnahmesitzung
Fester KamerabestandKamera oder Standort
Szenen, die sich im Laufe der Zeit verändernTag oder Woche
Medizinische Daten, Sportdaten oder PersonendatenPatient, Sportler oder Person
FotoserienAufnahmeereignis

Dateinamen enthalten oft den Gruppenschlüssel. Dieses Beispiel erstellt 900 Bilder von 6 Kameras und vergleicht die beiden Strategien:

import random
from collections import defaultdict

# File names carry the unit that must never straddle splits: camera_day_frame.jpg
images = [f"cam{c:02d}_day{d}_{f:04d}.jpg" for c in range(1, 7) for d in range(1, 4) for f in range(50)]

# WRONG: shuffle individual frames, so near-identical neighbors land in both splits
random.seed(0)
shuffled = random.sample(images, len(images))
train, val = shuffled[: int(0.8 * len(images))], shuffled[int(0.8 * len(images)) :]
shared = {i.split("_")[0] for i in train} & {i.split("_")[0] for i in val}
print(f"per-image split: {len(shared)} of 6 cameras appear in both train and val")

# RIGHT: shuffle whole cameras, then expand them back into images
groups = defaultdict(list)
for image in images:
    groups[image.split("_")[0]].append(image)
cameras = random.sample(sorted(groups), len(groups))
train = [i for cam in cameras[:5] for i in groups[cam]]
val = [i for cam in cameras[5:] for i in groups[cam]]
print(f"per-camera split: train {len(train)} images, val {len(val)} images, val cameras {cameras[5:]}")
per-image split: 6 of 6 cameras appear in both train and val
per-camera split: train 750 images, val 150 images, val cameras ['cam05']

Bei der Aufteilung pro Bild sieht die Validierung nie eine neue Kamera. Bei der Aufteilung pro Kamera schätzt der Wert, wie das Modell mit einer Kamera abschneidet, die es noch nie gesehen hat – genau die Zahl, die du brauchst.

Stolperfallen#

Zufälliges Mischen bei korrelierten Daten

Symptom: Die Validierung fällt deutlich besser aus als der erste Test im Einsatz. Lösung: Finde den Gruppenschlüssel – oft in Dateinamen oder Aufnahmemetadaten verborgen –, teile anhand dieses Schlüssels auf und prüfe die Aufteilung auf nahezu identische Bilder.

Eine Klasse fehlt in der Validierung

Symptom: Eine seltene Klasse ohne AP oder AP auf Grundlage von nur zwei Instanzen. Lösung: Zähle nach der Aufteilung nach Gruppen die Instanzen jeder Klasse pro Teilmenge und tausche ganze Gruppen aus, bis jede Klasse in ähnlichen Anteilen vorkommt. sklearn.model_selection.StratifiedGroupKFold automatisiert das.

Auf dem Testsatz abstimmen

Symptom: Der Testwert steigt über mehrere Experimente hinweg langsam an. Lösung: Fixiere den Testsatz, stelle ihn unter produktionsähnlichen Bedingungen zusammen und werte ihn pro abgeschlossenem Experiment nur einmal aus. Bei kleinen Datensätzen solltest du statt denselben Testsatz wiederzuverwenden den Durchschnitt über mehrere Aufteilungen mit k-facher Kreuzvalidierung bilden.

Dataset richtig aufteilen behandelt Aufteilungsverhältnisse und zeigt, wie du all das auf ein vollständiges Dataset anwendest.

Ausprobieren

Führe die Prüfung auf nahezu identische Bilder für dein Dataset (oder medical-pills) aus. Notiere, wie viele Validierungsbilder ein nahezu identisches Gegenstück im Trainingssatz haben. Benenne dann deinen Gruppenschlüssel, teile die Daten danach neu auf und führe die Leckprüfung aus der Lösung mit den neuen Dateilisten aus. Als Ergebnis benötigst du die Anzahl der nahezu identischen Paare vor und nach der Aufteilung sowie eine Leckprüfung, die eine leere Liste ausgibt.

Abgeschlossen, wenn
Du hast die Lektion abgeschlossen, wenn alle folgenden Punkte zutreffen.
  • Du hast die Anzahl der nahezu identischen Paare für deinen aktuellen Split ermittelt.

  • Du hast deinen Gruppenschlüssel benannt und die Daten danach neu aufgeteilt.

  • Die Leckprüfung gibt für deine neuen Splits eine leere Liste aus.

Lösung anzeigen

Eine Leckprüfung, die mit jeder Dateinamensliste funktioniert, wenn eine Funktion zum Extrahieren des Gruppenschlüssels übergeben wird:

def leaked_groups(splits, key):
    """Return every group key that appears in more than one split."""
    owner, leaks = {}, set()
    for split, files in splits.items():
        for name in files:
            group = key(name)
            if owner.setdefault(group, split) != split:
                leaks.add(group)
    return sorted(leaks)

# Ersetze diese Listen durch deine Dateinamen, z. B. [p.name for p in Path("images/train").glob("*.jpg")]
splits = {
    "train": ["cam01_day1_0001.jpg", "cam01_day1_0002.jpg", "cam02_day1_0001.jpg"],
    "val": ["cam03_day2_0001.jpg", "cam01_day1_0003.jpg"],
    "test": ["cam04_day3_0001.jpg"],
}
print(leaked_groups(splits, key=lambda name: name.split("_")[0]))  # Nach Kamera gruppieren
['cam01']

cam01 kommt sowohl in train als auch in val vor, also führt dieser Split zu Datenlecks. Verschiebe alle cam01-Bilder in einen Split und führe die Prüfung erneut aus, bis [] ausgegeben wird. Bei medical-pills, wo Einzelbilder aus einem Video dieselbe Ansicht wiederholen, gibt es in den Dateinamen keinen eindeutigen Gruppenschlüssel: Nimm entweder neue Validierungsvideos mit anderen Packungen auf oder gruppiere die Bilder anhand des Fingerabdrucks für nahezu identische Bilder und weise ganze Gruppen einem Split zu.

Wie es weitergeht

Wenn die Splits nun unverfälscht sind, liest du als Nächstes die daraus entstehenden Metriken.