Optimierung der On-Device-Inferenz für Apple Silicon
Eine benutzerdefinierte lokale Engine, die den Prefill- und Decode-Durchsatz verbessert.
Hybrid Compute auf Apple Silicon orchestriert eine Aufgabe zwischen Spitzenintelligenz in der Cloud und einem lokalen Modell auf dem Mac. Cloud-Modelle übernehmen Forschung und Schlussfolgerungen, während ein lokales Modell mit privaten Dateien und Apps auf dem Mac arbeitet.
Damit sich diese Arbeitsteilung nahtlos anfühlt, muss die lokale Inferenz mit dem Rest der Aufgabe Schritt halten. Dies erfordert eine Engine, die Prompts schnell verarbeiten und eine hohe Token-Generierungsrate aufrechterhalten kann.
Lily, unsere leichtgewichtige lokale Inferenz-Engine, wurde speziell für Apple Silicon und Qwen3.6-35B-A3B entwickelt, mit separaten Optimierungen für Prefill und Decode. Die Engine wird in Kürze als Open Source veröffentlicht.
Einleitung
Eine gängige Methode zum Ausführen von LLMs auf einem Mac ist MLX, Apples Open-Source-Framework für maschinelles Lernen für Apple Silicon. Die zugehörige Bibliothek MLX-LM fügt die Komponenten hinzu, die zum Laden und Generieren von Text mit einer Vielzahl von Sprachmodellen erforderlich sind. Zusammen bieten MLX und MLX-LM einen einsatzbereiten Allzweck-Stack für die lokale LLM-Inferenz.
Qwen3.6-35B-A3B ist ein sparsames Hybridmodell: Es nutzt Mixture-of-Experts-Routing (MoE) und kombiniert rekurrente Zustände fester Größe mit Full Attention. Diese architektonischen Entscheidungen reduzieren den erforderlichen Rechenaufwand, erzeugen jedoch auch unregelmäßige Arbeitslasten. Token werden an verschiedene Expertengewichte geroutet, und rekurrente Zustände sind von Natur aus sequenziell.
MLX-LM wählt bereits optimierte Kernel für Inferenzphasen und gängige Arbeitslastformen aus, aber seine wiederverwendbaren Operationen müssen viele Modellarchitekturen unterstützen. Eine Engine, die sich auf Qwen spezialisiert hat, kann sich auf Modell- und Laufzeitebene spezialisieren und Kernel, Datenverschiebung und Planung um die feste Struktur des Modells herum koordinieren.
Lily implementiert diese Spezialisierung End-to-End in einem einzigen Prozess. Eine Rust-Runtime lädt den Modell-Checkpoint und verwaltet den Sitzungszustand und die Generierungsschleife, eine OpenAI-kompatible Chat-Completions-API nimmt Anfragen an und streamt Token, und benutzerdefinierte Metal-Kernel führen Qwen-spezifische Operationen aus. Weder PyTorch noch MLX befindet sich im Ausführungspfad.

Wir messen Prefill- und Decode-Leistung separat. Der Prefill-Durchsatz erfasst, wie schnell die Engine den Prompt verarbeitet; der Decode-Durchsatz erfasst, wie schnell sie Ausgabetoken generiert.
Wir haben Qwen3.6-35B-A3B auf einem einzelnen MacBook Pro gebenchmarkt, das von einem M5 Max mit einer 40-Core-GPU und 128 GB Unified Memory angetrieben wird. Über zehn Prompt-Längen für den Prefill und zehn Kontextvariable für den Decode, von 256 bis zu 128K Token (K = 1.024), erzielt die Engine im Durchschnitt den 1,23-fachen Prefill-Durchsatz und den 1,35-fachen Decode-Durchsatz von MLX-LM. Bei einem 4K-Token-Prompt und einem 4K-Token-Decode-Kontext erreicht die benutzerdefinierte Engine 5.749,9 Prefill-Token pro Sekunde und 186,6 Decode-Token pro Sekunde, verglichen mit 4.737,5 und 140,9 bei MLX-LM. Über eine Sitzung mit mehreren Abfragen hinweg summieren sich diese Zeiteinsparungen mit jedem zusätzlichen Modellaufruf.

