# Guide de fine-tuning de Gemma 4

Vous pouvez désormais entraîner le modèle de Google [Gemma 4](https://unsloth.ai/docs/fr/modeles/qwen3.5) E2B, E4B, 26B-A4B et 31B avec [**Unsloth**](https://github.com/unslothai/unsloth). Unsloth prend en charge tous les réglages fins de vision, de texte, d’audio et de RL pour Gemma 4.

* Unsloth entraîne Gemma 4 **\~1,5x plus vite** avec **\~60 % de VRAM en moins** qu’avec des configurations FA2 (aucune perte de précision)
* Nous avons corrigé de nombreux [bugs universels pour l’entraînement de Gemma 4](#bug-fixes--tips) (non dérivés d’Unsloth).
* Gemma 4 E2B s’entraîne sur **8 Go de VRAM**. E4B nécessite 10 Go de VRAM.

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

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

| [**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](https://unsloth.ai/docs/fr/nouveau/studio)✨ notebook :

Vous pouvez voir plus de [notebooks 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 sur 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**/enregistrement des modèles au format GGUF, etc. et le fine-tuning complet **(FFT)** fonctionne également.

### :bug: Corrections de bugs + astuces

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

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

#### :grapes:L’accumulation de gradients peut gonfler vos pertes

{% columns %}
{% column %}

<div data-with-frame="true"><figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FET1GgLeZanVHDpPXLkM9%2FTransformers%20%2B%20TRL%20%2B%20Gemma-4.png?alt=media&#x26;token=0149149f-4d34-4bcb-a545-42e12d5127eb" alt=""><figcaption></figcaption></figure></div>
{% endcolumn %}

{% column %}

<div data-with-frame="true"><figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FZZola3h7ujfqz87VdnQm%2FUnsloth%20%2B%20Gemma-4.png?alt=media&#x26;token=37fc2b61-ae5b-4203-b9a7-388439aefae5" 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 de gradients ne soit pas correctement prise en compte - nous avons **corrigé cela dans Unsloth et Unsloth Studio.**

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

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

Vous pourriez voir cette erreur lors de l’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
```

Le coupable 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 livrés 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 le tout premier passage avant de l’attention plante dans `Cache.update`.

#### :no\_entry: `use_cache = True` la génération était incohérente 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 aberrants #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 les KV pour que les couches suivantes les réutilisent. Lorsque `use_cache=False` (comme le fait chaque tutoriel QLoRA, et comme `gradient_checkpointing=True` l’impose), `Gemma4TextModel.forward` saute la construction du cache, donc les couches KV partagées retombent sur un recalcul local de K et V à partir des états cachés courants. Les logits deviennent aberrants et la perte d’entraînement diverge.

**Avant (`unsloth/gemma-4-E2B-it`, prompt « What is 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 identiques)
```

#### :radio:Dépassement fp16 pour l’audio

`Gemma4AudioAttention` utilise `config.attention_invalid_logits_value = -1e9` dans un appel `masked_fill` . Sur fp16 (Tesla T4), -1e9 dépasse la valeur max 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
)
```

#### 💡Astuces pour Gemma-4

1. Si vous voulez **préserver la capacité de raisonnement** , vous pouvez mélanger des exemples de type raisonnement avec des réponses directes (gardez au minimum 75 % de raisonnement). Sinon, vous pouvez l’émettre entièrement.\
   \
   Utilisez `gemma-4` pour le modèle de chat sans réflexion et `gemma-4-thinking` pour la variante avec réflexion.\
   Utilisez la version avec réflexion pour les plus grands modèles 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" : "What is 2+2?"},
   ], tokenize = False, enable_thinking = True, add_generation_prompt = True)
   </code></pre>

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

   Réflexion désactivée :

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

   Affichera `<bos><|turn>user\nWhat is 2+2?<turn|>\n<|turn>model\n<|channel>thought\n<channel|>`
3. Gemma 4 est puissant pour le réglage fin 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 due à la quantification est minuscule. Gemma 4 E4B LoRA est encore meilleur.
5. Après le réglage fin, vous pouvez exporter vers [GGUF](#saving-export-your-fine-tuned-model) (pour llama.cpp/Unsloth/Ollama/etc.)

### ⚡Démarrage rapide

#### 🦥 Guide Unsloth Studio

{% columns %}
{% column %}
Gemma 4 peut être exécuté et affiné dans [Unsloth Studio](https://unsloth.ai/docs/fr/nouveau/studio), 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="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FpZlhqoILYOzznGpbudUk%2Funsloth%20studio%20gemma%20graphic.png?alt=media&#x26;token=75e41585-e363-45cf-a87e-4d02960766ed" 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 de démarrage 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="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FpZlhqoILYOzznGpbudUk%2Funsloth%20studio%20gemma%20graphic.png?alt=media&#x26;token=75e41585-e363-45cf-a87e-4d02960766ed" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}

{% step %}

#### Suivre la progression de l’entraînement

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

<div data-with-frame="true"><figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FeBrnu9zxARIkhOHzd0pq%2FScreenshot%202026-04-07%20at%205.53.32%E2%80%AFAM.png?alt=media&#x26;token=dae77231-5020-4e8c-b2b8-cc49a98a9edf" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}

{% step %}

#### Exporter votre modèle affiné

Une fois terminé, Unsloth Studio vous permet d’exporter le modèle aux formats GGUF, safetensor, etc.

<div data-with-frame="true"><figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FBtpx58zCdrOD4zB4DPSC%2FScreenshot%202026-04-07%20at%206.12.41%E2%80%AFAM.png?alt=media&#x26;token=05f05af2-5f7f-4b91-9c99-21d6a9b04935" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}

{% step %}

#### Comparer le modèle affiné au modèle d’origine

Cliquez sur `Mode comparaison` pour comparer l’adaptateur LoRA et le modèle d’origine.

<div data-with-frame="true"><figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fvm2CBSg7QBkKwTMKutyr%2FScreenshot%202026-04-07%20at%206.14.50%E2%80%AFAM.png?alt=media&#x26;token=8c9c159f-9d5b-4468-8984-681d19ebc427" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}
{% endstepper %}

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

Nous avons créé des notebooks 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 notebooks pour les modèles Gemma 4 plus grands, mais ils nécessitent 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**](https://unsloth.ai/docs/fr/commencer/reinforcement-learning-rl-guide)**, cela fonctionne dans Unsloth si vous désactivez l’inférence vLLM rapide et utilisez plutôt l’inférence Unsloth. Suivez nos exemples de notebook** [**RL Vision**](https://unsloth.ai/docs/fr/commencer/reinforcement-learning-rl-guide/vision-reinforcement-learning-vlm-rl) **.**
{% endhint %}

Ci-dessous se trouve une recette SFT texte autonome pour Gemma-4-26B-A4B-it. Il s’agit uniquement de texte - voir aussi notre section de [réglage fin de la vision](https://unsloth.ai/docs/fr/bases/vision-fine-tuning) 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", # Remplacez ceci par unsloth/gemma-4-E2B-it, etc.
    dtype = None, # None pour la détection automatique
    max_seq_length = 8192, # Choisissez n’importe quelle longueur pour un long contexte !
    load_in_4bit = True,  # Quantification 4 bits pour réduire la mémoire
    full_finetuning = False, # [NOUVEAU !] Nous avons maintenant le fine-tuning 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 !

Voyons d’abord comment Gemma 4 peut gérer des entrées multimodales. Nous utilisons les paramètres recommandés de 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" : "Dans quels films cet animal apparaît-il ?" }
    ]
}]
# Vous devrez peut-être attendre 1 minute pour le compilateur automatique d’Unsloth
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)

"""# Finetunons Gemma 4 !

Vous pouvez pour l’instant affiner les parties vision et texte via 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 du texte uniquement !
    finetune_language_layers   = True,  # Doit rester activé !
    finetune_attention_modules = True,  # L’attention est bonne pour GRPO
    finetune_mlp_modules       = True,  # Doit toujours rester activé !

    r = 8,           # Plus grand = meilleure précision, 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 réglages fins 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 rend 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 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 à des fins de réglage fin !"""

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 faisons du réglage fin. Le Processor 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 comment le modèle de chat a fonctionné ! Notez qu’il n’y a pas de jeton `<bos>` car le tokenizer du processor en ajoutera un."""

dataset[100]["text"]

"""<a name="Train"></a>
### Entraîner le modèle
Maintenant, entraînons notre modèle. Nous faisons 60 étapes pour aller plus vite, mais vous pouvez définir `num_train_epochs=1` pour une exécution complète, et désactiver `max_steps=None`.
"""

from trl import SFTTrainer, SFTConfig
trainer = SFTTrainer(
    model = model,
    tokenizer = tokenizer,
    train_dataset = dataset,
    eval_dataset = None, # Peut être configuré pour l’évaluation !
    args = SFTConfig(
        dataset_text_field = "text",
        per_device_train_batch_size = 1,
        gradient_accumulation_steps = 4, # Utilisez l’accumulation de gradients pour simuler la taille du lot !
        warmup_steps = 5,
        # num_train_epochs = 1, # À définir pour un entraînement complet.
        max_steps = 60,
        learning_rate = 2e-4, # Réduisez à 2e-5 pour les longs entraînements
        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 à augmenter la précision des réglages fins !"""

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 effectué ! Réimprimons la 100e ligne. Remarquez que l’échantillon n’a qu’un seul `<bos>` comme prévu !"""

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

"""Maintenant imprimons 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 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 avez une erreur OOM :

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

**Exemple de chargement 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 désormais 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>" %}

L’objectif du notebook est d’apprendre à Gemma 4 à résoudre des Sudoku en utilisant [GRPO](https://unsloth.ai/docs/fr/commencer/reinforcement-learning-rl-guide#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 grilles 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="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fw08jKlXDLJji37JZPYNx%2Fgemma%204%20rl%20sodoku%20nb.png?alt=media&#x26;token=379c607d-60b1-4b35-bcdd-bf6a86911f85" 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,
)
```

### Réglage fin MoE (26B-A4B)

Le **26B-A4B** modèle est le compromis 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 prudente de réglage fin est la suivante :

* utilisez **LoRA** plutôt qu’un réglage fin complet
* préférez **LoRA 16 bits / bf16** si la mémoire le permet
* commencez d’abord avec des contextes plus courts et des rangs plus petits
* montez en échelle seulement une fois que le pipeline est stable

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

### Réglage fin multimodal (E2B / E4B)

Parce que **E2B** et **E4B** prennent en charge **l’image** et **l’audio**, ce sont les principales variantes de Gemma 4 pour le réglage fin multimodal.

* chargez le modèle multimodal avec `FastVisionModel`
* gardez `finetune_vision_layers = False` d’abord
* affinez uniquement les couches de langage, d’attention et de MLP
* activez plus tard les couches de vision ou d’audio si votre tâche le nécessite

#### 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 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 réglage fin efficace en paramètres, ce qui nous permet de n’entraîner efficacement que 1 % de tous les paramètres du modèle.

**[NOUVEAU]** Nous prenons aussi en charge le réglage fin uniquement du composant vision, uniquement du composant 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 grand = meilleure précision, mais risque de surapprentissage
    lora_alpha = 32,                  # Alpha recommandé = r au minimum
    lora_dropout = 0,
    bias = "none",
    random_state = 3407,
    use_rslora = False,               # Nous prenons en charge LoRA stabilisé en rang
    loftq_config = None,               # Et LoftQ
    target_modules = "all-linear",    # Optionnel maintenant ! Peut spécifier une liste si nécessaire
)

"""<a name="Data"></a>
### Préparation des données
Nous utiliserons un échantillon de jeu de données de formules mathématiques manuscrites. L’objectif est de convertir ces images dans un format lisible par ordinateur — plus précisément 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 formater le jeu de données, toutes les tâches de réglage fin de vision doivent 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 = "Rédige la représentation LaTeX de 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 le fine-tuning :"""

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

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

converted_dataset[0]

"""Prenons le modèle de chat à instruction Gemma 4 et utilisons-le dans notre modèle de base"""

from unsloth import get_chat_template

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

"""Avant le fine-tuning, évaluons les performances du modèle de base. Nous ne nous attendons pas à de bons résultats, car il n’a encore jamais rencontré ce modèle de conversation."""

image = dataset[2]["image"]
instruction = "Rédige la représentation LaTeX de 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)

"""On voit que c’est absolument terrible ! Il 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 accélérer les choses, mais vous pouvez définir `num_train_epochs=1` pour une exécution complète, et désactiver `max_steps=None`. Nous prenons aussi en charge `DPOTrainer` et `GRPOTrainer` pour l’apprentissage par renforcement !!

Nous utilisons notre nouveau `UnslothVisionDataCollator`, qui nous aidera dans notre configuration de fine-tuning 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 entraînements complets
        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 d’autres

        # Vous DEVEZ inclure les éléments ci-dessous pour le fine-tuning 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 prompts multimodaux Gemma 4, placez l’image **avant** l’instruction textuelle.

{% code expandable="true" %}

```json
{
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "image", "image": "/chemin/vers/image OU objet"},
        {"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 réservé à **E2B / E4B** uniquement. Gardez les extraits courts et spécifiques à la tâche.

{% code expandable="true" %}

```json
{
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "audio", "audio": "/chemin/vers/audio OU objet"},
        {"type": "text", "text": "Transcrivez le segment de discours suivant en anglais en texte anglais. N’affichez que la transcription."}
      ]
    },
    {
      "role": "assistant",
      "content": [
        {"type": "text", "text": "Bonjour à tous et bon retour."}
      ]
    }
  ]
}
```

{% endcode %}

### Sauvegarde / exportation du modèle fine-tuné

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

#### Enregistrer au format GGUF

Unsloth prend en charge l’enregistrement direct au format 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 courante : **mauvais modèle de conversation / jeton EOS au moment de l’inférence** (vous devez utiliser le même modèle de conversation 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="../../bases/inference-and-deployment" %}
[inference-and-deployment](https://unsloth.ai/docs/fr/bases/inference-and-deployment)
{% endcontent-ref %}

{% content-ref url="../../bases/inference-and-deployment/saving-to-gguf" %}
[saving-to-gguf](https://unsloth.ai/docs/fr/bases/inference-and-deployment/saving-to-gguf)
{% endcontent-ref %}
{% endcolumn %}

{% column width="50%" %}
{% content-ref url="../../nouveau/studio/export" %}
[export](https://unsloth.ai/docs/fr/nouveau/studio/export)
{% endcontent-ref %}

{% content-ref url="../../bases/inference-and-deployment/vllm-guide" %}
[vllm-guide](https://unsloth.ai/docs/fr/bases/inference-and-deployment/vllm-guide)
{% 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 standard

Gemma 4 utilise les rôles standards :

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

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

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

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

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

Pour la plupart des assistants de production, la configuration la plus simple consiste à effectuer le fine-tuning sur **la réponse finale visible uniquement**.

#### 3. Règle du multi-tour

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


---

# Agent Instructions: Querying This Documentation

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

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

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

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

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