Direkt zum Hauptinhalt
Data Science und ML

Extreme Effizienz durch spezialisierte GPU-Kernel-Generierung erzielen

Zuverlässige, validierte GPU-Kernel-Generierung

von Leo Li, Daya Khudia und Lesheng Jin

  • Neue Kernel-Entwürfe lassen sich schnell und kostengünstig parallel erstellen. Vertrauen hingegen nicht. Das System kommt nur so schnell voran, wie wir diese Entwürfe überprüfen können.
  • Eine Zahl, die unglaublich schnell erscheint, ist oft ein Messfehler: verbleibende Arbeit aus einem vorherigen Durchlauf, ein Vergleich, bei dem die beiden Seiten nicht dasselbe taten, oder ein Kernel, der nur unter einer impliziten Annahme gut abschneidet.
  • Kontext ist ein Kompromiss, kein Haufen, den man maximieren sollte. Mehr Text gibt dem Modell mehr Arbeitsgrundlage, kostet aber auch mehr, und zusätzliche Notizen führen leichter dazu, dass der nächste Versuch abweicht. Zu wenig Kontext, und die Schleife gerät ins Stocken.
  • Ein Agent, der sich frei entfalten kann, schreibt bessere Kernel. Ein striktes übergeordnetes System muss das Feedback definieren und entscheiden, was freigegeben werden darf. Ein gutes Design erfordert beides.
  • Die generierten einzelnen Qwen 3.5 122B-Kernel waren 1,8–5,2-mal schneller als die besten in vLLM verfügbaren Implementierungen.

Traditionell verlassen sich Produktions-Inferenzsysteme auf generische Kernel, um unterschiedliche Modelle und Workloads zu verarbeiten. Dies ist suboptimal, da die Dimensionen von GPU-Operationen durch eine Kombination aus statischen Modellparametern und dynamischen Faktoren zur Anfragezeit bestimmt werden. Während ein Modell beispielsweise eine der Dimensionen für eine Matrixmultiplikation definiert, schwankt die andere Dimension basierend auf der spezifischen Token-Anzahl jeder Anfrage. Es gibt ein wachsendes Interesse an der agentenbasierten GPU-Kernel-Generierung, und jüngste Bemühungen sind vielversprechend. Wir sind einer Kernfrage nachgegangen: Wenn die Kernel-Generierung automatisiert werden kann, warum sollten dann Modelle mit völlig unterschiedlichen Größen (von 1 Milliarde bis 1 Billion Parameter) auf denselben Kernel zurückgreifen? Durch die Spezialisierung von Kerneln auf die spezifischen Dimensionen, die zur Laufzeit auftreten, können wir eine extreme Effizienz erreichen.

In diesem Blog teilen wir unsere Erfolge und Erkenntnisse aus dem Einsatz von Agenten zur Generierung von GPU-Kerneln. Wir haben Proteus entwickelt, ein System für extreme Spezialisierung, das ein Harness erfordert, das genau auf strenge Optimierung, Validierung und Kontextmanagement zugeschnitten ist.

image3.png
Abbildung 1: Vereinfachte Ansicht des Proteus-Harnesses

Herkömmliche Coding-Harnesses scheitern hier oft, weil Agenten zum „Reward-Hacking“ neigen: Sie befolgen eher den genauen Wortlaut der Regeln als deren eigentlichen Sinn. Wenn man einem Agenten einen Benchmark vorgibt, optimiert er unter Umständen den Benchmark und nicht die eigentlich gewünschte Operation.

Um dies zu beheben, schlägt Proteus Kernel vor, verifiziert sie anhand einer kontrollierten Referenzimplementierung, misst die Laufzeit der erfolgreichen Kernel und verbessert die besten Ergebnisse iterativ. Obwohl dieser Prozess unkompliziert ist, hängt sein Erfolg vollständig von der Lösung zweier grundlegender Herausforderungen ab. Abbildung 1 zeigt die vereinfachte Architektur unseres Designs. Mit unserem Proteus-Harness haben wir Qwen 3.5 122B-Kernel generiert, die 1,8- bis 5,2-mal schneller waren als die besten in vLLM verfügbaren.

Validierung

Ursprünglich hielten wir die Kernel-Suche für den schwierigen Teil: Wie lässt sich ein großer Programmraum durchsuchen, ohne auf einem Plateau ohne Verbesserungen stecken zu bleiben? In der Praxis war die erste Frage jedoch grundlegender: Messen wir überhaupt das, was wir zu messen glauben?

