> For the complete documentation index, see [llms.txt](https://unsloth.ai/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://unsloth.ai/docs/fr/commencer/reinforcement-learning-rl-guide/vision-reinforcement-learning-vlm-rl.md).

# Apprentissage par renforcement vision (VLM RL)

Entraînez des modèles de vision/multimodaux via GRPO et RL avec Unsloth !

Unsloth prend désormais en charge le RL vision/multimodal avec [Qwen3-VL](/docs/fr/modeles/tutorials/qwen3-how-to-run-and-fine-tune/qwen3-vl-how-to-run-and-fine-tune.md), [Gemma 3](/docs/fr/modeles/tutorials/gemma-3-how-to-run-and-fine-tune.md) et bien plus encore. Grâce à la particularité unique d'Unsloth [partage des poids](/docs/fr/commencer/reinforcement-learning-rl-guide.md#what-unsloth-offers-for-rl) et à ses noyaux personnalisés, Unsloth rend le RL des VLM **1,5 à 2× plus rapide,** utilise **90 % de VRAM en moins**, et permet **un contexte 15× plus long** que les configurations FA2, sans perte de précision. Cette mise à jour introduit également l' [GSPO](#gspo-rl) algorithme de Qwen.

Unsloth peut entraîner Qwen3-VL-8B avec GSPO/GRPO sur un GPU Colab T4 gratuit. Les autres VLM fonctionnent aussi, mais peuvent nécessiter des GPU plus puissants. Gemma nécessite des GPU plus récents que le T4 car vLLM [se limite au Bfloat16](/docs/fr/modeles/tutorials/gemma-3-how-to-run-and-fine-tune.md#unsloth-fine-tuning-fixes), nous recommandons donc la NVIDIA L4 sur Colab. Nos notebooks résolvent des problèmes de mathématiques numériques impliquant des images et des diagrammes :

* **Qwen-3 VL-8B** (inférence vLLM)**:** [Colab](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen3_VL_\(8B\)-Vision-GRPO.ipynb)
* **Qwen-2.5 VL-7B** (inférence vLLM)**:** [Colab](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2_5_7B_VL_GRPO.ipynb) •[ Kaggle](https://www.kaggle.com/notebooks/welcome?src=https://github.com/unslothai/notebooks/blob/main/nb/Kaggle-Qwen2_5_7B_VL_GRPO.ipynb\&accelerator=nvidiaTeslaT4)
* **Gemma-3-4B** (inférence Unsloth) : [Colab](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma3_\(4B\)-Vision-GRPO.ipynb)

Nous avons également ajouté nativement l'intégration VLM de vLLM dans Unsloth, donc pour utiliser l'inférence vLLM, il suffit d'activer le `fast_inference=True` indicateur lors de l'initialisation du modèle. Un grand merci à [Sinoué GAD](https://github.com/unslothai/unsloth/pull/2752) pour avoir fourni le [premier notebook](https://github.com/GAD-cell/vlm-grpo/blob/main/examples/VLM_GRPO_basic_example.ipynb) qui a facilité l'intégration du RL VLM !

Cette prise en charge VLM intègre également notre dernière mise à jour pour un RL encore plus efficace en mémoire et plus rapide, y compris notre [fonction Standby](/docs/fr/commencer/reinforcement-learning-rl-guide/memory-efficient-rl.md#unsloth-standby), qui limite de manière unique la dégradation de la vitesse par rapport aux autres implémentations.

{% hint style="info" %}
Vous ne pouvez utiliser `fast_inference` avec des VLM pris en charge par vLLM. Certains modèles, comme Llama 3.2 Vision, ne peuvent donc s'exécuter que sans vLLM, mais ils fonctionnent quand même dans Unsloth.
{% endhint %}

```python
os.environ['UNSLOTH_VLLM_STANDBY'] = '1' # Pour activer un GRPO économe en mémoire avec vLLM
model, tokenizer = FastVisionModel.from_pretrained(
    model_name = "Qwen/Qwen2.5-VL-7B-Instruct",
    max_seq_length = 16384, # Doit être aussi grand pour faire tenir l'image dans le contexte
    load_in_4bit = True, # False pour LoRA 16 bits
    fast_inference = True, # Activer l'inférence rapide vLLM
    gpu_memory_utilization = 0.8, # Réduire en cas de manque de mémoire
)
```

Il est également important de noter que vLLM ne prend pas en charge LoRA pour les couches de vision/encodeur, définissez donc `finetune_vision_layers = False` lors du chargement d'un adaptateur LoRA.\
Cependant, vous POUVEZ aussi entraîner les couches de vision si vous utilisez l'inférence via transformers/Unsloth.

```python
# Ajouter un adaptateur LoRA au modèle pour un ajustement fin efficace en paramètres
model = FastVisionModel.get_peft_model(
    model,

    finetune_vision_layers     = False,# fast_inference ne prend pas encore en charge finetune_vision_layers :(
    finetune_language_layers   = True, # False si vous n'ajustez pas finement les couches de langage
    finetune_attention_modules = True, # False si vous n'ajustez pas finement les couches d'attention
    finetune_mlp_modules       = True, # False si vous n'ajustez pas finement les couches MLP

    r = lora_rank, # Choisissez n'importe quel nombre > 0 ! Suggestions : 8, 16, 32, 64, 128
    lora_alpha = lora_rank*2, # *2 accélère l'entraînement
    use_gradient_checkpointing = "unsloth", # Réduit l'utilisation de la mémoire
    random_state = 3407,
)
```

## :butterfly:Problèmes et particularités du RL vision de Qwen 2.5 VL

Pendant le RL pour Qwen 2.5 VL, vous pourriez voir la sortie d'inférence suivante :

{% code overflow="wrap" %}

```
 addCriterion
 <tool_call>\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n\n addCriterion\n\n 自动生成\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n addCriterion\n\n\n addCriterion\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
```

{% endcode %}

Cela a également été [signalé](https://github.com/QwenLM/Qwen2.5-VL/issues/759) dans la sortie de Qwen2.5-VL-7B-Instruct, qui produisait des résultats inattendus "addCriterion". En fait, nous le constatons aussi ! Nous avons essayé des machines non Unsloth, en bfloat16 et en float16, ainsi que d'autres choses, mais cela persiste. Par exemple, l'élément 165, c'est-à-dire `train_dataset[165]` du [AI4Math/MathVista](https://huggingface.co/datasets/AI4Math/MathVista) jeu de données est ci-dessous :

{% code overflow="wrap" %}

```
La figure est une vue de dessus du trajet emprunté par un pilote de voiture de course lorsque sa voiture heurte le mur de la piste. Juste avant la collision, il se déplace à la vitesse $v_i=70 \mathrm{~m} / \mathrm{s}$ le long d'une ligne droite faisant $30^{\circ}$ avec le mur. Juste après la collision, il se déplace à la vitesse $v_f=50 \mathrm{~m} / \mathrm{s}$ le long d'une ligne droite faisant $10^{\circ}$ avec le mur. Sa masse $m$ est de $80 \mathrm{~kg}$. La collision dure $14 \mathrm{~ms}$. Quelle est la valeur de la force moyenne exercée sur le pilote pendant la collision ?
```

{% endcode %}

<figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-61a659529171fcc10ed6398a15912b21d6b1a076%2FUntitled.png?alt=media" alt="" width="128"><figcaption></figcaption></figure>

Et nous obtenons ensuite le charabia ci-dessus. On pourrait ajouter une fonction de récompense pour pénaliser l'ajout de addCriterion, ou pénaliser les sorties incohérentes. Cependant, l'autre approche consiste à l'entraîner plus longtemps. Par exemple, ce n'est qu'après environ 60 étapes que l'on voit réellement le modèle apprendre via le RL :

<figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-5f34f66f0ac6508fd28343b16592c59b889ec5ca%2Fimage.webp?alt=media" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
Forcer `<|assistant|>` lors de la génération réduira l'occurrence de ces résultats incohérents, comme prévu puisque c'est un modèle Instruct ; cependant, il reste préférable d'ajouter une fonction de récompense pour pénaliser les mauvaises générations, comme décrit dans la section suivante.
{% endhint %}

## :medal:Fonctions de récompense pour réduire le charabia

Pour pénaliser `addCriterion` et les sorties incohérentes, nous avons modifié la fonction de récompense pour pénaliser un excès de `addCriterion` et de nouvelles lignes.

```python
def formatting_reward_func(completions,**kwargs):
    import re
    thinking_pattern = f'{REASONING_START}(.*?){REASONING_END}'
    answer_pattern = f'{SOLUTION_START}(.*?){SOLUTION_END}'

    scores = []
    for completion in completions:
        score = 0
        thinking_matches = re.findall(thinking_pattern, completion, re.DOTALL)
        answer_matches = re.findall(answer_pattern, completion, re.DOTALL)
        if len(thinking_matches) == 1:
            score += 1.0
        if len(answer_matches) == 1:
            score += 1.0

        # Corriger les problèmes de addCriterion
        # Voir https://docs.unsloth.ai/new/vision-reinforcement-learning-vlm-rl#qwen-2.5-vl-vision-rl-issues-and-quirks
        # Pénaliser l'excès de addCriterion et des retours à la ligne
        if len(completion) != 0:
            removal = completion.replace("addCriterion", "").replace("\n", "")
            if (len(completion)-len(removal))/len(completion) >= 0.5:
                score -= 2.0

        scores.append(score)
    return scores
```

## :checkered\_flag:Apprentissage par renforcement GSPO

Cette mise à jour ajoute en outre GSPO ([Optimisation de politique de séquence de groupe](https://arxiv.org/abs/2507.18071)) qui est une variante de GRPO créée par l'équipe Qwen d'Alibaba. Ils ont constaté que GRPO entraîne implicitement des poids d'importance pour chaque jeton, même si, explicitement, les avantages ne sont pas mis à l'échelle ni modifiés pour chaque jeton.

Cela a conduit à la création de GSPO, qui attribue désormais l'importance à la vraisemblance de la séquence plutôt qu'aux vraisemblances individuelles des jetons. La différence entre ces deux algorithmes peut être vue ci-dessous, à la fois d'après l'article GSPO de Qwen et d'Alibaba :

<figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-45d743dd5dcd590626777ce09cfab61808aa8c24%2Fimage.png?alt=media" alt="" width="563"><figcaption><p>Algorithme GRPO, source : <a href="https://arxiv.org/abs/2507.18071">Qwen</a></p></figcaption></figure>

<figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-ee755850cbe17482ce240dde227d55c62e9a3e64%2Fimage.png?alt=media" alt="" width="563"><figcaption><p>Algorithme GSPO, source : <a href="https://arxiv.org/abs/2507.18071">Qwen</a></p></figcaption></figure>

Dans l'équation 1, on voit que les avantages mettent à l'échelle chacune des lignes dans les logprobs des jetons avant que ce tenseur ne soit additionné. En substance, chaque jeton reçoit la même mise à l'échelle, même si celle-ci a été attribuée à l'ensemble de la séquence plutôt qu'à chaque jeton individuellement. Un simple schéma de cela est présenté ci-dessous :

<figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-b3c944808a15dde0a7ff45782f9f074993304bf1%2FCopy%20of%20GSPO%20diagram%20(1).jpg?alt=media" alt="" width="286"><figcaption><p>Rapport de logprob GRPO mis à l'échelle ligne par ligne avec les avantages</p></figcaption></figure>

L'équation 2 montre que les rapports de logprob de chaque séquence sont additionnés et exponentiés après le calcul des rapports de logprob, et que seuls les rapports de séquence obtenus sont ensuite multipliés ligne par ligne par les avantages.

<figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-62fc5b50921e79cce155d2794201c9b96faf941e%2FGSPO%20diagram%20(1).jpg?alt=media" alt="" width="313"><figcaption><p>Rapport de séquence GSPO mis à l'échelle ligne par ligne avec les avantages</p></figcaption></figure>

Activer GSPO est simple, il suffit de définir le `importance_sampling_level = "sequence"` indicateur dans la configuration GRPO.

```python
training_args = GRPOConfig(
    output_dir = "vlm-grpo-unsloth",
    per_device_train_batch_size = 8,
    gradient_accumulation_steps = 4,
    learning_rate = 5e-6,
    adam_beta1 = 0.9,
    adam_beta2 = 0.99,
    weight_decay = 0.1,
    warmup_ratio = 0.1,
    lr_scheduler_type = "cosine",
    optim = "adamw_8bit",
    # beta = 0.00,
    epsilon = 3e-4,
    epsilon_high = 4e-4,
    num_generations = 8,    
    max_prompt_length = 1024,
    max_completion_length = 1024,
    log_completions = False,
    max_grad_norm = 0.1,
    temperature = 0.9,
    # report_to = "none", # Définissez sur "wandb" si vous souhaitez enregistrer dans Weights & Biases
    num_train_epochs = 2, # Pour un test rapide, augmentez pour un entraînement complet
    report_to = "none"
    
    # GSPO est ci-dessous :
    importance_sampling_level = "sequence",
    
    # Dr GRPO / GAPO etc
    loss_type = "dr_grpo",
)
```

Dans l'ensemble, Unsloth, désormais avec l'inférence rapide VLM vLLM, permet à la fois une réduction de 90 % de l'utilisation de la mémoire et une vitesse 1,5 à 2× plus rapide avec GRPO et GSPO !

Si vous souhaitez en savoir plus sur l'apprentissage par renforcement, consultez notre guide RL :

[Reinforcement Learning](/docs/fr/commencer/reinforcement-learning-rl-guide.md)

***Auteurs :** Un immense merci à* [*Keith*](https://www.linkedin.com/in/keith-truongcao-7bb84a23b/) *et* [*Datta*](https://www.linkedin.com/in/datta0/) *pour avoir contribué à cet article !*


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://unsloth.ai/docs/fr/commencer/reinforcement-learning-rl-guide/vision-reinforcement-learning-vlm-rl.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
