For the complete documentation index, see llms.txt. This page is also available as Markdown.

Speichereffizientes RL

Wir freuen uns, in Unsloth effizienteres Reinforcement Learning (RL) mit mehreren algorithmischen Fortschritten vorzustellen:

  • 1,2- bis 1,7-fach längere Kontextlängen ohne Verlangsamung und ohne zusätzlichen Speicherverbrauch!

  • 10 % schnellere RL-Trainingsläufe mit überarbeiteten Kernen und asynchronen Datenbewegungen

  • 2x schneller torch.compile Mal während des Modellladens

Unsloth bereits erhöht die RL-Trainingsgeschwindigkeit, das Kontextfenster und reduziert den VRAM-Verbrauch im Vergleich zu allen anderen Setups mit FA2 um 50–90 %, aber jetzt Unsloths Standby verbessert dies noch weiter. Unsere Standby-Funktion begrenzt den Geschwindigkeitsverlust im Vergleich zu anderen Implementierungen einzigartig und macht das Training manchmal sogar schneller!

Jetzt kann Qwen3-32B LoRA 16-Bit 6.144 Kontextlängen erreichen statt zuvor 3.600 (1,7x länger) auf 1x H100 80GB GPU. Llama-3.1-8B QLoRA 4bit kann 47.500 Längen erreichen statt zuvor 42.000 (1,13x länger).

Wir haben RL-Läufe durch verschiedene Kernel-Optimierungen um 10 % schneller gemacht und den LoRA-Kommunikationskanal zwischen CPU und GPU entfernt, wenn vom Trainings- in den Inferenzmodus gewechselt wird. Schließlich haben wir benutzerdefinierte torch.compile Flags verwendet, um den vLLM-Rollout um 10 % zu beschleunigen und die Kompilierzeit um das 2-Fache zu reduzieren.

So aktivierst du Optimierungen

Um Unsloths Standby Feature die Umgebungsvariable UNSLOTH_VLLM_STANDBY vor jedem Unsloth-Import. Dann setze gpu_memory_utilization = 0.95 und das war's!

import os
os.environ["UNSLOTH_VLLM_STANDBY"] = "1"

from unsloth import FastLanguageModel
import torch
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "unsloth/Qwen3-8B-Base",
    max_seq_length = 2048, # Kann für längere Reasoning-Traces erhöht werden
    load_in_4bit = False, # False für LoRA 16bit
    fast_inference = True,
    max_lora_rank = 32, # Größere Rank = intelligenter, aber langsamer
    gpu_memory_utilization = 0.95,
)

🎓Kein weiteres gpu_memory_utilization!

Mit den neuen RL-Verbesserungen von Unsloth musst du dich NIE wieder darum sorgen, gpu_memory_utilization zu tunen oder einzustellen – setze es einfach auf 90 % oder 95 % GPU-Auslastung – 100 % funktioniert leider nicht, da etwas Platz für kleine Tensoren benötigt wird. Früher musste man es von 30 % bis 95 % anpassen – jetzt nicht mehr! Setze es auf das Maximum und Unsloth erledigt den Rest!

⁉️Warum verbraucht RL so viel Speicher?

GRPO (und viele RL-Varianten) verlassen sich stark auf Generierung, die hauptsächlich von vLLM bereitgestellt wird. Aber das hat einen hohen Preis, da es ständigen GPU-Speicher für Gewichte, Aktivierungen und den KV-Cache benötigt.

Inferenz verbraucht viel VRAM

Während das Training ebenfalls VRAM nutzt!

Das bedeutet, dass RL gleichzeitig 2 VRAM-/Speichersätze auf der GPU vorhalten muss:

  1. Inferenz-Engine (enthält Modellgewichte, KV-Cache)

  2. Trainings-Engine (enthält Modellgewichte, Aktivierungen, Gradienten, Optimizer-Zustände)

Aktuelle RL-Frameworks müssen für eine 80GB-GPU 50/50 aufteilen, mit 50 % für Inferenz und 50 % für Training. Und das Verschieben der Gewichte vom Trainingsmodus in den Inferenzmodus kann ziemlich viel Zeit in Anspruch nehmen.

80GB GPU
Inferenz-Engine (50 %)
Trainings-Engine (50 %)

Modellgewichte

16GB

16GB

KV-Cache

24GB

Aktivierungen, Gradienten, Optimizer-Zustände

24GB

Frühere Unsloth-Versionen optimieren das Obige bereits intelligent, da wir den Gewichtespeicher von vLLM direkt gemeinsam nutzen, wodurch die doppelte Speichernutzung der Modellgewichte entfällt. Dadurch werden beispielsweise 16GB Speicher frei, die zur Erhöhung der Kontextlänge oder der Generierungsgeschwindigkeit genutzt werden können. Außerdem müssen wir keine Speicherbewegungen durchführen, was das Training schneller macht.

