Vibecoding GPU-Kernels

@maharshii
ENGLISCH09. Aug. 2026
118K
408
30
11
593

TL;DR

Maharshi erläutert einen Workflow zur Generierung von GPU-Kernels mittels LLMs, der auf einer verifizierbaren Schleife aus Kompilierungstests, Korrektheitsprüfungen gegen Referenzimplementierungen und iterativer Optimierung basiert.

GPU-Kernel von Hand zu schreiben erfordert Geduld, Mühe und auch deine Nerven. Ich habe mit modernen LLMs (Claude Opus 5, GPT 5.6 Sol) experimentiert, um Kernel buchstäblich für mich generieren zu lassen. Ich werde darüber sprechen, was ich dabei gelernt habe.

Ehrlich gesagt ist das Schreiben von GPU-Kernels eine geradezu peinlich gut verifizierbare Aufgabe.

Zuerst entscheidest du, für welche Operation(en) du den Kernel schreiben möchtest. Zweitens schreibst du die erste Version und stellst sicher, dass sie ohne offensichtliche Fehler kompiliert. Drittens überprüfst du die Korrektheit mit einer langsamen Referenzimplementierung. Wenn sie nicht übereinstimmt, versuchst du, das Korrektheitsproblem zu beheben. Danach benchmarkst du die Ausführungszeit des Kernels. Die nachfolgenden Versionen bauen darauf auf, und du optimierst weiter, bis du entweder die Roofline-Metriken erreichst oder zufrieden bist.

maharshi - inline image

Überprüfbare Schleife: GPU-Kernel-Entwicklung

Das Bild oben zeigt es als überprüfbare Schleife:

  • Der Kompiliercheck ist eine enge lokale Schleife (B <-> C), bevor du überhaupt an Korrektheit denkst.
  • Der Korrektheitscheck (D <-> E <-> F) ist der Kern der überprüfbaren Belohnungsschleife. Dieser Teil macht das Schreiben von Kernels zu einem guten Problem für die automatisierte Verifikation, da du eine Ground-Truth-Referenz zum Abgleich hast.
  • Optimierung (G -> H -> zurück zu D) nutzt für jede neue Version dieselbe Korrektheitsschleife, denn ein schneller, aber falscher Kernel ist wertlos – die Korrektheit muss für jede Version verifiziert werden.
  • Der Roofline-/Zufriedenheitscheck (I) ist die äußere Schleife, die entscheidet, ob du weiter optimierst oder aufhörst.

Erste Version

Das Bild oben ist immer noch eine übergeordnete Sicht, und der Teufel steckt im Detail. Wir müssen sicherstellen, dass unser LLM-Agent den gesamten benötigten Kontext hat, um überhaupt mit dem Schreiben einer guten ersten Version beginnen zu können.

Hier kommen die CUDA-DSLs ins Spiel. Triton, CuTeDSL und Tilelang sind diejenigen, mit denen man in Python sehr leicht anfangen kann. Die Lernkurve ist im Vergleich zu CUDA C++ weniger steil, aber die Abstraktionen in diesen DSLs könnten unseren Agenten noch mehr verwirren. Wir brauchen einen Weg, dem Agenten den Kontext dieser Abstraktionen zu vermitteln.

Moderne LLMs wissen bereits, wie man „gutes“ Triton schreibt. Sie können auch ohne Kontext gut mit Triton-Abstraktionen arbeiten. Bei anderen DSLs wie CuTeDSL (das deutlich mehr Kontrolle als Triton bietet) habe ich jedoch festgestellt, dass ein Kontextverzeichnis, in dem der Agent nach Verständnis für die DSL-Abstraktionen suchen kann, sehr hilft.

Zum Beispiel ist das Klonen des

NVIDIA cutlass

-Repositorys in das Kontextverzeichnis eine gute Möglichkeit, den Agenten nach Abstraktionen suchen zu lassen, die mit

Layout-Algebra, Copy/GEMM-Atomen, Speicherhierarchie, Beispiel-Kernels

und so weiter zusammenhängen, während er Kernel in CuTeDSL schreibt.

Meiner Erfahrung nach kompiliert eine gute erste Version des Kernels ohne offensichtliche Fehler und besteht den Korrektheitstest, über den ich gleich sprechen werde.

Test, Benchmark und Profiling

Wenn der Agent genug Kontext hat, verlagert sich der eigentliche Engpass auf die Validierung. Die Referenzimplementierung selbst und der Abgleich mit ihr werden immer wichtiger. Ich bezeichne diese Phase als Korrektheitstests oder einfach Tests. Die Geschwindigkeit der Referenzimplementierung ist nicht so wichtig wie ihre Absicht. Genau das, was du messen und verifizieren willst, wird dein Agent optimieren.

Normalerweise messe ich, wenn die Berechnung nicht in niedrigerer Präzision stattfinden soll, den maximalen absoluten/relativen Fehler (MAE), den mittleren quadratischen Fehler (MSE/RMSE) und den PSNR (Peak Signal to Noise Ratio). Wenn niedrigere Präzisionen im Spiel sind, messe ich eher PSNR und Kosinus-Ähnlichkeit (cossim).

