69 Punkte von GN⁺ 2026-02-17 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Ein von karpathy veröffentlichtes Kunstprojekt. Implementiert den gesamten GPT-Algorithmus in einer einzigen Datei mit 200 Zeilen, ganz ohne externe Abhängigkeiten
  • Der Unterschied zu produktiven LLMs liegt nur in Größe und Effizienz; der Kern ist identisch. Wer diesen Code versteht, hat das algorithmische Wesen von GPT verstanden
  • Enthält Dataset, Tokenizer, Autograd-Engine, eine GPT-2-ähnliche Transformer-Architektur, den Adam-Optimierer sowie Trainings- und Inferenzschleifen
  • Als Quintessenz aus 10 Jahren LLM-Vereinfachungsarbeit in früheren Projekten wie micrograd, makemore und nanogpt verdichtet es das Wesen von GPT auf eine minimale Form, die sich nicht weiter vereinfachen lässt
  • Trainiert auf 32.000 Namensdatensätzen und erzeugt plausibel wirkende neue Namen, wobei alle Berechnungen direkt mit skalarem Autograd ausgeführt werden
  • Der Trainingsprozess besteht aus Verlustberechnung → Backpropagation → Adam-Update und ist in etwa einer Minute ausführbar

Überblick über microgpt

  • microgpt ist ein 200 Zeilen langes Python-Skript, das den Trainings- und Inferenzprozess eines GPT-Modells vollständig implementiert
    • Ohne externe Bibliotheken enthält es Dataset, Tokenizer, Autograd, Modell, Optimierer und Trainingsschleife vollständig in einer Datei
  • Führt bestehende Projekte wie micrograd, makemore und nanogpt in einer einzigen Datei zusammen
  • Eine Implementierung, die nur noch den algorithmischen Kern übrig lässt, auf dem Niveau von „nicht weiter vereinfachbar“
  • Der vollständige Code ist als GitHub Gist, Webseite und Google Colab verfügbar

Aufbau des Datasets

  • Der Treibstoff großer Sprachmodelle ist ein Textdatenstrom. In der Produktion werden Internet-Webseiten verwendet, in microgpt dagegen ein einfaches Beispiel mit 32.000 Namen, jeweils einer pro Zeile
  • Jeder Name wird als ein einzelnes "Dokument" behandelt, und das Ziel des Modells ist es, statistische Muster in den Daten zu lernen, um ähnliche neue Dokumente zu erzeugen
  • Nach dem Training „halluziniert“ das Modell plausible neue Namen wie "kamon", "karai" oder "vialan"
  • Aus Sicht von ChatGPT ist auch ein Gespräch mit einem Nutzer nur ein "ungewöhnlich geformtes Dokument"; initialisiert man ein Dokument per Prompt, entspricht die Antwort des Modells einer statistischen Dokumentvervollständigung

Tokenizer

  • Da neuronale Netze nicht mit Zeichen, sondern mit Zahlen arbeiten, braucht man eine Methode, um Text in Sequenzen ganzzahliger Token-IDs umzuwandeln und wieder zurückzuführen
  • Produktive Tokenizer wie tiktoken (verwendet von GPT-4) arbeiten aus Effizienzgründen mit Zeichenblöcken, aber der einfachste Tokenizer weist jedem eindeutigen Zeichen im Dataset eine ganze Zahl zu
  • Die Kleinbuchstaben a-z werden sortiert, und jedem Zeichen wird per Index eine ID zugewiesen; der Integerwert selbst hat keine Bedeutung, jedes Token ist ein eigenständiges diskretes Symbol
  • Ein spezielles BOS-Token (Beginning of Sequence) signalisiert „ein neues Dokument beginnt/endet“, sodass "emma" als [BOS, e, m, m, a, BOS] eingerahmt wird
  • Die endgültige Vokabulargröße beträgt 27 (26 Kleinbuchstaben + 1 BOS)