80GB GPU
Inferenz-Engine (50 %)
Trainings-Engine (50 %)

Modellgewichte

16GB GEMEINSAM

<<< GEMEINSAM

KV-Cache

24GB + 8GB= 32GB

Aktivierungen, Gradienten, Optimizer-Zustände

24GB + 8GB=32GB

🦥Unsloth Standby

Aber wir können noch weiter gehen – zuerst stellen wir fest, dass RL Inferenz, dann Training, dann wieder Inferenz und dann wieder Training usw. durchführt.

Das bedeutet, dass der Speicherplatz für Inferenz und Training theoretisch wiederverwendet werden kann, da Inferenz und Training getrennte Modi sind – hier kommt die Sleep-Mode-Funktion von vLLM ins Spiel, die 2 Optionen hat:

  1. level = 1 kopiert Gewichte auf die CPU und löscht den KV-Cache

  2. level = 2 löscht Gewichte und löscht den KV-Cache

Aber zur Erinnerung: In Unsloth teilen wir den Speicherplatz von vLLM für die Gewichte – das bedeutet, dass wir eine neue Methode brauchen, um den KV-Cache zu löschen und die Löschung der Gewichte zu ignorieren, und wir nennen das Unsloth Standby.

80GB GPU
Inferenz-Engine
Trainings-Engine

Modellgewichte

16GB GEMEINSAM

<<< GEMEINSAM

Mehrzweck

64GB Speicher

KV-Cache

Aktivierungen, Gradienten, Optimizer-Zustände

Um dies zu aktivieren, füge einfach Folgendes vor jedem Unsloth-Import zu allen RL-/GRPO-Trainingsläufen hinzu:

🧪Leistungsexperimente

Hier erfährst du, wie wir den Speicherverbrauch und die Kontextlänge für GRPO benchmarked haben. Beachte, dass wir 2 Generierungen pro Prompt durchführen, weil GRPO nur funktioniert, wenn wir mindestens 2 Generierungen haben, für die wir Mittelwert und Varianz der Stichprobe berechnen können. Ohne 2 Generierungen ist die Standardabweichung einer Stichprobe 0. Dadurch werden die Vorteile, die dies verwenden: (Belohnung - Mittelwert)/Std nicht definiert.

Z=riμ1n(riμ)2Zn=1=r1μ11(r1μ)2=00=undefinedZ=\frac{r_i - \mu}{\sqrt{\frac{1}{n}\sum(r_i-\mu)^2}} \\ Z_{n=1}=\frac{r_1 - \mu}{\sqrt{\frac{1}{1}\sum(r_1-\mu)^2}}=\frac{0}{0}=\text{undefined}

Das bedeutet speziell für GRPO, dass eine maximale Kontextlänge von 6.144 für Qwen-3 32B tatsächlich 6.144 multipliziert mit 2 Generierungen, also 12.288 Länge, entspricht.

Wir bieten unten Experimente für Llama-3.1 8B sowohl auf LoRA (16bit) als auch auf QLoRA (4bit) an:

Falls du Unterschiede in der Trainingszeit bemerkst, sind sie nicht groß. In unserem direkten Vergleich bemerkten wir <1 % Verlangsamung der Trainingszeit oder sogar Beschleunigungen, die auf Messungenauigkeit zurückzuführen sein können.

Wir vermuten außerdem, dass Beschleunigungen durch geringeren Speicherdruck möglich sind, sodass auf Seiten des CUDA-Speicher-Allocators möglicherweise weniger Speicherbereinigung stattfindet.

Im obigen Bild siehst du den Unterschied zwischen dem Baseline- und dem Standby-Modus auf einer einzelnen T4-GPU für Qwen 3 4B. Wir können die gpu_memory_utilisation des vllm auf bis zu 0,95 erhöhen, ohne befürchten zu müssen, dass dies das Training beeinflusst. Das bedeutet, dass du längere Sequenzen mit höherer Kontextlänge unterbringen und mehr Sequenzen verarbeiten kannst. Im ersten Fall haben wir zum Beispiel genügend Speicher, um 32K-lange Sequenzen unterzubringen und zu verarbeiten, sofern das Training es zulässt, während früher alle Eingaben länger als 2K möglicherweise nicht passten und OOMs (Out of Memory) verursachten.

Experimente
Konfiguration
Status
GPU-Speichernutzung
Kommentare

Standby True

vllm_gpu_util 0,95

num_gen 2

grad_acc_steps 2

Läuft 40 Schritte / 40 Minuten

14,5 GiB (festgelegt durch vllm_gpu_util)

