PT-06 — Evaluation Comparative du Post-Training

Serie : Post-Training SOTA 2024-2025 (Epic #1742) Dernier livrable de la serie Pre-requis : PT-01 a PT-05 (tous merges) Objectifs pedagogiques : 1. Synthetiser les 4 techniques de post-training etudiees (SFT, DPO, GRPO, RLVR) 2. Comparer les metriques cibles : cout compute, qualite, data requirements, complexite 3. Définir un framework de decision pour choisir la bonne technique 4. Identifier les perspectives de recherche 2025-2026 5. Proposer un pipeline post-training optimal pour différents scénarios

References cles : - Rafailov et al., “Direct Préférence Optimization” (2023) — DPO - Shao et al., “DeepSeekMath” (2024) — GRPO - Deepseek-AI, “DeepSeek-R1” (2025) — RLVR - Ouyang et al., “Training language models to follow instructions with human feedback” (InstructGPT, 2022)

1. Recap de la serie Post-Training

Au cours de cette serie (PT-01 a PT-05), nous avons etudie les techniques majeures du post-training 2024-2025 :

Notebook Technique Idee cle
PT-01 Introduction Landscape RLHF, taxonomie des approches
PT-02 SFT (LoRA) Point de depart obligatoire, fine-tuning supervise
PT-03 DPO Préférence learning sans RL, paires chosen/rejected
PT-04 GRPO RL sans critic, avantage intra-group
PT-05 RLVR GRPO avec rewards verifiables (zero bruit)

L’evolution conceptuelle

SFT (supervise)
  |
  v
DPO (préférences humaines = "qu'est-ce qui est meilleur ?")
  |
  v
GRPO (rewards = "est-ce que c'est bon ?")
  |
  v
RLVR (verifiable = "est-ce que c'est EXACT ?")

Chaque étape affine le modèle de maniere complementaire. Le pipeline optimal n’est pas une seule technique mais une combinaison.

2. Tableau comparatif des 4 techniques

2.1 Comparaison technique

Critere SFT DPO GRPO RLVR
Type d’apprentissage Supervise Préférence RL (sans critic) RL (reward exact)
Données necessaires Input-Output paires Paires chosen/rejected Prompts + reward fn Prompts + verifier
Cout compute (relatif) 1x 1.5x 2x 2x
Memoire GPU (relatif) 1x 2x (ref model) 2x (G completions) 2x (G completions)
Hyperparametres cles lr, epochs beta, lr beta, G, epsilon beta, G, lr
Reward hacking N/A Possible (biais data) Possible Impossible
Domaine optimal General Alignement style General RL Math, code, puzzles
Implementation TRL SFTTrainer DPOTrainer GRPOTrainer GRPOTrainer + verifier

2.2 Comparaison des hyperparametres

Paramètre SFT DPO GRPO RLVR
Learning rate 2e-4 5e-7 1e-5 5e-6
Beta (KL) N/A 0.1 0.04 0.04
Group size N/A N/A 4-16 4-16
Batch size 4-16 4-16 1-4 1-4
Max sequence 512 512 256-512 256-512
Epochs 3-5 1-3 1-3 1-3

2.3 Cout data

Technique Volume data min. Type Cout annotation
SFT 1K-10K Input-Output Eleve (humain)
DPO 1K-10K paires Préférences Très eleve (comparaison humaine)
GRPO 100-1K prompts + Reward function Faible (fonction a ecrire)
RLVR 100-1K prompts + Verifier exact Très faible (code déterministe)
import warnings
warnings.filterwarnings("ignore", message=".*non-interactive.*", category=UserWarning)
warnings.filterwarnings("ignore", message=".*FigureCanvasAgg.*", category=UserWarning)
import pandas as pd

# Tableau comparatif interactif
comparison_data = {
    "Technique": ["SFT", "DPO", "GRPO", "RLVR"],
    "Notebook": ["PT-02", "PT-03", "PT-04", "PT-05"],
    "Learning Rate": ["2e-4", "5e-7", "1e-5", "5e-6"],
    "Beta (KL)": ["N/A", "0.1", "0.04", "0.04"],
    "GPU Memory (relatif)": ["1x", "2x", "2x", "2x"],
    "Data Min": ["1K samples", "1K pairs", "100 prompts", "100 prompts"],
    "Reward Type": ["N/A (labels)", "N/A (pairs)", "Heuristic", "Exact (zero-noise)"],
    "TRL Class": ["SFTTrainer", "DPOTrainer", "GRPOTrainer", "GRPOTrainer + verifier"],
    "Risk Hacking": ["N/A", "Possible", "Possible", "Impossible"],
}

df = pd.DataFrame(comparison_data)
df = df.set_index("Technique")
print("Tableau Comparatif Post-Training SOTA 2024-2025")
print("=" * 80)
print(df.to_string())
print()
print(f"Total notebooks dans la serie : 6 (PT-01 a PT-06)")
print(f"Modele utilise pour les demos : Qwen3.5-0.8B")
print(f"Framework : HuggingFace TRL + PEFT (LoRA)")
Tableau Comparatif Post-Training SOTA 2024-2025
================================================================================
          Notebook Learning Rate Beta (KL) GPU Memory (relatif)     Data Min         Reward Type               TRL Class Risk Hacking
Technique                                                                                                                            
SFT          PT-02          2e-4       N/A                   1x   1K samples        N/A (labels)              SFTTrainer          N/A
DPO          PT-03          5e-7       0.1                   2x     1K pairs         N/A (pairs)              DPOTrainer     Possible
GRPO         PT-04          1e-5      0.04                   2x  100 prompts           Heuristic             GRPOTrainer     Possible
RLVR         PT-05          5e-6      0.04                   2x  100 prompts  Exact (zero-noise)  GRPOTrainer + verifier   Impossible

Total notebooks dans la serie : 6 (PT-01 a PT-06)
Modele utilise pour les demos : Qwen3.5-0.8B
Framework : HuggingFace TRL + PEFT (LoRA)

Exercice 1 : Générateur de fiche comparative personnalisee

Le tableau comparatif de la section 2 couvre les 4 techniques principales. L’objectif est d’implementer une fonction generer_fiche qui genere une fiche comparative detaillee pour une technique donnee, incluant les hyperparametres recommandes, les prerequis data, et les limites connues.

Objectif : ecrire une fonction qui prend le nom d’une technique et retourne un dictionnaire structure avec toutes les informations essentielles pour un praticien.

Indices : - # Étape 1 : Créer un dictionnaire de reference par technique avec tous les champs utiles - # Étape 2 : Implementer la fonction de lookup avec validation du nom de technique - # Indice : inclure les pieges spécifiques a chaque technique (references aux sections detaillees de PT-02 a PT-05)

def generer_fiche(technique: str) -> dict:
    # TODO etudiant : generer une fiche detaillee pour la technique
    
    # Etape 1 : dictionnaire de reference
    FICHES = {
        "SFT": {
            "description": "",
            "hyperparams": {},
            "prerequis_data": "",
            "limites": [],
        },
        # TODO etudiant : completer DPO, GRPO, RLVR
    }
    
    # Etape 2 : lookup avec validation
    fiche = None  # TODO etudiant : recuperer la fiche ou retourner erreur
    return fiche

print("Exercice a completer : fiche comparative")
Exercice a completer : fiche comparative

3. Framework de decision

Arbre de decision pour choisir la bonne technique

Question : Quel est votre objectif ?
│
├── Alignement sur un style/format spécifique
│   └── SFT (PT-02)
│
├── Correction de comportements indesirables avec données humaines
│   └── DPO (PT-03)
│
├── Optimisation d'une metric objective (general)
│   └── GRPO (PT-04)
│
└── Domaine avec reponse exacte verifiable (math, code)
    └── RLVR (PT-05)

Recommandations par scénario

Scénario Pipeline recommande Raison
Chatbot d’entreprise SFT → DPO Style spécifique + alignement préférences
Modèle mathematique SFT → RLVR Raisonnement exact, pas de subjectivite
Code assistant SFT → RLVR Exécution verifiable (tests unitaires)
Redaction creative SFT → DPO Subjective, préférences humaines necessaires
Modèle generaliste SFT → DPO → GRPO Maximum d’alignement
Reasoning emergent SFT → RLVR C’est le chemin Deepseek-R1

Quand NE PAS utiliser chaque technique

  • SFT seul : si on veut un comportement qui n’existe pas dans les données d’entrainement
  • DPO : si on n’a PAS de données de préférence humaine (couteux a annoter)
  • GRPO heuristique : si on a un domaine avec verifier exact (utiliser RLVR a la place)
  • RLVR : si le domaine n’a PAS de reponse exacte (ex : generation creative)

Arbre de decision : quelle méthode de post-entrainement ?

Le même arbre de sélection, rendu sous forme de graphe : a chaque objectif correspond la méthode adaptee (et son notebook).

flowchart TD
    Q["Quel est votre objectif ?"]
    Q --> S["Alignement sur un style / format spécifique"] --> SFT["SFT (PT-02)"]
    Q --> D["Correction de comportements indesirables (données humaines)"] --> DPO["DPO (PT-03)"]
    Q --> G["Optimisation d'une metrique objective (general)"] --> GRPO["GRPO (PT-04)"]
    Q --> R["Domaine a reponse exacte verifiable (math, code)"] --> RLVR["RLVR (PT-05)"]
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

# Simulation des couts compute relatifs (estimes pour Qwen3.5-0.8B, 1K samples, 3 epochs)
techniques = ["SFT", "DPO", "GRPO", "RLVR"]
gpu_hours = [0.5, 0.8, 1.2, 1.3]  # Heures GPU RTX 3070
memory_gb = [2.0, 3.5, 4.0, 4.0]  # Go VRAM

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))

