Accueil / Articles

Explication du ajustement fin de GRPO : Apprendre à un LLM local à raisonner

GRPO abandonne le critique de PPO et apprend à partir de comparaisons entre groupes. Découvrez les cinq grandeurs fondamentales, les fonctions de récompense ainsi qu’un bref script d’entraînement pour Unsloth et TRL.

Éditeur : REACTAPP.TOP11 min de lecture2471 mots

Sources: Creating Reasoning Models with GRPO Finetuning

Les modèles axés sur le raisonnement, tels que DeepSeek-R1, ont attiré beaucoup d’attention, et de nombreuses personnes souhaitent désormais obtenir le même comportement avec un modèle plus petit qu’elles pourraient exécuter elles-mêmes. La technique généralement reconnue à cet égard est le réglage fin GRPO. Le réglage fin supervisé (SFT) apprend à un modèle à imiter les schémas présents dans des exemples. L’optimisation relative de politique par groupes (GRPO) utilise l’apprentissage par renforcement pour amener un modèle à produire des réponses efficaces, ce qui revient davantage à lui apprendre à penser qu’à lui faire adopter un certain ton.

Cet article explique quelle place occupe GRPO parmi les méthodes RLHF, ce que signifient ses cinq grandeurs clés, et comment celles-ci se transforment en quelques dizaines de lignes de code d’entraînement.

La place de GRPO parmi les méthodes d’ajustement des préférences

Le RLHF, ou apprentissage par renforcement à partir des retours humains, doit être considéré avant tout comme un terme générique. Le PPO, le GRPO et le DPO sont des optimiseurs différents visant le même objectif : aligner un modèle sur ce que les gens préfèrent.

Une comparaison culinaire aide à comprendre. Le RLHF correspond à l’idée d’améliorer un plat en le goûtant et en y apportant des ajustements. Le PPO est une méthode plus ancienne et plus lourde qui nécessite un deuxième modèle (un critiqueur) ainsi que beaucoup de mémoire GPU. Le GRPO est une méthode plus récente et plus efficace qui élimine le critiqueur et économise de la mémoire en comparant les réponses entre elles.

Le cycle d’apprentissage par renforcement sous-jacent

L’apprentissage par renforcement classique se déroule en boucle : l’agent perçoit un état, choisit une action, l’environnement change, une récompense est attribuée et un nouvel état apparaît. Lorsque le PPO (Proximal Policy Optimization) a été appliqué aux modèles de langage, le modèle de langage est devenu l’agent, et la configuration comprenait trois éléments :

  1. la politique de génération, qui correspond au modèle actuellement entraîné
  2. la politique de référence, le modèle original conservé en état figé
  3. le modèle de valeur, qui estime une récompense moyenne

Un modèle de récompense évalue les sorties, et l’entraînement vise à augmenter cette évaluation.

PPO suit une conception acteur-critique, ce qui signifie que deux réseaux distincts sont entraînés. L’acteur est le LLM lui-même. Le critique est un réseau de valeur de taille similaire qui prédit la récompense que une réponse devrait obtenir. Disposer des deux double à peu près la mémoire nécessaire pendant l’entraînement.

GRPO ne dispose pas de critiqueur. En l’omettant, l’utilisation de la mémoire diminue d’environ la moitié. Pour la version de référence, GRPO génère un groupe de réponses à la même demande, évalue chacune d’elles et utilise la moyenne du groupe comme point de référence pour déterminer quelles réponses étaient meilleures ou pires que les autres.

DeepSeek a présenté le GRPO dans son article DeepSeekMath de 2024, et cette méthode a ensuite été intégrée dans DeepSeek-R1.

Les cinq éléments qui sous-tendent le GRPO

Cinq concepts constituent cette méthode. Pour chacun d’eux, l’objectif est d’expliquer ce qu’il mesure et pourquoi il a été conçu de cette manière.

1. Le rapport de politique : jusqu’où l’opinion du modèle a-t-elle changé ?