Reicht aus, um 32K KVCache mit Blöcken von 2-4K oder z. B. 16K KVCache + 16K-Blöcken unterzubringen

Standby True

vllm_gpu_util 0,9

num_gen 2

grad_acc_steps 2

Läuft 32 Schritte in 40 Min

13,8 GiB (festgelegt durch …)

Reicht ungefähr aus, um ~28K KVCache mit Blöcken von 2-4K oder z. B. 15K KVCache + 15K-Blöcken unterzubringen

Standby False

vllm_gpu_util 0,9

num_gen 2

grad_acc_steps 2

Modell lädt, kann aber nicht trainieren, weil nicht einmal Batch-Größe 1 passt

OOM

Standby False

vllm_gpu_util 0,8

num_gen 2

grad_acc_steps 2

Modell lädt, kann aber nicht trainieren, weil nicht einmal Batch-Größe 1 passt

OOM

Standby False

vllm_gpu_util 0,7

num_gen 2

grad_acc_steps 2

Trainiert problemlos

28 Schritte dauern 39 Min

~15,1GiB

jede etwas längere Eingabe führt auf Colab zu OOM

Standby True

vllm_gpu_util 0,7

num_gen 2

grad_acc_steps 2

Trainiert problemlos

29 Schritte dauern 40 Min

13GiB, aber meistens etwa 10-11GB

Bei derselben Konfiguration sparen wir hier 2GiB, also 15 % Speicher. Kann bei längeren Sequenzen höher sein

H100-Experimente

Modell
GPU
Seq.-Länge
Anzahl der Generierungen
Grad.-Akk.-Schritte

Qwen2.5-14B-Instruct

NVIDIA H100 80GB PCIe

32,768

8

4

In unseren aufklappbaren Ergebnissen unten siehst du, dass es einen Unterschied von 9GiB im maximal verwendeten Speicher gibt (beachte, dass die GPU-Speichernutzung in unserem Fall zu 90 % der Zeit dem Spitzenwert entspricht). Um das einzuordnen: Mit TRL und LoRA konnten wir nur ein 8B-Parametermodell mit einer Kontextlänge von maximal 1024 feinabstimmen (32x weniger). Alles mit höherer Sequenzlänge (bei ähnlicher Konfiguration) führt dazu, dass der Prozess mit OOM fehlschlägt.

Klicken für Benchmarks von Unsloth Standby Mode vs. ohne Standby

Das Bild unten zeigt, wie Standby im Vergleich zu Nicht-Standby-Training mit Unsloth abschneidet. Es wurde über 3 Läufe gemittelt, um sicherzustellen, dass die Metriken nicht verrauscht sind. Tatsächlich würdest du bei genauerem Hineinzoomen sehen, dass das Aktivieren von Standby es ebenfalls schneller macht, wahrscheinlich aufgrund des zuvor besprochenen geringeren Speicherdrucks.

Frühere A100-40GB-Experimente

In unseren früheren Experimenten auf einer A100 40GB GPU mit Qwen-2.5-3b-instruct und 8 Generierungen pro Sample stellten wir fest, dass wir ohne Standby beim GRPO-Training (Modell in 16bit geladen, LoRA, nur Gewichte trainierbar) nur Sequenzlängen von 6K unterbringen konnten. Mit unserer Standby-Funktion konnten wir 10K und mehr unterbringen! Zum Vergleich: TRL kann dir bei gleicher Batch-Größe nur Kontextlängen von bis zu 1K bieten.

🎉Weitere Optimierungen

Wir wählen jetzt bessere Kompilierungs-Flags und reduzieren die Kompilierzeiten um 50 % oder mehr. Außerdem ist es uns gelungen, jede vLLM-Version dynamisch zu patchen, um gc.collect besser zu handhaben, aus Gründen der Abwärtskompatibilität, inspiriert von diesem vLLM-Pull-Request. Dadurch verkürzt sich die Kompilierzeit von 2 Minuten auf unter 40 Sekunden.

Wir haben außerdem torch.compile Flags optimiert und versucht, einige Flags zu aktivieren – leider combo_kernels und multi_kernel konnten auf vLLM 0.10 und Torch 2.8/2.9 nightly nicht korrekt funktionieren und coordinate_descent_tuning machte das Autotuning aller Kerne dramatisch langsamer. Früher wurde in unter einer Minute kompiliert, aber das Aktivieren dauerte über 13 Minuten und mehr, bei minimalen Leistungsgewinnen.

📚GRPO-Notebooks

Alle unsere GRPO-Notebooks haben Unsloth Standby standardmäßig aktiviert und alle Optimierungen! Siehe https://docs.unsloth.ai/get-started/unsloth-notebooks für alle unsere GRPO-Notebooks, oder probiere Folgendes unten:

Zuletzt aktualisiert

War das hilfreich?