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

Einen PyTorch-Schritt profilieren, um zu wissen, wo die Zeit hingeht

Definieren Sie zunächst den zu beobachtenden Schritt, trennen Sie Laden, Transfer, Berechnung und Aktualisierung und erfassen Sie dann ein kurzes, repräsentatives Fenster mit torch.profiler. Lesen Sie die CPU-Zeitachse und die verfügbaren GPU-Aktivitäten gemeinsam. Eine Python-Startzeit ist nicht die auf dem Beschleuniger abgeschlossene Ausführungszeit, und eine instrumentierte Aufzeichnung stellt für sich genommen noch keinen Benchmark dar.

7 Min. Lesezeit · Leitfaden für Entwickler

Eine Frage wählen, bevor eine Aufzeichnung geöffnet wird

Eine Aufzeichnung beantwortet eine präzise Frage besser: Wartet die Berechnung auf die Daten, wird eine Kopie wiederholt, oder wird ein kleiner Operator zu oft aufgerufen? Definieren Sie Eingabe, Ausgabe und Grenzen Ihres Schritts. Beim Training geben Sie an, ob er Backward, Optimierer-Aktualisierung und Lesen des Batches enthält. Bei der Inferenz trennen Sie das Laden des Modells und die Anfrage.

Behalten Sie ein kurzes Szenario bei, dessen Korrektheit Sie kennen. Notieren Sie Formen, Batch, Präzision, Modus des Modells, eventuelle Kompilierung und Datenquelle. Eine vereinfachte Eingabe kann helfen, ein Verhalten zu isolieren, stellt aber nicht mehr zwangsläufig die vollständige Last dar. Erwähnen Sie diesen Unterschied im Bericht.

Legen Sie die endgültige Einheit fest: Millisekunden pro Schritt oder verarbeitete Beispiele pro Sekunde. Die Summen von Ereignissen ersetzen nicht die verstrichene Zeit. Vergleichen Sie Fenster mit denselben Grenzen für Lesen und Transfer.

CPU-Zeit, GPU-Arbeit und Wartezeit unterscheiden

Die CPU bereitet Operationen vor und startet sie; die GPU kann sie später ausführen. Ein Python-Intervall kann daher Start, Wartezeit oder beides enthalten. Die CUDA-Dokumentation von PyTorch weist darauf hin, dass präzise Messungen diesen Asynchronismus berücksichtigen müssen, insbesondere durch Synchronisation oder dem Umfang angepasste Ereignisse.

Für eine gezielte Messung der GPU-Dauer können CUDA-Ereignisse geeignet sein. Für eine End-to-End-Latenz warten Sie auf das Ende der in dieser Latenz enthaltenen Arbeit und messen die gesamte Anfrage. Vermischen Sie diese beiden Einheiten nicht. Eine zwischen jeder Operation hinzugefügte Synchronisation kann eine reale Überlappung aufheben und das Programm verändern, das Sie zu verstehen versuchen.

Im Profiler beantworten die Eigenzeiten eines Operators und seine Zeiten einschließlich Unteroperationen ebenfalls unterschiedliche Fragen. Betrachten Sie die Zeitachse, bevor Sie die Zeilen der Tabelle addieren. Gleichzeitige oder verschachtelte Aktivitäten stellen keine disjunkten Anteile der verstrichenen Zeit dar.

Eine Startphase und ein aktives Fenster vorsehen

Der erste Durchlauf kann Initialisierung, Laden oder Kompilierung enthalten. Entscheiden Sie, ob Ihre Frage diesen Start oder eine bereits stabilisierte Phase betrifft. Behalten Sie beide Beobachtungen bei, wenn sie für die Nutzung wichtig sind, statt die anfänglichen Kosten aus einem als global dargestellten Mittelwert zu löschen.

Die Funktion schedule ermöglicht es, Wartezeit, Vorbereitung der Erfassung und aktives Fenster zu unterscheiden. Das Aufwärmen des Profilers ist kein Beweis dafür, dass Ihr Modell seinen stabilen Zustand erreicht hat. Prüfen Sie auch die auftretenden Formen und den Zustand der Caches. Eine Anwendung mit variablen Eingaben kann nach mehreren Iterationen neue Pfade durchlaufen.

Der unten vorgeschlagene didaktische Ablauf wartet auf einen Schritt, bereitet einen vor und erfasst zwei. Vier Schritte reichen aus, um den Mechanismus zu erklären, nicht aber, um eine Leistungsverteilung zu erstellen. Wählen Sie in einer echten Kampagne ein begründetes Fenster und wiederholen Sie die Messung nach der Analyse außerhalb des Profilers.