Automatische Differentiation (Autograd)

  • Für das Training neuronaler Netze braucht man Gradienten: Für jeden Parameter muss man wissen: „Wenn ich diesen Wert leicht erhöhe, steigt der Verlust dann, sinkt er, und um wie viel?“
  • Der Rechengraph hat viele Eingaben (Modellparameter und Eingabetokens), läuft aber auf einen einzigen skalaren Output, den Verlust (loss), hinaus
  • Backpropagation startet am Output und verfolgt den Graphen rückwärts. Dabei stützt sie sich auf die Kettenregel der Differentialrechnung, um die Gradienten des Verlusts bezüglich aller Eingaben zu berechnen
  • Implementiert über die Value-Klasse: Jeder Value kapselt einen einzelnen Skalar (.data) und verfolgt, wie er berechnet wurde
    • Bei Operationen wie Addition oder Multiplikation speichert ein neuer Value die Eingaben (_children) und die lokalen Ableitungen (_local_grads) der jeweiligen Operation
    • Beispiel: __mul__ speichert ∂(a·b)/∂a=b und ∂(a·b)/∂b=a
  • Unterstützte Operationsbausteine: Addition, Multiplikation, Potenzieren, log, exp, ReLU
  • Die Methode backward() durchläuft den Graphen in umgekehrt topologischer Reihenfolge und wendet in jedem Schritt die Kettenregel an
    • Am Verlustknoten beginnt sie mit self.grad = 1 (∂L/∂L=1)
    • Die lokalen Gradienten werden entlang des Pfads multipliziert und bis zu den Parametern weitergegeben
  • Akkumulation mit += (keine Zuweisung): Wenn sich der Graph verzweigt, fließen aus jedem Zweig unabhängig Gradienten ein und müssen aufsummiert werden (eine Folge der mehrvariablen Kettenregel)
  • Algorithmisch ist das identisch zu PyTorchs .backward(), arbeitet aber auf Skalar- statt Tensor-Ebene und ist dadurch deutlich einfacher, jedoch weniger effizient

Parameterinitialisierung

  • Parameter sind das Wissen des Modells: eine große Menge an Fließkommazahlen, die zufällig starten und während des Trainings wiederholt optimiert werden
  • Sie werden mit kleinen Zufallswerten aus einer Gaußschen Verteilung initialisiert
  • Sie bestehen aus im state_dict benannten Matrizen: Embedding-Tabelle, Attention-Gewichte, MLP-Gewichte und finale Ausgabeprojektion
  • Einstellung der Hyperparameter:
    • n_embd = 16: Embedding-Dimension
    • n_head = 4: Anzahl der Attention-Heads
    • n_layer = 1: Anzahl der Layer
    • block_size = 16: maximale Sequenzlänge
  • Das kleine Modell hat 4.192 Parameter (GPT-2 hat 1,6 Milliarden, moderne LLMs Hunderte Milliarden)

