Ein Reasoning-Modell, das eigenständig durch Matheaufgaben rechnet oder Code Schritt für Schritt überprüft, entsteht nicht allein durch überwachtes Finetuning. DeepSeek hat mit R1 gezeigt, dass ein Verstärkungslernen-Verfahren namens GRPO (Group Relative Policy Optimization) genau diesen Sprung schafft, und zwar ohne das separate Value-Netz, das klassisches PPO so speicherhungrig macht. Seit Hugging Face die Methode in die TRL-Bibliothek integriert hat, können Entwickler das Verfahren mit wenigen Codezeilen selbst ausprobieren. Dieses Tutorial zeigt in 12 Schritten, wie das in der Praxis funktioniert: von der Installation über die Reward-Funktion bis zum fertig trainierten Modell auf dem Hugging Face Hub.

Anders als bei LoRA-Finetuning, wie wir es im Tutorial zu Axolotl beschrieben haben, lernt das Modell bei GRPO nicht aus vorgegebenen Antwortpaaren, sondern aus eigenen Versuchen. Es generiert mehrere Antworten auf dieselbe Frage, eine Reward-Funktion bewertet jede davon, und das Modell verschiebt seine Wahrscheinlichkeiten in Richtung der besser bewerteten Gruppe. Genau dieses Prinzip steckt hinter den Reasoning-Fähigkeiten aktueller Open-Weight-Modelle.

Wer schon einmal ein Modell per LoRA oder mit klassischem supervised Finetuning angepasst hat, kennt das Grundprinzip: Man zeigt dem Modell viele Beispiele aus Eingabe und gewünschter Ausgabe, und es lernt, diese Muster nachzubilden. GRPO setzt einen Schritt später an. Es geht nicht mehr darum, bekannte Antworten zu imitieren, sondern darum, eigenständig bessere Antworten zu finden, gemessen an einem klar definierten Erfolgskriterium. Genau deshalb eignet sich das Verfahren so gut für Aufgaben, bei denen richtig und falsch objektiv unterscheidbar sind, aber schlecht für Aufgaben, bei denen es vor allem auf Stil oder Geschmack ankommt. Dieses Tutorial arbeitet mit einem kleinen, schnell trainierbaren Modell, damit sich jeder Schritt auch ohne Rechenzentrum im Hintergrund nachvollziehen lässt, zeigt aber an jeder Stelle auch, wie der Übergang zu größeren Reasoning-Modellen aussieht.

Was ist GRPO und warum brauchen Reasoning-Modelle es

GRPO wurde im DeepSeekMath-Paper eingeführt und kam anschließend beim Training von DeepSeek-R1 zum Einsatz, wie die Hugging-Face-Dokumentation zur TRL-Bibliothek bestätigt. Das Verfahren gehört zur Familie der Reinforcement-Learning-Methoden für das Post-Training von Sprachmodellen: Nach dem klassischen Pretraining und einem optionalen supervised Finetuning generiert das Modell selbst Antworten, und eine Belohnungsfunktion bewertet die Qualität dieser Antworten.

Der entscheidende Unterschied zu PPO liegt in der Berechnung des Vorteils (Advantage). PPO benötigt ein separat trainiertes Value-Modell, das abschätzt, wie gut eine Antwort im Vergleich zu einer erwarteten Baseline ist. GRPO verzichtet auf dieses Value-Netz komplett. Stattdessen generiert das Modell pro Prompt eine ganze Gruppe von Antworten (in der TRL-Standardkonfiguration acht Stück), berechnet für jede einen Reward und normalisiert die Rewards innerhalb dieser Gruppe. Eine Antwort, die besser als der Gruppendurchschnitt abschneidet, bekommt einen positiven Vorteil, eine schlechtere einen negativen. Laut Hugging Face macht diese Architektur GRPO deutlich speichereffizienter als PPO, weil kein zusätzliches Value-Netz im GPU-Speicher gehalten werden muss.

Für Reasoning-Aufgaben ist das besonders wertvoll, weil sich Zwischenschritte nur schwer einzeln bewerten lassen. Bei einer Matheaufgabe zählt am Ende vor allem, ob das Ergebnis stimmt. GRPO lässt das Modell mehrere Lösungswege ausprobieren und verstärkt die Pfade, die zum richtigen Ergebnis führen, unabhängig davon, wie der Rechenweg im Detail aussieht. Genau das beschreibt Hugging Face im offiziellen Cookbook: Die Methode eignet sich besonders gut, um Test-Time-Compute für erweitertes Reasoning zu skalieren, etwa bei komplexen mathematischen Aufgaben.

Der Grund, warum GRPO über den akademischen Kontext hinaus relevant geworden ist, liegt vor allem im Ressourcenbedarf. Klassisches PPO-basiertes RLHF verlangt neben dem zu trainierenden Modell noch ein Reward-Modell und ein Value-Modell gleichzeitig im Speicher, was besonders bei großen Sprachmodellen schnell an Hardware-Grenzen stößt. GRPO braucht nur das trainierende Modell selbst und optional ein eingefrorenes Referenzmodell für die KL-Kontrolle, das sich mit beta=0.0 sogar komplett weglassen lässt. Dieser reduzierte Speicherbedarf ist ein wesentlicher Grund, warum sich das Verfahren so schnell über DeepSeek-R1 hinaus verbreitet hat und heute fester Bestandteil vieler Trainingspipelines für Open-Weight-Reasoning-Modelle ist.

Voraussetzungen: Hardware, Software und Versionen

Bevor es losgeht, ein Überblick über die benötigten Werkzeuge. Die TRL-Bibliothek von Hugging Face liegt aktuell in Version 1.14.0 vor, veröffentlicht am 25. September 2026, mit rund 19.000 Sternen auf GitHub. Für die vollen Funktionen von GRPOTrainer inklusive der neueren Loss-Varianten verlangt die Dokumentation mindestens transformers 5.8.0, während die Grundfunktion environment_factory bereits ab transformers 5.2.0 läuft. Für dieses Tutorial nutzen wir zusätzlich die exakten Versionen, mit denen Hugging Face das offizielle Praxisbeispiel im LLM-Kurs getestet hat, damit der Code garantiert lauffähig bleibt.