Ein Modell optimiert den Score, den man ihm vorgibt. Es benötigt dafür keinen außergewöhnlichen Exploit: Es kann einfach sein, dass die Evaluierung eine bestimmte Annahme trifft. Ein Beispiel waren Kernel für Rotary Position Embeddings (RoPE), ein häufiger Schritt in Attention-Layern. Ein Kandidat könnte kompilierten Code aus einem früheren Versuch wiederverwenden und dadurch effizienter wirken als ein fairer Neuaufbau von Grund auf. Ein anderer könnte einen Batch von GPU-Launches in einem Graphen (z. B. einem CUDA-Graphen) aufzeichnen und sie als eine Einheit abspielen, während die Baseline, mit der wir verglichen haben, jeden Teil immer noch separat startete – die beiden Seiten leisteten also nicht dieselbe Arbeit. Ein weiterer Kandidat war stark bei den Eingabegrößen, die wir in das sichtbare Testset aufgenommen hatten, aber schwach bei Größen, die ihm nicht gezeigt worden waren.

Daher haben wir die frühe Designarbeit in den Checker und nicht in den Prompt gesteckt. Messen Sie die Zeit für beide Seiten auf dieselbe Weise, bei Bedarf auch mit mehr als einem Timer (z. B. CUDA-Event-Timer, tatsächliche Laufzeit und CUPTI-Timer) für eine Gegenprüfung. Löschen Sie verbleibende kompilierte Zustände, die nicht fortbestehen sollten, und halten Sie die Reihenfolge von Setup und Teardown konsistent, damit eine Seite keine Arbeit überspringen kann, für die die andere noch bezahlen muss. Messen Sie die Zeit der Gewinner erneut, bevor Sie sie als Ausgangspunkt für die nächste Runde verwenden. Behalten Sie einige Tests zurück, die der Kandidat nicht sehen kann, damit er sich nicht nur an die Prüfung anpasst. Um ein "Schummeln" bei der Evaluierung durch künstlich aufgeblähte Leistung zu verhindern, implementieren wir automatisierte Konsistenzprüfungen, um theoretisch unmögliche Beschleunigungen (z. B. >100x) zu markieren, welche die physische GPU-Bandbreite und die Rechenlimits überschreiten. Dies schützt vor denselben Reward-Hacking-Fallstricken, die in früheren Branchenfällen beobachtet wurden, in denen Agenten für die Metriken des Harnesses statt für echte Leistungssteigerungen optimierten. Ohne diese Einschränkungen führte die Generierung von mehr Kerneln meist nur zu mehr Rauschen.

Die Betonung des Checkers verschiebt auch den Engpass der agentenbasierten Kernel-Generierung. Bei reiner Programmsuche (d. h. einer iterativen Optimierung, bei der das System Programme durch wiederholtes Generieren von Varianten durchsucht) sind gute Kandidaten selten, sodass das Schreiben der Programme den Großteil der Kosten ausmacht. Wir können viele Entwürfe parallel erstellen, aber wir können die Validierung nicht überspringen. Wir müssen die Validierung sorgfältig gestalten, und die Überprüfung muss auf echten GPUs, isoliert und mehr als einmal durchgeführt werden. Das System bewegt sich so schnell, wie es einem Kernel vertrauen kann, nicht so schnell, wie es einen schreiben kann.

image4.png
Abbildung 2: Token-Nutzung in verschiedenen Phasen bei unserem ursprünglichen Harness.
token usage by the improved harness
Abbildung 3: Token-Nutzung in verschiedenen Phasen bei unserem verbesserten Harness.

Kontextmanagement

Eine weitere Herausforderung besteht darin, zu bestimmen, was das Kernel-Generierungsmodell sehen darf. Es ist ein Abwägen. Gibt man dem Modell einen größeren Prompt, hat es mehr Informationen: den aktuell besten Kernel, die jüngsten Fehler, Profiler-Hinweise, Notizen aus früheren Durchläufen. Das kann helfen. Es kostet aber auch mehr, da wir für jedes Token bezahlen, das das Modell liest. Und je größer der Prompt wird, desto leichter kann der nächste Versuch abweichen. Nützliche Signale vermischen sich mit veralteten Ratschlägen, widersprüchlichen Tipps und Details, die für eine andere Eingabegröße oder eine andere Operation gelten. Das Modell weiß nicht immer, welchen Sätzen es vertrauen soll, also folgt es den lautesten oder allen ein wenig.

Gibt man ihm zu wenig, passiert das Gegenteil. Jeder Versuch beginnt bei null. Dieselben Sackgassen treten wieder auf. Nichts wird aus dem letzten Durchlauf oder einer verwandten Operation übernommen, und die Schleife kommt nicht voran.

Wir wollten eine Wissensebene (Knowledge Layer) haben, die dabei hilft: sich zu merken, was funktioniert hat, es später wiederzuverwenden, und das ohne menschliches Eingreifen. Diese Ebene bringt einen zweiten Kompromiss mit sich: zwischen dem Detailgrad einer gespeicherten Erkenntnis und ihrer allgemeinen Anwendbarkeit.