colors = ["#2196F3", "#FF9800", "#4CAF50", "#E91E63"]

# GPU hours
bars1 = ax1.bar(techniques, gpu_hours, color=colors, alpha=0.8, edgecolor="black", linewidth=0.5)
ax1.set_ylabel("Heures GPU (RTX 3070, estim.)")
ax1.set_title("Cout Compute Relatif")
ax1.set_ylim(0, max(gpu_hours) * 1.3)
for bar, val in zip(bars1, gpu_hours):
    ax1.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.03, f"{val}h", ha="center", fontsize=10)

# Memory
bars2 = ax2.bar(techniques, memory_gb, color=colors, alpha=0.8, edgecolor="black", linewidth=0.5)
ax2.set_ylabel("VRAM requise (Go)")
ax2.set_title("Memoire GPU Relatif")
ax2.set_ylim(0, max(memory_gb) * 1.4)
for bar, val in zip(bars2, memory_gb):
    ax2.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.05, f"{val} Go", ha="center", fontsize=10)

plt.suptitle("Post-Training SOTA 2024-2025 — Cout Compute vs Memoire (Qwen3.5-0.8B, 1K samples, 3 epochs)", fontsize=11)
plt.tight_layout()
plt.savefig("pt06_cost_comparison.png", dpi=100, bbox_inches="tight")
plt.show()
print("Figure sauvegardee : pt06_cost_comparison.png")
Figure sauvegardee : pt06_cost_comparison.png