Als Nächstes erklären wir, wie Qwens Architektur modellspezifische Optimierungsmöglichkeiten auf Apple Silicon schafft. Danach gehen wir die resultierenden Prefill- und Decode-Änderungen durch. Wir behandeln auch, wo zusätzliche Optimierungen keine Vorteile mehr bringen, bevor wir mit einem End-to-End-Vergleich gegen MLX-LM abschließen.
Qwen-spezifische Optimierungsmöglichkeiten auf Apple Silicon
Qwen erzeugt drei verschiedene Arbeitslastformen
Qwen3.6-35B-A3B enthält 35 Milliarden Parameter, aktiviert jedoch nur etwa 3 Milliarden für jedes Token. Ein Router bewertet 256 Experten-Subnetzwerke und wählt acht aus, neben einem gemeinsamen Experten, der jedes Token verarbeitet. Dieses sparsame MoE-Design reduziert die Berechnung, erzeugt jedoch ungleichmäßige Arbeit: Experten erhalten unterschiedliche Mengen an Token, und jedes Token erfordert Gewichte aus einer anderen Kombination von Experten.
Qwen kombiniert außerdem 10 Full-Attention-Schichten mit 30 Gated DeltaNet-Schichten. Diese beiden Schichttypen behalten frühere Informationen auf unterschiedliche Weise bei.
Die Attention-Schichten verwenden Grouped-Query Attention (GQA). Qwen hat 16 Query-Heads und zwei Key-Value-Heads (KV-Heads), wobei sich acht Query-Heads einen KV-Head teilen. Die gemeinsame Nutzung macht den KV-Cache kleiner und ermöglicht die Wiederverwendung gecachter Daten über Query-Heads hinweg. Der Cache speichert weiterhin neue Keys und Values für jedes Token, sodass jeder Decode-Schritt bei wachsendem Kontext mehr Daten liest.
Gated DeltaNet komprimiert stattdessen frühere Informationen in einen rekurrenten Zustand fester Größe. Ein gelerntes Gate steuert, wie viel des bestehenden Zustands beibehalten werden soll, während ein Delta-Update Informationen aus dem aktuellen Token einbindet. Das Modell definiert diese Aktualisierungen rekurrent, sodass jedes Token vom Zustand abhängt, der vom vorhergehenden Token erzeugt wurde. Während des Prefills kann eine Engine dieselbe Berechnung jedoch auf zwei Arten auswerten. Sie kann die Token direkt durchscannen, während sie den Zustand weiterführt, oder die Aktualisierungen in Blöcke umorganisieren, die mehr Matrixoperationen und Token-Ebene-Parallelität offenlegen. Welcher Ansatz schneller ist, hängt von den Modelldimensionen, der Arbeitslast und der Hardware ab.
Zusammen erzeugen diese Strukturen drei Rechenmuster: ungleichmäßige Expertengruppen, Attention über einen wachsenden Cache und eine Rekurrenz fester Größe, die direkt oder in Blöcken ausgewertet werden kann.
Apple Silicon bietet verschiedene Pfade für unterschiedliche Arbeitslasten
Prefill verarbeitet viele Prompt-Token-Aktivierungszeilen auf einmal. Die hier betrachtete lokale Arbeitslast dekodiert typischerweise eine Anfrage nach der anderen (Batch 1) und verarbeitet eine neue Zeile pro Schritt. Dieser Unterschied verändert die Verwendung derselben Modellgewichte. Prefill kann jeden Gewichtsblock über Hunderte oder Tausende von Zeilen hinweg wiederverwenden. Decode kann dies größtenteils nicht, da jedes neue Token einen weiteren Durchlauf durch die Gewichte erfordert.
Apple Silicon platziert CPU und GPU hinter dem Unified Memory, einem einzigen physischen Speicherpool, der für beide zugänglich ist. Dies ermöglicht es dem Modell, resident zu bleiben, ohne eine separate GPU-Kopie zu pflegen, macht die Datenverschiebung jedoch nicht kostenlos. Das Lesen von Gewichten und Zwischenwerten verbraucht nach wie vor Speicherbandbreite, während Register und anderer On-Chip-Speicher schneller, aber viel kleiner sind.
Die M5-GPU bietet auch unterschiedliche Rechenpfade. Die linearen Schichten des Prefills verwenden General Matrix-Matrix Multiplication (GEMM), wobei eine Gewichtsmatrix auf viele Zeilen gleichzeitig angewendet wird. Kompatible GEMMs können den Neural Accelerator in jedem GPU-Kern durch Metal-4-Tensoroperationen nutzen. Der Batch-1-Decode verwendet stattdessen General Matrix-Vector Multiplication (GEMV), wobei dieselben Gewichte auf eine Zeile angewendet werden. Bei geringer Wiederverwendung von Gewichten ist GEMV hauptsächlich durch die Speicherbandbreite begrenzt und eignet sich besser für die Vektor-Arithmetik-Logikeinheiten (ALUs) der GPU als für Neural Accelerators, die für Matrixoperationen mit größerer Datenwiederverwendung konzipiert sind.
Diese Ausführungspfade sind nicht exklusiv für Lily. MLX arbeitet über denselben Unified Memory und wählt optimierte Matrix- und Vektorkernel entsprechend der Arbeitslastform aus. Die Qwen-Implementierung von MLX-LM gruppiert bereits Expertenarbeit, wertet Gated DeltaNet mit einem fusionierten rekurrenten Metal-Kernel aus und verwendet GQA-bewusste Attention. Diese Funktionen sind der gemeinsame Ausgangspunkt für eine effiziente Qwen-Inferenz auf Apple Silicon.
Optimierungsstrategie
Lilys engerer Fokus ermöglicht es ihr, diese gemeinsamen Ausführungspfade um Qwens exakte Architektur und Dimensionen herum zu koordinieren. Sie nutzt phasenspezifische GPU-Pfadstrukturen, bildet Qwens Experten-, Rekurrenz- und Attention-Arbeitslasten ab, um die Datenverschiebung zu minimieren, und wählt Kernel und Layouts entsprechend der gemessenen Arbeitslastform aus. Die Strategie besteht aus drei Teilen:
- Anpassung des GPU-Pfads an die Inferenzphase. Matrixorientierte Ausführung verwenden, wenn der Prefill Gewichte über viele Zeilen hinweg wiederverwenden kann, und vektororientierte Ausführung, wenn der Batch-1-Decode jeweils eine Zeile verarbeitet.
- Abbildung von Qwens Struktur auf die GPU bei gleichzeitiger Minimierung der Datenverschiebung. Gewichte komprimiert halten, bis sie verwendet werden, geroutete Expertenarbeit organisieren, ohne zur CPU zurückzukehren, den Gated DeltaNet-Zustand während seines rekurrenzen Scans im Chip behalten und die von Grouped-Query Attention gemeinsam genutzten KV-Daten wiederverwenden.
- Anpassung von Kerneln an die Arbeitslastform. Wählen Sie innerhalb jeder Phase Kachelgrößen, Ausführungslayouts und Attention-Pfade aus der verfügbaren Zeilenanzahl, der Verteilung der Zeilen auf Experten, den Dimensionen der Operation und der aktuellen Kontextlänge aus.
Die folgenden Abschnitte erklären diese Entscheidungen. Bei Optimierungen, die in abgeglichenen Ablationen auf einem M5 Max evaluiert wurden, schätzen wir ihre Auswirkungen ab, indem wir ansonsten identische Engine-Konfigurationen vergleichen, die sich nur in der untersuchten Optimierung unterscheiden. Da diese Experimente Versionen unserer Engine mit sich selbst vergleichen, erklären sie Mechanismen anstatt die Endergebnisse gegen MLX-LM zu zerlegen.
Prefill: Wiederverwendung von Gewichten und Beibehaltung des Routings auf der GPU
Prefill legt viele Token-Zeilen auf einmal offen, aber Qwen routet diese Zeilen ungleichmäßig über Experten hinweg und aktualisiert den rekurrenten Zustand durch die Sequenz hindurch. Seine Optimierungen fallen in drei Gruppen: Organisation der sparsamen Expertenarbeit um die gerouteten Zeilen herum, Beibehaltung des Gated DeltaNet-Scans im Chip und Unterteilung langer Prompts in begrenzte Chunks.