Vorgeschlagenes Beispiel: vier Schritte mit gut lesbaren Grenzen

Das folgende Fragment wurde nicht ausgeführt. Es setzt voraus, dass model, optimizer, loss_fn, loader und device existieren, dass das Modell auf device liegt und dass der Loader mindestens vier Batches von x-y-Paaren liefert. Es führt Aktualisierungen durch: Verwenden Sie einen experimentellen Zustand, der dafür vorgesehen ist, nicht eine Sitzung, deren Gewichte Sie bewahren müssen.

Die Beschriftungen trennen CPU-Lesen, Transfer und Training. Der Iterator wird vor dem Fenster erstellt, wodurch ein Teil seines Starts aus dem Umfang ausgeschlossen wird. Die Datei wird neu gewählt, um das Überschreiben einer Spur zu vermeiden. Das Beispiel verweigert eine Erfassung auf der GPU, wenn diese nicht verfügbar ist, statt stillschweigend eine CPU-Spur als GPU-Analyse auszugeben.

Das Signal step() rückt den Zeitplan nach jedem Schritt vor. Das offizielle Rezept beschreibt diese Verknüpfung zwischen Iterationen und Erfassung. Auf einem ROCm-Stack bleibt das PyTorch-Gerät weiterhin cuda genannt; die Verfügbarkeit der Beschleuniger-Erfassung hängt dennoch vom Build und seinen Werkzeugen ab. Prüfen Sie, welche Aktivitäten tatsächlich im Ergebnis vorhanden sind.

Lehrreiche Erfassung eines kurzen Fensters, nicht ausgeführt
from pathlib import Path
import torch
from torch.profiler import (
    profile, schedule, record_function,
    ProfilerActivity, supported_activities,
)

trace = Path("trace-etape.json")
if trace.exists():
    raise FileExistsError("Choisissez un nouveau nom de trace")
activities = [ProfilerActivity.CPU]
if device.type == "cuda":
    if ProfilerActivity.CUDA not in supported_activities():
        raise RuntimeError("Collecte GPU indisponible dans ce build")
    activities.append(ProfilerActivity.CUDA)
iterator = iter(loader)
model.train()

with profile(
    activities=activities,
    schedule=schedule(wait=1, warmup=1, active=2, repeat=1),
    record_shapes=False, profile_memory=False, with_stack=False,
    on_trace_ready=lambda p: p.export_chrome_trace(str(trace)),
) as prof:
    for _ in range(4):
        with record_function("lecture_batch_cpu"):
            x, y = next(iterator)
        with record_function("transfert"):
            x, y = x.to(device), y.to(device)
        with record_function("entrainement"):
            optimizer.zero_grad(set_to_none=True)
            loss = loss_fn(model(x), y)
            loss.backward()
            optimizer.step()
        prof.step()
print(prof.key_averages().table(
    sort_by="self_cpu_time_total", row_limit=8,
))

Eine Beobachtung in eine überprüfbare Hypothese verwandeln

Beginnen Sie mit dem aktiven Fenster und prüfen Sie, ob die erwarteten Beschriftungen erscheinen. Untersuchen Sie anschließend die Lücken zwischen Aktivitäten, die Kopien und die Wiederholungen. Eine lange Wartezeit in lecture_batch_cpu deutet auf die Eingabe-Pipeline hin; sie misst nicht direkt den Speicher. Eine häufige Kopie lädt dazu ein, die Platzierung der Tensoren zu untersuchen, ohne zu belegen, dass sie unnötig ist.

Formulieren Sie eine einzige Hypothese und schlagen Sie dann eine kontrollierte Änderung vor. Wenn beispielsweise eine Konstante in jedem Schritt neu erstellt und übertragen wird, prüfen Sie, ob ihre Lebensdauer mehrere Schritte umfassen kann, ohne das Ergebnis zu ändern. Wenn ein Operator dominant erscheint, untersuchen Sie seine Formen und die Anzahl der Aufrufe, bevor Sie einen Ersatz suchen.

Die folgenden Zeilen sind mögliche Lesarten, keine Feststellungen aus einer ausgeführten Spur. Es wird keine Dauer und keine Beschleunigung angekündigt. Die nützliche Schlussfolgerung ist ein nächstes Experiment, das die vorgeschlagene Ursache bestätigen oder widerlegen kann.