Exercice 2 : Simulateur de cout pour un projet personnalise

Les couts presentes sont des estimations pour Qwen3.5-0.8B (0.8 Md de parametres, architecture hybride 18x attention lineaire + 6x full attention). L’objectif est d’implementer une fonction simuler_cout_projet qui calcule le cout total d’un pipeline post-training complet (SFT + DPO + GRPO) en tenant compte de la taille du modèle, du nombre de samples, et du GPU disponible.

Objectif : ecrire une fonction qui retourne un rapport de cout detaille (GPU-heures par étape, VRAM requise, cout annotation, duree estimee).

Indices : - # Étape 1 : Définir les couts unitaires par technique (GPU-h/1000 samples, annotation h/1000 samples) - # Étape 2 : Calculer le cout cumulatif d’un pipeline multi-étapes - # Indice : verifier si le GPU est suffisant pour chaque étape et lever un avertissement sinon

def simuler_cout_projet(
    model_size_params_m: float = 800,  # millions de parametres (Qwen3.5-0.8B)
    n_samples: int = 1000,
    techniques: list[str] = ["SFT", "DPO"],
    gpu_vram_gb: float = 8.0,
) -> dict:
    # TODO etudiant : simuler le cout d'un projet post-training
    
    # Etape 1 : couts unitaires par technique
    COUTS = {
        "SFT":  {"gpu_h_per_1k": 0.5, "annot_h_per_1k": 40, "vram_mult": 1.0},
        "DPO":  {"gpu_h_per_1k": 0.8, "annot_h_per_1k": 120, "vram_mult": 1.4},
        "GRPO": {"gpu_h_per_1k": 1.2, "annot_h_per_1k": 120, "vram_mult": 1.8},
        "RLVR": {"gpu_h_per_1k": 1.3, "annot_h_per_1k": 0, "vram_mult": 1.6},
    }
    
    rapport = {"etapes": [], "total_gpu_h": 0, "total_annot_h": 0, "avertissements": []}
    
    for tech in techniques:
        # Etape 2 : calculer les couts par etape
        pass  # TODO etudiant : accumuler GPU-h, annotation, verifier VRAM
    
    return rapport  # TODO etudiant : retourner le rapport complet

