> For the complete documentation index, see [llms.txt](https://docs.clore.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clore.ai/guides/guides_v2-fr/entrainement/trl.md).

# TRL (entraînement RLHF/DPO)

**TRL** (Transformer Reinforcement Learning) est la bibliothèque officielle de HuggingFace pour entraîner des modèles de langage avec des techniques d'apprentissage par renforcement. Avec plus de 10K d'étoiles sur GitHub, elle fournit des implémentations à la pointe de la recherche de RLHF, DPO, PPO, GRPO et d'autres algorithmes d'alignement pour les LLM.

{% hint style="success" %}
Tous les exemples peuvent être exécutés sur des serveurs GPU loués via [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

***

## Qu'est-ce que TRL ?

TRL est la bibliothèque derrière bon nombre des modèles de langage les mieux alignés aujourd'hui. Elle fournit :

* **SFT (Supervised Fine-Tuning)** — réglage par instruction standard au format ChatML
* **RLHF/PPO** — Proximal Policy Optimization classique avec un modèle de récompense
* **DPO** — Direct Preference Optimization (aucun modèle de récompense nécessaire !)
* **GRPO** — Group Relative Policy Optimization (méthode de DeepSeek-R1)
* **KTO** — Kahneman-Tversky Optimization (fonctionne avec des préférences non appariées)
* **Modélisation de récompense** — entraîner un modèle de récompense à partir de données de préférences humaines
* **IterativeSFT** — RL en ligne avec une configuration plus simple
* **ORPO** — Odds Ratio Preference Optimization

TRL s'intègre nativement à l'écosystème HuggingFace : `transformers`, `peft`, `datasets`, `accelerate`, et `bitsandbytes`.

{% hint style="info" %}
**Quel algorithme devriez-vous utiliser ?**

* **DPO** — le plus simple, le plus stable. À utiliser lorsque vous disposez de données de préférence appariées (choisi/rejeté).
* **PPO** — le plus puissant mais complexe. À utiliser lorsque vous disposez d'un modèle de récompense ou d'une fonction de score.
* **GRPO** — excellent pour les tâches de raisonnement/mathématiques. Méthode d'entraînement de DeepSeek-R1.
* **SFT** — commencez toujours ici avant d'appliquer une méthode RL.
  {% endhint %}

***

## Exigences serveur

| Composant | Minimum                   | Recommandé                      |
| --------- | ------------------------- | ------------------------------- |
| GPU       | RTX 3090 (24 Go)          | A100 80 Go / H100               |
| VRAM      | 16 Go (SFT/DPO 7B + LoRA) | 80 Go (entraînement complet 7B) |
| RAM       | 32 Go                     | 64 Go+                          |
| CPU       | 8 cœurs                   | 16+ cœurs                       |
| Stockage  | 100 Go                    | 300 Go+                         |
| OS        | Ubuntu 20.04+             | Ubuntu 22.04                    |
| Python    | 3.9+                      | 3.11                            |
| CUDA      | 11.8+                     | 12.1+                           |

### VRAM par tâche

| Tâche | Modèle      | Méthode     | VRAM             |
| ----- | ----------- | ----------- | ---------------- |
| SFT   | Llama 3 8B  | QLoRA 4-bit | \~8 Go           |
| DPO   | Llama 3 8B  | LoRA        | \~20 Go          |
| PPO   | Llama 3 8B  | Complet     | \~80 Go (2×A100) |
| GRPO  | Qwen 7B     | LoRA        | \~24 Go          |
| SFT   | Llama 3 70B | QLoRA 4-bit | \~48 Go          |
| DPO   | Llama 3 70B | LoRA        | \~80 Go          |

***

## Ports

| Port | Service | Remarques                                           |
| ---- | ------- | --------------------------------------------------- |
| 22   | SSH     | Accès terminal, transfert de fichiers, surveillance |

TRL est une bibliothèque d'entraînement — elle s'exécute comme une commande CLI/script Python, aucun serveur web requis.

***

## Installation sur Clore.ai

### Étape 1 — Louer un serveur

1. Aller à [Clore.ai Marketplace](https://clore.ai/marketplace)
2. Filtrer pour **VRAM ≥ 24 Go** (RTX 3090, A100, ou H100)
3. Choisir une **PyTorch** ou **CUDA 12.1** image de base
4. Sélectionner **Stockage ≥ 200 Go** pour les modèles et les jeux de données
5. Ouvrir le port **22** pour l'accès SSH

### Étape 2 — Se connecter via SSH

```bash
ssh root@<server-ip> -p <ssh-port>
```

### Étape 3 — Installer TRL

```bash
# Créer un environnement virtuel Python
python3 -m venv /opt/trl
source /opt/trl/bin/activate

# Installer TRL avec toutes les dépendances
pip install trl

# Installer des dépendances supplémentaires pour les workflows complets
pip install \
    transformers \
    datasets \
    peft \
    accelerate \
    bitsandbytes \
    wandb \
    scipy \
    sentencepiece \
    protobuf

# Vérifier le support GPU
python3 -c "import torch; print(f'CUDA: {torch.cuda.is_available()}, GPU: {torch.cuda.get_device_name(0)}')"
```

### Étape 4 — Authentification HuggingFace

```bash
# Connexion pour accéder aux modèles protégés (Llama, Gemma)
huggingface-cli login
# Saisissez votre token HF depuis https://huggingface.co/settings/tokens

# Ou définissez une variable d'environnement
export HF_TOKEN=hf_votre-token-ici
```

### Étape 5 — Optionnel : suivi Weights & Biases

```bash
# Configurer le suivi des expériences (fortement recommandé)
pip install wandb
wandb login  # Saisissez votre clé API W&B depuis https://wandb.ai/settings

# Ou désactiver W&B
export WANDB_DISABLED=true
```

***

## Supervised Fine-Tuning (SFT)

SFT est toujours la première étape avant toute technique RL.

### Préparez votre jeu de données

```python
# Format : bibliothèque datasets avec une colonne 'messages' ou 'text'
# Format ChatML (recommandé)
from datasets import Dataset

data = [
    {
        "messages": [
            {"role": "system", "content": "Vous êtes un assistant de cloud GPU utile."},
            {"role": "user", "content": "Comment louer un GPU sur Clore.ai ?"},
            {"role": "assistant", "content": "Visitez clore.ai/marketplace, filtrez par caractéristiques GPU, sélectionnez un serveur, puis cliquez sur Louer. L'accès SSH est fourni immédiatement après le paiement."}
        ]
    },
    # ... plus d'exemples
]

dataset = Dataset.from_list(data)
dataset.save_to_disk("data/sft_dataset")
dataset.push_to_hub("votre-username/mon-sft-dataset")  # optionnel
```

### Script d'entraînement SFT

```python
# sft_train.py
from trl import SFTTrainer, SFTConfig
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
import torch

# Configuration du modèle
model_name = "meta-llama/Llama-3.2-8B-Instruct"

# QLoRA : configuration de quantification 4-bit
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

# Charger le modèle
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
)

# Charger le tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# Configuration LoRA
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

# Charger le jeu de données
dataset = load_dataset("trl-lib/ultrachat_200k", split="train_sft[:10%]")

# Configuration d'entraînement
training_config = SFTConfig(
    output_dir="./sft_output",
    num_train_epochs=3,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    warmup_ratio=0.05,
    lr_scheduler_type="cosine",
    fp16=False,
    bf16=True,
    max_seq_length=2048,
    dataset_text_field="messages",
    logging_steps=10,
    save_steps=100,
    save_total_limit=3,
    push_to_hub=False,
    report_to="wandb",  # ou "none"
)

# Initialiser le trainer
trainer = SFTTrainer(
    model=model,
    args=training_config,
    train_dataset=dataset,
    peft_config=lora_config,
    tokenizer=tokenizer,
)

# Entraîner
trainer.train()
trainer.save_model("./sft_final")
```

```bash
# Lancer l'entraînement
python3 sft_train.py
```

***

## DPO (Direct Preference Optimization)

DPO est la méthode d'alignement la plus populaire — aucun modèle de récompense nécessaire, seulement des paires de préférence.

### Préparer le jeu de données DPO

```python
# Format : chaque exemple a 'prompt', 'chosen', 'rejected'
from datasets import Dataset

data = [
    {
        "prompt": "Expliquez comment optimiser l'utilisation du GPU",
        "chosen": "Pour optimiser l'utilisation du GPU : 1) Utilisez des tailles de batch plus grandes pour maximiser l'occupation, 2) Activez la précision mixte (bf16/fp16), 3) Profilez avec nvidia-smi pour identifier les goulots d'étranglement, 4) Utilisez les streams CUDA pour les opérations parallèles.",
        "rejected": "Il suffit d'utiliser plus de GPU."
    },
    # ... plus de paires de préférence
]

dataset = Dataset.from_list(data)
```

### Script d'entraînement DPO

```python
# dpo_train.py
from trl import DPOTrainer, DPOConfig
from transformers import AutoTokenizer, AutoModelForCausalLM
from datasets import load_dataset
import torch

model_name = "./sft_final"  # Commencez à partir de votre modèle SFT !

# Charger le modèle SFT (la politique à aligner)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

# Modèle de référence (copie gelée du modèle SFT)
ref_model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# Charger le jeu de données de préférences
dataset = load_dataset("trl-lib/ultrafeedback_binarized", split="train[:5%]")

# Configuration DPO
dpo_config = DPOConfig(
    output_dir="./dpo_output",
    num_train_epochs=1,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=4,
    learning_rate=5e-7,           # Beaucoup plus bas que pour le SFT
    beta=0.1,                     # Coefficient de pénalité KL
    loss_type="sigmoid",          # Perte DPO standard
    max_length=2048,
    max_prompt_length=512,
    bf16=True,
    logging_steps=10,
    save_steps=50,
    report_to="wandb",
)

trainer = DPOTrainer(
    model=model,
    ref_model=ref_model,
    args=dpo_config,
    train_dataset=dataset,
    tokenizer=tokenizer,
)

trainer.train()
trainer.save_model("./dpo_final")
```

***

## PPO (Proximal Policy Optimization)

PPO est l'approche RLHF classique — à utiliser lorsque vous disposez d'un signal de récompense :

```python
# ppo_train.py
from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead
from transformers import AutoTokenizer, pipeline
from datasets import load_dataset
import torch

model_name = "./sft_final"

# Modèle de politique (avec tête de valeur pour PPO)
model = AutoModelForCausalLMWithValueHead.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
)

tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# Modèle de récompense (peut être toute fonction de scoring)
sentiment_pipe = pipeline(
    "sentiment-analysis",
    model="distilbert/distilbert-base-uncased-finetuned-sst-2-english",
    device=0,
)

def reward_fn(texts):
    """Noter chaque réponse. Retourner une liste de tenseurs de récompense."""
    results = sentiment_pipe(texts)
    rewards = []
    for result in results:
        score = result["score"] if result["label"] == "POSITIVE" else -result["score"]
        rewards.append(torch.tensor(score))
    return rewards

ppo_config = PPOConfig(
    output_dir="./ppo_output",
    learning_rate=1.41e-5,
    mini_batch_size=1,
    batch_size=4,
    gradient_accumulation_steps=4,
    kl_penalty="kl",
    target_kl=6.0,
    cliprange=0.2,
    vf_coef=0.1,
)

trainer = PPOTrainer(
    config=ppo_config,
    model=model,
    ref_model=None,  # Copie automatiquement le modèle initial comme référence
    tokenizer=tokenizer,
)

# Boucle d'entraînement
dataset = load_dataset("imdb", split="train[:1000]")
for epoch in range(3):
    for batch in trainer.dataloader:
        queries = batch["input_ids"]
        
        # Générer des réponses
        responses = trainer.generate(queries, max_new_tokens=100)
        
        # Noter les réponses
        texts = tokenizer.batch_decode(responses, skip_special_tokens=True)
        rewards = reward_fn(texts)
        
        # Mise à jour PPO
        stats = trainer.step(queries, responses, rewards)
        trainer.log_stats(stats, batch, rewards)
```

***

## GRPO (Group Relative Policy Optimization)

GRPO est utilisé dans DeepSeek-R1 pour l'entraînement au raisonnement :

```python
# grpo_train.py
from trl import GRPOTrainer, GRPOConfig
from transformers import AutoTokenizer, AutoModelForCausalLM
from datasets import Dataset
import re, torch

model_name = "Qwen/Qwen2.5-7B-Instruct"

model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Jeu de données de mathématiques
def make_math_dataset():
    examples = [
        {"prompt": "What is 2+2?", "answer": "4"},
        {"prompt": "What is 15 * 7?", "answer": "105"},
        # ... plus de problèmes de mathématiques
    ]
    return Dataset.from_list(examples)

dataset = make_math_dataset()

def correctness_reward(completions, answer, **kwargs):
    """Récompenser 1.0 si la réponse est correcte, 0.0 sinon."""
    rewards = []
    for completion in completions:
        # Extraire le nombre final de la complétion
        numbers = re.findall(r'\d+', completion[-1]["content"])
        if numbers and numbers[-1] == answer:
            rewards.append(1.0)
        else:
            rewards.append(0.0)
    return rewards

grpo_config = GRPOConfig(
    output_dir="./grpo_output",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    num_generations=8,       # GRPO génère G réponses par prompt
    learning_rate=5e-7,
    bf16=True,
    logging_steps=10,
)

trainer = GRPOTrainer(
    model=model,
    args=grpo_config,
    train_dataset=dataset,
    reward_funcs=correctness_reward,
    tokenizer=tokenizer,
)

trainer.train()
```

***

## Entraînement Multi-GPU

Utilisez `accelerate` pour l'entraînement distribué :

```bash
# Configurer accelerate pour le multi-GPU
accelerate config

# Exemple de configuration pour 4 GPUs :
# - compute_environment: LOCAL_MACHINE
# - distributed_type: MULTI_GPU
# - num_processes: 4
# - mixed_precision: bf16

# Lancer l'entraînement sur tous les GPUs
accelerate launch sft_train.py
accelerate launch dpo_train.py

# Ou spécifier les GPUs explicitement
CUDA_VISIBLE_DEVICES=0,1,2,3 accelerate launch \
  --num_processes 4 \
  --mixed_precision bf16 \
  sft_train.py
```

***

## Utilisation du CLI TRL

TRL fournit des commandes CLI pratiques :

```bash
# SFT via CLI
trl sft \
  --model_name_or_path meta-llama/Llama-3.2-8B-Instruct \
  --dataset_name trl-lib/ultrachat_200k \
  --dataset_text_field messages \
  --output_dir ./cli_sft_output \
  --num_train_epochs 3 \
  --per_device_train_batch_size 2 \
  --gradient_accumulation_steps 4 \
  --learning_rate 2e-4 \
  --bf16 \
  --use_peft \
  --lora_r 16 \
  --lora_alpha 32

# DPO via CLI
trl dpo \
  --model_name_or_path ./cli_sft_output \
  --dataset_name trl-lib/ultrafeedback_binarized \
  --output_dir ./cli_dpo_output \
  --num_train_epochs 1 \
  --beta 0.1 \
  --bf16
```

***

## Surveillance de l'entraînement

```bash
# Surveiller l'utilisation GPU
watch -n 1 nvidia-smi

# Surveiller la perte d'entraînement (si vous utilisez W&B)
# Ouvrez https://wandb.ai/votre-username dans le navigateur

# Vérifier le répertoire de sortie pour les checkpoints
ls -lh sft_output/checkpoint-*/

# Reprendre depuis un checkpoint
python3 sft_train.py --resume_from_checkpoint sft_output/checkpoint-500/
```

***

## Recommandations GPU Clore.ai

L'entraînement TRL est l'un des workloads les plus gourmands en VRAM. Choisissez votre GPU en fonction de la taille du modèle et de la méthode :

| Tâche                                         | GPU                | Remarques                                                                                            |
| --------------------------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------- |
| SFT / DPO sur 7–8B (QLoRA)                    | **RTX 3090** 24 Go | \~8 Go pour QLoRA 4-bit ; tient confortablement ; \~0,12 $/h sur Clore.ai                            |
| SFT / DPO sur 7–8B (LoRA bf16)                | **RTX 4090** 24 Go | Même VRAM que le 3090 mais calcul \~30 % plus rapide ; excellent pour la vitesse d'itération         |
| SFT complet sur 7B ou DPO sur 13B             | **A100 40 Go**     | 40 Go permet l'entraînement 7B en précision complète ; la mémoire ECC évite les erreurs silencieuses |
| PPO / fine-tune complet 7B, ou tout QLoRA 70B | **A100 80 Go**     | PPO nécessite 2× modèle policy+ref en VRAM ; 80 Go exécute les deux sans OOM                         |

**Conseil pratique :** Commencez sur RTX 3090 avec QLoRA pour l'expérimentation — entraînez Llama 3 8B en \~2 h sur 10K exemples. Une fois la pipeline validée, passez à A100 80GB pour les runs en précision complète ou les modèles 70B.

**Chiffres de vitesse (Llama 3 8B SFT, QLoRA, batch=4, seq=2048) :**

* RTX 3090 : \~1 100 tokens/sec en débit d'entraînement
* RTX 4090 : \~1 450 tokens/sec
* A100 80GB : \~2 800 tokens/sec (bf16 complet, sans quantification)

***

## Dépannage

### Erreur CUDA Out of Memory

```bash
# Réduire la taille du batch
per_device_train_batch_size=1
gradient_accumulation_steps=16  # Conserver la même taille de lot effective

# Utiliser la quantification 4 bits (QLoRA)
# Ajouter BitsAndBytesConfig avec load_in_4bit=True

# Activer le gradient checkpointing
gradient_checkpointing=True

# Réduire la longueur des séquences
max_seq_length=1024  # au lieu de 2048+

# Vérifier la mémoire GPU
nvidia-smi --query-gpu=memory.used,memory.total --format=csv
```

### La perte est NaN

```bash
# Cause fréquente : taux d'apprentissage trop élevé
learning_rate=1e-5  # Essayer plus bas

# Cause fréquente : mauvaises données (chaînes vides, valeurs None)
# Valider le jeu de données :
python3 -c "
from datasets import load_from_disk
ds = load_from_disk('data/sft_dataset')
print(ds[0])
print(f'Length: {len(ds)}')
# Vérifier la présence de None
none_count = sum(1 for x in ds if x.get('messages') is None)
print(f'None count: {none_count}')
"

# Activer bf16 au lieu de fp16 (plus stable)
bf16=True
fp16=False
```

### DPO : `chosen_rewards > rejected_rewards` est Faux

```bash
# Cela signifie que le modèle préfère les réponses rejetées — surapprentissage ou mauvaises données
# Solutions :
# 1. Vérifier la qualité de votre jeu de données
# 2. Réduire beta (moins de pénalité KL)
# 3. Réduire le taux d'apprentissage
# 4. Ajouter plus d'entraînement SFT avant DPO
beta=0.05  # Essayer des valeurs plus petites
```

### L'entraînement est très lent

```bash
# Activer Flash Attention 2
pip install flash-attn --no-build-isolation

# Dans votre code :
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    attn_implementation="flash_attention_2",
    torch_dtype=torch.bfloat16,
)

# Utiliser bf16 au lieu de fp16 sur les GPU Ampere+ (A100, RTX 3000+)
bf16=True

# Augmenter le nombre de workers du DataLoader
dataloader_num_workers=4

# Vérifier si le GPU est réellement utilisé
nvidia-smi  # Devrait montrer une forte utilisation du GPU
```

### `tokenizer.pad_token` avertissement

```bash
# Correction standard pour les tokenizers Llama/Mistral
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"  # Important pour la stabilité de l'entraînement
```

### Permission refusée / HuggingFace 401

```bash
# Se reconnecter
huggingface-cli login

# Définir le token dans l'environnement
export HF_TOKEN=hf_votre-token

# Pour les modèles/jeux de données privés, assurez-vous d'avoir l'accès :
# Aller sur https://huggingface.co/meta-llama/Llama-3.2-8B-Instruct
# Cliquer sur "Request access" et accepter la licence
```

***

## Sauvegarder et partager votre modèle

```bash
# Fusionner les poids LoRA dans le modèle de base
python3 << 'EOF'
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

base_model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-8B-Instruct",
    torch_dtype=torch.bfloat16,
    device_map="auto"
)
model = PeftModel.from_pretrained(base_model, "./sft_final")
merged = model.merge_and_unload()
merged.save_pretrained("./merged_model")

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-8B-Instruct")
tokenizer.save_pretrained("./merged_model")
print("Modèle fusionné enregistré !")
EOF

# Pousser vers HuggingFace
huggingface-cli upload your-username/my-trl-model ./merged_model
```

***

## Liens utiles

* **GitHub**: <https://github.com/huggingface/trl> ⭐ 10K+
* **Documentation**: <https://huggingface.co/docs/trl>
* **Article DPO**: <https://arxiv.org/abs/2305.18290>
* **GRPO / DeepSeek-R1**: <https://arxiv.org/abs/2501.12599>
* **Article PPO (RLHF)**: <https://arxiv.org/abs/2203.02155>
* **HuggingFace PEFT**: <https://github.com/huggingface/peft>
* **Weights & Biases**: <https://wandb.ai>
* **Flash Attention**: <https://github.com/Dao-AILab/flash-attention>
* **Clore.ai Marketplace**: <https://clore.ai/marketplace>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-fr/entrainement/trl.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