Scrollen Sie durch die Tabelle, um alle Spalten zu lesen.
Lehrreiche Interpretationen, die in Ihrer eigenen Spur zu prüfen sind
Mögliche BeobachtungHypotheseNächste Kontrolle
GPU ohne Aktivität während des LesensDie Eingabe-Pipeline kommt nicht mitGleiche Berechnung mit bereits vorbereitetem Batch
Wiederkehrende Kopien einer KonstanteUngeeignete Platzierung oder LebensdauerEinmal verschieben, Ausgaben prüfen
Viele kleine StartsFragmentierte ArbeitBündelung und Gesamtkosten untersuchen
Ein langer OperatorAusschlaggebende Form oder AlgorithmusDenselben Operator und seine Eingaben vergleichen

Kosten und Informationen der Instrumentierung begrenzen

Beginnen Sie mit einer kurzen Erfassung und wenigen Optionen. Aktivieren Sie Formen, Stapel oder Speicher nur, wenn eine Frage es erfordert. Die PyTorch-API weist darauf hin, dass diese Informationen zusätzliche Kosten verursachen; die Erfassung der Formen kann sogar Referenzen auf Tensoren behalten. Ein detailliertes Profil kann daher die Dauern oder die Speicherbelegung des Programms verändern.

Eine Trace kann Operatornamen, Formen und je nach Optionen Codepfade enthalten. Prüfen Sie sie, bevor Sie sie teilen. Eine Bereichsbezeichnung sollte den Schritt beschreiben, ohne E-Mail, Token, privaten Pfad oder Eingabeinhalt einzubinden. Wählen Sie einen Trace-Reader, der zu Ihrer Umgebung passt, und behalten Sie die Erfassung unter Ihrer Kontrolle.

Wenn die erwarteten GPU-Ereignisse fehlen, füllen Sie deren Zeiten nicht mit null. Geben Sie an, dass sie nicht beobachtet wurden, und prüfen Sie die Unterstützung der Erfassung. Ein Fehlen von Ereignissen im Tool ist kein Beweis für das Fehlen von Berechnungen.

Die Optimierung außerhalb des Profilers validieren

Gehen Sie vom selben relevanten Zustand aus und vergleichen Sie die Korrektheit vor und nach der Änderung. Beim Training verändert ein zusätzlicher Schritt die Gewichte; zwei nacheinander gestartete Aufnahmen sind nicht zwangsläufig ein gleichwertiger Vergleich. Bewahren Sie Code, Parameter und Ausgangspunkt auf, damit Sie den Unterschied erklären können.

Messen Sie anschließend das Szenario ohne detaillierte Erfassung, mit demselben Aufwärmen und mehreren Durchläufen. Berichten Sie den Umfang, die Rohwerte und deren Streuung. Eine lokale Verbesserung kann in der gesamten Schleife verschwinden oder die Qualität verschlechtern: Beides muss in die Entscheidung einfließen.

Nutzen Sie die Beobachtungen schließlich, um die tatsächlich benötigten Ressourcen genauer zu bestimmen. Eine Trace von Ihrem Arbeitsplatz klassifiziert nicht die Angebote von Kernodeck und beweist weder den Host-Prozessor noch das Netzwerk eines gemieteten Servers. Der GPU-Vergleich erfordert eine Last, Bedingungen und Ergebnisse, die auf den betreffenden Ressourcen vergleichbar sind.

Ihre Fragen

Zeigt die größte CPU-Zeit den langsamsten GPU-Operator an?

Nein. Sie kann Start, Verarbeitung auf der Host-Seite oder Warten einschließen. Betrachten Sie die GPU-Ereignisse und ihre Chronologie, wenn die Erfassung sie liefert. Die nach CPU-Zeit sortierte Tabelle beantwortet nur diese Perspektive.

Soll ich alle CUDA-Zeiten der Tabelle addieren?

Nicht, um automatisch die Gesamtdauer zu erhalten. Aktivitäten können sich überschneiden, und Ereignisse können verschachtelt sein. Definieren Sie ein Zeitfenster der verstrichenen Zeit und nutzen Sie die Trace, um deren Inhalt zu erklären.

Reichen zwei aktive Schritte aus, um eine Leistung zu veröffentlichen?

Nein. Der vorgeschlagene kleine Ablauf veranschaulicht die API. Ein verwertbares Ergebnis erfordert ein repräsentatives Fenster, Wiederholungen, ein explizites Aufwärmen und eine abschließende Messung ohne den Overhead der detaillierten Erfassung.

Kann eine CPU-Trace ROCm diagnostizieren?

Sie kann die Arbeit auf der Host-Seite beleuchten, ersetzt aber nicht die GPU-Aktivitäten. PyTorch verwendet auch unter ROCm den Namen cuda; prüfen Sie das Backend, die unterstützten Aktivitäten und die tatsächlich aufgezeichneten, bevor Sie die Trace interpretieren.