GPUs für Ihre Projekte · Krypto-Zahlung ohne KYC So mieten Sie
Deutsch
Konsole öffnen
Praktischer Leitfaden / KERNODECK

Der DataLoader blockiert: Daten vor den Workern prüfen

Beginnen Sie mit num_workers=0 und einer festen Reihenfolge, prüfen Sie eine Stichprobe und dann einen vollständigen Batch, und trennen Sie Lesen, Transformationen, Zusammenstellung und GPU-Transfer. Führen Sie anschließend die Worker schrittweise wieder ein. Eine GPU, die wartet, beweist nicht, dass der Speicher langsam ist: ein Datenfehler, eine Serialisierung oder eine teure Zusammenstellung kann die Kette vor der Berechnung blockieren.

7 Min. Lesezeit · Leitfaden für Entwickler

Definieren, was der Loader liefern soll

Schreiben Sie den Ausgabevertrag, bevor Sie optimieren: Anzahl der Elemente, Typ jedes Felds, Dimensionen, Wertebereich der Ziele und Regel für unvollständige Eingaben. Unterscheiden Sie die Kennung des Beispiels von seiner Position in einem Batch. Eine Transformation kann eine Form ändern oder eine Eingabe herausfiltern; das Trainingsprogramm muss wissen, ob dies zulässig ist.

Nehmen Sie eine repräsentative Stichprobe, die eine gewöhnliche Datei, einen Grenzfall und das letzte Element des Datensatzes enthält. Öffnen Sie jedes Element mit genau derselben Vorbereitung wie das Dataset. Prüfen Sie dann deren Zusammenstellung. Ein erfolgreicher Einzelzugriff beweist nicht, dass mehrere Ergebnisse gestapelt werden können. Dokumentieren Sie für einen Text Padding und Maske; für ein Bild Kanäle, Dimensionen und Achsenreihenfolge.

Legen Sie den Umfang fest: lokale oder entfernte Daten, Dekodierung inbegriffen oder nicht, feste oder zufällige Transformationen. Behalten Sie ihn zwischen zwei Einstellungen bei; ein scheinbarer Gewinn kann von entfernter Arbeit stammen.

Auf einen Prozess zurückgehen, um den Fehler zu lesen

Reproduzieren Sie zunächst mit num_workers=0, shuffle=False und einem kleinen Batch. Das Laden läuft dann im Hauptprozess ab und der Fehler-Traceback ist in der Regel lesbarer. Die DataLoader-Dokumentation empfiehlt diese Möglichkeit zum Debuggen. Protokollieren Sie die Kennung des Elements, das fehlschlägt, vor dessen Dekodierung, ohne dessen sensiblen Inhalt in die Logs zu kopieren.

Gehen Sie durch Trennung vor: Rohzugriff, Transformation, collate_fn, dann Transfer. Wenn der Durchlauf vor dem Transfer fehlschlägt, ist das Ändern von CUDA nicht die erste Spur. Wenn er nur mit mehreren Workern blockiert, untersuchen Sie die Objekte und Ressourcen, die an diese Prozesse übergeben werden. Vergleichen Sie die erste Iteration und die folgenden: der Start der Worker kann eine anfängliche Wartezeit erklären, ohne ein wiederkehrendes Problem zu belegen.

Ein Timeout kann eine Wartezeit sichtbar machen, behebt aber weder eine nicht verfügbare Quelle noch einen blockierten Worker. Behalten Sie den letzten bekannten Schritt bei und reduzieren Sie die Anzahl der Eingaben, statt dieses Timeout unbegrenzt zu erhöhen.

Ausgearbeitetes Beispiel: drei erwartete Kanäle, ein abweichendes Bild

Betrachten wir vier didaktische Datensätze. Die ersten drei ergeben einen Tensor der Form [3, 16, 16], der vierte [1, 16, 16]. Bei einem Vertrag, der drei Kanäle vorschreibt, muss das vierte Element vor dem Stapeln identifiziert werden. Dieses Szenario wurde hier nicht ausgeführt; es beschreibt ein erwartetes Ergebnis anhand der gewählten Formen.

Die folgende Funktion setzt voraus, dass jeder Datensatz die Felder id, x und y besitzt, dass x ein CPU-Tensor und y ein ganzzahliger Index ist. Sie weist die Inkonsistenz zurück, anstatt das Bild stillschweigend zu entfernen. Entscheiden Sie für Ihr Projekt ausdrücklich, ob ein monochromes Bild in drei Kanäle umgewandelt oder beim Import verworfen werden soll. Diese Entscheidung hängt von der Bedeutung der Daten und der vom Modell erwarteten Vorverarbeitung ab.