Optimierung der sparsamen Expertenberechnung
Dequantisierung von Gewichten während der Matrixmultiplikation
Der Qwen3.6-35B-A3B-Checkpoint verwendet gruppenweise affine 4-Bit-Quantisierung. Jedes Gewicht wird als 4-Bit-Ganzzahlcode gespeichert, während sich jede Gruppe von 64 Gewichten einen bfloat16-Skalierungsfaktor und -Bias teilt, die zur Rekonstruktion ihrer Werte verwendet werden. Dies reduziert das Modell mit 35 Milliarden Parametern von etwa 70 GB an bfloat16-Gewichten auf einen 19,4-GB-Checkpoint, wodurch es praktikabel wird, das Modell auf dem Mac resident zu halten.
Die für die Matrixmultiplikation verwendete Metal-4-Tensoroperation verbraucht bfloat16-Operanden anstelle der gepackten 4-Bit-Repräsentation. Vor der Multiplikation muss die GPU die Gewichte in bfloat16 rekonstruieren. Das optimierte gruppierte GEMM in Lily führt diese Konvertierung jeweils für eine kleine Gewichtskachel durch und hält das Ergebnis nur lange genug im On-Chip-Threadgroup-Speicher, um es mit den gerouteten Aktivierungszeilen zu multiplizieren. Die Akkumulation verwendet 32-Bit-Gleitkommazahlen, und die Ausgabe wird in bfloat16 geschrieben. Das vollständige expandierte Gewichtsarray wird niemals im Unified Memory erstellt.
In der Ablation läuft die Dequantisierung als separate Operation: Sie expandiert die 4-Bit-Gewichte in ein bfloat16-Array im Unified Memory, wonach der Matrix-Kernel dieses Array wieder einliest. Bei einem 512-Token-Prompt steigerte das Verschieben der Dequantisierung in das gruppierte GEMM den End-to-End-Prefill-Durchsatz um 77,4 %, indem dieses temporäre Schreiben und Lesen eliminiert wurde.
Beibehaltung des Experten-Routings auf der GPU
Das gruppierte GEMM erfordert, dass die jedem Experten zugewiesenen Aktivierungszeilen zusammenhängend gespeichert werden. Nach der Auswahl von acht Experten pro Token zählt ein Histogramm, wie viele Zuweisungen an jeden Experten gegangen sind. Ein Präfix-Scan verwandelt diese Zählungen in Start-Offsets, ein Scatter-Schritt platziert Zeilen in ihren Expertengruppen, und eine Blockkarte listet die Matrixblöcke fester Größe auf, die das gruppierte GEMM verarbeiten muss.
Der optimierte Pfad hält diese gesamte Sequenz für jeden Prompt-Chunk in einem einzigen Command Buffer, einer geordneten Charge von GPU-Operationen. Eine Ablation pausiert stattdessen, damit die CPU die Routing-Zwischenprodukte inspizieren und die nächste Operation übergeben kann. Das Belassen von Histogramm und Präfix-Scan auf der GPU fügt zwei Kernel hinzu, entfernt jedoch die CPU-GPU-Synchronisation innerhalb jeder MoE-Schicht.
Bei einem 512-Token-Prompt erhöhte das Aktivieren des GPU-residenten Routings den End-to-End-Prefill um 89 %. Dies zeigt auch, warum die Kernelsanzahl allein irreführend sein kann: Die schnellere Route startet mehr Kernel, wartet jedoch niemals innerhalb der Schicht auf die CPU.
Anpassung der Kachelgröße an die Expertenlast
Bei einem 2K-Token-Prompt erzeugt das Routen jedes Tokens an acht von 256 Experten 16.384 Token-Experten-Zuweisungen oder durchschnittlich 64 Aktivierungszeilen pro Experte. Die tatsächliche Verteilung ist ungleichmäßig: Einige Experten erhalten viele Zeilen, während andere wenige erhalten.
Das gruppierte GEMM unterteilt die Ausgabe jedes Experten in Kacheln, die kleine rechteckige Blöcke der Ausgabe einer Matrixmultiplikation sind. Jede Kachel wird einer GPU-Threadgroup zugewiesen. Auf den GPUs von Apple Silicon enthält eine Threadgroup eine oder mehrere Simdgroups, von denen jede aus 32 Threads besteht, die Anweisungen im Gleichschritt (Lockstep) ausführen.
Größere Kacheln verteilen die Einrichtungs- und Setup-Kosten auf mehr Zeilen und legen mehr parallele Arbeit offen, aber ein Teil einer großen Kachel bleibt im Leerlauf, wenn ein Experte nur wenige Zeilen erhält. Kachelgröße und Simdgroup-Anzahl sind daher gekoppelt.
Eine Ablation fixiert die Kachel auf 16 Zeilen. Gegenüber dieser Kontrolle verbesserte das Aktivieren der 32-Zeilen-Kachel mit vier Simdgroups den End-to-End-Prefill bei 2K Token um 13,2 %.
Beibehaltung des rekurrenten Zustands im Chip
Während des Prefills scannt jede Gated DeltaNet-Schicht den Prompt der Reihe nach, während sie ihren rekurrenten Zustand weiterführt. Bei deaktivierter Register-Residenz verwendet die Ablation einen blockweisen Scan. Bei einem 2K-Token-Prompt verschiebt dieser Pfad 256 MiB (Mebibytes) an Zustand pro Schicht und stoppt wiederholt kooperierende Threads an Barrieren, Synchronisationspunkten, an denen alle beteiligten Threads aufeinander warten müssen.
Der rekursente Zustand ist eine Matrix. Der optimierte Kernel weist jede Spalte einer Simdgroup zu. Die Simdgroup teilt die Spalte unter ihren Threads auf, lädt die Spalte einmal in ihre Register und führt den Zustand durch den gesamten Scan. Die Threads tauschen Zwischenergebnisse über Simdgroup-Operationen aus anstelle von Threadgroup-Speicher, einem On-Chip-Speicher, der von einer Threadgroup gemeinsam genutzt wird. Der fertige Zustand wird erst nach dem Scan zurückgeschrieben.
Der Zustand und sein Gate verwenden ein 32-Bit-Gleitkommaformat, da sich kleine Rundungsfehler bei sequenziellen Aktualisierungen summieren. Query- und Key-Aktivierungen verbleiben in bfloat16.
Bei einem 2K-Token-Prompt verbesserte das Aktivieren des im Register residierenden Scans den End-to-End-Prefill um 5,6 %. Experten-GEMMs machten etwa 90 % der Prefill-Zeit aus. Der sequenzielle Scan legt nicht genügend wiederverwendbare Matrixarbeit offen, um von den Neural Accelerators zu profitieren.
Begrenzung des temporären Speichers durch Prompt-Chunking
Die Laufzeit verarbeitet einen langen Prompt als Sequenz begrenzter Chunks, anstatt temporäre Daten für jeden Prompt-Token gleichzeitig im Speicher zu behalten. Modellgewichte verbleiben im Unified Memory residierend, während der rekurrente Zustand und der KV-Cache den Kontext von einem Chunk zum nächsten übertragen. Es wird kein früherer Kontext verworfen.
Ohne Chunking wachsen temporäre Aktivierungsarrays mit dem vollständigen Prompt und konkurrieren mit Modellgewichten, dem rekurrenten Zustand und dem KV-Cache um den Unified Memory. Durch Chunking bleiben nur die temporären Werte eines Segments gleichzeitig aktiv, wonach dieser Speicher freigegeben oder vor der Verarbeitung des nächsten Segments wiederverwendet wird. Dies deckt den Spitzenspeicherbedarf ab und ermöglicht der Engine, längere Prompts zu verarbeiten, ohne die Ausgabe des Modells zu verändern.
Chunked Prefill ist in vielen Engines beliebt und für das Serving langer Multi-Turn-Trajektorien in diesen speicherbeschränkten Umgebungen von entscheidender Bedeutung. Die Gesamt-Prefill-Zeit für Attention-Schichten bleibt quadratisch zur Prompt-Länge, mit etwas zusätzlichem Overhead durch wiederholte KV-Ladevorgänge früherer Chunks.
Decode: Minimierung der verschobenen Bytes pro Token
Der Batch-1-Decode verarbeitet jeweils eine neue Zeile. Bei geringer Wiederverwendung von Gewichten hängt sein Durchsatz hauptsächlich davon ab, wie viele Bytes die Engine für jedes Token verschiebt. Die Decode-Änderungen fallen in vier Gruppen: Optimierung des Ein-Zeilen-Gewichtspfads, Beibehaltung jedes Schritts auf der GPU, Reduzierung des Zwischen- und Zustands-Traffics und effizientes Lesen des Attention-Caches.