PaketGetestete VersionZweck
Python3.10 oder neuerLaufzeitumgebung
trl0.14.0 (Kursbeispiel) / 1.14.0 (aktuell)GRPOTrainer, GRPOConfig
transformers4.47.1 (Basis) / ab 5.8.0 für neue FeaturesModell- und Tokenizer-Klassen
datasets3.2.0Laden von Trainingsdaten
peft0.14.0LoRA-Adapter
accelerate1.2.1Multi-GPU-Orchestrierung
bitsandbytes0.45.28-Bit-Optimizer, Quantisierung
wandb0.19.7 (optional)Trainings-Monitoring

Bei der Hardware kommt es stark auf die Modellgröße an. GRPO generiert während des Trainings mehrere vollständige Antworten pro Prompt (Rollouts), bevor überhaupt ein Gradientenschritt passiert. Das treibt den Speicherbedarf gegenüber reinem supervised Finetuning spürbar nach oben, weil Inferenz und Training gleichzeitig im Speicher liegen. Die folgende Tabelle zeigt grobe Richtwerte aus der Praxis, nicht offizielle Mindestanforderungen von Hugging Face:

ModellgrößeTrainingsmethodeRichtwert VRAMBeispiel-GPU
135M – 500MVolles Finetuning oder LoRA8–16 GBRTX 3060, Colab T4
0,5B – 1,7BLoRA16–24 GBRTX 4090, A10G
7B – 8BQLoRA + vLLM Colocate24–48 GBA100 40GB, RTX 6000 Ada
32B und größerQLoRA + vLLM Server-ModusMulti-GPU (mehrere A100/H100)DeepSpeed ZeRO-3, mehrere Knoten

Für die ersten Schritte reicht eine einzelne GPU mit 16 bis 24 GB VRAM, etwa eine A10G, wie sie auf Google Colab oder Hugging Face Spaces verfügbar ist. Ein kostenloser Hugging-Face-Account wird zusätzlich benötigt, um das trainierte Modell später auf den Hub zu laden.

GRPO im Vergleich zu PPO und DPO

Wer sich zum ersten Mal mit RL-Finetuning beschäftigt, verwechselt schnell GRPO, PPO und DPO. Alle drei gehören zum Post-Training, unterscheiden sich aber deutlich in Aufwand und Anwendungsfall.

KriteriumPPODPOGRPO
Zusätzliches Value-ModellJaNeinNein
TrainingsdatenOnline-Rollouts + Reward-ModellStatische PräferenzpaareOnline-Rollouts + Reward-Funktion(en)
Advantage-BerechnungValue-Funktion (GAE)Implizit über Log-Likelihood-VerhältnisGruppen-normalisierte Rewards
Referenzmodell (KL-Kontrolle)JaJaOptional, per Default deaktiviert (beta=0.0)
Typischer EinsatzzweckKlassisches RLHF mit gelerntem Reward-ModellPräferenz-Finetuning ohne Online-SamplingReasoning-Modelle im DeepSeek-R1-Stil

DPO trainiert direkt aus Präferenzpaaren wie “Antwort A ist besser als Antwort B”, ohne dass das Modell während des Trainings selbst generieren muss. Das macht DPO rechnerisch günstig, aber es fehlt der Online-Anteil: Das Modell lernt nur aus vorab gesammelten Paaren, nicht aus seinen aktuellen eigenen Versuchen. GRPO dagegen ist ein Online-Verfahren. Das Modell generiert während jedes Trainingsschritts frische Antworten, eine Reward-Funktion bewertet sie sofort, und genau diese Rückkopplung erlaubt es, mathematische Korrektheit, Code-Ausführbarkeit oder Formatvorgaben direkt zu belohnen, ganz ohne ein separat trainiertes Reward-Modell.

Wann klassisches PPO trotzdem die richtige Wahl bleibt

PPO ist nicht automatisch veraltet, nur weil GRPO weniger Speicher braucht. Sobald ein Team bereits ein gut kalibriertes Reward-Modell besitzt, etwa aus einem klassischen RLHF-Prozess mit menschlichem Feedback, liefert PPO oft feingranularere Belohnungssignale als eine regelbasierte Reward-Funktion. Für Aufgaben mit weichen, schwer formalisierbaren Kriterien wie Tonfall oder Hilfsbereitschaft bleibt ein gelerntes Reward-Modell häufig die robustere Grundlage, auch wenn es mehr Rechenleistung kostet.

Wann DPO die pragmatischere Alternative ist

Wer bereits über einen Datensatz mit Präferenzpaaren verfügt oder keine Infrastruktur für Online-Rollouts aufbauen will, fährt mit DPO oft schneller ans Ziel. Es entfällt die gesamte Rollout-Generierung während des Trainings, wodurch der Speicherbedarf planbarer wird und sich die Trainingszeit besser vorhersagen lässt. Der Kompromiss: DPO kann nur so gut werden wie die Qualität der vorab gesammelten Präferenzdaten, während GRPO kontinuierlich aus frischen, modellaktuellen Antworten lernt.

Schritt 1 und 2: Python-Umgebung und TRL installieren

Zuerst eine saubere virtuelle Umgebung anlegen, damit sich die GRPO-Abhängigkeiten nicht mit anderen Projekten in die Quere kommen.

python3 -m venv grpo-env
source grpo-env/bin/activate

pip install -qqq datasets==3.2.0 transformers==4.47.1 trl==0.14.0 \
    peft==0.14.0 accelerate==1.2.1 bitsandbytes==0.45.2 wandb==0.19.7 \
    --progress-bar off
pip install -qqq flash-attn --no-build-isolation --progress-bar off