Nach der Korrektur müssen die vier Kennungen weiterhin vorhanden sein und der zusammengestellte Tensor muss die Form [4, 3, 16, 16] haben. Fügen Sie eine auf die Ziele abgestimmte Prüfung hinzu: ein korrekt dimensioniertes Bild kann dennoch eine ungültige Annotation tragen.

Vorgeschlagene didaktische Zusammenstellung, nicht ausgeführt
import torch
from torch.utils.data import DataLoader

def assemble(records):
    for item in records:
        if tuple(item["x"].shape) != (3, 16, 16):
            raise ValueError(f"Unerwartete Form für {item['id']}")
    return {
        "ids": [item["id"] for item in records],
        "x": torch.stack([item["x"] for item in records]),
        "y": torch.tensor([item["y"] for item in records],
                          dtype=torch.long),
    }

# dataset ist Ihr Dataset, das die beschriebenen Datensätze erzeugt.
# Erstellen Sie den Loader in einem Multiprozess-Skript unter dem main-Guard.
if __name__ == "__main__":
    loader = DataLoader(dataset, batch_size=4, num_workers=0,
                        shuffle=False, collate_fn=assemble)
    iterator = iter(loader)
    batch = next(iterator)

Workers wieder einführen, ohne die Daten zu ändern

Gehen Sie von null auf eine kleine Anzahl von Workern über und behalten Sie dabei Batch, Reihenfolge und Transformationen bei. Testen Sie eine vollständige Epoche und dann eine zweite: Manche Fehler treten erst beim Neustart eines Iterators oder nach dem Verbrauch von Ressourcen auf. Mehr Parallelität ist nur dann nützlich, wenn die Vorbereitungsarbeit tatsächlich parallel voranschreiten kann.

Die Startmethoden hängen vom System und der Python-Version ab. Schützen Sie bei spawn den Programmeinstieg mit if __name__ == '__main__' und definieren Sie Dataset, collate_fn und Worker-Funktionen auf Modulebene statt in lokalen Lambdas. Die Prozessdokumentation erklärt auch, warum geerbte Locks oder Threads Blockierungen verursachen können. Behalten Sie die Initialisierung der Zugriffe pro Prozess bei, wenn die Bibliothek dies erfordert.

Prüfen Sie bei einem IterableDataset die Aufteilung zwischen den Workern anhand von Identifikatoren: Mehrere Worker dürfen nicht jeweils denselben ganzen Stream konsumieren. Beurteilen Sie nicht nur die Anzahl der Batches; suchen Sie auch nach Duplikaten und fehlenden Elementen.

Wartezeit und Durchsatz mit einer klaren Einheit messen

Verwenden Sie zwei ergänzende Beobachtungen. Ein Durchlauf nur des Loaders zählt die in einem definierten Intervall vorbereiteten Beispiele. Ein integrierter Durchlauf untersucht, was geschieht, wenn das Modell diese Daten konsumiert. Ersterer hilft, die Vorbereitung zu isolieren; er repräsentiert nicht automatisch den Durchsatz des Trainings.

Zählen Sie in Ihrem Protokoll die tatsächlich gelieferten Beispiele und teilen Sie diese durch die verstrichenen Sekunden. Geben Sie die ausgeschlossenen Durchläufe für den Start, den Daten-Cache, die Transformationen und die Anzahl der Wiederholungen an. Behalten Sie die Werte jedes Durchlaufs, statt nur den besten auszuwählen. Die folgende Tabelle ist ein Erfassungsbogen: Es sind keine Leistungswerte ausgefüllt.

Wenn die Formen variieren, kann eine Anzahl von Beispielen pro Sekunde eine Änderung der Last verdecken. Fügen Sie die relevante Einheit hinzu, etwa dekodierte Pixel oder tatsächlich vorbereitete Tokens, und behalten Sie zugleich die Beispiele bei. Um Wartezeiten in der vollständigen Schleife zu lokalisieren, benennen Sie das Lesen des nächsten Batches getrennt von der Berechnung.