Ce rapport compare la probabilité qu’accorde le modèle mis à jour à une réponse avec la probabilité que lui accordait le modèle précédent : la nouvelle probabilité de réponse y pour un stimulus x, divisée par l’ancienne.

En mettant de côté les symboles, cela revient à se demander dans quelle mesure le modèle est maintenant plus ou moins susceptible de produire cette réponse par rapport à avant cette étape d’entraînement.

Pensez à un étudiant avant et après une nuit de révision : certaines réponses semblent désormais plus évidentes, tandis que d’autres le sont moins. Le rapport reflète ce changement de confiance.

  • Un chiffre supérieur à 1 indique que le modèle est plus confiant dans la réponse qu’auparavant.
  • Un chiffre inférieur à 1 signifie que la confiance a diminué et que le modèle s’éloigne de cette réponse.
  • Un chiffre exactement égal à 1 signifie que la mise à jour n’a rien changé pour cette réponse.

Pourquoi est-ce important ? En apprentissage par renforcement classique, on pourrait dire qu’une réponse à forte récompense mérite une augmentation importante de sa probabilité. Cela est risqué, car une pression trop forte peut faire que le modèle fluctue de manière excessive et abandonne un bon comportement simplement parce qu’une réponse a eu de la chance. Ce rapport agit comme une limite de vitesse : GRPO limite les grandes variations afin que le modèle évolue progressivement et non de manière erratique.

2. La récompense moyenne : quel a été le score moyen de ce lot ?

La moyenne correspond à la somme des récompenses obtenues pour le groupe de G réponses, divisée par G. G est le nombre de réponses extraites pour une question, et chaque réponse reçoit un score émis par le modèle de récompense.

Disons que vous demandez à un modèle de résoudre un problème de mathématiques et que vous extrayez cinq réponses de manière aléatoire. L’une est parfaite (récompense 1,0), une autre partiellement correcte (0,5) et une troisième clairement fausse (0,0). La moyenne vous indique à quel point le modèle se comporte bien sur ce problème en ce moment.

C’est son rôle qui rend GRPO intéressant. PPO avait besoin d’un critique, un deuxième réseau dont la seule fonction était de prédire la récompense attendue, et son entraînement était coûteux, gourmand en mémoire et sujette aux erreurs. GRPO se demande pourquoi prédire la moyenne alors qu’on peut la calculer directement. En extrayant un groupe de réponses et en calculant leur moyenne, on obtient la valeur de référence gratuitement, sans réseau supplémentaire ni mémoire inutilement consommée. C’est ce « groupe » qui figure dans le nom de la méthode.

3. L’écart type : à quel point les scores sont-ils dispersés ?

La déviation standard mesure à quel point chaque récompense s’éloigne de la moyenne, en prenant la racine carrée de l’écart moyen au carré. Alors que la moyenne décrit les performances typiques, elle indique ici la cohérence.

Une valeur élevée signifie que les réponses sont très hétérogènes, certaines excellentes et d’autres médiocres. Une valeur faible signifie que le modèle produit des réponses de qualité similaire à chaque fois.

Prenons deux étudiants. L’étudiant A obtient les notes 90, 10, 95, 5 et 88, avec une moyenne de 57,6 et un écart important : une grande instabilité. L’étudiant B obtient les notes 58, 56, 60, 57 et 59, avec une moyenne de 58 et un écart très faible : une médiocrité constante.

Dans GRPO, la déviation agit comme un normaliseur. Lorsque les réponses varient fortement, les différences entre les récompenses contiennent des informations pertinentes et justifient des mises à jour plus importantes. Lorsque le modèle est déjà cohérent, de petits écarts entre les récompenses peuvent être du bruit, donc les mises à jour doivent être plus prudentes.

4. L’avantage relatif au groupe : cette réponse a-t-elle surpassé les autres ?

C’est le cœur de la méthode. L’avantage pour une réponse i est sa récompense moins la moyenne du groupe, divisé par l’écart type du groupe. Cela transforme les récompenses brutes en un score relatif qui guide l’apprentissage.

La soustraction indique de combien la réponse est meilleure ou pire que la moyenne. La division, quant à elle, permet de normaliser les scores afin qu’ils soient comparables entre différentes questions et étapes d’entraînement.

