> 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 de 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,5x plus rapide** avec **\~60 % de VRAM en moins** que les configurations FA2 (sans 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="/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>

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

| [ (Unsloth)](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)✨ notebook :

Vous pouvez voir d'autres [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 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**/sauvegarde des modèles en GGUF, etc. et affinage complet **(FFT)** fonctionne également.

### :bug: Corrections de bugs + conseils

{% 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 sur Gemma-3N, Llama Vision, les modèles de vision Mistral et d'autres.

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

#### :grapes:L'accumulation de gradient peut gonfler 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 de gradient ne soit pas correctement prise en compte - nous avons **corrigé cela dans Unsloth et Unsloth Studio.**

Pour en savoir plus sur l'accumulation de gradient, consultez notre article de correction de bug sur l'accumulation de gradient : <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 : index de liste hors limites
```

Le coupable est ci-dessous :

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

Où 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 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 fait chaque tutoriel QLoRA, et comme `gradient_checkpointing=True` l'impose), `Gemma4TextModel.forward` saute la construction du cache, donc les couches partageant le KV retombent sur le 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é binaire exacte, les 9 tokens identiques)
```

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

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

```python
RuntimeError : la valeur ne peut pas être convertie en type c10::Half sans dépassement
```

C'é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 voulez **préserver la capacité de raisonnement** capacité, vous pouvez mélanger des exemples de type raisonnement avec des réponses directes (conservez au minimum 75 % de raisonnement). Sinon, vous pouvez le désactiver complètement.\n\nUtilisez `gemma-4` pour le modèle de conversation sans réflexion et `gemma-4-thinking` pour la variante avec réflexion.\nUtilisez la version avec réflexion pour les 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" : "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 minime. 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 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 sur 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 %}

#### Installez 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'intégration pour choisir un modèle, un jeu de données et les 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 du contexte comme vous le souhaitez.

<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 lancer 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.\nUne fois terminé, le modèle sera enregistré automatiquement.

<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 les 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 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 également créé des notebooks 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 plutôt l'inférence Unsloth. Suivez nos** [**RL vision**](/docs/fr/commencer/reinforcement-learning-rl-guide/vision-reinforcement-learning-vlm-rl.md) **exemples de notebook.**
{% endhint %}

Voici une recette SFT texte autonome pour Gemma-4-26B-A4B-it. Il s'agit uniquement de texte - consultez aussi notre [affinage vision](/docs/fr/bases/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 la détection automatique
    max_seq_length = 8192, # Choisissez n'importe quelle valeur pour un long contexte !
    load_in_4bit = True,  # Quantification 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 à accès restreint
)

"""# Gemma 4 peut traiter du texte, de la vision et de 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 d'aide 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)

"""# Affinons Gemma 4 !

Pour l'instant, vous pouvez affiner les parties vision et texte via la 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,  # À laisser activé !
    finetune_attention_modules = True,  # L'attention est bonne pour GRPO
    finetune_mlp_modules       = True,  # À laisser toujours activé !

    r = 8,           # Plus grand = meilleure précision, mais risque de surapprentissage
    lora_alpha = 8,  # Alpha recommandé : au moins égal à r
    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 conversation. Nous prenons en charge `zephyr, chatml, mistral, llama, alpaca, vicuna, vicuna_old, phi3, llama3, phi4, qwen2.5, gemma3, gemma-4` et bien d'autres.
"""

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

"""Nous prenons 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 d'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 conversation `Gemma-3` aux conversations et l'enregistrer dans `text`. Nous supprimons le jeton `<bos>` à l'aide de removeprefix(`'<bos>'`) puisque nous effectuons un affinage. 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 ce que donne le modèle de conversation ! Remarquez qu'il n'y a pas de jeton `<bos>`, car 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 faisons 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`.
"""

from trl import SFTTrainer, SFTConfig
trainer = SFTTrainer(
    model = model,
    tokenizer = tokenizer,
    train_dataset = dataset,
    eval_dataset = None, # Vous pouvez configurer une évaluation !
    args = SFTConfig(
        dataset_text_field = "text",
        per_device_train_batch_size = 1,
        gradient_accumulation_steps = 4, # Utilisez l'accumulation de gradient pour simuler la taille de lot !
        warmup_steps = 5,
        # num_train_epochs = 1, # Définissez cela pour un entraînement complet.
        max_steps = 60,
        learning_rate = 2e-4, # Réduisez à 2e-5 pour les entraînements longs
        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 également 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 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 effectué ! Réimprimons la 100e ligne. Remarquez que l'exemple ne contient qu'un seul `<bos>`, comme prévu !"""

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

"""Imprimons maintenant l'exemple masqué - vous ne devriez voir que la réponse :"""

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 manquez de mémoire :

* Réduisez `per_device_train_batch_size` en **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é (il est conçu pour réduire l'utilisation de la VRAM et augmenter la longueur du 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,     # Le QLoRA MoE n’est pas recommandé, un 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 de 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>" %}

L’objectif du notebook est d’apprendre à Gemma 4 à résoudre des 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 cellules vides, et nous le récompenserons pour les placements corrects et l’achèvement 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="/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,
)
```

### Ajustement fin MoE (26B-A4B)

Le **26B-A4B** est le compromis vitesse / qualité de 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 d’ajustement fin consiste à :

* utiliser **LoRA** plutôt qu’un ajustement fin 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
* augmenter l’échelle seulement après stabilisation du pipeline

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

### Ajustement fin multimodal (E2B / E4B)

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

* chargez le modèle multimodal avec `FastVisionModel`
* gardez `finetune_vision_layers = False` d’abord
* n’ajustez finement que les couches de langage, d’attention et de MLP
* activez les couches de vision ou d’audio plus tard si votre tâche en a besoin

#### Exemple de LoRA multimodal Gemma 4 :

{% code expandable="true" %}

````python
from unsloth import FastVisionModel # pour les LLMs
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 le LoRA 16 bits.
    use_gradient_checkpointing = "unsloth", # True ou "unsloth" pour les longs contextes
)

"""Nous ajoutons maintenant des adaptateurs LoRA pour un ajustement fin 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’ajustement fin uniquement de la composante vision, uniquement de la composante langage, ou des deux. De plus, vous pouvez choisir d’ajuster finement les modules d’attention, les couches MLP, ou les deux !
"""

model = FastVisionModel.get_peft_model(
    model,
    finetune_vision_layers     = True, # False si vous n’ajustez pas finement les couches de vision
    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 = 32,                           # Plus il est élevé, plus la précision est grande, mais il peut y avoir surapprentissage
    lora_alpha = 32,                  # alpha recommandé = r au minimum
    lora_dropout = 0,
    bias = "none",
    random_state = 3407,
    use_rslora = False,               # Nous prenons en charge le LoRA à rang stabilisé
    loftq_config = None,               # Et LoftQ
    target_modules = "all-linear",    # Facultatif maintenant ! Vous pouvez 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 en un format lisible par ordinateur—plus précisément en 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 afficher 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 d’ajustement fin 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 = "Écrivez 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 au format « correct » pour l’ajustement fin :"""

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 d’instructions 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 l’ajustement fin, é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 chat."""

image = dataset[2]["image"]
instruction = "Écrivez 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 également en charge `DPOTrainer` et `GRPOTrainer` pour l’apprentissage par renforcement !!

Nous utilisons notre nouveau `UnslothVisionDataCollator`, qui nous aidera dans notre configuration d’ajustement fin 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 cela à la place de max_steps pour les exécutions d’entraînement 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 & Biases ou autres

        # Vous DEVEZ inclure les éléments ci-dessous pour l’ajustement fin 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 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\": \"Magasin d’exemple\", \"total\": \"19.99\"}"}
      ]
    }
  ]
}
```

{% endcode %}

#### Format d’exemple audio

L’audio est réservé à **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 OU objet"},
        {"type": "text", "text": "Transcrivez le segment de discours suivant, en anglais, en texte anglais. Ne renvoyez que la transcription."}
      ]
    },
    {
      "role": "assistant",
      "content": [
        {"type": "text", "text": "Bonjour à tous et bon retour."}
      ]
    }
  ]
}
```

{% endcode %}

### Sauvegarde / export du modèle ajusté finement

Vous pouvez consulter nos guides spécifiques d’inférence / de déploiement pour [Unsloth Studio](/docs/fr/nouveau/studio/export.md), [llama.cpp](/docs/fr/bases/inference-and-deployment/saving-to-gguf.md), [vLLM](/docs/fr/bases/inference-and-deployment/vllm-guide.md), [llama-server](/docs/fr/bases/inference-and-deployment/llama-server-and-openai-endpoint.md), [Ollama](/docs/fr/bases/inference-and-deployment/saving-to-ollama.md) ou [SGLang](/docs/fr/bases/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 publier les GGUF sur 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 signale la cause la plus courante : **modèle de chat incorrect / jeton EOS au moment de l’inférence** (vous devez utiliser le même modèle de chat que celui avec lequel vous l’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/bases/inference-and-deployment.md)
{% endcontent-ref %}

{% content-ref url="/pages/0ce33fc68eed069d43cdcfb76b9793ce71c64c1f" %}
[GGUF & llama.cpp](/docs/fr/bases/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/bases/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é au format de chat standard plutôt qu’aux 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 l’ajustement fin SFT :

* gardez un format cohérent
* décidez si vous voulez entraîner sur **des blocs de pensée visibles** ou sur **uniquement les réponses finales**
* faites **pas** mélangez 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 à effectuer l’ajustement fin sur **uniquement la réponse finale visible**.

#### 3. Règle 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 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.