Scrollen Sie durch die Tabelle, um alle Spalten zu lesen.
Erfassungsbogen zum Ausfüllen mit Ihrer Last, ohne angenommene Leistungswerte
EinstellungGeprüfte ElementeBeobachtete DauerErwartetes Ergebnis
workers=0Identifikatoren, Formen, ZieleIn Sekunden zu messenKorrekte Referenz
Kleine Anzahl von WorkernDieselbe Menge von EingabenIn Sekunden zu messenTatsächlicher Gewinn oder Mehraufwand
Gleiche Einstellung, zweite EpocheKein Verlust und keine DuplikationIn Sekunden zu messenEffekt von Start und Caches

Speicher, Vorladen und Transfers getrennt behandeln

Worker und wartende Batches verbrauchen Host-Speicher. Beobachten Sie ihn während Ihres Versuchs, bevor Sie schlussfolgern, dass nur die VRAM zählt. Ein tieferes Vorladen kann die Wartezeit verlagern und zugleich die Belegung erhöhen; es garantiert nicht mehr Ergebnisse pro Sekunde. Reduzieren Sie zuerst die verdächtige Variable und vergleichen Sie denselben Umfang.

pin_memory und nicht blockierende Transfers betreffen die Übertragung von Daten zu einem Beschleuniger. Das PyTorch-Optimierungsrezept stellt sie als Hebel dar, die zusammen mit Hardware und Last zu prüfen sind. Sie beheben keine fehlerhafte Dekodierung. Beginnen Sie mit CPU-Daten in den Workern und organisieren Sie dann den Transfer in dem Prozess, der die Berechnung steuert. Der Nutzen und die tatsächliche Überlappung müssen beobachtet, nicht angenommen werden.

Wenn persistent_workers verwendet wird, denken Sie an die Ressourcen und Zustände, die zwischen zwei Epochen erhalten bleiben. Eine zufriedenstellende Einstellung bei einem einzelnen Batch reicht nicht aus, um das Schließen von Dateien oder die Erneuerung der Quelle zu überprüfen.

Eine Einstellung erst akzeptieren, wenn die Daten korrekt bleiben

Das erwartete Ergebnis ist eine Schleife, die alle vorgesehenen Eingaben im gewählten Rahmen ohne stille Fehler empfängt. Vergleichen Sie die Identifikatoren und Ziele vor und nach der Optimierung. Erklären Sie drop_last, wenn Sie den letzten unvollständigen Batch auslassen. Wenn die Transformationen zufällig sind, kontrollieren Sie deren Richtlinie, statt eine Pixelgleichheit zu verlangen, die dieser Richtlinie widersprechen würde.

Behalten Sie die einfachste Einstellung bei, die den gemessenen Bedarf erfüllt. Eine Erhöhung der Worker-Anzahl kann nichts verbessern, wenn der Speicher, die Dekodierung oder das Modell bereits eine Grenze vorgeben. Die CPU-, RAM- und Speicherressourcen eines Servers lassen sich nicht aus dem Namen seiner GPU ableiten: Geben Sie diese Anforderungen separat an, wenn Sie Ihre Kernodeck-Umgebung vorbereiten.

Ihre Fragen

Deaktiviert num_workers=0 das GPU-Training?

Nein. Es verlagert das Laden der Daten in den Hauptprozess. Das Modell kann weiterhin auf der GPU rechnen. Diese Einstellung ermöglicht vor allem, Fehler beim Lesen, Transformieren und Zusammenstellen direkter zu erkennen.

Sollte man so viele Worker wählen wie CPU-Kerne?

Nicht automatisch. Die richtige Einstellung hängt von der Vorbereitungsarbeit, dem Speicher, den Datenzugriffen und der Verbrauchsgeschwindigkeit des Modells ab. Vergleichen Sie einige Werte, indem Sie dieselbe Last beibehalten und die gelieferten Eingaben kontrollieren.

Behebt ein kleinerer Batch einen Worker, der abbricht?

Er kann den Speicherdruck verändern, behebt aber keine ungültige Annotation, keine nicht serialisierbare Ressource oder eine unlesbare Datei. Reproduzieren Sie zunächst mit null Workern, um den betroffenen Schritt zu identifizieren.

Misst die in next(iterator) verbrachte Zeit die Festplatte?

Nein. Nach iterator=iter(loader) wartet next(iterator) auf einen Batch. Dekodierung, Transformationen, Zusammenstellung, Kommunikation zwischen Prozessen und Vorladen können dazwischenkommen. Eine reine Lesemessung und eine Spur der vollständigen Schleife beantworten unterschiedliche Fragen.