Architektur

  • Die Modellarchitektur ist eine zustandslose Funktion: Sie nimmt Token, Position, Parameter sowie zwischengespeicherte Schlüssel/Werte früherer Positionen entgegen und gibt Logits (Scores) für das nächste Token zurück
  • Orientiert sich an GPT-2, aber leicht vereinfacht: RMSNorm (statt LayerNorm), keine Biases, ReLU (statt GeLU)
  • Hilfsfunktionen

    • linear: berechnet per Matrix-Vektor-Multiplikation ein Skalarprodukt für jede Zeile der Gewichtungsmatrix, eine gelernte lineare Transformation als Grundbaustein neuronaler Netze
    • softmax: wandelt rohe Scores (Logits) in eine Wahrscheinlichkeitsverteilung um, wobei alle Werte im Bereich [0,1] liegen und in Summe 1 ergeben; zur numerischen Stabilität wird zuerst der Maximalwert abgezogen
    • rmsnorm: skaliert einen Vektor so um, dass er eine Einheits-Root-Mean-Square hat, damit Aktivierungen beim Durchlaufen des Netzes nicht wachsen oder schrumpfen; stabilisiert das Training
  • Modellstruktur

    • Embeddings: Token-ID und Positions-ID verweisen jeweils auf Zeilen in den Embedding-Tabellen (wte, wpe); die beiden Vektoren werden addiert, um gleichzeitig zu kodieren, was das Token ist und wo es sich in der Sequenz befindet
      • Moderne LLMs überspringen Positions-Embeddings und verwenden relative Positionierungstechniken wie RoPE
    • Attention-Block: projiziert das aktuelle Token in drei Vektoren: Q (Query), K (Key), V (Value)
      • Query: „Wonach suche ich?“, Key: „Was trage ich in mir?“, Value: „Was liefere ich, wenn ich ausgewählt werde?“
      • Beispiel: Beim Vorhersagen nach dem zweiten „m“ in „emma“ kann das Modell eine Query wie „Welcher Vokal kam zuletzt?“ lernen; das frühere „e“ passt gut zu dieser Query und erhält ein hohes Attention-Gewicht
      • Keys und Values werden dem KV-Cache hinzugefügt, sodass auf frühere Positionen verwiesen werden kann
      • Jeder Attention-Head berechnet das Skalarprodukt zwischen der Query und allen zwischengespeicherten Keys (skaliert mit √d_head), erhält per softmax die Attention-Gewichte und bildet die gewichtete Summe der zwischengespeicherten Values
      • Die Ausgaben aller Heads werden verkettet und mit attn_wo projiziert
      • Der Attention-Block ist der einzige Ort, an dem ein Token an Position t die früheren Token 0..t-1 „sehen“ kann; Attention ist der Kommunikationsmechanismus zwischen Token
    • MLP-Block: ein 2-schichtiges Feedforward-Netzwerk: Expansion auf das 4-Fache der Embedding-Dimension → ReLU anwenden → wieder verkleinern
      • Hier findet der Großteil des positionsweisen „Denkens“ statt
      • Anders als Attention ist dies zu Zeitpunkt t eine vollständig lokale Berechnung
      • Transformer wechseln Kommunikation (Attention) und Berechnung (MLP) ab
    • Residual-Verbindungen: Sowohl Attention- als auch MLP-Block addieren ihre Ausgabe wieder auf die Eingabe
      • Dadurch können Gradienten direkt durch das Netz fließen und tiefe Modelle trainierbar machen
    • Ausgabe: Der finale Hidden State wird mit lm_head auf die Vokabulargröße projiziert, um pro Token ein Logit zu erzeugen (hier 27 Zahlen); hohes Logit = hohe Wahrscheinlichkeit, dass dieses Token als Nächstes kommt
    • Besonderheit des KV-Caches: Die Nutzung eines KV-Caches während des Trainings ist selten, aber weil microgpt jeweils nur ein Token auf einmal verarbeitet, wird er explizit aufgebaut; die zwischengespeicherten Keys und Values sind lebende Value-Knoten im Rechengraphen und damit Ziel der Backpropagation

Trainingsschleife

  • Die Trainingsschleife wiederholt fortlaufend: (1) Dokument auswählen → (2) Modell-Forward-Pass über die Token ausführen → (3) Verlust berechnen → (4) per Backpropagation Gradienten erhalten → (5) Parameter aktualisieren
  • Tokenisierung

    • In jedem Trainingsschritt wird ein Dokument ausgewählt und auf beiden Seiten mit BOS umschlossen: „emma“ → [BOS, e, m, m, a, BOS]
    • Das Ziel des Modells ist es, bei gegebenen vorherigen Token jedes nächste Token vorherzusagen
  • Forward-Pass und Verlust

    • Die Token werden dem Modell nacheinander einzeln zugeführt, wobei der KV-Cache aufgebaut wird
    • An jeder Position gibt das Modell 27 Logits aus, die per softmax in Wahrscheinlichkeiten umgewandelt werden
    • Der Verlust an jeder Position ist die negative Log-Wahrscheinlichkeit des korrekten nächsten Tokens: −log p(target); das nennt man Cross-Entropy-Loss
    • Der Verlust misst, wie überrascht das Modell von dem tatsächlich folgenden Token ist: Bei Wahrscheinlichkeit 1.0 ist der Verlust 0, bei einer Wahrscheinlichkeit nahe 0 ist der Verlust +∞
    • Die positionsweisen Verluste über das gesamte Dokument werden gemittelt, um einen einzelnen skalaren Verlust zu erhalten
  • Backward-Pass

    • Ein einziger Aufruf von loss.backward() führt die Backpropagation über den gesamten Rechengraphen aus
    • Danach zeigt .grad jedes Parameters, wie er verändert werden muss, um den Verlust zu senken
  • Adam-Optimierer

    • Statt einfachem Gradientenabstieg (p.data -= lr * p.grad) wird Adam verwendet
    • Für jeden Parameter werden zwei gleitende Mittelwerte geführt:
      • m: Mittelwert der jüngsten Gradienten (Momentum)
      • v: Mittelwert der quadrierten jüngsten Gradienten (Anpassung der Lernrate pro Parameter)
    • m_hat und v_hat sind die Bias-korrigierten Varianten der bei 0 initialisierten Werte m und v
    • Die Lernrate wird während des Trainings linear abgesenkt
    • Nach dem Update wird mit .grad = 0 zurückgesetzt
  • Trainingsergebnis

    • Über 1.000 Schritte sinkt der Verlust von etwa 3.3 (zufälliges Raten unter 27 Token: −log(1/27)≈3.3) auf etwa 2.37
    • Niedriger ist besser und das Minimum ist 0 (perfekte Vorhersage), also gibt es noch Verbesserungspotenzial, aber das Modell lernt klar die statistischen Muster von Namen

