> 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/modeles/gemma-4/train.md).

# Guide de fine-tuning Gemma 4

Vous pouvez désormais entraîner les modèles de Google [Gemma 4](https://unsloth.ai/docs/models/gemma-4) 12B, E2B, E4B, 26B-A4B et 31B avec [**Unsloth**](https://github.com/unslothai/unsloth). Unsloth prend en charge l'affinage vision, texte, audio et RL pour Gemma 4.

* Unsloth entraîne Gemma 4 **\~1,5× plus rapide** avec **\~60 % de VRAM en moins** que les configurations FA2 (sans perte de précision)
* Nous avons corrigé de nombreux [bugs pour l'entraînement de Gemma 4](#bug-fixes--tips) (non dérivés d'Unsloth).
* Gemma 4 E2B fonctionne avec **8 Go de VRAM**. E4B nécessite 10 Go de VRAM.

<a href="/pages/11ad65c8cb780dbffa6556d9554801824345ccfa#quickstart" class="button primary" data-icon="bolt">Démarrage rapide</a><a href="/pages/11ad65c8cb780dbffa6556d9554801824345ccfa#bug-fixes--tips" class="button secondary" data-icon="sparkle">Corrections de bugs + Conseils</a>

Affinez Gemma 4 via nos **gratuits** **carnets Google Colab**:

| [**E4B + E2B** (Studio)](https://colab.research.google.com/github/unslothai/unsloth/blob/main/studio/Unsloth_Studio_Colab.ipynb) | [**31B** (Kaggle)](https://www.kaggle.com/code/danielhanchen/gemma4-31b-unsloth) | [E4B **(Vision + texte)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E4B\)-Vision.ipynb) | [E4B **(Audio)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E4B\)-Audio.ipynb) | [E2B **(RL GRPO)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E2B\)_Reinforcement_Learning_Sudoku_Game.ipynb) |
| -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |

{% columns %}
{% column %}
Vous pouvez exécuter et entraîner Gemma 4 gratuitement avec une interface dans notre [Unsloth Studio](/docs/fr/nouveau/studio.md)✨ carnet :

Vous pouvez consulter davantage de [carnets ici](#unsloth-core-code-based-guide).
{% endcolumn %}

{% column %}
{% embed url="<https://colab.research.google.com/github/unslothai/unsloth/blob/main/studio/Unsloth_Studio_Colab.ipynb>" %}
{% endcolumn %}
{% endcolumns %}

* Vous pouvez aussi entraîner Gemma 4 avec [l'apprentissage par renforcement](#reinforcement-learning-rl) (RL) sur 9 Go de VRAM.
* Gemma 4 E2B LoRA fonctionne avec 8 à 10 Go de VRAM. E4B LoRA nécessite 17 Go de VRAM.
* **31B QLoRA fonctionne avec 22 Go** et 26B-A4B LoRA nécessite >40 Go
* **Exportation**/enregistrer les modèles en GGUF, etc. et affinage complet **(FFT)** fonctionne aussi.

### :bug: Corrections de bugs + Conseils

{% hint style="success" %}
Si vous voyez **Gemma-4 E2B et E4B afficher une perte de 13 à 15, c'est tout à fait normal** - c'est une particularité courante des modèles multimodaux. Cela s'est aussi produit sur Gemma-3N, Llama Vision, les modèles vision de Mistral et d'autres.

**Gemma 26B et 31B ont une perte plus faible, de 1 à 3 ou moins. La vision sera 2 fois plus élevée, donc 3 à 5**
{% endhint %}

#### :grapes:L'accumulation des gradients peut augmenter artificiellement vos pertes

{% columns %}
{% column %}

<div data-with-frame="true"><figure><img src="/files/3126691d25d114e2ad767a10b21969a269e95ceb" alt=""><figcaption></figcaption></figure></div>
{% endcolumn %}

{% column %}

<div data-with-frame="true"><figure><img src="/files/ede801396523d6cd32323b2c36db9e0b5781bb14" alt=""><figcaption></figcaption></figure></div>
{% endcolumn %}
{% endcolumns %}

Si vous voyez des pertes supérieures à 13-15 (comme 100 ou 300), il est très probable que l'accumulation des gradients ne soit pas correctement prise en compte - nous avons **corrigé cela dans Unsloth et Unsloth Studio.**

Pour en savoir plus sur l'accumulation des gradients, consultez notre article de correction de bug sur l'accumulation des gradients : <https://unsloth.ai/blog/gradient>

#### :interrobang:IndexError lors de l'inférence de Gemma-4 31B et 26B-A4B

Vous pourriez voir cette erreur lors d'une inférence avec 31B et 26B :

```python
File "/.../cache_utils.py", line 937, in update
    keys, values = self.layers[layer_idx].update(...)
IndexError: list index out of range
```

La cause est ci-dessous :

```python
if hasattr(decoder_config, "num_kv_shared_layers"):
    layer_types = layer_types[: -decoder_config.num_kv_shared_layers]
```

Or Gemma-4 31B et 26B-A4B sont fournis avec `num_kv_shared_layers = 0`. En Python, `-0 == 0`, donc `layer_types[:-0]` se réduit à `layer_types[:0] == []`. Le cache est construit avec zéro emplacement de couche et la toute première passe avant d'attention plante dans `Cache.update`.

#### :no\_entry: `use_cache = True` la génération était du charabia pour E2B, E4B

[Voir le problème](https://github.com/huggingface/transformers/issues/45242) "\[Gemma 4] `use_cache=False` corrompt le calcul de l'attention, produisant des logits incohérents #45242"

Gemma-4 E2B et E4B partagent l'état KV entre les couches (`num_kv_shared_layers = 20` et `18`). Le cache est le seul endroit où les premières couches stockent le KV pour que les couches ultérieures le réutilisent. Lorsque `use_cache=False` (comme le définissent tous les tutoriels QLoRA, et comme `gradient_checkpointing=True` l'impose), `Gemma4TextModel.forward` saute la construction du cache, donc les couches partageant le KV passent au recalcul local de K et V à partir des états cachés actuels. Les logits deviennent incohérents et la perte d'entraînement diverge.

**Avant (`unsloth/gemma-4-E2B-it`, invite "Combien font 1+1 ?") :**

```
use_cache=True  -> '1 + 1 = **2**'
use_cache=False -> 'BROAD\肯. Specificallyboard K supposed\_n통  \'
max_abs_logit_diff: 48.937500
```

**Après notre correction :**

```
use_cache=True  -> '1 + 1 = **2**'
use_cache=False -> '1 + 1 = **2**'
max_abs_logit_diff: 0.000000     (parité bit à bit exacte, les 9 jetons sont identiques)
```

#### :radio:Dépassement de capacité en float16 audio

`Gemma4AudioAttention` utilise `config.attention_invalid_logits_value = -1e9` dans un `masked_fill` appel. Sur fp16 (Tesla T4), -1e9 dépasse la valeur maximale fp16 de 65504, provoquant :

```python
RuntimeError: value cannot be converted to type c10::Half without overflow
```

Cela était dû à `self.config.attention_invalid_logits_value` :

```python
attn_weights = attn_weights.masked_fill(
    attention_mask.logical_not(), self.config.attention_invalid_logits_value
)
```

#### 💡Conseils pour Gemma-4

1. Si vous souhaitez **préserver la capacité de raisonnement** de raisonnement, vous pouvez mélanger des exemples de type raisonnement avec des réponses directes (conservez au minimum 75 % de raisonnement). Sinon, vous pouvez l'émettre entièrement.\n\nUtilisez `gemma-4` pour le modèle de chat sans réflexion et `gemma-4-thinking` pour la variante avec réflexion.\nUtilisez la version avec réflexion pour les modèles plus grands 26B et 31B, et la version sans réflexion pour les petits modèles.<br>

   ```python
   from unsloth.chat_templates import get_chat_template
   tokenizer = get_chat_template(
       tokenizer,
       chat_template = "gemma-4-thinking", # Ou "gemma-4"
   )
   ```
2. Pour activer le mode réflexion, utilisez `enable_thinking = True / False` dans `tokenizer.apply_chat_template`<br>

   Réflexion activée :

   <pre class="language-python" data-overflow="wrap"><code class="lang-python">processor.tokenizer.apply_chat_template([
       {"role" : "user", "content" : "Combien font 2+2 ?"},
   ], tokenize = False, enable_thinking = True, add_generation_prompt = True)
   </code></pre>

   Affichera `<bos><|turn>system\n<|think|><turn|>\n<|turn>user\nCombien font 2+2 ?<turn|>\n<|turn>model\n`<br>

   Réflexion désactivée :

   ```python
   processor.tokenizer.apply_chat_template([
       {"role" : "user", "content" : "Combien font 2+2 ?"},
   ], tokenize = False, enable_thinking = False, add_generation_prompt = True)
   ```

   Affichera `<bos><|turn>user\nCombien font 2+2 ?<turn|>\n<|turn>model\n<|channel>thought\n<channel|>`
3. Gemma 4 est puissant pour l'affinage multilingue, car il prend en charge 140 langues.
4. Il est recommandé d'entraîner **E4B QLoRA** plutôt que **E2B LoRA** car E4B est plus grand et la différence de précision de quantification est minuscule. Gemma 4 E4B LoRA est encore meilleure.
5. Après l'affinage, vous pouvez exporter vers [GGUF](#saving-export-your-fine-tuned-model) (pour llama.cpp/Unsloth/Ollama/etc.)

### ⚡Démarrage rapide

#### 🦥 Guide d'Unsloth Studio

{% columns %}
{% column %}
Gemma 4 peut être exécuté et affiné dans [Unsloth Studio](/docs/fr/nouveau/studio.md), notre nouvelle interface web open source pour l'IA locale.

Avec Unsloth Studio, vous pouvez exécuter des modèles localement sur **MacOS, Windows**, Linux et entraîner des GPU NVIDIA. La prise en charge de l'entraînement Intel, MLX et AMD arrive ce mois-ci.
{% endcolumn %}

{% column %}

<div data-with-frame="true"><figure><img src="/files/1bfca8ddb6083207315871656a48d7dab27b9437" alt=""><figcaption></figcaption></figure></div>
{% endcolumn %}
{% endcolumns %}

{% stepper %}
{% step %}

#### Installer Unsloth

Exécutez dans votre terminal :

**MacOS, Linux, WSL :**

```bash
curl -fsSL https://unsloth.ai/install.sh | sh
```

**Windows PowerShell :**

```bash
irm https://unsloth.ai/install.ps1 | iex
```

{% hint style="success" %}
**L'installation sera rapide et prendra environ 1 à 2 minutes.**
{% endhint %}
{% endstep %}

{% step %}

#### Lancer Unsloth

**MacOS, Linux, WSL et Windows :**

```bash
unsloth studio -H 0.0.0.0 -p 8888
```

**Puis ouvrez `http://localhost:8888` dans votre navigateur.**
{% endstep %}

{% step %}

#### Entraîner Gemma 4

Lors du premier lancement, vous devrez créer un mot de passe pour sécuriser votre compte et vous reconnecter plus tard. Vous verrez ensuite un bref assistant d'accueil pour choisir un modèle, un jeu de données et des paramètres de base. Vous pouvez le passer à tout moment.

Recherchez Gemma 4 dans la barre de recherche et sélectionnez le modèle et le jeu de données souhaités. Ensuite, ajustez vos hyperparamètres et la longueur de contexte selon vos besoins.

<div data-with-frame="true"><figure><img src="/files/1bfca8ddb6083207315871656a48d7dab27b9437" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}

{% step %}

#### Surveiller la progression de l'entraînement

Après avoir cliqué sur démarrer l'entraînement, vous pourrez surveiller et observer la progression de l'entraînement du modèle. La perte d'entraînement devrait diminuer régulièrement.\nUne fois terminé, le modèle sera automatiquement enregistré.

<div data-with-frame="true"><figure><img src="/files/e60a0e51da6ae0ff7342416211897ffddd6cf338" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}

{% step %}

#### Exportez votre modèle affiné

Une fois terminé, Unsloth Studio vous permet d'exporter le modèle vers des formats GGUF, safetensor, etc.

<div data-with-frame="true"><figure><img src="/files/532c1203fd646e3902d3740944eb7783dc0efe24" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}

{% step %}

#### Comparer le modèle affiné au modèle original

Cliquez sur `Mode Comparaison` pour comparer l'adaptateur LoRA et le modèle original.

<div data-with-frame="true"><figure><img src="/files/49feb6a69a89008175dc55031867f3876e597312" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}
{% endstepper %}