Wer die neueste TRL-Version mit den zusätzlichen Loss-Varianten (dazu später mehr) nutzen möchte, installiert stattdessen die aktuelle Hauptversion direkt aus PyPI:

pip install -U "trl[vllm]"

Das Extra [vllm] installiert zusätzlich die vLLM-Integration, die für schnellere Antwortgenerierung während des Trainings sorgt. Für kleine Modelle wie in diesem Tutorial ist sie nicht zwingend, für größere Modelle ab etwa 7B Parametern beschleunigt sie den Rollout-Schritt spürbar.

Schritt 3: Installation prüfen

Kurzer Check, ob alles korrekt installiert ist und die GPU erkannt wird:

python3 -c "
import torch, trl
print('TRL Version:', trl.__version__)
print('CUDA verfuegbar:', torch.cuda.is_available())
print('GPU:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'keine GPU gefunden')
"

Erwartete Ausgabe bei einer korrekt eingerichteten Umgebung mit einer A10G-GPU:

TRL Version: 0.14.0
CUDA verfuegbar: True
GPU: NVIDIA A10G

Wer optional Weights & Biases zum Mitverfolgen des Trainings nutzen möchte, meldet sich jetzt einmalig an:

python3 -c "import wandb; wandb.login()"

Ein Account ist nicht zwingend nötig, das Training läuft auch ohne. Für die Interpretation der Reward- und Loss-Kurven später im Tutorial ist ein Dashboard aber deutlich angenehmer als reine Konsolenausgaben.

Welche Datensätze sich für GRPO eignen

Nicht jeder Datensatz, der für supervised Finetuning funktioniert, eignet sich automatisch für GRPO. Entscheidend ist, dass sich zu jedem Prompt eine Referenz oder eine Prüfregel formulieren lässt, mit der sich eine generierte Antwort automatisch bewerten lässt, ohne dass ein Mensch jede einzelne Antwort manuell durchsehen muss. Mathematische Aufgaben mit eindeutigem Zahlenergebnis, Code mit ausführbaren Testfällen oder strukturierte Formate mit festen Regeln erfüllen dieses Kriterium gut. Offene, stark subjektive Aufgaben wie kreatives Schreiben dagegen lassen sich nur schwer mit einer einfachen Reward-Funktion abdecken, weil objektive Richtig-falsch-Kriterien fehlen.

Ein zweiter Faktor ist die Schwierigkeitsstreuung im Datensatz. Sind alle Aufgaben für das Basismodell entweder viel zu leicht oder viel zu schwer, bekommt die Reward-Funktion innerhalb einer Gruppe kaum unterschiedliche Werte zu sehen, und der gruppen-normalisierte Vorteil bleibt nahe null. Ein Datensatz mit einer breiten Mischung aus leichten, mittleren und schweren Beispielen sorgt dafür, dass in jeder Gruppe von acht Generierungen tatsächlich sowohl richtige als auch falsche Antworten auftauchen, was für ein brauchbares Lernsignal notwendig ist. Für den Formattest reicht meist eine einfache Datenstruktur mit Prompt- und Referenzspalte, wie sie auch AI-MO/NuminaMath-TIR verwendet:

{
  "problem": "Loese die Gleichung 3x + 7 = 22 nach x auf.",
  "solution": "x = 5",
  "messages": [
    {"role": "user", "content": "Loese die Gleichung 3x + 7 = 22 nach x auf."}
  ]
}

Beim Zusammenstellen eigener Datensätze lohnt sich zusätzlich ein Blick auf die Verteilung der erwarteten Antwortlängen. Enthält der Datensatz überwiegend sehr kurze Referenzantworten, neigt das Modell dazu, auch bei komplexeren Prompts vorschnell abzubrechen, weil kürzere Antworten im Training häufiger belohnt wurden. Ein bewusst gemischtes Verhältnis aus kurzen und längeren Aufgaben verhindert, dass sich diese Verzerrung einschleicht.

Schritt 4 und 5: Datensatz und Basismodell laden

Als Einstiegsbeispiel eignet sich eine Aufgabe, die sich leicht objektiv bewerten lässt, damit die Reward-Funktion simpel bleibt. Wir folgen dem offiziellen Hugging-Face-Praxisbeispiel und trainieren ein Modell darauf, Kurzgeschichten in einer festen Ziellänge zusammenzufassen, mit dem Datensatz mlabonne/smoltldr.

from datasets import load_dataset

dataset = load_dataset("mlabonne/smoltldr")
print(dataset)

Als Basismodell verwenden wir HuggingFaceTB/SmolLM-135M-Instruct. Mit 135 Millionen Parametern läuft es auf praktisch jeder GPU und eignet sich damit gut, um den GRPO-Ablauf einmal komplett durchzuspielen, bevor man auf ein größeres Modell wie SmolLM2-1.7B oder Qwen2.5-0.5B-Instruct wechselt.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

model_id = "HuggingFaceTB/SmolLM-135M-Instruct"
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype="auto",
    device_map="auto",
    attn_implementation="flash_attention_2",
)
tokenizer = AutoTokenizer.from_pretrained(model_id)

Schritt 6: LoRA-Adapter für weniger VRAM-Verbrauch

Selbst bei einem kleinen Modell lohnt sich LoRA, weil GRPO durch die parallelen Rollouts ohnehin mehr Speicher braucht als ein einfaches supervised Finetuning. PEFT reduziert die Zahl der trainierbaren Parameter drastisch, ohne die Qualität des Ergebnisses spürbar zu verschlechtern.

from peft import LoraConfig, get_peft_model

lora_config = LoraConfig(
    task_type="CAUSAL_LM",
    r=16,
    lora_alpha=32,
    target_modules="all-linear",
)
model = get_peft_model(model, lora_config)
print(model.print_trainable_parameters())

Schritt 7 und 8: Reward-Funktionen schreiben

