🟢 🏥 In der Praxis Veröffentlicht: · 3 Min. Lesezeit ·

Wie PyTorch Tausende von Tests aus wenigen Template-Klassen generiert — ein Leitfaden zur Test-Infrastruktur

Redaktionelle Illustration: PyTorch-Werkzeuge für automatisiertes Testen und CI-Infrastruktur-Optimierung

Der PyTorch-Blog-Beitrag von Riya Punia (Red Hat) erklärt, warum CI-Fehlschläge seltsame Namen wie TestMatmulCUDA.test_basic_cuda_float32 statt des ursprünglichen TestMatmul.test_basic tragen — die Tests werden beim Import durch Gerät- und dtype-Kombinationen dynamisch generiert.

🤖

Dieser Artikel wurde mithilfe von künstlicher Intelligenz aus Primärquellen erstellt.

Wenn der PyTorch-CI einen Fehlschlag mit einem Namen wie TestMatmulCUDA.test_basic_cuda_float32 meldet, findet der Entwickler diese Klasse im Quellcode oft nicht. Das ist kein Bug — es ist Absicht. Riya Punia von Red Hat veröffentlichte am 3. Juli 2026 im PyTorch-Blog einen detaillierten Leitfaden, der die Mechanismen hinter diesem System offenlegt.

Test-Generierung beim Import

Das Herzstück der PyTorch-Test-Infrastruktur ist die Funktion instantiate_device_type_tests(), definiert in torch/testing/_internal/common_device_type.py. Diese Funktion empfängt eine Template-Klasse — die selbst nicht ausführbar ist — und erstellt daraus zur Laufzeit konkrete Klassen für jedes unterstützte Gerät.

Eine Template-Klasse TestMatmul mit einer Methode test_basic wird zu drei konkreten Klassen: TestMatmulCPU, TestMatmulCUDA und TestMatmulMPS. Jede Methode erhält Suffixe für alle relevanten dtype-Kombinationen: test_basic_cuda_float32, test_basic_cuda_float16, test_basic_cuda_bfloat16 und so weiter. Unterstützte Geräte umfassen CPU, CUDA, MPS (Apple Silicon) und XPU (Intel); dtypes schließen float16, float32, float64 und bfloat16 ein.

Die Namenskonvention ist konsistent: <KlassenName><GERÄT>.<methode>_<gerät>_<dtype>. Dieses Wissen ist essenziell für das Debugging von CI-Fehlschlägen.

Häufige Falle: Template-Klasse im pytest-Filter ansprechen

Einer der häufigsten Fehler, die Punia nennt, ist die Verwendung des ursprünglichen Template-Namens im pytest -k-Filter. Der Befehl pytest test/test_torch.py -k "TestMatmul" findet nichts, da die Klasse TestMatmul zur Laufzeit nicht als ausführbare Klasse existiert — es existieren nur TestMatmulCPU, TestMatmulCUDA und andere generierte Varianten. Der korrekte Aufruf ist pytest test/test_torch.py -k "test_basic_cuda_float32" -x.

OpInfos: Metadaten-Schicht für Operatoren

Der zweite Pfeiler der Test-Infrastruktur sind OpInfos — zentrale Einträge, die beschreiben, wie jeder PyTorch-Operator getestet werden soll. Sie sind in torch/testing/_internal/opinfo/core.py definiert, das globale Operator-Register befindet sich in torch/testing/_internal/common_methods_invocations.py.

Jeder OpInfo-Eintrag enthält: Operatorname, Aufrufvarianten, unterstützte dtypes, Generatoren für Beispiel-Eingaben, numerische Toleranzen und Skips für bestimmte Kombinationen. Ein generisches Test-Template mit dem @ops-Decorator iteriert automatisch über alle eingetragenen Operatoren und führt den Test für jede Kombination aus — ohne eine einzige Zeile duplizierten Codes.

Das Ergebnis: Eine kleine Anzahl von Template-Tests deckt Tausende konkreter Testfälle ab. Punia bezeichnet dies als den grundlegenden Mechanismus, der die Wartbarkeit der PyTorch-Test-Suite ermöglicht, die eine enorme Anzahl von Operatoren und Hardware-Zielen umfasst.

Struktur der Schlüsseldateien