print("Exercice a completer : simulateur de cout")
Exercice a completer : simulateur de cout
# Simulation qualitative des resultats attendus par technique
# (Estimes, pas de claim BEATS — terrain pedagogique)

results = {
    "Technique": ["Base (no FT)", "SFT", "DPO", "GRPO", "RLVR"],
    "Accuracy GSM8K (%)": [15, 35, 40, 45, 55],
    "Coherence (1-5)": [2.5, 3.5, 4.0, 3.8, 4.2],
    "Instruction Following (1-5)": [2.0, 4.0, 4.5, 4.0, 4.0],
    "Reasoning Depth (1-5)": [1.5, 2.5, 3.0, 3.5, 4.5],
    "Style Control (1-5)": [1.0, 4.5, 4.0, 3.0, 3.0],
}

df_results = pd.DataFrame(results)
df_results = df_results.set_index("Technique")
print("Resultats attendus (Qwen3.5-0.8B, estimation pedagogique)")
print("=" * 80)
print(df_results.to_string())
print()
print("Note : ces chiffres sont des ESTIMATIONS pedagogiques.")
print("Pas de claim BEATS quantitatif (sample insuffisant pour multi-seed).")
print("Pour des resultats rigoureux : voir papers de reference (DPO, GRPO, RLVR).")
Resultats attendus (Qwen3.5-0.8B, estimation pedagogique)
================================================================================
              Accuracy GSM8K (%)  Coherence (1-5)  Instruction Following (1-5)  Reasoning Depth (1-5)  Style Control (1-5)
Technique                                                                                                                 
Base (no FT)                  15              2.5                          2.0                    1.5                  1.0
SFT                           35              3.5                          4.0                    2.5                  4.5
DPO                           40              4.0                          4.5                    3.0                  4.0
GRPO                          45              3.8                          4.0                    3.5                  3.0
RLVR                          55              4.2                          4.0                    4.5                  3.0

Note : ces chiffres sont des ESTIMATIONS pedagogiques.
Pas de claim BEATS quantitatif (sample insuffisant pour multi-seed).
Pour des resultats rigoureux : voir papers de reference (DPO, GRPO, RLVR).

4. Le pipeline post-training optimal (synthese)

Le pipeline en 4 étapes (recommandation 2025)

Étape 1 : SFT (obligatoire)
  - Pourquoi : le modèle de base ne suit pas d'instructions
  - Cout : modere (1K-10K examples)
  - Gain : instruction following de base

Étape 2 : DPO (recommande si budget annotation)
  - Pourquoi : alignement fin sur les préférences humaines
  - Cout : eleve (données de préférence)
  - Gain : style, coherence, securite

Étape 3 : GRPO (optionnel, si reward function disponible)
  - Pourquoi : optimiser une metric objective
  - Cout : modere (compute + reward function)
  - Gain : performance sur la metric ciblee

Étape 4 : RLVR (si domaine verifiable)
  - Pourquoi : raisonner de maniere fiable
  - Cout : faible (vérifier = code déterministe)
  - Gain : émergence de raisonnement, accuracy math/code

Ce que Deepseek-R1 a fait differemment

Deepseek-R1 a saute l’étape DPO et est passe directement SFT → RLVR. Pourquoi ? - Pas de données de préférence humaine a grande echelle - Le reward verifiable (math) etait suffisant pour guider l’apprentissage - Résultat : émergence de chain-of-thought sans supervision humaine

Leçon : si votre domaine a un vérifier exact, DPO est optionnel. RLVR seul suffit pour le raisonnement.

5. Perspectives de recherche 2025-2026

5.1 Techniques emergentes

Technique Paper Ideee Statut
ORPO Hong et al. (2024) Merge SFT + DPO en une seule étape Production-ready
KTO Ethayarajh et al. (2024) DPO sans paires (points individuels) TRL integre
NCA Chen et al. (2024) Noise Contrastive Alignment Experimental
RLOO Ahmadian et al. (2024) Leave-one-out baseline pour REINFORCE TRL integre
Online DPO Guo et al. (2024) DPO avec generation en ligne Actif
Self-play RL Meta (2025) Le modèle genere ses propres préférences Recherche