Eine sehr spezifische Notiz („entrolle diese Schleife bei diesem Kernel mit dieser Eingabegröße“) kann genau das sein, was der nächste Versuch benötigt. Sie kann jedoch auch leicht bei der nächsten Operation, der nächsten GPU oder einer anderen Eingabegröße falsch angewendet werden. Eine sehr allgemeine Notiz („Nutze den On-Chip-Speicher besser“) trifft fast überall zu, sagt dem Modell aber fast nichts Konkretes darüber, was zu tun ist. Wir haben beide Fehlermuster beobachtet. Wenn die Erkenntnisse zu allgemein waren, beschrieben sie einen Fehler, ohne eine konkrete Maßnahme zu nennen. Wenn wir mehr Details speicherten, waren diese oft zu stark an einen einzelnen Durchlauf gebunden, um dem nächsten zu helfen. Bei einem langen Durchlauf wurde der Großteil dessen, was das Modell las und schrieb, für das Abrufen und Weiterleiten dieses Speichers aufgewendet, anstatt für das Schreiben von Kerneln. Die Speicherebene leistete viel Arbeit. Sie machte den nächsten Kandidaten jedoch nicht besser. Abbildung 2 zeigt die Aufschlüsselung der Token-Kosten eines solchen Systems. Die Kosten werden von den Wissensebenen dominiert.

Die Version von Wissen, die es wert ist, behalten zu werden, ist kleiner und hält die Waage zwischen Allgemeingültigkeit und Spezifität. Wenn das Modell im Begriff ist, einen Kernel zu schreiben, sollte sein Prompt nur Kontext mit hohem Vertrauen enthalten: umsetzbare Erkenntnisse, die spezifische Situationen mit Aktionen verknüpfen (destilliert aus früheren Zuordnungen von Modifikationen zu deren Auswirkungen), sowie prägnante Fehlerhinweise aus eng verwandten übergeordneten Durchläufen. Abgerufen über hierarchische Tag-Filterung in Kombination mit einer hybriden Suche (Schlüsselwort + Semantik), sollten die Erkenntnisse spezifisch genug sein, um danach zu handeln, und klar genug eingegrenzt, um zu verdeutlichen, wo sie nicht anwendbar sind. Tiefere Operationen wie das Reorganisieren und weitere Destillieren des Erkenntnisspeichers gehören in Hintergrund-Jobs und nicht in eine synchrone Multi-Hop-Traversierung über vergangene Durchläufe bei jedem Versuch. Wenn eine Erkenntnis nicht die Situation und die Aktion benennen kann, ist es es nicht wert, sie in den Prompt aufzunehmen. Abbildung 3 zeigt die Aufschlüsselung der Token-Kosten nach der Behebung des Problems mit der Wissensebene. Nach dieser Korrektur wird der Großteil der Token für die Generierung von Kandidaten aufgewendet.

Fallstudie: Gated DeltaNet Packed Decode

Ein konkretes Beispiel ist der Packed-Decode-Kernel auf dem Gated-DeltaNet-Pfad in Qwen 3.5 122B. Die Operation aktualisiert einen rekurrenten Zustand und schreibt die Decode-Ausgabe aus gepackten QKV-Eingaben, Gate-Parametern und Zustandsindizes. Wir haben diese Aufgabe genutzt, um den vollständigen Proteus-Kreislauf auf NVIDIA B200-GPUs mit einem Triton-Backend zu durchlaufen: Validierung des Aufgabenvertrags, Messung der Referenzimplementierung, Abfrage von Kandidaten-Kerneln bei Agenten, Durchführung statischer Prüfungen und Builds, Überprüfung der Korrektheit gegenüber der kontrollierten Referenz, Benchmarking nur verifizierter Kandidaten und anschließende Neumessung der besten Kandidaten.

Abbildung 4 ist von links nach rechts zu lesen. Der Baseline-Knoten verankert den Benchmark bei 0,025 ms. Kandidat 0000 ist der sichere Ausgangspunkt (Seed): Er reproduzierte die Packed-Decode-Struktur und bestand die Validierung, war jedoch langsamer als die Referenz. Daher behielt Proteus ihn als gemessenen Elternknoten (Parent), anstatt ihn als Erfolg zu werten. Von dort aus optimierte Proteus nicht mehr einen einzigen generischen Kernel für jede Dimension (Shape), sondern teilte die Suche in dimensionsspezifische Pfade auf.

image1.png
Abbildung 4: Eine Fallstudie zur Kernel-Evolution durch den Proteus-Harness