Die Reward-Funktion ist das Herzstück von GRPO. Sie entscheidet, welches Verhalten belohnt wird, und damit letztlich, was das Modell lernt. Laut TRL-Dokumentation muss eine Reward-Funktion Schlüsselwortargumente wie prompts, completions und completion_ids entgegennehmen und eine Liste von Fließkommazahlen zurückgeben, einen Wert pro generierter Antwort. Sie kann synchron oder asynchron definiert sein, und TRL erlaubt es, mehrere Reward-Funktionen gleichzeitig zu kombinieren.

Für das Zusammenfassungs-Beispiel belohnen wir Antworten, die möglichst nah an einer Ziellänge von 50 Tokens liegen:

ideal_length = 50

def reward_len(completions, **kwargs):
    return [-abs(ideal_length - len(completion)) for completion in completions]

Für echte Reasoning-Aufgaben wie Mathe-Beweise sieht die Reward-Funktion anders aus. Im offiziellen Cookbook zum GRPO-Post-Training nutzt Hugging Face den Datensatz AI-MO/NuminaMath-TIR zusammen mit der Bibliothek math_verify, um die extrahierte Antwort mit der Musterlösung zu vergleichen:

import re

def accuracy_reward(completions, ground_truth, **kwargs):
    matches = [re.search(r"\\boxed\{(.*?)\}", c) for c in completions]
    contents = [m.group(1) if m else "" for m in matches]
    return [1.0 if c == gt else 0.0 for c, gt in zip(contents, ground_truth)]

Damit das Modell überhaupt in einem auswertbaren Format antwortet, kommt bei Reasoning-Aufgaben zusätzlich ein System-Prompt zum Einsatz, der das Modell anweist, seinen Denkprozess in <think>-Tags und die Antwort in <answer>-Tags zu verpacken. Eine zweite Reward-Funktion kann dann zusätzlich prüfen, ob dieses Format eingehalten wurde, und beide Rewards lassen sich in der Trainer-Konfiguration kombinieren, etwa mit unterschiedlicher Gewichtung für Format und Korrektheit.

Eine solche Format-Reward-Funktion prüft rein strukturell, ob die erwarteten Tags vorhanden sind, unabhängig vom Inhalt:

import re

def format_reward(completions, **kwargs):
    pattern = r"^.*?.*?$"
    return [1.0 if re.match(pattern, c, re.DOTALL) else 0.0 for c in completions]

Beide Funktionen zusammen an den Trainer zu übergeben ist in TRL denkbar einfach, weil GRPOTrainer eine Liste von Reward-Funktionen akzeptiert und die Werte automatisch summiert:

trainer = GRPOTrainer(
    model=model,
    reward_funcs=[format_reward, accuracy_reward],
    args=training_args,
    train_dataset=dataset,
)

In der Praxis hat sich bewährt, den Format-Reward niedriger zu gewichten als den Korrektheits-Reward, etwa indem man ihn vor der Rückgabe mit einem Faktor von 0,2 bis 0,5 multipliziert. So lernt das Modell zuerst das Format, ohne dass es sich lohnt, ausschließlich auf Formattreue zu optimieren und die eigentliche Aufgabe zu vernachlässigen.

Schritt 9: GRPOConfig konfigurieren

GRPOConfig erbt vom bekannten TrainingArguments-Muster aus der transformers-Bibliothek, bringt aber GRPO-spezifische Parameter mit. Die wichtigsten laut aktueller TRL-Dokumentation:

ParameterStandardwertBedeutung
num_generations8Anzahl generierter Antworten pro Prompt (Gruppengröße)
max_completion_length512Maximale Länge der generierten Antwort
learning_rate1e-6Lernrate für die Policy-Updates
beta0.0KL-Divergenz-Koeffizient; 0.0 lädt kein Referenzmodell
epsilon0.2Clipping-Grenze für das Policy-Verhältnis
loss_type“dapo”Loss-Variante: grpo, dapo, dr_grpo, sapo oder vespo
scale_rewards“group”Reward-Normalisierung: group, batch oder deaktiviert

Für unser SmolLM-Beispiel reichen deutlich konservativere Werte, wie sie auch im Hugging-Face-Kurs verwendet werden:

from trl import GRPOConfig

training_args = GRPOConfig(
    output_dir="GRPO",
    learning_rate=2e-5,
    per_device_train_batch_size=8,
    gradient_accumulation_steps=2,
    max_prompt_length=512,
    max_completion_length=96,
    num_generations=8,
    optim="adamw_8bit",
    num_train_epochs=1,
    bf16=True,
    report_to=["wandb"],
    remove_unused_columns=False,
    logging_steps=1,
)

Schritt 10 und 11: Training starten und Ergebnisse interpretieren

Mit Modell, Reward-Funktion und Konfiguration lässt sich der Trainer initialisieren und das Training starten:

from trl import GRPOTrainer
import wandb

trainer = GRPOTrainer(
    model=model,
    reward_funcs=[reward_len],
    args=training_args,
    train_dataset=dataset["train"],
)

wandb.init(project="GRPO")
trainer.train()

Auf einer einzelnen A10G-GPU, wie sie auf Google Colab oder über Hugging-Face-Spaces verfügbar ist, dauert dieses Training laut Hugging Face rund eine Stunde. GRPOTrainer protokolliert dabei unter anderem den mittleren Reward und den Loss-Wert.

Ein Detail überrascht Einsteiger regelmäßig: Der Loss beginnt bei null und steigt im Trainingsverlauf an, obwohl das Modell besser wird. Das ist bei GRPO kein Fehler. Der Loss ist proportional zur KL-Divergenz gegenüber der ursprünglichen Policy. Je mehr sich das Modell in Richtung höherer Rewards bewegt, desto weiter entfernt es sich von seinem Ausgangszustand, und genau diese wachsende Abweichung zeigt sich als steigender Loss. Der Reward-Verlauf ist der aussagekräftigere Indikator: Bei der Ziellängen-Aufgabe nähert er sich mit der Zeit der Null an, weil das Modell lernt, Zusammenfassungen möglichst nah an der Zielvorgabe von 50 Tokens zu erzeugen.

