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.
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.| Einstellung | Geprüfte Elemente | Beobachtete Dauer | Erwartetes Ergebnis |
|---|---|---|---|
| workers=0 | Identifikatoren, Formen, Ziele | In Sekunden zu messen | Korrekte Referenz |
| Kleine Anzahl von Workern | Dieselbe Menge von Eingaben | In Sekunden zu messen | Tatsächlicher Gewinn oder Mehraufwand |
| Gleiche Einstellung, zweite Epoche | Kein Verlust und keine Duplikation | In Sekunden zu messen | Effekt 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.