#### 🦥 Guide Unsloth Core (basé sur le code)

Nous avons créé des carnets gratuits pour Gemma 4 :

| [E4B **(Inférence + texte)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E4B\)-Text.ipynb) | [E4B **(Vision + texte)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E4B\)-Vision.ipynb) | [E4B **(Audio)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E4B\)-Audio.ipynb) |
| ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| [**31B** (Kaggle)](https://www.kaggle.com/code/danielhanchen/gemma4-31b-unsloth)                                                   | [E2B **(Vision + texte)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E2B\)-Vision.ipynb) | [E2B **(Audio)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E2B\)-Audio.ipynb) |

Et pour l'apprentissage par renforcement (RL) : [E2B **(RL GRPO)**](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(E2B\)_Reinforcement_Learning_Sudoku_Game.ipynb)

Nous avons aussi créé des carnets pour les plus grands modèles Gemma 4, mais ils nécessitent une A100 :

| [Gemma-4-26B-A4B](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(26B_A4B\)-Vision.ipynb) - GPU A100 | [Gemma-4-31B](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Gemma4_\(31B\)-Vision.ipynb) - GPU A100 |
| --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |

{% hint style="info" %}
**Si vous souhaitez faire** [**GRPO**](/docs/fr/commencer/reinforcement-learning-rl-guide.md)**, cela fonctionne dans Unsloth si vous désactivez l'inférence rapide vLLM et utilisez l'inférence Unsloth à la place. Suivez nos** [**Vision RL**](/docs/fr/commencer/reinforcement-learning-rl-guide/vision-reinforcement-learning-vlm-rl.md) **exemples de carnets.**
{% endhint %}

Voici ci-dessous une recette SFT texte autonome pour Gemma-4-26B-A4B-it. Il s'agit uniquement de texte — consultez aussi notre [affinage vision](/docs/fr/notions-de-base/vision-fine-tuning.md) section pour plus de détails.

{% code expandable="true" %}

````python
from unsloth import FastModel
import torch

model, tokenizer = FastModel.from_pretrained(
    model_name = "unsloth/gemma-4-26B-A4B-it", # Modifiez ceci en unsloth/gemma-4-E2B-it etc
    dtype = None, # None pour détection automatique
    max_seq_length = 8192, # Choisissez n'importe quelle valeur pour un contexte long !
    load_in_4bit = True,  # Quantification en 4 bits pour réduire la mémoire
    full_finetuning = False, # [NOUVEAU !] Nous avons maintenant l'affinage complet !
    # token = "YOUR_HF_TOKEN", # Jeton HF pour les modèles protégés
)

"""# Gemma 4 peut traiter le texte, la vision et l'audio !

Découvrons d'abord comment Gemma 4 peut gérer les entrées multimodales. Nous utilisons les paramètres recommandés par Gemma 4 : `temperature = 1.0, top_p = 0.95, top_k = 64`
"""

from transformers import TextStreamer
# Fonction utilitaire pour l'inférence
def do_gemma_4_inference(messages, max_new_tokens = 128):
    _ = model.generate(
        **tokenizer.apply_chat_template(
            messages,
            add_generation_prompt = True, # Doit être ajouté pour la génération
            tokenize = True,
            return_dict = True,
            return_tensors = "pt",
        ).to("cuda"),
        max_new_tokens = max_new_tokens,
        use_cache=True,
        temperature = 1.0, top_p = 0.95, top_k = 64,
        streamer = TextStreamer(tokenizer, skip_prompt = True),
    )

"""# Gemma 4 peut voir des images !

<img src="https://files.worldwildlife.org/wwfcmsprod/images/Sloth_Sitting_iStock_3_12_2014/story_full_width/8l7pbjmj29_iStock_000011145477Large_mini__1_.jpg" alt="Texte alternatif" height="256">
"""

sloth_link = "https://files.worldwildlife.org/wwfcmsprod/images/Sloth_Sitting_iStock_3_12_2014/story_full_width/8l7pbjmj29_iStock_000011145477Large_mini__1_.jpg"

messages = [{
    "role" : "user",
    "content": [
        { "type": "image", "image" : sloth_link },
        { "type": "text",  "text" : "Quels films cet animal a-t-il tournés ?" }
    ]
}]
# Vous devrez peut-être attendre 1 minute que le compilateur automatique d'Unsloth s'exécute
do_gemma_4_inference(messages, max_new_tokens = 256)

"""Faisons un poème sur les paresseux !"""

messages = [{
    "role": "user",
    "content": [{ "type" : "text",
                  "text" : "Écris un poème sur les paresseux." }]
}]
do_gemma_4_inference(messages)

"""# Affinons Gemma 4 !

Vous pouvez pour l'instant affiner les parties vision et texte par sélection - la partie audio peut aussi être affinée - nous travaillons à la rendre sélectionnable également !

Nous ajoutons maintenant des adaptateurs LoRA afin de n'avoir à mettre à jour qu'un petit nombre de paramètres !
"""

model = FastModel.get_peft_model(
    model,
    finetune_vision_layers     = False, # Désactivez pour le texte uniquement !
    finetune_language_layers   = True,  # Doit rester activé !
    finetune_attention_modules = True,  # L'attention est utile pour GRPO
    finetune_mlp_modules       = True,  # Doit toujours rester activé !

    r = 8,           # Plus grand = précision plus élevée, mais risque de surapprentissage
    lora_alpha = 8,  # alpha recommandé = r au minimum
    lora_dropout = 0,
    bias = "none",
    random_state = 3407,
)

"""<a name="Data"></a>
### Préparation des données
Nous utilisons maintenant le format `Gemma-4` pour les affinages de type conversation. Nous utilisons le jeu de données [FineTome-100k de Maxime Labonne](https://huggingface.co/datasets/mlabonne/FineTome-100k) au format ShareGPT. Gemma-4 affiche les conversations multi-tours comme ci-dessous :

```
<bos><|turn>user
Bonjour<turn|>
<|turn>model
Salut !<turn|>
```
Nous utilisons notre fonction `get_chat_template` pour obtenir le bon modèle de chat. Nous prenons en charge `zephyr, chatml, mistral, llama, alpaca, vicuna, vicuna_old, phi3, llama3, phi4, qwen2.5, gemma3, gemma-4` et bien plus encore.
"""

from unsloth.chat_templates import get_chat_template
tokenizer = get_chat_template(
    tokenizer,
    chat_template = "gemma-4-thinking",
)

"""Nous récupérons les 3000 premières lignes du jeu de données"""

from datasets import load_dataset
dataset = load_dataset("mlabonne/FineTome-100k", split = "train[:3000]")

"""Nous utilisons maintenant `standardize_data_formats` pour essayer de convertir les jeux de données au bon format en vue de l'affinage !"""

from unsloth.chat_templates import standardize_data_formats
dataset = standardize_data_formats(dataset)

"""Voyons à quoi ressemble la ligne 100 !"""

dataset[100]

"""Nous devons maintenant appliquer le modèle de chat `Gemma-3` aux conversations, et l'enregistrer dans `text`. Nous supprimons le jeton `<bos>` à l'aide de removeprefix(`'<bos>'`) puisque nous affinons le modèle. Le processeur ajoutera ce jeton avant l'entraînement et le modèle n'en attend qu'un seul."""

def formatting_prompts_func(examples):
   convos = examples["conversations"]
   texts = [tokenizer.apply_chat_template(convo, tokenize = False, add_generation_prompt = False).removeprefix('<bos>') for convo in convos]
   return { "text" : texts, }

dataset = dataset.map(formatting_prompts_func, batched = True)

"""Voyons le résultat du modèle de chat ! Notez qu'il n'y a pas de jeton `<bos>` puisque le tokenizer du processeur en ajoutera un."""

dataset[100]["text"]

"""<a name="Train"></a>
### Entraîner le modèle
Maintenant, entraînons notre modèle. Nous effectuons 60 étapes pour accélérer les choses, mais vous pouvez définir `num_train_epochs=1` pour une exécution complète d'entraînement, et désactiver `max_steps=None`.
"""

from trl import SFTTrainer, SFTConfig
trainer = SFTTrainer(
    model = model,
    tokenizer = tokenizer,
    train_dataset = dataset,
    eval_dataset = None, # Peut configurer l'évaluation !
    args = SFTConfig(
        dataset_text_field = "text",
        per_device_train_batch_size = 1,
        gradient_accumulation_steps = 4, # Utilisez l'AG pour simuler la taille de lot !
        warmup_steps = 5,
        # num_train_epochs = 1, # Définissez ceci pour une exécution complète d'entraînement.
        max_steps = 60,
        learning_rate = 2e-4, # Réduisez à 2e-5 pour les longues exécutions d'entraînement
        logging_steps = 1,
        optim = "adamw_8bit",
        weight_decay = 0.001,
        lr_scheduler_type = "linear",
        seed = 3407,
        report_to = "none", # Utilisez TrackIO/WandB, etc.
    ),
)

"""Nous utilisons aussi la méthode `train_on_completions` d'Unsloth pour n'entraîner que sur les sorties de l'assistant et ignorer la perte sur les entrées de l'utilisateur. Cela aide à améliorer la précision des affinages !"""

from unsloth.chat_templates import train_on_responses_only
trainer = train_on_responses_only(
    trainer,
    instruction_part = "<|turn>user\n",
    response_part = "<|turn>model\n",
)

"""Vérifions que le masquage de la partie instruction est bien fait ! Imprimons à nouveau la 100e ligne.  Remarquez que l'exemple n'a qu'un seul `<bos>` comme prévu !"""

tokenizer.decode(trainer.train_dataset[100]["input_ids"])

"""Imprimons maintenant l'exemple masqué - vous devriez voir que seule la réponse est présente :"""

tokenizer.decode([tokenizer.pad_token_id if x == -100 else x for x in trainer.train_dataset[100]["labels"]]).replace(tokenizer.pad_token, " ")

"""# Entraînons maintenant le modèle !

Pour reprendre un entraînement, définissez `trainer.train(resume_from_checkpoint = True)`
"""

trainer_stats = trainer.train()
````

{% endcode %}

{% hint style="info" %}
Si vous êtes en OOM :

* Réduisez `per_device_train_batch_size` à **1** et/ou réduisez `max_seq_length`.&#x20;
* Conservez `use_`[`gradient_checkpointing`](/docs/fr/blog/500k-context-length-fine-tuning.md#unsloth-gradient-checkpointing-enhancements)`="unsloth"` activé (c’est conçu pour réduire l’utilisation de la VRAM et augmenter la longueur du contexte).
  {% endhint %}

**Exemple de chargeur pour MoE (LoRA bf16) :**

```python
import os
import torch
from unsloth import FastModel

model, tokenizer = FastModel.from_pretrained(
    model_name = "unsloth/Gemma-4-26B-A4B-it",
    max_seq_length = 2048,
    load_in_4bit = False,     # La QLoRA MoE n’est pas recommandée, le dense 31B convient
    load_in_16bit = True,     # LoRA bf16/16 bits
    full_finetuning = False,
)
```

Une fois chargé, vous attacherez des adaptateurs LoRA et entraînerez de manière similaire à l’exemple SFT ci-dessus.

### Apprentissage par renforcement (RL)

Vous pouvez maintenant entraîner Gemma 4 avec RL, GSPO, GRPO, etc. avec [notre notebook gratuit](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen3_5_\(4B\)_Vision_GRPO.ipynb).

{% columns %}
{% column %}
Gemma 4 E2B RL fonctionne sur 9 Go.

{% embed url="<https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen3_5_(4B)_Vision_GRPO.ipynb>" %}

Le but du notebook est de faire apprendre à Gemma 4 à résoudre des grilles de Sudoku en utilisant [GRPO](/docs/fr/commencer/reinforcement-learning-rl-guide.md#from-rlhf-ppo-to-grpo-and-rlvr).

Le modèle élaborera une stratégie pour remplir les cases vides, et nous le récompenserons pour les placements corrects et la résolution de puzzles valides.

Vous pouvez exécuter Gemma 4 RL avec Unsloth même s’il n’est pas pris en charge par vLLM, en définissant `fast_inference=False` lors du chargement du modèle :
{% endcolumn %}

{% column %}

<figure><img src="/files/6410670644afbeb75e73c5c57fd4d9930539c2d4" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

```python
from unsloth import FastLanguageModel

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/gemma-4-E2B-it",
    fast_inference=False,
)
```

### Affinage MoE (26B-A4B)

Le **26B-A4B** modèle constitue le juste milieu entre vitesse et qualité dans la gamme Gemma 4. Comme il s’agit d’un **MoE** modèle avec seulement un sous-ensemble de paramètres actifs par jeton, une approche d’affinage prudente consiste à :

* utiliser **LoRA** plutôt qu’un affinage complet
* privilégier **LoRA 16 bits / bf16** si la mémoire le permet
* commencer d’abord avec des contextes plus courts et des rangs plus faibles
* ne monter en échelle qu’une fois le pipeline stabilisé

Si votre objectif est la meilleure qualité possible et que vous disposez de plus de mémoire, utilisez **31B** à la place.

### Affinage multimodal (E2B / E4B)

Parce que **E2B** et **E4B** prennent en charge **image** et **audio**, ils constituent les principales variantes de Gemma 4 pour l’affinage multimodal.

* chargez le modèle multimodal avec `FastVisionModel`
* conservez `finetune_vision_layers = False` d’abord
* affinez uniquement les couches de langage, d’attention et MLP
* activez ensuite les couches de vision ou d’audio si votre tâche l’exige

#### Exemple de LoRA multimodale Gemma 4 :

{% code expandable="true" %}

````python
from unsloth import FastVisionModel # FastLanguageModel pour les LLM
import torch

model, processor = FastVisionModel.from_pretrained(
    "unsloth/gemma-4-26B-A4B-it",
    load_in_4bit = True, # Utilisez le 4 bits pour réduire l’utilisation de la mémoire. False pour LoRA 16 bits.
    use_gradient_checkpointing = "unsloth", # True ou "unsloth" pour un long contexte
)

"""Nous ajoutons maintenant des adaptateurs LoRA pour un affinage efficace en paramètres, ce qui nous permet d’entraîner efficacement seulement 1 % de tous les paramètres du modèle.

**[NOUVEAU]** Nous prenons également en charge l’affinage uniquement du composant de vision, uniquement du composant de langage, ou des deux. De plus, vous pouvez choisir d’affiner les modules d’attention, les couches MLP, ou les deux !
"""

model = FastVisionModel.get_peft_model(
    model,
    finetune_vision_layers     = True, # False si vous n’affinez pas les couches de vision
    finetune_language_layers   = True, # False si vous n’affinez pas les couches de langage
    finetune_attention_modules = True, # False si vous n’affinez pas les couches d’attention
    finetune_mlp_modules       = True, # False si vous n’affinez pas les couches MLP

    r = 32,                           # Plus la valeur est grande, plus la précision est élevée, mais cela peut surapprendre
    lora_alpha = 32,                  # L’alpha recommandé est au moins égal à r
    lora_dropout = 0,
    bias = "none",
    random_state = 3407,
    use_rslora = False,               # Nous prenons en charge LoRA à rang stabilisé
    loftq_config = None,               # Et LoftQ
    target_modules = "all-linear",    # Facultatif désormais ! Peut spécifier une liste si nécessaire
)

"""<a name="Data"></a>
### Préparation des données
Nous utiliserons un ensemble de données échantillonné de formules mathématiques manuscrites. L’objectif est de convertir ces images dans un format lisible par ordinateur — en particulier LaTeX — afin qu’elles puissent être rendues. C’est particulièrement utile pour les expressions complexes.

Vous pouvez accéder au jeu de données [ici](https://huggingface.co/datasets/unsloth/LaTeX_OCR). Le jeu de données complet est [ici](https://huggingface.co/datasets/linxy/LaTeX_OCR).
"""

from datasets import load_dataset
dataset = load_dataset("unsloth/LaTeX_OCR", split = "train")

"""Prenons un aperçu du jeu de données. Nous examinerons la deuxième image et sa légende correspondante."""

dataset

dataset[2]["image"]

dataset[2]["text"]

"""Nous pouvons aussi rendre le LaTeX directement dans le navigateur !"""

from IPython.display import display, Math, Latex

latex = dataset[3]["text"]
display(Math(latex))

"""Pour mettre en forme le jeu de données, toutes les tâches d’affinage vision devraient suivre ce format :

```python
[
    {
        "role": "user",
        "content": [
            {"type": "text", "text": instruction},
            {"type": "image", "image": sample["image"]},
        ],
    },
    {
        "role": "user",
        "content": [
            {"type": "text", "text": instruction},
            {"type": "image", "image": sample["image"]},
        ],
    },
]
```
"""

instruction = "Écrivez la représentation LaTeX pour cette image."

def convert_to_conversation(sample):
    conversation = [
        {
            "role": "user",
            "content": [
                {"type": "text", "text": instruction},
                {"type": "image", "image": sample["image"]},
            ],
        },
        {"role": "assistant", "content": [{"type": "text", "text": sample["text"]}]},
    ]
    return {"messages": conversation}
pass

"""Convertissons le jeu de données dans le format « correct » pour l’affinage :"""

converted_dataset = [convert_to_conversation(sample) for sample in dataset]

"""Le premier exemple est maintenant structuré comme ci-dessous :"""

converted_dataset[0]

"""Prenons le modèle de chat Gemma 4 avec le template d’instructions et utilisons-le dans notre modèle de base"""

from unsloth import get_chat_template

processor = get_chat_template(
    processor,
    "gemma-4-thinking"
)

"""Avant l’affinage, évaluons les performances du modèle de base. Nous ne nous attendons pas à de très bons résultats, car il n’a encore jamais rencontré ce modèle de chat."""

image = dataset[2]["image"]
instruction = "Écrivez la représentation LaTeX pour cette image."

messages = [
    {
        "role": "user",
        "content": [{"type": "image"}, {"type": "text", "text": instruction}],
    }
]
input_text = processor.apply_chat_template(messages, add_generation_prompt = True)
inputs = processor(
    image,
    input_text,
    add_special_tokens = False,
    return_tensors = "pt",
).to("cuda")

from transformers import TextStreamer

text_streamer = TextStreamer(processor, skip_prompt = True)
result = model.generate(**inputs, streamer = text_streamer, max_new_tokens = 128,
                        use_cache = True, temperature = 1.0, top_p = 0.95, top_k = 64)

"""Vous pouvez voir que c’est absolument terrible ! Cela ne suit pas du tout les instructions

<a name="Train"></a>
### Entraîner le modèle
Maintenant, entraînons notre modèle. Nous effectuons 60 étapes pour aller plus vite, mais vous pouvez définir `num_train_epochs=1` pour une exécution complète, et définir `max_steps=None`. Nous prenons également en charge `DPOTrainer` et `GRPOTrainer` pour l’apprentissage par renforcement !!

Nous utilisons notre nouveau `UnslothVisionDataCollator` qui nous aidera dans notre configuration d’affinage vision.
"""

from unsloth.trainer import UnslothVisionDataCollator
from trl import SFTTrainer, SFTConfig

trainer = SFTTrainer(
    model = model,
    train_dataset = converted_dataset,
    processing_class = processor.tokenizer,
    data_collator = UnslothVisionDataCollator(model, processor),
    args = SFTConfig(
        per_device_train_batch_size = 1,
        gradient_accumulation_steps = 4,
        max_grad_norm = 0.3,
        warmup_ratio = 0.03,
        max_steps = 60,
        # num_train_epochs = 2, # Définissez ceci à la place de max_steps pour des exécutions complètes
        learning_rate = 2e-4,
        logging_steps = 1,
        save_strategy = "steps",
        optim = "adamw_8bit",
        weight_decay = 0.001,
        lr_scheduler_type = "cosine",
        seed = 3407,
        output_dir = "outputs",
        report_to = "none", # Pour Weights and Biases ou autres

        # Vous DEVEZ mettre les éléments ci-dessous pour l’affinage vision :
        remove_unused_columns = False,
        dataset_text_field = "",
        dataset_kwargs = {"skip_prepare_dataset": True},
        max_length = 2048,
    )
)

trainer_stats = trainer.train()
````

{% endcode %}

#### Format d’exemple d’image

Rappelez-vous : pour les invites multimodales Gemma 4, placez l’image **avant** l’instruction textuelle.

{% code expandable="true" %}

```json
{
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "image", "image": "/path/to/image OR object"},
        {"type": "text", "text": "Extrayez tout le texte de ce reçu. Retournez les lignes d’articles, le total, le commerçant et la date sous forme de JSON."}
      ]
    },
    {
      "role": "assistant",
      "content": [
        {"type": "text", "text": "{\"merchant\": \"Example Store\", \"total\": \"19.99\"}"}
      ]
    }
  ]
}
```

{% endcode %}

#### Format d’exemple audio

L’audio est pour **E2B / E4B** uniquement. Gardez les clips courts et spécifiques à la tâche.

{% code expandable="true" %}

```json
{
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "audio", "audio": "/path/to/audio OR object"},
        {"type": "text", "text": "Transcrivez le segment vocal suivant en anglais en texte anglais. Ne renvoyez que la transcription."}
      ]
    },
    {
      "role": "assistant",
      "content": [
        {"type": "text", "text": "Bonjour à tous et bon retour."}
      ]
    }
  ]
}
```

{% endcode %}

### Enregistrement / exportation du modèle affiné

Vous pouvez consulter nos guides spécifiques d’inférence / déploiement pour [Unsloth Studio](/docs/fr/nouveau/studio/export.md), [llama.cpp](/docs/fr/notions-de-base/inference-and-deployment/saving-to-gguf.md), [vLLM](/docs/fr/notions-de-base/inference-and-deployment/vllm-guide.md), [llama-server](/docs/fr/notions-de-base/inference-and-deployment/llama-server-and-openai-endpoint.md), [Ollama](/docs/fr/notions-de-base/inference-and-deployment/saving-to-ollama.md) ou [SGLang](/docs/fr/notions-de-base/inference-and-deployment/sglang-guide.md).

#### Enregistrer en GGUF

Unsloth prend en charge l’enregistrement direct en GGUF :

```python
model.save_pretrained_gguf("directory", tokenizer, quantization_method = "q4_k_m")
model.save_pretrained_gguf("directory", tokenizer, quantization_method = "q8_0")
model.save_pretrained_gguf("directory", tokenizer, quantization_method = "f16")
```

Ou pousser des GGUF vers Hugging Face :

```python
model.push_to_hub_gguf("hf_username/directory", tokenizer, quantization_method = "q4_k_m")
model.push_to_hub_gguf("hf_username/directory", tokenizer, quantization_method = "q8_0")
```

Si le modèle exporté se comporte moins bien dans un autre environnement d’exécution, Unsloth indique la cause la plus fréquente : **template de chat incorrect / jeton EOS au moment de l’inférence** (vous devez utiliser le même template de chat que celui avec lequel vous avez entraîné).

Pour plus de détails, lisez nos guides d’inférence :

{% columns %}
{% column width="50%" %}
{% content-ref url="/pages/44b6f06033c7dbf3b6521a33337058e295acc604" %}
[Inférence et déploiement](/docs/fr/notions-de-base/inference-and-deployment.md)
{% endcontent-ref %}

{% content-ref url="/pages/0ce33fc68eed069d43cdcfb76b9793ce71c64c1f" %}
[GGUF & llama.cpp](/docs/fr/notions-de-base/inference-and-deployment/saving-to-gguf.md)
{% endcontent-ref %}
{% endcolumn %}

{% column width="50%" %}
{% content-ref url="/pages/817a1275219e1e8d86fe100d223ac4b0862ab3a1" %}
[Model Export](/docs/fr/nouveau/studio/export.md)
{% endcontent-ref %}

{% content-ref url="/pages/682151c53afcf1f6d611eb29ad62b7182b5187ea" %}
[vLLM](/docs/fr/notions-de-base/inference-and-deployment/vllm-guide.md)
{% endcontent-ref %}
{% endcolumn %}
{% endcolumns %}

### Bonnes pratiques pour les données Gemma 4

Gemma 4 comporte quelques détails de formatage à garder à l’esprit.

#### 1. Utilisez les rôles de chat standards

Gemma 4 utilise les rôles standard :

* `system`
* `user`
* `assistant`

Cela signifie que votre jeu de données SFT doit être rédigé dans un format de chat classique plutôt que dans les anciens formats de rôles spécifiques à Gemma.

#### 2. Le mode réflexion est explicite

Si vous souhaitez conserver un comportement de type réflexion pendant le SFT :

* gardez le format cohérent
* décidez si vous voulez entraîner sur **des blocs de pensée visibles** ou sur **les réponses finales uniquement**
* faites **pas** mélanger plusieurs formats de pensée incompatibles dans le même jeu de données

Pour la plupart des assistants de production, la configuration la plus simple consiste à affiner sur la **réponse finale visible uniquement**.

#### 3. Règle des conversations multi-tours

Pour les conversations multi-tours, ne conservez que la **réponse finale visible** dans l’historique de conversation. Ne **pas** réinjectez pas les blocs de pensée précédents dans les tours suivants.


---

# 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, and the optional `goal` query parameter:

```
GET https://unsloth.ai/docs/fr/modeles/gemma-4/train.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