Neben Reward und Loss lohnt sich ein Blick auf zwei weitere Metriken, die GRPOTrainer standardmäßig mitschreibt. Die KL-Divergenz zeigt, wie weit sich die Policy bereits vom Ausgangsmodell entfernt hat, ein plötzlicher Sprung deutet oft auf eine zu hohe Lernrate hin. Die Clip-Fraction gibt an, wie oft das Policy-Verhältnis durch epsilon begrenzt werden musste, ein dauerhaft hoher Wert spricht dafür, dass die Updates pro Schritt zu groß ausfallen und die Lernrate oder die Batchgröße angepasst werden sollte. Beide Werte lassen sich in Weights & Biases neben Reward und Loss als eigene Kurven darstellen und liefern oft den entscheidenden Hinweis, warum ein Training nicht wie erwartet konvergiert.

Beispielhafte Konsolenausgabe während des Trainings:

{'loss': 0.0, 'reward': -32.4, 'kl': 0.0, 'epoch': 0.02}
{'loss': 0.0031, 'reward': -18.7, 'kl': 0.004, 'epoch': 0.15}
{'loss': 0.0089, 'reward': -6.2,  'kl': 0.011, 'epoch': 0.48}
{'loss': 0.0142, 'reward': -1.8,  'kl': 0.017, 'epoch': 0.83}
{'loss': 0.0168, 'reward': -0.6,  'kl': 0.021, 'epoch': 1.00}

Schritt 12: Modell speichern und veröffentlichen

Nach dem Training werden die LoRA-Gewichte mit dem Basismodell zusammengeführt und lassen sich direkt auf den Hugging Face Hub hochladen:

merged_model = trainer.model.merge_and_unload()
merged_model.push_to_hub(
    "SmolGRPO-135M",
    private=False,
    tags=["GRPO", "reinforcement-learning"],
)

Ein schneller Funktionstest mit der transformers-Pipeline zeigt, ob das Modell wie gewünscht reagiert:

from transformers import pipeline

generator = pipeline("text-generation", model="SmolGRPO-135M")
output = generator(
    [{"role": "user", "content": "Fasse folgenden Text in einem Satz zusammen: ..."}],
    max_new_tokens=96,
    do_sample=True,
    temperature=0.5,
)
print(output)

Skalieren: Multi-GPU-Training mit vLLM und DeepSpeed

Sobald das Modell größer wird, reicht eine einzelne GPU nicht mehr. TRL bietet dafür zwei vLLM-Modi. Im Colocate-Modus läuft vLLM auf derselben GPU wie das Training und ist für einzelne Maschinen gedacht:

from trl import GRPOConfig

training_args = GRPOConfig(
    use_vllm=True,
    vllm_mode="colocate",
    vllm_gpu_memory_utilization=0.3,
)

Für Multi-Node-Setups läuft vLLM stattdessen als eigener Server, an den der Trainer seine Rollout-Anfragen schickt:

# Auf dem Inferenz-Knoten:
VLLM_SERVER_DEV_MODE=1 vllm serve  \
    --weight-transfer-config '{"backend": "nccl"}'

# In der Trainingskonfiguration:
training_args = GRPOConfig(
    use_vllm=True,
    vllm_mode="server",
    vllm_server_host="",
)

Für Modelle ab etwa 70 Milliarden Parametern empfiehlt die TRL-Dokumentation DeepSpeed ZeRO-3, um die Modellgewichte über mehrere Knoten zu verteilen:

accelerate launch \
    --config_file examples/accelerate_configs/deepspeed_zero3.yaml \
    --num_processes 32 \
    --num_machines 4 \
    train_grpo.py

Wichtig dabei: Die Zahl bei --num_processes muss zur tatsächlichen Anzahl an GPUs über alle Knoten hinweg passen, sonst hängt der Start, statt eine klare Fehlermeldung auszugeben. Wer schon mit LoRA-Finetuning gearbeitet hat, kennt das Prinzip von accelerate bereits, GRPO nutzt dieselbe Infrastruktur nur mit einem zusätzlichen Rollout-Schritt davor.

Bei der Wahl zwischen Colocate- und Server-Modus entscheidet meist die verfügbare Infrastruktur. Colocate eignet sich für einzelne Maschinen mit mehreren GPUs, weil Trainer und vLLM sich den Speicher auf denselben Karten teilen und keine zusätzliche Netzwerkkommunikation nötig ist. Der Server-Modus trennt Rollout-Generierung und Gradienten-Updates auf unterschiedliche Maschinen, was bei sehr großen Modellen den Durchsatz erhöht, aber zusätzliche Netzwerklatenz und einen separaten Betriebsaufwand für den vLLM-Server mit sich bringt. Für die ersten Experimente mit eigenen Reward-Funktionen ist der Colocate-Modus fast immer der einfachere Einstieg, der Wechsel zum Server-Modus lohnt sich erst, wenn die Modellgröße oder der Datensatzumfang deutlich wachsen.

Vorher-Nachher: So verändert sich das Antwortverhalten

Um zu sehen, ob GRPO tatsächlich etwas bewirkt, lohnt sich ein direkter Vergleich derselben Eingabe vor und nach dem Training. Beim Ziellängen-Beispiel aus diesem Tutorial sieht das typischerweise so aus:

Prompt: "Fasse die folgende Kurzgeschichte zusammen."

Vor dem Training (Basismodell, 187 Tokens):
"Die Geschichte handelt von einem Mann, der eines Tages beschliesst,
seine gewohnte Umgebung zu verlassen und eine lange Reise anzutreten,
bei der er zahlreiche Herausforderungen meistert und am Ende zu neuen
Erkenntnissen ueber sich selbst gelangt, wobei besonders die Begegnungen
mit anderen Charakteren eine wichtige Rolle spielen und die Handlung
in mehreren Wendungen..."