Inferenz

  • Nach Abschluss des Trainings können mit dem Modell neue Namen gesampelt werden; bei fixierten Parametern wird der Forward-Pass in einer Schleife ausgeführt, und jedes erzeugte Token wird als nächste Eingabe zurückgeführt
  • Sampling-Prozess

    • Jedes Sample beginnt mit einem BOS-Token („neuen Namen beginnen“)
    • Das Modell erzeugt 27 Logits → Umwandlung in Wahrscheinlichkeiten → zufälliges Sampling eines Tokens entsprechend dieser Wahrscheinlichkeiten
    • Dieses Token wird als nächste Eingabe zurückgeführt; wiederholt wird, bis das Modell erneut BOS („fertig“) erzeugt oder die maximale Sequenzlänge erreicht ist
  • Temperatur (Temperature)

    • Vor softmax werden die Logits durch die Temperatur geteilt
    • Temperatur 1.0: direktes Sampling aus der vom Modell gelernten Verteilung
    • Niedrige Temperatur (z. B. 0.5): macht die Verteilung schärfer, sodass das Modell eher konservative Top-Auswahlen trifft
    • Temperatur nahe 0: wählt immer das einzelne Token mit der höchsten Wahrscheinlichkeit (greedy decoding)
    • Hohe Temperatur: macht die Verteilung flacher und die Ausgaben vielfältiger, aber weniger konsistent

Ausführung

  • Nur Python erforderlich (kein pip install, keine Abhängigkeiten): python train.py
  • Auf einem MacBook dauert es etwa 1 Minute
  • In jedem Schritt wird der Verlust ausgegeben: von ~3.3 (zufällig) auf ~2.37 fallend
  • Nach dem Training werden halluzinierte neue Namen erzeugt: „kamon“, „ann“, „karai“ usw.
  • Läuft auch in einem Google-Colab-Notebook, Fragen können an Gemini gestellt werden
  • Andere Datensätze ausprobieren, mit höherem num_steps länger trainieren, mit größerem Modell bessere Ergebnisse erzielen

Entwicklungsschritte des Codes

Datei Hinzugefügter Inhalt
train0.py Bigramm-Zähltabelle — kein neuronales Netz, keine Gradienten
train1.py MLP + manuelle Gradienten (numerisch & analytisch) + SGD
train2.py Autograd (Value-Klasse) — ersetzt manuelle Gradienten
train3.py Positions-Embeddings + Single-Head-Attention + rmsnorm + Residual
train4.py Multi-Head-Attention + Layer-Schleife — vollständige GPT-Architektur
train5.py Adam-Optimierer — das ist train.py
  • In den Revisions des Gists build_microgpt.py lassen sich alle Versionen und die Diffs zwischen den einzelnen Schritten ansehen