Imaginez qu’on évalue un examen très difficile dont la moyenne de la classe est de 40 sur 100. Un élève obtient 60. En tant que note brute, cela semble médiocre, mais par rapport à la classe, c’est 20 points au-dessus de la moyenne, ce qui est excellent. Le principe est identique : on ignore les valeurs absolues des récompenses et on se demande si cette réponse est meilleure que ce que le modèle produit habituellement pour ce même stimulus.

Trois propriétés rendent cette méthode utile.

  1. Aucun critiqueur. L’avantage du PPO dépendait d’un critiqueur qui estimait la récompense attendue. Le GRPO remplace cette estimation par une moyenne empirique au sein du groupe.
  2. Auto-calibration. Si le modèle de récompense est biaisé et évalue tout de manière trop élevée ou trop basse, la forme relative compense ce biais. Seul le classement au sein du groupe compte.
  3. Stabilité. Grâce à la normalisation, la vitesse d’apprentissage s’adapte. Lorsque le modèle explore largement, les mises à jour sont importantes. À mesure qu’il converge, elles deviennent plus modestes.

5. La pénalité KL : rester reconnaissable soi-même

Ce est le frein de sécurité. Alors que GRPO pousse le modèle vers des réponses à forte récompense, le terme KL tire dans la direction opposée en interdisant au modèle de devenir quelqu’un d’autre. Il compare le modèle actuel avec le modèle de référence figé, qui est généralement le modèle de base d’avant le début de l’apprentissage par renforcement. La divergence KL est une mesure de l’écart entre deux distributions de probabilité. La formule présentée dans la source est une estimation couramment utilisée par token, basée sur le rapport entre les probabilités de référence et celles actuelles.

Imaginez le modèle de base comme un généraliste très cultivé capable d’écrire de la poésie, de déboguer du code et de résumer les actualités. Ensuite, vous appliquez l’apprentissage par renforcement pour en faire un expert en mathématiques. Sans le terme KL, il pourrait devenir tellement obsédé par les récompenses liées aux mathématiques qu’il oublierait tout le reste, allant même jusqu’à produire du charabia mathématique pour des demandes sans rapport.

Un KL faible signifie que le modèle ressemble encore à son état initial. Un KL élevé indique qu’il s’est éloigné considérablement, peut-être en surapprenant le modèle de récompense ou en perdant ses capacités générales.

Les modèles de récompense sont imparfaits et peuvent être manipulés. Un modèle sans terme KL pourrait découvrir que commencer par « Laissez-moi réfléchir pas à pas » lui vaut une récompense supplémentaire, même si cela ne change rien. S’ancrer sur les références permet en quelque sorte de contourner ces systèmes de récompense. En pratique, le terme KL est intégré dans la fonction de perte avec un poids faible, compris entre 0,01 et 0,04. Il n’a pas pour but d’arrêter les progrès, mais simplement de maintenir un équilibre dans ceux-ci.