Optimierung des Ein-Zeilen-Gewichtspfads
MLX verteilt Ein-Zeilen-Arbeit bereits an spezialisierte Matrix-Vektor-Kernel. Da Lily kein MLX verwendet, muss die benutzerdefinierte Laufzeit dieselbe grundlegende Strategie bereitstellen. Unser zeilenparalleler GEMV ist für eine Aktivierungszeile ausgelegt. Eine Simdgroup arbeitet am Ausgang zusammen, während sie verschiedene Teile der Gewichtsmatrix parallel liest.
Beibehaltung jedes Decode-Schritts auf der GPU
Beibehaltung der Token-Übergabe auf der GPU
Jeder Decode-Schritt endet mit der Auswahl des nächsten Tokens; der folgende Schritt beginnt mit diesem Token als Eingabe. Das Senden der Auswahl an die CPU und dann zurück an die GPU fügt jedem Token einen Synchronisationspunkt hinzu. Unsere Laufzeit wechselt stattdessen zwischen zwei Command Buffers und zwei GPU-residenten Token-Slots ab. Die GPU wählt das Token mit der höchsten Punktzahl aus und schreibt dessen Token-ID direkt in den Eingabeschlupf für den nächsten Decode-Schritt, während die CPU nachfolgende Arbeit vorbereitet.
Überlappung unabhängiger GPU-Arbeit
In einem aufgezeichneten Batch-1-Decode-Schritt löste das Generieren eines Tokens 795 GPU-Kernel aus. Ihre Abhängigkeiten bildeten 555 sequenzielle Stufen, wodurch einige Kernel gleichzeitig ausgeführt werden konnten. Metals serieller Ausführungsmodus führte jedoch jeden Kernel der Reihe nach aus.
Der optimierte Decode-Pfad zeichnet die tatsächlichen Datenabhängigkeiten in einem gleichzeitigen Metal-Pass auf. Unabhängige Kernel-Starts können zur gleichen Zeit ausgeführt werden, wenn die GPU-Ressourcen dies erlauben. Eine Barriere wird nur dann eingefügt, wenn spätere Arbeit ein früheres Ergebnis erfordert.
Reduzierung des Zwischen- und Zustands-Traffics
Separate Kernel materialisieren oft ein Zwischenergebnis: Ein Kernel schreibt ein temporäres Ergebnis in den Speicher, und der nächste liest das Ergebnis zurück. Der optimierte Decode-Pfad fusioniert vier Ketten: die beiden Experten-Eingabeprojektionen mit ihrer Gated-Aktivierung; die Experten-Ausgabeprojektion mit ihrem Routing-Score und dem Ergebnis des gemeinsamen Experten; Query- und Key-Vorbereitung vor der Attention; sowie die rekurrente Aktualisierung mit ihrer Normalisierung. Jeder fusionierte Kernel hält temporäre Werte in Registern, anstatt sie durch den Speicher zu senden.
Fusion verkürzt auch den Abhängigkeitsgraphen: Wenn ein temporäres Schreiben verschwindet, verschwindet auch die Barriere, die seinen Verbraucher schützte.
Effizientes Lesen des Attention-Caches
Coalescing von Attention-Cache-Lesevorgängen
Attention liest Keys und Values während jedes Decode-Schritts aus dem KV-Cache. In der Ablation fordern benachbarte GPU-Threads nicht immer benachbarte Bytes an, was das Speichersystem zwingt, mehr separate Transaktionen zu bedienen. Das Aktivieren von koaleszierten Ladevorgängen sorgt dafür, dass benachbarte Threads benachbarte Bytes anfordern, damit die Hardware ihre Lesevorgänge kombinieren kann.
In der bfloat16-Konfiguration erhöhte das Coalescing die Key-Bandbreite von 33,8 auf 47,9 GB/s, die Value-Bandbreite von 42,0 auf 61,8 GB/s und verbesserte den End-to-End-Decode bei einem Kontext von 3.840 Token um 2,1 %.
Packen von Query-Heads zur Wiederverwendung von KV-Zeilen
Grouped-Query Attention lässt acht Query-Heads sich einen KV-Head teilen. Bei der Ablation läuft jeder Query-Head in einer separaten Simdgroup, sodass alle acht unabhängig voneinander dieselbe gecachte KV-Zeile anfordern. Der optimierte Kernel packt vier Query-Heads in eine Threadgroup, die jede KV-Zeile einmal lädt und sie über vier Attention-Berechnungen hinweg wiederverwendet. Eine zweite Threadgroup verarbeitet die verbleibenden vier Heads.
Diese Technik, die gemeinhin als GQA-Packing bezeichnet wird, führt dieselbe Arithmetik durch und erzeugt identische Ausgabebytes, während sie acht unabhängige KV-Anfragen auf zwei gemeinsame Ladevorgänge reduziert. Gegenüber der ungepackten Ablation verbesserte sie den End-to-End-Decode-Durchsatz bei einem 32K-Token-Kontext um 23,8 %.
Wechsel der Attention-Layouts bei langen Kontexten
Jeder Decode-Schritt in einer Full-Attention-Schicht scannt den bestehenden KV-Cache. Ein Layout mit festen Blöcken unterteilt diesen Cache in gleich große Teile, die die GPU parallel verarbeiten kann. Die zusätzliche Planung lohnt sich nicht, wenn der Cache klein ist, aber das Layout mit festen Blöcken gleicht die Arbeit gleichmäßiger aus, während der Kontext wächst.
Für dieses Modell hält die Laufzeit den allgemeinen Attention-Pfad unter 32K Token und verwendet den Pfad mit festen Blöcken ab 32K oder mehr. Der Wechsel erfolgt, wenn jeder Head 256 Werte hat und sich acht Query-Heads einen KV-Head teilen; andere Formen verbleiben auf dem allgemeinen Pfad. Eine Ablation deaktiviert diesen Schalter und verwendet immer den allgemeinen Pfad. Das Aktivieren der Route mit festen Blöcken verbesserte den End-to-End-Decode bei 32K um 7,7 %, bei 64K um 27,4 % und bei 128K um 40,2 %.
Grenzen weiterer Optimierung
Einige Änderungen verbesserten eine isolierte Operation, verbesserten jedoch nicht die End-to-End-Inferenz.
Spekulative Dekodierung, die ein kleineres Modell verwendet, um Token für die Verifizierung durch das vollständige Modell vorzuschlagen, machte den Batch-1-Decode um 18 % langsamer. Die Verifizierung verarbeitete Gruppen von zwei bis fünf Zeilen, eine ineffiziente Form für diese Hardware, und die Zeilen wählten oft unterschiedliche Experten aus, wodurch die Menge der gelesenen Experten-Gewichtsdaten erhöht wurde. Das Reduzieren des Ausgabevokabulars des Drafters verbesserte den Durchsatz des Drafters um 4,7–5,1 %, beschleunigte jedoch nicht die vollständige spekulative Schleife. Dieses Ergebnis ist arbeitslastspezifisch: Unser gebatchtes Qwen-Deployment auf Blackwell verwendet spekulative Dekodierung unter anderen Bedingungen.
Andere Experimente umfassten das Reduzieren von GPU-Starts, das Überlapaen ganzer Phasen, die Verwendung größerer Prefill-Kacheln, die Anwendung breiterer Fusionsvorgänge, die Beschleunigung des Routers und die Kombination der Ausgabeprojektion mit der Token-Auswahl. Keines davon verbesserte die vollständige Inferenzschleife.
Messungen der Hardware-Grenzen zeigten zudem wenig verbleibenden Spielraum bei den Hauptoperationen für Prefill und Decode. Die MoE-GEMMs und -GEMVs erreichten 97,9 % bzw. 90,3 % der schnellsten nachhaltigen Gewichtsleseraten für ihre Zugriffsmuster. Das Entfernen der Arithmetik aus dem sparsamen GEMV veränderte den Durchsatz nur um 0,2 %, was bestätigt, dass das Lesen von Gewichten und nicht die Berechnung die limitierende Ressource war. Die Matrixmultiplikation des Prefills erreichte isoliert ähnlich 93 % des theoretischen Matrixlimits und 80–86 % innerhalb der getesteten Modelle.
End-to-End-Leistung
Der End-to-End-Vergleich lädt identische 4-Bit-Checkpoint-Bytes in beide Engines und führt jeweils eine Anfrage auf einem 40-Core, 128-GB-M5-Max aus. Innerhalb jeder Runde laufen die beiden Engines in abwechselnder Reihenfolge, um Verzerrungen durch Hintergrundlast und Änderungen der Chip-Temperatur zu reduzieren. Wir vergleichen mit dem schnellsten Direkterzeugungspfad von MLX-LM, nicht mit dessen Server, sodass sich die Messung auf die Modellausführung statt auf den Serving-Overhead konzentriert.
Der Sweep umfasst zehn Prompt-Längen für den Prefill und zehn Kontextlängen für den Decode, von 256 bis 128K Token. Der Prefill-Durchsatz steigt zunächst an, da die Engine feste Einrichtungskosten auf mehr Token verteilt. Der Prefill erreicht seinen Höchststand bei einem ca. 4K-Token-Prompt und sinkt dann ab, da die zehn Full-Attention-Schichten mehr Arbeit verrichten, je länger der Prompt wird. Der Decode bleibt bei kurzen Kontexten nahezu flach und nimmt ab, sobald das Lesen des wachsenden KV-Caches ins Gewicht fällt. Die benutzerdefinierte Engine ist bei jeder aufgezeichneten Länge schneller.
Da eine spezialisierte Ausführung die Reihenfolge von Gleitkommaoperationen ändern kann, haben wir auch die numerische Konsistenz gegenüber MLX-LM überprüft. In einem lehrergesteuerten Vergleich sagten beide Engines das nächste Token aus demselben Referenzpräfix an jeder von 192 Positionen voraus, wodurch verhindert wurde, dass frühere Unterschiede spätere Eingaben beeinflussten. Lilys Perplexität war nur 0,04 % höher, und sie wählte an 96,35 % der getesteten Positionen dasselbe am höchsten bewertete Token aus.