5.2 Tendances cles

  1. Elimination du reward model : DPO, GRPO, RLVR suppriment le besoin d’entrainer un RM separe. Tendance qui s’accelere.

  2. Process reward > Outcome reward : verifier chaque étape du raisonnement (pas seulement la reponse finale). Plus précis, mais plus complexe.

  3. Scaling laws du RL : le compute RL est de plus en plus efficace. Deepseek-R1 a montre que RL pur > SFT+RL sur le raisonnement.

  4. Constitutional AI : le modèle apprend de ses propres outputs via des principles (Anthropic). Evolue vers self-alignment.

  5. Multimodal post-training : etendre SFT/DPO/GRPO aux modèles vision, audio, video. Challenge : définir des rewards verifiables pour ces domaines.

5.3 Questions ouvertes

  • RLVR generalise : peut-on définir des verifiers pour des domaines non-mathematiques (creation, argumentation) ?
  • Emergence vs scale : le phenomene d’emergence du raisonnement est-il robuste a travers les tailles de modèles ?
  • Data efficiency : combien de prompts sont reellement necessaires pour RLVR ? 100 ? 1 000 ? 10 000 ?
  • Safety : comment garantir que le RL n’introduit pas de comportements dangereux lors de l’exploration ?

6. Conclusion de la serie Post-Training

Ce que nous avons couvert (PT-01 a PT-06)

Notebook Contribution clee
PT-01 Cartographie du paysage post-training 2024-2025
PT-02 SFT LoRA : le fondement, fine-tuning param-efficace
PT-03 DPO : préférence learning sans RL, Bradley-Terry
PT-04 GRPO : RL sans critic, avantage intra-group
PT-05 RLVR : rewards verifiables, emergence du raisonnement
PT-06 Synthese : comparaison, decision framework, perspectives

Les 3 lecons cles

  1. Le pipeline est cumulatif : SFT → DPO → GRPO/RLVR. Chaque étape affine le modèle. Ne pas sauter SFT.

  2. Le reward définit la technique : si vous avez un verifier exact (math, code), utilisez RLVR. Si vous avez des préférences humaines, utilisez DPO. Sinon, GRPO avec reward heuristique.

  3. L’honnetete prime : en pedagogie comme en recherche, rapporter honnetement les résultats. INCONCLUSIF > faux BEATS. 10 prompts ne font pas une evaluation rigoureuse.

Pour aller plus loin

  • Practice : re-executer les notebooks avec LOAD_MODEL_AND_TRAIN = True sur GPU
  • Papers : lire les papers de reference (Rafailov 2023, Shao 2024, Deepseek-R1 2025)
  • TRL docs : https://huggingface.co/docs/trl/ pour les dernières integrations
  • Communaute : HuggingFace Discord, r/LocalLLaMA pour les discussions pratiques

Exercice 3 : Planificateur de pipeline post-training

La section 4 presente le pipeline optimal en 4 étapes. L’objectif est d’implementer une fonction planifier_pipeline qui, a partir d’un cahier des charges, genere la sequence de techniques recommandee avec les couts estimes et les durees.

Objectif : ecrire une fonction qui prend un scénario (type de domaine, budget GPU, disponibilite de données) et retourne un plan d’exécution ordonne.

Indices : - # Étape 1 : Définir les paramètres du scénario (domaine, has_gpu, data_available) - # Étape 2 : Construire la liste ordonnee d’étapes selon les règles du decision framework - # Indice : le pipeline SFT est toujours la première étape, ensuite DPO si préférences, GRPO/RLVR si rewards

def planifier_pipeline(
    domaine: str = "general",         # "math", "code", "chatbot", "creative", "general"
    has_preferences: bool = False,
    has_verifier: bool = False,
    gpu_vram_gb: float = 8.0,
    budget_heures: float = 10.0,
) -> list[dict]:
    # TODO etudiant : generer le pipeline recommande
    pipeline = []
    
    # Etape 1 : SFT est toujours obligatoire
    # pipeline.append({"etape": "SFT", "technique": "SFTTrainer", "duree_estimee": ...})
    
    # Etape 2 : ajouter DPO, GRPO ou RLVR selon le contexte
    # TODO etudiant : conditions et ajouts
    
    return pipeline  # TODO etudiant : retourner le pipeline ordonne

print("Exercice a completer : planificateur pipeline")
Exercice a completer : planificateur pipeline
Retour au sommet