Nach 1 Epoche GRPO-Training (52 Tokens):
"Ein Mann verlaesst sein gewohntes Leben fuer eine Reise voller
Herausforderungen und gewinnt dabei neue Erkenntnisse ueber sich
selbst, vor allem durch die Begegnungen unterwegs."

Die zweite Antwort liegt mit 52 Tokens deutlich näher an der Zielvorgabe von 50 Tokens als die 187 Tokens lange Ausgangsantwort. Bei einer Reasoning-Aufgabe mit Accuracy-Reward zeigt sich der Effekt anders: Die Antwortlänge bleibt ähnlich, aber der Anteil an Antworten, deren \boxed{}-Ergebnis mit der Musterlösung übereinstimmt, steigt über die Trainingsschritte an. Genau diesen Anteil sollte man während des Trainings separat mitloggen, zusätzlich zum rohen Reward-Mittelwert, weil er sich direkter interpretieren lässt.

Fünf häufige Fehler beim GRPO-Finetuning

Die folgenden Fehler tauchen in Support-Foren und GitHub-Issues rund um GRPOTrainer besonders häufig auf. Die meisten davon lassen sich vermeiden, wenn man sie einmal kennt, kosten aber ohne Vorwarnung schnell einen ganzen Nachmittag Fehlersuche.

  • Reward-Funktion ohne Varianz: Gibt die Funktion für jede Antwort in einer Gruppe denselben Wert zurück, ist der gruppen-normalisierte Vorteil überall null. Das Modell bekommt kein Lernsignal, obwohl das Training scheinbar normal läuft.
  • Zu wenige Generierungen pro Prompt: Bei niedrigem num_generations schwankt die Gruppen-Normalisierung stark. Zwei oder vier Samples liefern oft zu verrauschte Vorteile, acht bis 16 sind in der Praxis stabiler, kosten aber mehr Rechenzeit.
  • Fehlendes Antwortformat: Ohne passenden System-Prompt produziert das Modell bei Reasoning-Aufgaben keine auswertbaren <think>– oder \boxed{}-Strukturen. Die Reward-Funktion findet dann nichts zu bewerten und gibt durchgehend null zurück.
  • Reward Hacking: Eine zu simple Reward-Funktion lässt sich austricksen. Eine reine Längenbelohnung etwa kann dazu führen, dass das Modell sinnlose Füllwörter produziert, nur um die Zielzahl an Tokens zu erreichen, statt inhaltlich zu antworten.
  • VRAM unterschätzt: Wer die Speicherplanung wie bei supervised Finetuning macht, wird während der Rollout-Generierung von Out-of-Memory-Fehlern überrascht, weil GRPO Inferenz und Training gleichzeitig im Speicher hält.

Die meisten dieser Fehler fallen nicht sofort beim Start auf, sondern erst nach mehreren hundert Trainingsschritten, wenn der Reward-Verlauf stagniert oder sich unerwartet verhält. Deshalb lohnt es sich, in den ersten Läufen bewusst kleine Zwischenschritte zu loggen und stichprobenartig einzelne generierte Antworten manuell zu lesen, statt sich ausschließlich auf die aggregierten Metriken im Dashboard zu verlassen.

Troubleshooting: Acht Probleme und ihre Lösungen

Die folgende Tabelle sammelt die Probleme, die in Diskussionen rund um GRPOTrainer am häufigsten gemeldet werden, zusammen mit der wahrscheinlichsten Ursache und einem konkreten ersten Lösungsschritt. Bei komplexeren Fällen hilft es fast immer, das Training zunächst mit einem winzigen Datensatz-Ausschnitt und wenigen Trainingsschritten laufen zu lassen, um die Fehlerquelle einzugrenzen, bevor man den vollen Lauf erneut startet.

ProblemWahrscheinliche UrsacheLösung
CUDA out of memory während der GenerierungZu viele parallele Rollouts für die verfügbare GPUnum_generations oder per_device_train_batch_size senken, vllm_gpu_memory_utilization reduzieren
Reward bleibt konstant bei 0Regex/Parser findet das erwartete Format nichtEinzelne completions manuell ausgeben und gegen die Reward-Funktion testen, System-Prompt prüfen
Loss wird NaNLernrate zu hoch oder Rewards extrem unskaliertlearning_rate senken, scale_rewards=”group” aktiv lassen, Gradient Clipping prüfen
vLLM-Server nicht erreichbarFalscher Host/Port oder Server noch nicht gestartetvllm_server_host und Firewall-Regeln prüfen, Server-Logs kontrollieren
Training extrem langsamRollout-Generierung ohne vLLM oder Server-Modus bei Single-Node-Setupvllm_mode=”colocate” für Einzelmaschinen nutzen, flash-attention aktivieren
Modell verbessert sich nichtZu wenig Gruppenvarianz oder beta zu hoch eingestelltnum_generations erhöhen, beta schrittweise senken, Reward-Verteilung loggen
ImportError bei math_verifyPaket für Reasoning-Reward nicht installiertpip install math_verify nachholen
Multi-GPU-Start hängtaccelerate-Konfiguration passt nicht zur tatsächlichen GPU-Zahl–num_processes und –num_machines exakt auf die Cluster-Topologie abstimmen

Fortgeschrittene Tipps für den produktiven Einsatz

Wer über das erste Testmodell hinauswill, findet in der aktuellen TRL-Version mehrere Stellschrauben, die im Standard-Tutorial selten auftauchen. Die loss_type-Option akzeptiert neben dem klassischen grpo-Loss auch dapo, dr_grpo, sapo und vespo. Diese Varianten unterscheiden sich in der Art, wie sie mit sehr langen oder sehr kurzen Antworten umgehen, und lohnen einen Vergleich, sobald die Standardkonfiguration an ihre Grenzen stößt.

