KI‑Kompass
Kompass

Wie eine GPU aufgebaut ist

Recheneinheiten, Warps, Tensor Cores und Speicherhierarchie: was tatsächlich passiert, wenn eine Matrixmultiplikation auf einer Grafikkarte ausgeführt wird.

·2 Min. Lesezeit·Von Fachredaktion Technik
DETAILGRAD
3 Abschnitte

Die Idee

Stellen Sie sich eine Fabrikhalle mit hundert Arbeitsgruppen vor. Jede Gruppe hat 32 Leute, die alle denselben Handgriff gleichzeitig ausführen, jeder an einem anderen Werkstück. Wer aus der Reihe tanzt, hält die ganze Gruppe auf.

Genau so arbeitet eine Grafikkarte. Diese Bauform erklärt beides: die enorme Leistung bei gleichförmigen Aufgaben und den völligen Einbruch bei verzweigungsreichem Code.

Die Ebenen

EbeneUmfangEntspricht
Fadeneine Rechnungein Arbeiter
Warp32 Fäden im Gleichschritteine Gruppe
Blockbis zu 1.024 Fäden mit gemeinsamem Speichereine Schicht an einem Tisch
Recheneinheit (SM)führt viele Blöcke auseine Werkbank
Karte60 bis 150 Recheneinheitendie Halle

Die Speicherhierarchie

Sie ist der eigentliche Schlüssel zur Leistung.

EbeneGrößeLatenzBandbreite
Register256 KB je Recheneinheit~1 Taktsehr hoch
Shared Memory100 bis 228 KB je Recheneinheit~20 Taktehoch
L2-Cache40 bis 100 MB~200 Taktemittel
Kartenspeicher (HBM)24 bis 192 GB~400 Takte1 bis 8 TB/s
Hauptspeicher über PCIebeliebig~10.000 Takte32 bis 64 GB/s

Der Sprung von der vierten zur fünften Zeile ist der Grund, warum ein Modell, das nicht in den Kartenspeicher passt, nicht ein bisschen langsamer wird, sondern um den Faktor 30 bis 100.

Divergenz

Kosten einer Verzweigung im Warp

t = k · t_ideal (im Extremfall k = 32)

Nehmen die 32 Fäden eines Warps verschiedene Zweige, werden alle Zweige nacheinander ausgeführt.

t_ideal
Zeit ohne Verzweigung
k
Anzahl unterschiedlicher Pfade innerhalb eines Warps

Ein if in einem Kernel ist deshalb nicht kostenlos, sondern kostet im schlimmsten Fall den Faktor 32. Praktisch schreibt man Kernel so, dass alle Fäden eines Warps denselben Pfad nehmen, etwa durch Sortieren der Daten vor der Verarbeitung.

Kachelung einer Matrixmultiplikation

Der naive Weg liest für jedes Ergebniselement eine ganze Zeile und eine ganze Spalte aus dem Kartenspeicher. Bei n = 4096 sind das 2 · n³ = 1,4e11 Lesevorgänge. Die gekachelte Variante lädt Blöcke von T × T in den Shared Memory und benutzt jedes geladene Element T Mal:

Reduktion der Speicherzugriffe durch Kachelung

Zugriffe_naiv = 2 · n³ Zugriffe_gekachelt = 2 · n³ / T

Die Zahl der Zugriffe auf den langsamen Kartenspeicher sinkt um den Faktor der Kachelgröße.

T
Kachelgröße, üblich 32 bis 128
n
Matrixdimension

Bei T = 64 ist das ein Faktor 64 weniger Speicherverkehr. Genau diese Optimierung steckt in cuBLAS und CUTLASS, und deshalb erreicht eine handgeschriebene naive Matrixmultiplikation typischerweise unter 5 Prozent der Kartenleistung.

Tensor Cores und die passenden Formate

Tensor Cores rechnen Blöcke fester Größe, etwa 16 × 16 × 16, in einem Befehl. Damit sie greifen, müssen drei Bedingungen erfüllt sein:

  • Das Datenformat passt: float16, bfloat16, int8, fp8 oder tf32. Reines float32 nutzt sie nicht.
  • Die Matrixdimensionen sind Vielfache der Blockgröße, meist 8 oder 16. Eine Breite von 4095 statt 4096 kostet spürbar Leistung.
  • Der Speicher ist passend ausgerichtet, was Bibliotheken üblicherweise sicherstellen.

Die zweite Bedingung erklärt, warum Modellbreiten in der Praxis immer glatte Zahlen wie 4096, 5120 oder 8192 sind.

Auslastung messen

Eine hohe Auslastung der Recheneinheiten ist nicht das Ziel; ein hoher Anteil tatsächlich genutzter Rechenleistung ist es. Die aussagekräftigen Größen sind der Anteil erreichter Spitzenleistung und der Anteil erreichter Speicherbandbreite. Liegt der erste bei 8 Prozent und der zweite bei 85 Prozent, ist die Aufgabe speichergebunden und jede weitere Rechenleistung nutzlos, siehe Speicher und Bandbreite.

War diese Seite hilfreich?
Wie eine GPU aufgebaut ist