Punia nennt fünf Schlüsseldateien, die das infrastrukturelle Fundament bilden:

  • torch/testing/_internal/common_utils.py — gemeinsame Test-Utilities, Basis-TestCase-Klasse, run_tests()
  • torch/testing/_internal/common_device_type.pyinstantiate_device_type_tests(), Dekoratoren @dtypes, @ops
  • torch/testing/_internal/opinfo/core.py — OpInfo-Eintrags-Definitionen und Metadaten
  • torch/testing/_internal/common_methods_invocations.pyop_db-Register aller Operatoren
  • test/run_test.py — CI-Style-Runner mit Sharding-Unterstützung

Wie debuggt man einen CI-Fehlschlag?

Der PyTorch-CI verwendet Dr. CI — ein Werkzeug, das Pull Requests automatisch mit gruppierten Fehlschlägen und Shard-Informationen kommentiert. Der von Punia empfohlene Debugging-Ablauf: (1) Shard-Information aus Dr.-CI-Kommentar entnehmen, (2) Logs des spezifischen CI-Jobs auf hud.pytorch.org finden, (3) generierten Testnamen extrahieren, (4) lokal mit dem exakten generierten Namen reproduzieren.

Zur Ausführungssteuerung stehen Umgebungsvariablen zur Verfügung: PYTORCH_TESTING_DEVICE_ONLY_FOR begrenzt Tests auf das gewählte Gerät, PYTORCH_TEST_WITH_SLOW aktiviert langsame Tests, und PYTORCH_TEST_WITH_DYNAMO deckt Tests unter torch.compile ab. Es gibt auch EXPECTTEST_ACCEPT, das aufgezeichnete Ausgaben (Snapshots) für Tests, die diese verwenden, automatisch aktualisiert.

Punia warnt außerdem vor einem weiteren häufigen Fehler: der Verwendung von torch.randn() in dtype-generischen Tests. torch.randn() erzeugt immer einen float32-Tensor — in einem Test, der für bfloat16 läuft, ist das inkorrekt. Der empfohlene Ersatz ist make_tensor(), das das dtype-Argument des generierten Tests respektiert.

Praktische Implikation

Der Leitfaden richtet sich an alle, die zu PyTorch beitragen oder ungewöhnliche CI-Fehlschläge debuggen, gilt aber auch allgemein: Dynamische Test-Generierung beim Import ist ein Muster, das in größeren Python-Projekten überall dort auftritt, wo kombinatorische Räume ohne Code-Explosion abgedeckt werden müssen. Den Unterschied zwischen Template-Klasse und generierten Klassen zu verstehen, ist der erste Schritt zur produktiven Arbeit mit solchen Systemen. Für PyTorch konkret verkürzt diese Erkenntnis den Weg von „CI ist mit unbekanntem Namen fehlgeschlagen” zu „ich habe eine lokale Reproduktion” auf eine einzige Suche auf hud.pytorch.org.

Häufig gestellte Fragen

Warum stimmt der Testname im CI nicht mit dem Namen im Quellcode überein?
PyTorch generiert konkrete Tests beim Import mit instantiate_device_type_tests(). Eine Template-Klasse TestMatmul mit der Methode test_basic wird zur Laufzeit zu den Klassen TestMatmulCPU, TestMatmulCUDA, TestMatmulMPS mit Methoden wie test_basic_cuda_float32 erweitert — das heißt, das ursprüngliche Template existiert im Code nicht als ausführbare Klasse.
Was sind OpInfos und wozu dienen sie?
OpInfos sind Metadaten-Einträge, die zentral beschreiben, wie ein einzelner Operator getestet werden soll: unterstützte dtypes, Eingabe-Samples, Toleranzen, Skips. Ein generisches Test-Template mit @ops-Decorator erhält automatisch alle diese Kombinationen und führt den Test für jede aus — ohne Code-Duplikation pro Operator.
Wie reproduziert man lokal einen CI-Fehlschlag?
Aus dem Dr.-CI-Kommentar den Shard-Namen heraussuchen, den generierten Testnamen ermitteln (z.B. TestMatmulCUDA.test_basic_cuda_float32) und ausführen: pytest test/test_torch.py -k 'test_basic_cuda_float32' -x. Ein Targeting der Template-Klasse ohne Geräte-Suffix findet den Test nicht.