Mehrere Reward-Funktionen gleichzeitig zu kombinieren ist in der Praxis fast immer sinnvoller als eine einzelne. Für Reasoning-Modelle bietet sich eine Gewichtung aus Format-Reward (hält sich das Modell an die vorgegebene Struktur), Korrektheits-Reward (stimmt das Endergebnis) und optional einem Längenstrafe-Term, um endlose Grübel-Schleifen zu verhindern. Der Parameter scale_rewards steuert dabei, ob die Normalisierung pro Gruppe oder über den gesamten Batch erfolgt, wobei eine Batch-weite Standardabweichung bei stark schwankender Aufgabenschwierigkeit robustere Gradienten liefert.

Der Parameter entropy_coef samt der Option use_adaptive_entropy hilft gegen ein häufiges Spätsymptom: Das Modell konvergiert zu früh auf eine einzige Antwortstrategie und hört auf, innerhalb einer Gruppe unterschiedliche Lösungswege auszuprobieren. Eine leichte Entropie-Regularisierung hält die Exploration länger aufrecht. Wer Reward Hacking frühzeitig erkennen will, sollte die Reward-Verteilung über die Zeit in Weights & Biases beobachten, nicht nur den Mittelwert. Ein plötzlicher Sprung bei gleichzeitig sinkender inhaltlicher Qualität ist meist ein Hinweis darauf, dass das Modell eine Lücke in der Reward-Funktion gefunden hat.

Für Produktionsmodelle lohnt sich außerdem ein Curriculum-Ansatz: erst mit leichteren Aufgaben starten, bei denen das Modell schnell positive Rewards erzielt, und die Schwierigkeit erst steigern, wenn die Erfolgsquote über einen Schwellenwert steigt. Das verhindert, dass das Modell am Anfang ausschließlich negative Rewards sieht und keine brauchbaren Gradienten bekommt.

Asynchrone Reward-Funktionen lohnen sich, sobald die Bewertung selbst Zeit kostet, etwa wenn ein Reward-Schritt Code tatsächlich in einer Sandbox ausführt oder eine externe API abfragt. TRL unterstützt async-def-Reward-Funktionen nativ, wodurch mehrere Bewertungen parallel laufen können, statt die GPU während der Wartezeit auf eine einzelne Antwort ungenutzt zu lassen. Bei Code-Reasoning-Aufgaben ist das fast immer der Fall: Der Reward ergibt sich erst, nachdem generierter Code in einer isolierten Umgebung ausgeführt und gegen Testfälle geprüft wurde, was deutlich länger dauert als ein einfacher String-Vergleich.

Ein oft übersehener Hebel ist die Wahl des Basismodells. GRPO verstärkt vorhandene Fähigkeiten, erschafft aber keine völlig neuen. Ein Basismodell, das grundsätzlich nie korrekte Zwischenschritte produziert, liefert der Reward-Funktion kaum positive Beispiele zum Verstärken, wodurch das Training ins Leere läuft. In der Praxis funktioniert GRPO deshalb am zuverlässigsten auf einem Modell, das die Zielaufgabe bereits gelegentlich löst, sei es durch Pretraining-Wissen oder ein vorheriges supervised Finetuning, und dessen Erfolgsquote GRPO dann systematisch erhöht.

Das komplette Projekt als Referenz

Zur Übersicht noch einmal der vollständige Trainingscode in einer Datei, der alle bisherigen Schritte zusammenführt und sich direkt ausführen lässt:

import torch
import wandb
from datasets import load_dataset
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, AutoTokenizer
from trl import GRPOConfig, GRPOTrainer

# 1) Datensatz laden
dataset = load_dataset("mlabonne/smoltldr")

# 2) Basismodell laden
model_id = "HuggingFaceTB/SmolLM-135M-Instruct"
model = AutoModelForCausalLM.from_pretrained(
    model_id, torch_dtype="auto", device_map="auto",
    attn_implementation="flash_attention_2",
)
tokenizer = AutoTokenizer.from_pretrained(model_id)

# 3) LoRA anwenden
lora_config = LoraConfig(
    task_type="CAUSAL_LM", r=16, lora_alpha=32, target_modules="all-linear",
)
model = get_peft_model(model, lora_config)

# 4) Reward-Funktion
ideal_length = 50
def reward_len(completions, **kwargs):
    return [-abs(ideal_length - len(c)) for c in completions]

# 5) Trainingskonfiguration
training_args = GRPOConfig(
    output_dir="GRPO",
    learning_rate=2e-5,
    per_device_train_batch_size=8,
    gradient_accumulation_steps=2,
    max_prompt_length=512,
    max_completion_length=96,
    num_generations=8,
    optim="adamw_8bit",
    num_train_epochs=1,
    bf16=True,
    report_to=["wandb"],
    remove_unused_columns=False,
    logging_steps=1,
)

# 6) Trainer starten
trainer = GRPOTrainer(
    model=model,
    reward_funcs=[reward_len],
    args=training_args,
    train_dataset=dataset["train"],
)

wandb.init(project="GRPO")
trainer.train()

# 7) Modell speichern und hochladen
merged_model = trainer.model.merge_and_unload()
merged_model.push_to_hub("SmolGRPO-135M", private=False, tags=["GRPO"])

Dieses Skript ist bewusst klein gehalten, damit es sich in unter einer Stunde auf einer einzelnen A10G-GPU durchtrainieren lässt. Für Reasoning-Aufgaben ersetzt man Datensatz und Reward-Funktion durch die in Schritt 8 gezeigte accuracy_reward-Variante mit dem NuminaMath-TIR-Datensatz und behält die restliche Struktur bei. Wer den kompletten DeepSeek-R1-Trainingsprozess nachvollziehen möchte, findet im Open-R1-Projekt von Hugging Face eine deutlich umfangreichere Referenzimplementierung.

