Article
PyTorch Profiler verstehen: Performance-Engpässe beim Machine-Learning-Training aufdecken
Kurzbeschreibung
Was Sie nicht profilieren können, können Sie nicht optimieren. Dieser Artikel führt in die Grundlagen von torch.profiler ein und zeigt, wie Entwickler Engpässe im Training systematisch aufdecken können.
Einleitung
Ob Sie mehr Token pro Sekunde aus einem Large Language Model herausholen, Millisekunden bei der Inferenz sparen oder verstehen wollen, warum Ihr Training langsamer läuft als erwartet – der Weg führt zwangsläufig über Profiling. Die Herausforderung: Profiling hat eine steile Lernkurve. Profiler-Traces sind dichte Wände aus farbigen Rechtecken, die Events tragen einschüchternde Namen, und die meisten Tutorials setzen voraus, dass man sie bereits lesen kann.
Zwei zentrale Artefakte
Der torch.profiler liefert zwei zentrale Artefakte: die Profiler-Tabelle und den Profiler-Trace. Die Tabelle zeigt statistische Zusammenfassungen und beantwortet die Frage „Was dauert am längsten?" – ideal zur Identifikation von Hotspots. Der Trace bietet eine zeitliche Ausführungsansicht und klärt „Wann und warum ist eine Operation aufgetreten?" mit separaten Lanes für CPU- und GPU-Aktivitäten.
Overhead-bound vs. Compute-bound
Ein zentrales Konzept ist die Unterscheidung zwischen „overhead-bound" und „compute-bound" Algorithmen. Bei kleinen Matrizen verbringt die GPU meiste Zeit im Leerlauf, während die CPU mit Kernel-Vorbereitung und Dispatch beschäftigt ist. Größere Matrizen verschieben das Verhältnis zugunsten echter GPU-Rechenzeit. Der Artikel demonstriert dies an Matrix-Multiplikationen: bei 64×64-Matrizen liegt die GPU-Zeit unter 1% der CPU-Zeit, bei 4096×4096-Matrizen gleichen sich beide an.
Ein weiterer wichtiger Aspekt ist die Dispatch-Kette: vom Python-Aufruf über ATen-Operationen bis hin zu CUDA-Kerneln. Für matmul-Operationen feuert cuBLAS zusätzlich eine Occupancy-Query (cudaOccupancyMaxActiveBlocksPerMultiprocessor), um die optimale Kernel-Variante auszuwählen – ein wichtiges Diagnosemerkmal in Traces.
Der Artikel vergleicht zudem den Eager-Mode mit torch.compile und zeigt, wie Inductor mathematisch äquivalente Operationen umschreibt: torch.add(torch.matmul(x, w), b) wird zu einem einzigen aten::addmm(b, x, w)-Aufruf auf Dispatcher-Ebene. Die eigentliche GPU-Arbeit bleibt jedoch unverändert – ein GEMM-Kernel mit Bias-Epilog.
Link: Original bei HuggingFace