Entwickelt für die lokale Plattform
Apple Silicon ist keine kleinere Rechenzentrums-GPU. Es ist eine vollständige lokale Inferenzplattform mit eigenen Hardware- und Softwareeigenschaften. Der Unified Memory verleiht einem einzelnen Knoten eine sehr hohe Obergrenze dafür, wie viel Modell und Zustand er halten kann. Die M5 Neural Accelerators absorbieren die dichte Matrixarbeit beim Prefill. Die Vektor-ALUs übernehmen den bandbreitenbeschränkten Rest mit geringer Wiederverwendung beim Decode.
Qwen bietet weitere Möglichkeiten zur Spezialisierung: Experten-Routing und rekurrenten Zustand auf der GPU behalten, unnötige Zwischenprodukte eliminieren, unabhängige Arbeit überlappen, gemeinsame KV-Daten wiederverwenden und Kernel an die Arbeitslastform anpassen.
Mit modell- und plattformspezifischer Optimierung kann ein Mac ein großes, sparsames Modell effizient ausführen. Zukünftige Arbeiten werden die Abdeckung über Modelle, Chips und Serving-Arbeitslasten hinweg erweitern und die hier auf einer Konfiguration validierten Mechanismen in eine allgemeinere Laufzeitrichtlinie umwandeln.
Das breitere Prinzip besteht darin, die Engine sowohl an die Architektur des Modells als auch an die spezifischen Rechen- und Speicherpfade der Hardware anzupassen. Da sich Open-Weight-Modelle und Hardware an der vordersten Front weiterentwickeln, wird eine hochleistungsfähige lokale Inferenz zunehmend von Engines abhängen, die auf beide zugeschnitten sind, anstatt von solchen, die ihre Unterschiede abstrahieren.