Tokenwerk · Das LLM-Lehrbuch

Kapitel 38 · VII · Bau dein LLM · 5 Minuten

Schritt 6: Text erzeugen

Dein Modell schreibt! Mit Temperatur und Top-k erzeugst du Märchen, Token für Token – und siehst, warum Greedy in Schleifen landet.

Was wir bauen

Dein Modell ist trainiert. Jetzt soll es schreiben. Die Datei generate.py lädt das gespeicherte Modell und erzeugt Text, Token für Token – mit Temperatur und Top-k aus Kapitel 24. Gut 30 Zeilen, und am Ende schreibt dein eigenes Modell Märchen.

Das Modell laden

python
# Text erzeugen: Token für Token (Kapitel 24)
import sys

import torch

from model import GPT, Config
from tokenizer import Tokenizer

tok = Tokenizer.load("data/tokenizer.json")
checkpoint = torch.load("data/model.pt")
model = GPT(Config(**checkpoint["config"]))
model.load_state_dict(checkpoint["model"])
model.eval()

Wir bauen das Modell mit denselben Einstellungen wieder auf, die train.py gespeichert hat, und laden die Gewichte hinein. model.eval() schaltet Dropout aus – beim Schreiben wollen wir keinen zusätzlichen Zufall im Modell selbst.

Token für Token schreiben

python
@torch.no_grad()

Das ist die Schleife aus Kapitel 24:

  1. Der Text beginnt mit <bos> und dem Prompt, als Token-IDs.
  2. Das Modell bekommt höchstens die letzten 128 Tokens zu sehen – sein Kontextfenster. Was davor stand, ist für diesen Schritt vergessen.
  3. Von der Ausgabe nehmen wir nur die letzte Position: [0, -1]. Die sagt das nächste Token vorher.
  4. Geteilt durch die Temperatur, dann Top-k: Nur die 40 besten Kandidaten kommen in die Lostrommel.
  5. torch.multinomial würfelt nach den Wahrscheinlichkeiten.
  6. Ist das gezogene Token <eos>, hat das Modell selbst „fertig“ gesagt – es hat im Training gelernt, wo Absätze enden. Sonst anhängen und weiter.

Die letzten Zeilen lesen den Prompt von der Kommandozeile. Ohne Prompt startet das Modell mit „Es war einmal“.

Die ganze Datei

python
# Text erzeugen: Token für Token (Kapitel 24)
import sys

import torch

from model import GPT, Config
from tokenizer import Tokenizer

tok = Tokenizer.load("data/tokenizer.json")
checkpoint = torch.load("data/model.pt")
model = GPT(Config(**checkpoint["config"]))
model.load_state_dict(checkpoint["model"])
model.eval()


@torch.no_grad()
def generate(prompt, max_tokens=150, temperature=0.8, top_k=40):
    ids = [tok.special["<bos>"]] + tok.encode(prompt)
    for _ in range(max_tokens):
        x = torch.tensor([ids[-model.cfg.context :]])          # nur das Kontextfenster
        logits = model(x)[0, -1] / temperature                  # letzte Position, Temperatur
        top = torch.topk(logits, top_k)
        probs = torch.softmax(top.values, dim=-1)               # Top-k: nur die besten würfeln
        next_id = top.indices[torch.multinomial(probs, 1)].item()
        if next_id == tok.special["<eos>"]:
            break                                               # das Modell hat „fertig“ gesagt
        ids.append(next_id)
    return tok.decode(ids)


torch.manual_seed(0)
prompt = sys.argv[1] if len(sys.argv) > 1 else "Es war einmal"
print(generate(prompt))

Ausführen

bash
python generate.py "Es war einmal ein König"
text
Es war einmal ein König und ein kleines Drechsler, und der war so schön, daß er
ein Futter mehr tragen konnte, das hatte einer von der andere näherz, aber sie
dachte, wie der er wäre, wenn es sich so viel von den Haar. Da sprach er:
»Bringt mir doch die Schwert herum, daß ich dich nicht sehen war.«

Ein ehrlicher Blick darauf:

  • Was das Modell kann: Satzbau, Kommas, wörtliche Rede in »Guillemets«, typische Märchenwörter („Da sprach er“), alte Rechtschreibung („daß“). Die meisten Wörter sind echt.
  • Was es nicht kann: einen Sinn über mehrere Sätze halten. Mal fehlt ein Artikel, mal erfindet es Wörter wie „näherz“. Mit einer Million Parametern und einem Buch als Futter ist das normal. ChatGPT hat hunderttausendmal mehr Parameter und Millionen Bücher gelesen.

Probier eigene Anfänge: „Der Wolf“, „Rotkäppchen ging“, „Die Hexe sprach“. Jeder Start gibt eine andere Geschichte.

Experimente mit der Temperatur

Ändere in generate die Temperatur und vergleiche. Mit demselben Anfang und demselben Seed kam bei mir heraus:

Einstellung Ergebnis
temperature=0.3 Es war einmal ein König und ein kleines Häuschen, der hatte eine schöne große Past, die schöne große Pastüre …
temperature=0.8 Es war einmal ein König und ein kleines Drechsler, und der war so schön, daß er …
temperature=1.5 Es war einmal ein König und sie sprach, dabei wäre ein Kind über jeden; die schönste Tochter voll Tür barten das Wasser des Waldes Zwerge …
top_k=1 (Greedy) Es war einmal ein König, der hatte ein schönes Kind, der hatte ein schönes Kind, der hatte ein schönes Kind …

Genau wie in Kapitel 24 beschrieben: Niedrige Temperatur wird vorsichtig und wiederholt sich gern. Hohe Temperatur wird wild und unsinnig. Und Greedy – immer nur das wahrscheinlichste Token – landet prompt in einer Endlosschleife. Die 0,8 ist ein guter Kompromiss.

Wenn etwas schiefgeht

  • FileNotFoundError: data/model.pt – Erst python train.py ausführen.
  • RuntimeError: Error(s) in loading state_dict – model.py wurde nach dem Training verändert. Entweder die Änderung zurücknehmen oder neu trainieren.
  • Der Text endet sofort – Das Modell hat früh <eos> gezogen. Einfach noch einmal starten oder einen längeren Anfang geben.
  • Nur Buchstabensalat – Das Training ist schiefgegangen. Liegt der beste Validierungs-Loss über 4,5? Dann zurück zu Schritt 5.

Kurz gemerkt

  • Generieren heißt: vorhersagen, würfeln, anhängen, wiederholen – bis <eos> oder zur Höchstlänge.
  • Nur die letzte Position zählt, und das Modell sieht höchstens sein Kontextfenster.
  • Temperatur und Top-k entscheiden zwischen langweilig, brauchbar und wirr. Greedy landet schnell in Schleifen.