Unterschiede zu produktiven LLMs

  • microgpt enthält das vollständige algorithmische Wesen von GPT-Training und -Ausführung; der Unterschied zu produktiven LLMs wie ChatGPT verändert nicht den Kernalgorithmus, sondern betrifft die Dinge, die ihn im großen Maßstab funktionsfähig machen
  • Daten

    • Statt 32K kurzer Namen wird mit Billionen von Internet-Text-Token trainiert (Webseiten, Bücher, Code usw.)
    • Deduplizierung der Daten, Qualitätsfilterung und sorgfältige Mischung über verschiedene Domänen hinweg
  • Tokenizer

    • Statt einzelner Zeichen wird ein Subword-Tokenizer wie BPE (Byte Pair Encoding) verwendet
    • Häufig gemeinsam auftretende Zeichenfolgen werden zu einem einzelnen Token zusammengeführt; gängige Wörter wie "the" sind ein einzelnes Token, seltene Wörter werden in Teile zerlegt
    • Ein Vokabular von ~100K Token ist deutlich effizienter, weil pro Position mehr Inhalt gesehen wird
  • Autograd

    • Statt eines skalaren Value-Objekts in reinem Python werden Tensoren (große mehrdimensionale Zahlenarrays) verwendet, die auf GPU/TPU laufen und Milliarden von Fließkommaoperationen pro Sekunde ausführen
    • PyTorch übernimmt das Autograd für Tensoren, und CUDA-Kernel wie FlashAttention fusionieren mehrere Operationen
    • Die Mathematik ist dieselbe, nur werden viele Skalare parallel verarbeitet
  • Architektur

    • microgpt: 4.192 Parameter, ein Modell auf GPT-4-Niveau: Hunderte Milliarden
    • Insgesamt ein sehr ähnliches Transformer-Netzwerk, aber viel breiter (Einbettungsdimension 10.000+) und viel tiefer (100+ Layer)
    • Zusätzliche Lego-Block-Typen und geänderte Reihenfolge:
      • RoPE (rotary positional embeddings) — statt gelernter Positionseinbettungen
      • GQA (grouped query attention) — reduziert die Größe des KV-Cache
      • gated linear activations — statt ReLU
      • MoE-Layer (Mixture of Experts)
    • Die Kernstruktur mit Attention (Kommunikation) und MLP (Berechnung), die sich über dem Residual Stream abwechseln, bleibt weitgehend erhalten
  • Training

    • Statt eines Dokuments pro Schritt werden große Batches verwendet (Millionen Token pro Schritt), dazu Gradientenakkumulation, Mixed Precision (float16/bfloat16) und sorgfältiges Hyperparameter-Tuning
    • Für das Training von Frontier-Modellen laufen Tausende GPUs über Monate hinweg
  • Optimierung

    • microgpt: Adam + einfacher linearer Lernratenabfall
    • Im großen Maßstab ist Optimierung ein eigenes Fachgebiet: reduzierte Präzision (bfloat16, fp8), Training auf großen GPU-Clustern
    • Optimizer-Einstellungen (Lernrate, Weight Decay, Beta-Parameter, Warmup-/Decay-Schedules) müssen präzise abgestimmt werden; die richtigen Werte hängen von Modellgröße, Batch-Größe und Datensatz-Zusammensetzung ab
    • Scaling Laws (z. B. Chinchilla) geben vor, wie ein festes Compute-Budget zwischen Modellgröße und Anzahl der Trainingstoken aufgeteilt werden sollte
    • Werden diese Details im großen Maßstab falsch gesetzt, kann das Computing im Wert von Millionen Dollar verschwenden; Teams führen daher vor einem vollständigen Trainingslauf umfangreiche kleine Experimente durch
  • Post-Training

    • Das aus dem Training kommende Basismodell (ein „vortrainiertes“ Modell) ist ein Dokument-Vervollständiger, kein Chatbot
    • Der Weg zu ChatGPT besteht aus zwei Schritten:
      • SFT (Supervised Fine-Tuning): Dokumente werden durch kuratierte Gespräche ersetzt und das Training fortgesetzt, ohne algorithmische Änderung
      • RL (Reinforcement Learning): Das Modell erzeugt eine Antwort → es wird eine Bewertung vergeben (Menschen, „Judge“-Modelle, Algorithmen) → aus dem Feedback wird gelernt
    • Grundsätzlich wird immer noch auf Dokumenten trainiert, aber nun bestehen die Dokumente aus vom Modell selbst erzeugten Token
  • Inferenz

    • Um das Modell an Millionen Nutzer auszuliefern, ist ein eigener Engineering-Stack nötig: Request-Batching, Verwaltung und Paging des KV-Cache (z. B. vLLM), spekulatives Decoding für Geschwindigkeit, Quantisierung zur Speicherreduktion (Ausführung in int8/int4), Verteilung des Modells über mehrere GPUs
    • Im Kern wird weiterhin das nächste Token einer Sequenz vorhergesagt, aber es fließt viel Aufwand in das Engineering, um das schneller zu machen