Der Batch-1-Reparaturpfad erzeugte bei Kandidat 012 einen dimensionsspezifischen Kernel, der eine 1,5-fache Beschleunigung bei der Single-Batch-Decode-Dimension erreichte. Die stärksten Ergebnisse wurden auf dem Serving-Decode-Pfad erzielt: Kandidat 030 wies mit 0,018 ms die geringste gemessene Kernel-Latenz auf, und Kandidat 036 erzielte mit 1,6x die beste Beschleunigung für eine bestimmte Dimension. Dieses erfolgreiche Serving-Fragment war auf das Layout Batch=4, Key=128, Value=128 spezialisiert und verarbeitete die Value-Dimension in 64er-Blöcken (Chunks). Es handelt sich also um einen sicheren Kernel für diese spezifische Dimension und nicht um einen universellen Ersatz.

Der letzte Umweg im Zeitverlauf zeigt, warum der Trace wichtig ist. Spätere Versuche mit C++-Generierungen (anstelle von Triton) stießen auf Build- und Generierungsfehler, und der lange Durchlauf endete, nachdem das Versuchsbudget dieses Zweigs aufgebraucht war. Das nützliche Artefakt ist daher nicht nur der schnellste Kandidat. Es ist der gesamte in der Abbildung gezeigte Pfad: Semantische Fehler wurden verworfen, korrekte, aber langsamere Kernel wurden gemessen, und die tatsächlichen Leistungssteigerungen blieben mit der Form verknüpft, die ihre sichere Integration in einen Produktions-Kernel ermöglicht.

Woran wir als Nächstes arbeiten

Die von uns entwickelte evolutionäre Schleife agiert als strenger Autor. Sie ruft das Modell oft nach einem festen Muster auf: den aktuell besten Kernel nehmen, eine kleine Änderung ausprobieren, prüfen, wiederholen. Das nimmt dem Agenten die benötigte Autonomie. Er kann nicht ohne Weiteres die Struktur ändern, die Sprache wechseln oder einen unbrauchbaren Entwurf verwerfen.

Die Schleife wird weiterhin benötigt. Nicht, um den Kernel zu schreiben, sondern um dem Agenten einen verlässlichen nächsten Hinweis zu geben. Dieser Hinweis muss aus zwei Quellen stammen.

Erstens: die Kommunikation mit der Wissensebene (Knowledge Layer): einige Erkenntnisse, die spezifisch genug sind, um darauf basierend zu handeln, und so eingegrenzt, dass wir wissen, wo sie nicht anwendbar sind. Ohne das beginnt jeder Versuch bei null.

Zweitens: Ergebnisse von einer vertrauenswürdigen Prüfinstanz (Checker): Korrektheit und Timing, die der Agent nicht selbst gemessen hat. Diese Zahlen sind Hinweise für den nächsten Versuch. Sie sind auch die einzigen Werte, denen wir vertrauen sollten. Wenn der Agent seine eigene Arbeit zeitlich misst, landen wir wieder bei verbleibenden Caches, ungleichen Vergleichen und Tests, die er einsehen kann.

Die Aufteilung, die wir anstreben, ist also feiner als „Agent versus Schleife“. Gib dem Agenten Autonomie darüber, wie ein Kernel geschrieben wird. Behalte die Schleife als Kanal für Speicher und Evaluierung bei. Der Agent macht Vorschläge. Die Schleife gibt zurück, was sie sehen darf und ob der letzte Vorschlag tatsächlich erfolgreich war.

Proteus hat spezialisierte Kernel für Teile von Qwen 3.5 122B auf seinem Gated DeltaNet-Pfad (einem Block im Stil von Linear-Attention) entwickelt, die auf NVIDIA B200-GPUs laufen. Die Beschleunigungen bei den einzelnen Kerneln lagen im Bereich von 1,8x bis 5,2x.

Die Lehre daraus ist, dass die Generierung der kostengünstige Schritt ist. Validierung und Kontextmanagement sind der schwierige Teil. Hier sind sorgfältige Entwicklungszeit und Innovationen gefragt.

Die agentische GPU-Kernel-Generierung hat das unglaubliche Potenzial extremer Spezialisierung freigesetzt, aber der Aufbau zuverlässiger, produktionsreifer Harnesses bleibt eine anspruchsvolle Herausforderung. Wir stellen uns den härtesten Herausforderungen an der Schnittstelle von AI und Systemen und suchen mutige Engineers, die mit uns die Zukunft der effizienten Inferenz gestalten. Wenn du leidenschaftlich gerne die Grenzen des Machbaren verschiebst, wir stellen ein!

(Dieser Blogbeitrag wurde mit KI-gestützten Tools übersetzt.) Originalbeitrag

Erhalten Sie die neuesten Beiträge in Ihrem Posteingang

Abonnieren Sie unseren Blog und erhalten Sie die neuesten Beiträge direkt in Ihren Posteingang.