# Speichereffizientes RL

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

* **1,2- bis 1,7-fach erhöhte Kontextlängen** ohne Verlangsamung und ohne zusätzlichen Speicherverbrauch!
* **10% schnellere RL-Trainingläufe** mit überarbeiteten Kerneln 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 um 50–90% gegenüber allen anderen Setups mit FA2, aber jetzt [**Unsloths Standby**](#unsloth-standby) verbessert dies noch weiter. Unsere Standby-Funktion begrenzt einzigartig die Geschwindigkeitsverschlechterung im Vergleich zu anderen Implementierungen und macht das Training manchmal sogar schneller!

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

Wir haben RL-Läufe um 10% beschleunigt durch verschiedene Kernel-Optimierungen 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 vLLM's Rollout um 10% zu beschleunigen, und die Kompilierzeit um das 2-fache reduziert.

## :sparkles:Wie man Optimierungen aktiviert

nn.Linear **Unsloths Standby** Funktion, setzen Sie die Umgebungsvariable `UNSLOTH_VLLM_STANDBY` vor jedem Unsloth-Import. Setzen Sie dann `gpu_memory_utilization = 0.95` und das war's!

```python
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-Spuren erhöht werden
    load_in_4bit = False, # False für LoRA 16bit
    fast_inference = True,
    max_lora_rank = 32, # Größerer Rang = intelligenter, aber langsamer
    gpu_memory_utilization = 0.95,
)
```

## :mortar\_board:Nie mehr `gpu_memory_utilization`!

Mit Unsloths neuen RL-Verbesserungen müssen Sie sich NIE wieder um das Feinabstimmen oder Setzen von `gpu_memory_utilization` kümmern - setzen Sie 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 zwischen 30% und 95% abstimmen - das ist jetzt nicht mehr nötig! Setzen Sie es auf das Maximum und Unsloth kümmert sich um den Rest!

## :interrobang:Warum verwendet RL so viel Speicher?

GRPO (und viele RL-Varianten) sind stark auf Generation angewiesen, die hauptsächlich von vLLM angetrieben wird. Das hat jedoch hohe Kosten, da konstant **GPU-Speicher für Gewichte, Aktivierungen und den KV-Cache benötigt wird**.

{% columns %}
{% column %}
Inference benötigt viel VRAM

<figure><img src="https://797013937-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-7e25501083081b201d59f6000219cafa535d2b2d%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}
Während Training ebenfalls VRAM verwendet!

<figure><img src="https://797013937-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-189fd45a9e7a6fa1e98d1c9646b57bd0ec48481d%2Ffig6-2.avif?alt=media" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

Das bedeutet, RL muss gleichzeitig zwei Sätze von VRAM / Speicher auf der GPU halten:

1. Inference-Engine (hat Modellgewichte, KV-Cache)
2. Training-Engine (hat Modellgewichte, Aktivierungen, Gradienten, Optimizer-Zustände)

Aktuelle RL-Frameworks müssen 50/50 für eine 80GB GPU aufteilen, mit 50% für Inferenz und 50% für Training. Und das Verschieben von Gewichten vom Trainings- in den Inferenzmodus kann einige Zeit dauern.

<table><thead><tr><th width="251.51666259765625">80GB GPU</th><th>Inference Engine (50%)</th><th>Training Engine (50%)</th></tr></thead><tbody><tr><td>Modellgewichte</td><td>16GB</td><td>16GB</td></tr><tr><td>KV-Cache</td><td>24GB</td><td></td></tr><tr><td>Aktivierungen, Gradienten, Optimizer-Zustände</td><td></td><td>24GB</td></tr></tbody></table>

Frühere Unsloth-Versionen optimierten das Obige bereits intelligent, da wir **vLLM's Gewichtsspeicher direkt teilen, was die doppelte Speichernutzung der Modellgewichte entfernt**. Das schafft zum Beispiel 16GB Platz frei, die verwendet werden können, um die Kontextlänge oder die Generationsgeschwindigkeit zu erhöhen. Außerdem müssen wir keine Speicherbewegungen durchführen, was das Training beschleunigt.

| 80GB GPU                                      | Inference Engine (50%) | Training Engine (50%) |
| --------------------------------------------- | ---------------------- | --------------------- |
| Modellgewichte                                | **16GB GETEILT**       | **<<< GETEILT**       |
| KV-Cache                                      | 24GB + 8GB= **32GB**   |                       |
| Aktivierungen, Gradienten, Optimizer-Zustände |                        | 24GB + 8GB=**32GB**   |

## 🦥Unsloth Standby

Aber wir können noch weiter gehen - wir stellen zunächst fest, dass RL Inferenz, dann Training, dann wieder Inferenz, dann Training usw. durchführt.

<figure><img src="https://797013937-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-6e9b6a2f7381de84ed6eeb0feedc566cd443acf3%2F5b957843-eb58-4778-8b90-f25767c51495.png?alt=media" alt=""><figcaption></figcaption></figure>

Das bedeutet, der Speicherplatz für Inferenz und Training kann theoretisch wiederverwendet werden, da Inferenz und Training separate Modi sind - hier kommt [vLLM's Schlafmodus-Funktion](https://docs.vllm.ai/en/latest/features/sleep_mode.html#rlhf-weight-updates) 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 vLLM's Speicherplatz für die Gewichte - das bedeutet, wir brauchen eine neue Möglichkeit, den KV-Cache zu löschen und das Löschen der Gewichte zu ignorieren, und wir nennen das Unsloth Standby.

| 80GB GPU                                                                                                                                                        | Inference Engine | Training Engine                               |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | --------------------------------------------- |
| Modellgewichte                                                                                                                                                  | **16GB GETEILT** | **<<< GETEILT**                               |
| <p><mark style="background-color:purple;"><strong>Mehrzweck</strong></mark></p><p><mark style="background-color:purple;"><strong>64GB Platz</strong></mark></p> | KV-Cache         | Aktivierungen, Gradienten, Optimizer-Zustände |

Um dies zu aktivieren, fügen Sie einfach Folgendes zu allen RL / GRPO-Trainingsläufen hinzu, bevor Sie Unsloth importieren:

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

## 🧪Performance-Experimente

Hier erfahren Sie, wie wir die Speichernutzung und Kontextlänge für GRPO benchmarked haben. Beachten Sie, dass wir **2 Generationen pro Prompt durchführen, weil für GRPO zu funktionieren**, wir mindestens 2 Generationen benötigen, um Mittelwert und Varianz der Stichprobe zu berechnen. **Ohne 2 Generationen ist die Standardabweichung einer Stichprobe 0**. Das verursacht, dass die Vorteile, die dies verwenden: (Belohnung - Mittelwert)/Std **nicht definiert sind**.

$$
Z=\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 ist eine maximale Kontextlänge von 6.144 für Qwen-3 32B tatsächlich 6.144 multipliziert mit 2 Generationen, d. h. 12.288 in der Länge.

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

<figure><img src="https://797013937-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-2f83185e373186aa67bc2ce7d1814b2edb0f3ce6%2Foutput%20(10).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

**Wenn Sie Unterschiede in der Trainingszeit bemerken, sind sie nicht groß**. In unserem direkten Vergleich stellten wir <1% Trainingszeit-Verlangsamungen oder sogar Beschleunigungen fest, die dem Messfehler zugeschrieben werden können.

Wir vermuten außerdem, dass Beschleunigungen durch reduzierten Speicherdruck möglich sind, sodass weniger Speicherbereinigung auf der CUDA-Speicherallocator-Seite erforderlich sein könnte.

<figure><img src="https://797013937-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-db26f62f9080dba942add171880537c3f516f065%2Fgpu%20mem%20cofigure.png?alt=media" alt=""><figcaption></figcaption></figure>

Im obigen Bild sehen Sie den Unterschied zwischen Baseline- und Standby-Modus auf einer einzelnen T4-GPU für Qwen 3 4B. <mark style="background-color:green;">**Wir können vLLM's**</mark><mark style="background-color:green;">**&#x20;**</mark><mark style="background-color:green;">**`gpu_memory_utilisation`**</mark><mark style="background-color:green;">**&#x20;**</mark><mark style="background-color:green;">**auf bis zu 0,95 erhöhen, ohne zu befürchten, dass es das Training beeinträchtigt**</mark>. Das bedeutet, Sie können höhere Kontextlängen-Sequenzen unterbringen und mehr Sequenzen können verarbeitet werden. Im ersten Fall zum Beispiel haben wir genug Speicher, um 32K-Längen-Sequenzen unterzubringen und zu verarbeiten, sofern das Training dies erlaubt, wohingegen früher alle Eingaben, die länger als 2K waren, möglicherweise nicht passten und zu OOMs (Out of Memory) führten.

<table data-full-width="true"><thead><tr><th>Experimente</th><th>Konfiguration</th><th>Status</th><th>GPU-Speichernutzung</th><th>Kommentare</th></tr></thead><tbody><tr><td><ol><li><a href="https://colab.research.google.com/drive/18CssBY5C0mStnLvu2Hlt4aFLoPugRG0K?usp=sharing">u0.95gen2ga1s Qwen3_(4B)-GRPO.ipynb</a></li></ol></td><td><p><code>standby True</code></p><p><code>vllm_gpu_util 0.95</code></p><p><code>num_gen 2</code></p><p><code>grad_acc_steps 2</code></p></td><td>Läuft 40 Schritte / 40 Minuten</td><td><p>14,5 GiB (gesetzt durch vllm_gpu_util)</p><p><br></p></td><td>Genug, um in 32K KVCache mit Chunkgrößen von 2–4K zu passen oder z. B. 16K KVCache + 16K Chunks</td></tr><tr><td><ol start="2"><li><a href="https://colab.research.google.com/drive/1q0TOUychygfreI2wKpg51sqnRhs5cYnX?usp=sharing">u9ge2ga2s Qwen3_(4B)-GRPO.ipynb</a></li></ol></td><td><p><code>standby True</code></p><p><code>vllm_gpu_util 0.9</code></p><p><code>num_gen 2</code></p><p><code>grad_acc_steps 2</code></p></td><td>Läuft 32 Schritte in 40 m</td><td>13,8 GiB (gesetzt durch…)</td><td>Ungefähr genug, um in ~28K KVCache mit Chunkgrößen von 2–4K zu passen oder z. B. 15K KVCache + 15K Chunks</td></tr><tr><td><ol start="3"><li><a href="https://colab.research.google.com/drive/12Uw8y5beLzPtx11mCWCYyh9Z_PEHHdId?usp=sharing">u9ge2ga2ns Qwen3_(4B)-GRPO.ipynb</a></li></ol></td><td><p><code>standby False</code></p><p><code>vllm_gpu_util 0.9</code></p><p><code>num_gen 2</code></p><p><code>grad_acc_steps 2</code></p></td><td>Modell lädt, kann aber nicht trainieren, weil selbst Batch-Größe 1 nicht passt</td><td>OOM</td><td><br></td></tr><tr><td><ol start="4"><li><a href="https://colab.research.google.com/drive/1GwTlaP5CLsW-BcE1LqZWkz6S8VTWYdJ2?usp=sharing">u8ge2ga2ns Qwen3_(4B)-GRPO.ipynb</a></li></ol></td><td><p><code>standby False</code></p><p><code>vllm_gpu_util 0.8</code></p><p><code>num_gen 2</code></p><p><code>grad_acc_steps 2</code></p></td><td>Modell lädt, kann aber nicht trainieren, weil selbst Batch-Größe 1 nicht passt</td><td>OOM</td><td><br></td></tr><tr><td><ol start="5"><li><a href="https://colab.research.google.com/drive/1IuSUNzEBTiURK-vbTQuRDuUl0Ya2pz2t?usp=sharing">u7ge2ga2ns Qwen3_(4B)-GRPO.ipynb</a></li></ol></td><td><p><code>standby False</code></p><p><code>vllm_gpu_util 0.7</code></p><p><code>num_gen 2</code></p><p><code>grad_acc_steps 2</code></p></td><td><p>Trainiert einwandfrei</p><p>28 Schritte dauern 39min</p></td><td>~15,1GiB</td><td>jede Eingabe, die etwas länger ist, führt zu OOM auf Colab</td></tr><tr><td><ol start="6"><li><a href="https://colab.research.google.com/drive/1RY7HwpZ0luJT70OyLJ6zXKZQ2COdT9QJ?usp=sharing">u7gen2ga2s Qwen3_(4B)-GRPO.ipynb</a></li></ol></td><td><p><code>standby True</code></p><p><code>vllm_gpu_util 0.7</code></p><p><code>num_gen 2</code></p><p><code>grad_acc_steps 2</code></p></td><td><p>Trainiert einwandfrei</p><p>29 Schritte dauern 40min</p></td><td>13GiB, aber die meiste Zeit um die 10–11GB</td><td>Bei derselben Konfiguration sparen wir hier 2GiB bzw. 15% Speicher.<br>Kann bei längeren Sequenzen höher sein</td></tr></tbody></table>

### H100-Experimente

| Modell               | GPU                   | Seq-Länge | Anzahl Generationen | Grad-Acc-Schritte |
| -------------------- | --------------------- | --------- | ------------------- | ----------------- |
| Qwen2.5-14B-Instruct | NVIDIA H100 80GB PCIe | 32,768    | 8                   | 4                 |

In unseren zusammenklappbaren Ergebnissen unten sehen Sie, dass es einen Unterschied von 9GiB im verwendeten Spitzenpeicher gibt (beachten Sie, dass in 90% der Fälle die GPU-Speichernutzung in unserem Fall dem Spitzenpeicher entspricht). **Um das in Perspektive zu setzen: Mit TRL und LoRA konnten wir maximal ein 8B-Parameter-Modell mit einer Kontextlänge von 1024 feinabstimmen (32x weniger).** Alles mit höherer Sequenzlänge (bei ähnlicher Konfiguration) führt dazu, dass der Prozess mit OOM fehlschlägt.

<details>

<summary>Klicken Sie für Unsloth Standby-Modus vs. keine Standby-Benchmarks</summary>

```
Standby-Modus aktiviert:

|===========================================================================|
|                  PyTorch CUDA-Speicherübersicht, Geräte-ID 0                 |
|---------------------------------------------------------------------------|
|            CUDA OOMs: 0            |        cudaMalloc-Retrys: 0         |
|===========================================================================|
|        Metrik          | Akt. Nutzung | Spitzenutzung | Ges. Allok. | Ges. Freig. |
|---------------------------------------------------------------------------|
| Allokierter Speicher   |  32249 MiB   |  43042 MiB    | 128336 GiB  | 128305 GiB  |
|       aus großem Pool  |  31415 MiB   |  42165 MiB    | 127204 GiB  | 127173 GiB  |
|       aus kleinem Pool |    834 MiB   |   1184 MiB    |   1132 GiB  |   1131 GiB  |
|---------------------------------------------------------------------------|
| Aktiver Speicher       |  32249 MiB   |  43042 MiB    | 128336 GiB  | 128305 GiB  |
|       aus großem Pool  |  31415 MiB   |  42165 MiB    | 127204 GiB  | 127173 GiB  |
|       aus kleinem Pool |    834 MiB   |   1184 MiB    |   1132 GiB  |   1131 GiB  |
|---------------------------------------------------------------------------|
| Angeforderter Speicher |  32199 MiB   |  42987 MiB    | 128176 GiB  | 128145 GiB  |
|       aus großem Pool  |  31364 MiB   |  42110 MiB    | 127047 GiB  | 127016 GiB  |
|       aus kleinem Pool |    834 MiB   |   1184 MiB    |   1129 GiB  |   1128 GiB  |
|---------------------------------------------------------------------------|
| Reservierter GPU-Speicher |  37644 MiB |  47504 MiB    | 705806 MiB  | 668162 MiB  |
|       aus großem Pool  |  36376 MiB   |  46588 MiB    | 682818 MiB  | 646442 MiB  |
|       aus kleinem Pool |   1268 MiB   |   1284 MiB    |  22988 MiB  |  21720 MiB  |
|---------------------------------------------------------------------------|
| Nicht freigabbarer Speicher | 713142 KiB |   4633 MiB | 103206 GiB | 103205 GiB |
|       aus großem Pool  | 525312 KiB   |   4594 MiB    | 101923 GiB  | 101922 GiB  |
|       aus kleinem Pool | 187830 KiB   |    250 MiB    |   1283 GiB  |   1283 GiB  |
|---------------------------------------------------------------------------|
| Allokationen           |    3460      |    4809       |   15606 K   |   15603 K   |
|       aus großem Pool  |     395      |     563       |    2812 K   |    2811 K   |
|       aus kleinem Pool |    3065      |    4270       |   12794 K   |   12791 K   |
|---------------------------------------------------------------------------|
| Aktive Allokationen    |    3460      |    4809       |   15606 K   |   15603 K   |
|       aus großem Pool  |     395      |     563       |    2812 K   |    2811 K   |
|       aus kleinem Pool |    3065      |    4270       |   12794 K   |   12791 K   |
|---------------------------------------------------------------------------|
| Reservierte GPU-Segmente |     913    |     920       |   13260     |   12347     |
|       aus großem Pool  |     279      |     305       |    1766     |    1487     |
|       aus kleinem Pool |     634      |     642       |   11494     |   10860     |
|---------------------------------------------------------------------------|
| Nicht freigabare Allokationen |     422 |     628    |    4766 K   |    4765 K   |
|       aus großem Pool  |      66      |      92       |    1290 K   |    1289 K   |
|       aus kleinem Pool |     356      |     555       |    3476 K   |    3475 K   |
|---------------------------------------------------------------------------|
| Oversize-Allokationen  |       0      |       0       |       0     |       0     |
|---------------------------------------------------------------------------|
| Oversize-GPU-Segmente  |       0      |       0       |       0     |       0     |
|===========================================================================|


Ohne Standby:

|===========================================================================|
|                  PyTorch CUDA-Speicherübersicht, Geräte-ID 0                 |
|---------------------------------------------------------------------------|
|            CUDA OOMs: 0            |        cudaMalloc-Retrys: 0         |
|===========================================================================|
|        Metrik          | Akt. Nutzung | Spitzenutzung | Ges. Allok. | Ges. Freig. |
|---------------------------------------------------------------------------|
| Allokierter Speicher   |  32711 MiB   |  52084 MiB    | 142756 GiB  | 142724 GiB  |
|       aus großem Pool  |  31877 MiB   |  51207 MiB    | 141499 GiB  | 141467 GiB  |
|       aus kleinem Pool |    834 MiB   |   1184 MiB    |   1257 GiB  |   1256 GiB  |
|---------------------------------------------------------------------------|
| Aktiver Speicher       |  32711 MiB   |  52084 MiB    | 142756 GiB  | 142724 GiB  |
|       aus großem Pool  |  31877 MiB   |  51207 MiB    | 141499 GiB  | 141467 GiB  |
|       aus kleinem Pool |    834 MiB   |   1184 MiB    |   1257 GiB  |   1256 GiB  |
|---------------------------------------------------------------------------|
| Angeforderter Speicher |  32572 MiB   |  51658 MiB    | 141898 GiB  | 141866 GiB  |
|       aus großem Pool  |  31738 MiB   |  50780 MiB    | 140644 GiB  | 140613 GiB  |
|       aus kleinem Pool |    833 MiB   |   1184 MiB    |   1253 GiB  |   1252 GiB  |
|---------------------------------------------------------------------------|
| Reservierter GPU-Speicher |  49552 MiB |  52188 MiB    |  86354 MiB  |  36802 MiB  |
|       aus großem Pool  |  48320 MiB   |  51300 MiB    |  84740 MiB  |  36420 MiB  |
|       aus kleinem Pool |   1232 MiB   |   1232 MiB    |   1614 MiB  |    382 MiB  |
|---------------------------------------------------------------------------|
| Nicht freigabbarer Speicher |      0 B |      0 B     |      0 B    |      0 B    |
|       aus großem Pool  |      0 B     |      0 B      |      0 B    |      0 B    |
|       aus kleinem Pool |      0 B     |      0 B      |      0 B    |      0 B    |
|---------------------------------------------------------------------------|
| Allokationen           |    3460      |    4809       |   17440 K   |   17437 K   |
|       aus großem Pool  |     395      |     564       |    2742 K   |    2741 K   |
|       aus kleinem Pool |    3065      |    4270       |   14698 K   |   14695 K   |
|---------------------------------------------------------------------------|
| Aktive Allokationen    |    3460      |    4809       |   17440 K   |   17437 K   |
|       aus großem Pool  |     395      |     564       |    2742 K   |    2741 K   |
|       aus kleinem Pool |    3065      |    4270       |   14698 K   |   14695 K   |
|---------------------------------------------------------------------------|
| Reservierte GPU-Segmente |       0    |       0       |       0     |       0     |
|       aus großem Pool  |       0      |       0       |       0     |       0     |
|       aus kleinem Pool |       0      |       0       |       0     |       0     |
|---------------------------------------------------------------------------|
| Nicht freigabare Allokationen |       0 |       0    |       0     |       0     |
|       aus großem Pool  |       0      |       0       |       0     |       0     |
|       aus kleinem Pool |       0      |       0       |       0     |       0     |
|---------------------------------------------------------------------------|
| Oversize-Allokationen  |       0      |       0       |       0     |       0     |
|---------------------------------------------------------------------------|
| Oversize-GPU-Segmente  |       0      |       0       |       0     |       0     |
|===========================================================================|
```

</details>

Das Bild unten zeigt, wie Standby im Vergleich zu Training ohne Standby mit Unsloth abschneidet. Es ist über 3 Läufe gemittelt, um sicherzustellen, dass die Metriken nicht verrauscht sind. Tatsächlich würden Sie, wenn Sie nahe genug heranzoomen, sehen, dass das Aktivieren des Standby es auch schneller macht, wahrscheinlich aufgrund des geringeren Speicherdrucks, wie zuvor besprochen.

<figure><img src="https://797013937-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-2f285043ea8afa38d1082513e424662d8cd04b90%2Ftrainglobalstep.png?alt=media" alt=""><figcaption></figcaption></figure>

### Frühere A100 40GB-Experimente

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

<figure><img src="https://797013937-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-c7cd807b5d513b04f5f3a6219bfcea0fb12e442a%2Fqwen3%20gpu%20mem.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

## :tada:Weitere Optimierungen

Wir wählen jetzt bessere Kompilierungsflags aus und reduzieren die Kompilierzeiten um 50% oder mehr. Wir haben es außerdem geschafft, jede vLLM-Version dynamisch zu patchen, um `gc.collect` besser aus Gründen der Rückwärtskompatibilität zu handhaben, inspiriert von diesem [vLLM-Pull-Request](https://github.com/vllm-project/vllm/pull/21146). Das reduziert die Kompilierzeiten 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 mit vLLM 0.10 und Torch 2.8/2.9 nightly nicht korrekt funktionieren und `coordinate_descent_tuning` machte das Autotuning aller Kernel dramatisch langsamer. Früher dauerte die Kompilierung unter einer Minute, aber das Aktivieren davon dauerte über 13 Minuten und mehr, mit minimalen Leistungsgewinnen.

## :books: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 probieren Sie das Folgende:

* [**Qwen3 (4B)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen3_\(4B\)-GRPO.ipynb) **-** Advanced GRPO LoRA
* [**DeepSeek-R1-0528-Qwen3 (8B)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/DeepSeek_R1_0528_Qwen3_\(8B\)_GRPO.ipynb) (für mehrsprachige Anwendungsfälle)
* [Gemma 3 (1B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma3_\(1B\)-GRPO.ipynb)
* [Llama 3.2 (3B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Advanced_Llama3_2_\(3B\)_GRPO_LoRA.ipynb) - Advanced GRPO LoRA
* [Llama 3.1 (8B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Llama3.1_\(8B\)-GRPO.ipynb)
* [Phi-4 (14B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Phi_4_\(14B\)-GRPO.ipynb)
* [Mistral v0.3 (7B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Mistral_v0.3_\(7B\)-GRPO.ipynb)
* [Qwen2.5 (3B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2.5_\(3B\)-GRPO.ipynb)