Wie du die Kernel-Versionen tatsächlich auf einer GPU zum Laufen bringst, hängt davon ab, ob die GPU lokal oder über die Cloud verfügbar ist. Unabhängig davon sollte unser Agent in irgendeiner Form auf seine Ausgaben zugreifen können.

Ich finde die folgende Rung-Methodik einen guten Weg, um eine beliebige Anzahl N von Testfunktionen zu haben:

python
1def rung(name):
2 def deco(fn):
3 try:
4 out = fn()
5 results[name] = {"ok": True, **(out or {})}
6 print(f"[{name}] ok " + " ".join(f"{k}={v}" for k, v in (out or {}).items()))
7 except Exception as e:
8 results[name] = {"ok": False, "err": f"{type(e).__name__}: {e}"}
9 print(f"[{name}] FAILED {type(e).__name__}: {e}")
10 traceback.print_exc()
11 return fn
12 return deco

die du so aufrufen kannst:

python
1out = {}
2
3@rung("pre-checks")
4def _():
5 run_pure_checks()
6 run_dsl_checks()
7
8@rung("run")
9def _():
10 out["o"] = custom_kernel(*inputs)
11 torch.cuda.synchronize()
12 return {"shape": tuple(out["o"].shape),
13 "finite": bool(torch.isfinite(out["o"]).all())}

Für die Benchmark-Stufe kannst du mehrere Dinge tun:

  • Die End-to-End-Kernel-Ausführungszeit für die insgesamt aufgewendete Zeit benchmarken
  • Intra-Kernel-Tracing verwenden, um Abschnitte innerhalb eines Kernels zu benchmarken und sie in die Ausgabe zu schreiben (mit einem benutzerdefinierten Tracer oder CUPTI)
  • Den generierten IR, PTX, SASS und CUBIN in ein Dumps-Verzeichnis schreiben und den Agenten durchgehen lassen

Der letzte Punkt lässt sich noch etwas ausführen. Manchmal kann es vorkommen, dass das DSL beim Absenken suboptimales PTX (und schließlich SASS) erzeugt und du bessere Anweisung(en) oder Formen findest, die stattdessen verwendet werden können. Unser Agent kann die PTX/SASS-Textdateien durchlesen und Code auf niedrigerer Ebene inline einfügen, anstatt das DSL den suboptimalen Teil übernehmen zu lassen. Auch hier ist es sehr hilfreich, die „durchsuchbare“ PTX-Dokumentation als Kontext zu übergeben.

Der letzte Baustein, der alles zusammenführt, ist Profiling. Wenn dein Agent Zugriff auf das NCU-CLI (Nsight Compute Systems) hat, kannst du es bitten, ein Profiling durchzuführen und einen Bericht für deinen Kernel zu erstellen, als Teil der oben beschriebenen überprüfbaren Feedback-Schleife.

Schlussgedanken

„Ist die GPU-Kernel-Entwicklung also tot?“

„Naja, ja – aber eigentlich nein“

Ja, denn der schwierige Teil von Layouts, Indexierung, Abstraktionen und der Gesamtstruktur kann von Agenten mit ausreichend Kontext weitgehend gelöst werden. Du kannst die Arbeit von 2-3 Wochen leicht auf 1-2 Tage reduzieren. Nein, weil sich der eigentliche Engpass von den Kernels zu den Validierungen verlagert hat. Es gibt jetzt nicht mehr den einen Weg: Je besser dein Kontext und dein Testaufbau (Harness), desto schneller der Prozess. Spezialfälle profitieren sogar noch mehr, und ein guter Harness ist alles, was du brauchst.

Letztendlich ist es weiterhin nötig, die Agenten nicht als autonom zu betrachten, sondern als wirklich kluge Assistenten, die du führen kannst. Hier kommt dein grundlegendes Verständnis von GPUs und Kernels ins Spiel. Der menschliche Teil (du) wird hier weiterhin gebraucht.

Es ist ein bittersüßes Gefühl, ich weiß :)

Mit einem Klick speichern

Virale Artikel mit YouMind per KI tief lesen

Speichere die Quelle, stelle gezielte Fragen, fasse die Argumentation zusammen und verwandle einen viralen Artikel in wiederverwendbare Notizen in einem einzigen KI-Arbeitsbereich.

YouMind entdecken
Für Creator

Verwandle dein Markdown in einen sauberen 𝕏-Artikel

Wenn du eigene Langtexte veröffentlichst, wird die 𝕏-Formatierung von Bildern, Tabellen und Codeblöcken mühsam. YouMind macht aus einem ganzen Markdown-Entwurf einen sauberen, sofort postbaren 𝕏-Artikel.

Markdown zu 𝕏 testen

Mehr Muster zum Entschlüsseln

Aktuelle virale Artikel

Mehr virale Artikel entdecken