FAQ

  • Versteht das Modell etwas wirklich?

    • Eine philosophische Frage, aber mechanisch betrachtet: Es geschieht nichts Magisches
    • Das Modell ist eine große mathematische Funktion, die Eingabetoken auf eine Wahrscheinlichkeitsverteilung für das nächste Token abbildet
    • Während des Trainings werden die Parameter so angepasst, dass das korrekte nächste Token wahrscheinlicher wird
    • Ob das „Verstehen“ darstellt, ist Ansichtssache, aber der Mechanismus steckt vollständig in diesen 200 Zeilen
  • Warum funktioniert das?

    • Das Modell hat Tausende anpassbare Parameter, und der Optimizer verschiebt sie bei jedem Schritt ein wenig so, dass der Loss sinkt
    • Über viele Schritte stabilisieren sich die Parameter auf Werten, die statistische Regelmäßigkeiten in den Daten erfassen
    • Bei Namen etwa: Sie beginnen oft mit einem Konsonanten, „qu“ tritt häufig zusammen auf, drei Konsonanten in Folge sind selten usw.
    • Das Modell lernt keine expliziten Regeln, sondern eine Wahrscheinlichkeitsverteilung, die dies widerspiegelt
  • Was hat das mit ChatGPT zu tun?

    • ChatGPT skaliert genau diese gleiche Kernschleife (Vorhersage des nächsten Tokens, Sampling, Wiederholen) massiv hoch und ergänzt Post-Training, um sie dialogfähig zu machen
    • Beim Chatten sind System-Prompt, Nutzernachricht und Antwort allesamt einfach Token einer Sequenz
    • Das Modell vervollständigt ein Dokument genauso wie microgpt Namen vervollständigt, nämlich ein Token nach dem anderen
  • Was sind „Halluzinationen“?

    • Das Modell erzeugt Token, indem es aus einer Wahrscheinlichkeitsverteilung sampelt
    • Es hat keinen Begriff von Wahrheit, sondern kennt nur Sequenzen, die im Licht der Trainingsdaten statistisch plausibel sind
    • Wenn microgpt einen Namen wie „karia“ „halluziniert“, ist das dasselbe Phänomen wie wenn ChatGPT selbstbewusst falsche Fakten nennt
    • Beides sind plausibel klingende Vervollständigungen, die nicht real sein müssen
  • Warum ist es so langsam?

    • microgpt verarbeitet in reinem Python jeweils nur ein Skalar, und ein einzelner Trainingsschritt dauert mehrere Sekunden
    • Auf GPUs läuft dieselbe Mathematik über Millionen Skalare parallel und dadurch um Größenordnungen schneller
  • Kann man es bessere Namen erzeugen lassen?

    • Ja: länger trainieren (num_steps erhöhen), das Modell größer machen (n_embd, n_layer, n_head), einen größeren Datensatz verwenden
    • Das sind dieselben Stellhebel, die auch im großen Maßstab wichtig sind
  • Was passiert, wenn man den Datensatz ändert?

    • Das Modell lernt jedes Muster, das in den Daten steckt
    • Ersetzt man ihn durch Städtenamen, Pokémon-Namen, englische Wörter oder kurze Gedichte, lernt es stattdessen, genau diese zu erzeugen
    • Der übrige Code muss nicht geändert werden

Noch keine Kommentare.

Noch keine Kommentare.