La mise à jour expliquée simplement

  1. Générer un groupe de réponses à une question.
  2. Évaluer chacune avec le modèle de récompense.
  3. Calculer la moyenne et l’écart type de ces scores.
  4. Déterminer l’avantage de chaque réponse, c’est-à-dire à quel point elle se situe au-dessus ou en dessous de la moyenne.
  • Vérifiez le ratio de politique pour voir dans quelle mesure la confiance en chaque réponse a changé.
  • Supprimez les grandes variations afin que le modèle ne fluctue pas excessivement.
  • Pénalisez l’écart par rapport au référentiel à l’aide du terme KL.
  • Mettez à jour le modèle pour privilégier les réponses présentant un avantage relatif élevé.
  • Le résultat est un modèle qui apprend à raisonner, non pas en mémorisant des réponses correctes, mais en découvrant quels schémas de pensée surpassent régulièrement sa propre moyenne.

    Des équations à trainer.train()

    Une fois les aspects mathématiques abordés, voici du code qui met cela en pratique. Il utilise Unsloth pour charger un modèle Llama 3.2 3B Instruct en 4 bits avec un backend vLLM, ajoute des adaptateurs LoRA, impose un format de raisonnement via un prompt système, et construit l’ensemble d’entraînement à partir de GSM8K. vLLM est nécessaire car GRPO doit générer de nombreuses complétions par prompt rapidement.

    from unsloth import FastLanguageModel
    from datasets import load_dataset
    import re
    
    # 1. Load 4-bit model with vLLM backend for fast group generation
    model, tokenizer = FastLanguageModel.from_pretrained(
        model_name="unsloth/Llama-3.2-3B-Instruct",
        max_seq_length=1024,
        load_in_4bit=True,
        fast_inference=True,
        max_lora_rank=32,
        gpu_memory_utilization=0.6,
    )
    
    # 2. Attach LoRA adapters
    model = FastLanguageModel.get_peft_model(
        model,
        r=32,
        target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],
        lora_alpha=64,
        use_gradient_checkpointing="unsloth",
    )
    
    # 3. Enforcing reasoning format - GRPO needs structure to reward
    SYSTEM_PROMPT = "Respond in the following format:\n<reasoning>\n...\n</reasoning>\n<answer>\n...\n</answer>"
    
    # 4. Load GSM8K and wrap prompts
    dataset = load_dataset("openai/gsm8k", "main")["train"]
    dataset = dataset.map(lambda x: {
        "prompt": [
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": x["question"]}
        ],
        "answer": x["answer"].split("####")[1].strip()
    })
    #vLLM is used in GRPO because GRPO requires the AI to generate a ma
    

    Fonctions de récompense

    La conception des récompenses constitue la partie la plus délicate du ajustement fin GRPO. Une erreur dans cette conception amène le modèle à contourner vos règles de notation au lieu de raisonner. Les scores individuels sont additionnés pour former la récompense brute qui alimente le calcul de l’avantage. L’ensemble ci-dessous comprend cinq fonctions, chacune ayant une raison d’existence.

    1. correctness_reward est le signal principal. Il extrait le texte contenu dans les balises de réponse et attribue 2,0 en cas de correspondance avec la vérité absolue, sinon 0,0. Le poids est délibérément élevé afin que le fait d’avoir raison l’emporte toujours sur l’apparence soignée du texte.
    2. int_reward sert de filet de sécurité. Au début de l’entraînement, presque tout est incorrect ; il attribue donc 0,5 rien que pour la production d’un nombre valide, ce qui maintient un signal d’apprentissage actif jusqu’à ce que le modèle commence à résoudre des problèmes.
  • soft_format_reward et strict_format_reward récompensent respectivement de 0,5 la structure de balises « raisonnement-puis-réponse ». La version souple tolère les différences de mise en page, tandis que la version stricte exige une position exacte. Ensemble, elles transforment les résultats désordonnés en outputs propres.
  • xmlcount_reward verse 0,125 pour chaque balise bien placée et déduit une petite somme en cas de balises dupliquées ou de texte supplémentaire après la réponse. Il s’agit d’une petite touche d’amélioration qui a un impact cumulatif.
  • Chacune de ces fonctions est simple à part entière. Lorsqu’elles sont utilisées ensemble, la correction garantit le résultat, le format guide l’organisation et les détails s’arrangent d’eux-mêmes.

    def extract_xml_answer(text: str) -> str:
        return text.split("<answer>")[-1].split("</answer>")[0].strip()
    
    # Primary signal: is the final answer correct?
    def correctness_reward(prompts, completions, answer, **kwargs):
        responses = [c[0]["content"] for c in completions]
        extracted = [extract_xml_answer(r) for r in responses]
        return [2.0 if r == a else 0.0 for r, a in zip(extracted, answer)]
    
    # Dense shaping rewards - keep learning signal alive even when answers are wrong
    def int_reward(completions, **kwargs):
        return [0.5 if extract_xml_answer(c[0]["content"]).isdigit() else 0.0 for c in completions]
    
    def strict_format_reward(completions, **kwargs):
        pattern = r"^<reasoning>\n.*?\n</reasoning>\n<answer>\n.*?\n</answer>\nquot;
        return [0.5 if re.match(pattern, c[0]["content"]) else 0.0 for c in completions]
    
    def soft_format_reward(completions, **kwargs):
        pattern = r"<reasoning>.*?</reasoning>\s*<answer>.*?</answer>"
        return [0.5 if re.match(pattern, c[0]["content"]) else 0.0 for c in completions]
    
    def xmlcount_reward(completions, **kwargs):
        def score(text):
            count = 0.0
            if text.count("<reasoning>\n") == 1: count += 0.125
            if text.count("\n</reasoning>\n") == 1: count += 0.125
            if text.count("\n<answer>\n") == 1:
                count += 0.125
                count -= len(text.split("\n</answer>\n")[-1]) * 0.001
            if text.count("\n</answer>") == 1:
                count += 0.125
                count -= (len(text.split("\n</answer>")[-1]) - 1) * 0.001
            return count
        return [score(c[0]["content"]) for c in completions]pyt
    

    Le formateur

    from trl import GRPOConfig, GRPOTrainer
    
    trainer = GRPOTrainer(
        model=model,
        processing_class=tokenizer,
        reward_funcs=[
            xmlcount_reward,      # tag quality
            soft_format_reward,   # structure (forgiving)
            strict_format_reward, # structure (exact)
            int_reward,           # partial credit
            correctness_reward,   # ground-truth match
        ],
        args=GRPOConfig(
            learning_rate=5e-6,
            per_device_train_batch_size=1,
            gradient_accumulation_steps=1,
            num_generations=8,          # G = group size
            max_prompt_length=256,
            max_completion_length=200,
            max_steps=250,
            warmup_ratio=0.1,
            max_grad_norm=0.1,
            output_dir="outputs",
        ),
        train_dataset=dataset,
    )
    
    trainer.train()
    

    À chaque étape, GRPOTrainer effectue les cinq calculs décrits ci-dessus.

    Pourquoi le DPO a du mal avec le raisonnement

    Le DPO est élégant car il évite complètement l’apprentissage par renforcement. Il reformule le problème en un problème de classification : étant donné une question et deux réponses, il s’agit d’apprendre à privilégier la bonne réponse. Cela fonctionne bien lorsque les étiquettes de préférence sont fiables.

    Cependant, le raisonnement n’est pas vraiment un problème de préférence. C’est un problème de recherche.

    Supposons que vous vouliez qu’un modèle prouve un théorème de géométrie. Le DPO a besoin d’une personne ou d’un modèle plus puissant pour indiquer quelle des deux démonstrations est meilleure. Que se passe-t-il si les deux sont fausses ? Et si la démonstration correcte nécessite 12 étapes et n’a jamais été sélectionnée ? Le DPO ne peut apprendre que à partir des paires qui lui sont fournies et ne peut pas découvrir de nouvelle stratégie de raisonnement.

    GRPO génère un ensemble de réponses à la même question, les évalue chacune et détermine celles qui dépassent la moyenne. Cela signifie qu’il explore différentes possibilités. Il peut découvrir une méthode de raisonnement inédite, l’évaluer positivement et la renforcer, sans que personne n’ait auparavant suivi cette approche.

    En termes simples, DPO est moins coûteux à mettre en œuvre mais limite le modèle à la qualité de ses données de préférence. GRPO est plus cher par étape, mais permet d’aller au-delà des données annotées par des humains pour atteindre un raisonnement véritablement nouveau.

    Pensées finales

    GRPO apprend à un modèle à raisonner en identifiant quelles de ses propres réponses dépassent sa moyenne. En supprimant le critère d’évaluation, on réduit l’utilisation de la mémoire tout en conservant le signal d’apprentissage ; avec des fonctions de récompense adaptées et un échantillonnage par groupe, on peut améliorer le raisonnement d’un modèle local sur une seule carte graphique. Récompensez le comportement que vous souhaitez vraiment, maintenez le modèle stable et surveillez la valeur KL.