Bevor ein GRPO-trainiertes Modell in eine Anwendung übernommen wird, lohnt sich ein letzter Schritt, der im Code selbst nicht sichtbar ist: die Evaluation auf einem Testset, das während des Trainings nie verwendet wurde. Weil GRPO das Modell gezielt auf die Reward-Funktion optimiert, kann ein Modell auf den Trainingsdaten hervorragend abschneiden und trotzdem auf neuen, leicht anders formulierten Aufgaben schwächer werden. Ein sauber getrenntes Testset, idealerweise mit Aufgaben aus einer anderen Quelle als die Trainingsdaten, zeigt zuverlässiger, ob das Modell tatsächlich generalisiert hat oder nur die spezifischen Muster der Trainingsverteilung gelernt hat.

Wie GRPO-Finetuning sich in bestehende Workflows einfügt

GRPO ersetzt kein supervised Finetuning, sondern baut typischerweise darauf auf. Ein üblicher Ablauf beginnt mit einem instruction-getunten Basismodell, wie es viele Teams bereits mit LoRA oder über Frameworks wie Unsloth erstellt haben. Erst danach folgt die GRPO-Phase, um gezielt Reasoning-Fähigkeiten zu verstärken. Wer die trainierten Modelle anschließend in einer Retrieval-Pipeline einsetzen will, kann sie direkt in eine bestehende RAG-Pipeline einhängen, und für die Qualitätskontrolle vor dem Produktivbetrieb bietet sich ein systematischer Benchmark-Aufbau an, um die Reasoning-Verbesserung objektiv zu messen statt sich auf einzelne Stichproben zu verlassen.

Wichtig ist dabei, GRPO nicht als einmaligen Schritt zu betrachten. Weil das Verfahren online aus eigenen Rollouts lernt, lässt es sich gut iterativ einsetzen: Reward-Funktion anpassen, kurz nachtrainieren, Ergebnis prüfen, erneut anpassen. Genau dieser kurze Zyklus unterscheidet GRPO von einem klassischen, einmaligen Finetuning-Lauf und macht es zu einem Werkzeug, das über die gesamte Lebensdauer eines Modells relevant bleibt.

Auch beim Rechenbudget lohnt sich eine realistische Einschätzung. Die Rollout-Phase, in der das Modell mehrere Antworten pro Prompt generiert, macht bei GRPO einen erheblichen Teil der Trainingszeit aus, oft deutlich mehr als der eigentliche Gradientenschritt. Wer die Kosten grob planen will, sollte deshalb nicht nur die reine GPU-Stundenzahl für das Training kalkulieren, sondern auch die Anzahl der Rollouts pro Beispiel einbeziehen: Ein Datensatz mit 10.000 Beispielen und acht Generierungen pro Prompt erzeugt effektiv 80.000 Modellantworten pro Epoche, bevor überhaupt ein einziges Gewicht aktualisiert wird. Diese Rechnung hilft, realistische Erwartungen an Trainingsdauer und Cloud-Kosten zu setzen, bevor der erste vollständige Lauf startet.

Häufig gestellte Fragen

Was unterscheidet GRPO grundsätzlich von klassischem PPO?
GRPO verzichtet auf das separate Value-Modell, das PPO für die Advantage-Berechnung braucht. Stattdessen generiert es pro Prompt eine Gruppe von Antworten und normalisiert die Rewards innerhalb dieser Gruppe. Das spart GPU-Speicher und Trainingskomplexität.

Brauche ich zwingend eine GPU mit 24 GB VRAM?
Nein. Für ein kleines Modell wie SmolLM-135M reicht laut Hugging Face bereits eine A10G-GPU, wie sie kostenlos über Google Colab verfügbar ist. Größere Modelle ab 7B Parametern profitieren dagegen deutlich von mehr Speicher und idealerweise vLLM.

Ist vLLM für GRPO zwingend erforderlich?
Nein, GRPOTrainer funktioniert auch ohne vLLM. Für größere Modelle beschleunigt die vLLM-Integration allerdings die Rollout-Generierung erheblich, weil sie Inferenz effizienter organisiert als die Standard-generate-Methode von transformers.

Wie lange dauert ein typisches GRPO-Training?
Das hängt stark von Modellgröße, Datensatz und Hardware ab. Das kleine SmolLM-Beispiel in diesem Tutorial läuft laut Hugging Face rund eine Stunde auf einer A10G-GPU. Größere Reasoning-Modelle mit mehreren GPUs können mehrere Tage benötigen.

Funktioniert GRPO auch außerhalb von Mathe- und Code-Aufgaben?
Ja. Jede Aufgabe, für die sich eine automatische, überprüfbare Reward-Funktion formulieren lässt, eignet sich grundsätzlich, etwa Formatvorgaben, Zusammenfassungslängen oder regelbasierte Bewertungen. Schwieriger wird es bei Aufgaben, die sich nur subjektiv beurteilen lassen, dort braucht man häufig zusätzlich ein gelerntes Reward-Modell.

Was ist der praktische Unterschied zwischen GRPO und DPO?
DPO trainiert aus statischen Präferenzpaaren, ohne dass das Modell während des Trainings selbst generieren muss. GRPO ist ein Online-Verfahren: Das Modell erzeugt laufend neue Antworten, die direkt bewertet werden. Das macht GRPO flexibler für Aufgaben mit klaren, automatisch prüfbaren Erfolgskriterien.

Muss ich Weights & Biases verwenden, um GRPO zu trainieren?
Nein, das Training funktioniert auch ohne. Ein Monitoring-Tool erleichtert aber die Fehlersuche erheblich, weil sich Reward- und Loss-Verläufe sonst nur aus Konsolenausgaben rekonstruieren lassen.

Woran erkenne ich Reward Hacking frühzeitig?
Ein plötzlicher, unerwartet schneller Anstieg des Rewards bei gleichzeitig sinkender inhaltlicher Qualität der Antworten ist ein typisches Warnsignal. Stichprobenartiges manuelles Gegenlesen der generierten completions während des Trainings deckt solche Fälle meist schneller auf als reine Metriken.