# Fine-tuning de LLMs sur GPU Intel avec Unsloth

Vous pouvez maintenant affiner des LLMs sur votre appareil Intel local avec Unsloth ! Lisez notre guide pour savoir exactement comment commencer à entraîner votre propre modèle personnalisé.

Avant de commencer, assurez-vous d'avoir :

* **GPU Intel :** Data Center GPU Max Series, Arc Series ou Intel Ultra AIPC
* **OS :** Linux (Ubuntu 22.04+ recommandé) ou Windows 11 (recommandé)
* **Windows uniquement :** Installez Intel oneAPI Base Toolkit 2025.2.1 (sélectionnez la version 2025.2.1)
* **Pilote graphique Intel :** Dernier pilote recommandé pour Windows/Linux
* **Python :** 3.10+

### Construire Unsloth avec le support Intel

{% stepper %}
{% step %}

#### Créer un nouvel environnement conda (optionnel)

```bash
conda create -n unsloth-xpu python==3.10
conda activate unsloth-xpu
```

{% endstep %}

{% step %}

#### Installer Unsloth

```bash
git clone https://github.com/unslothai/unsloth.git
cd unsloth
pip install .[intel-gpu-torch290]
```

{% hint style="info" %}
Linux uniquement : Installer [vLLM](https://unsloth.ai/docs/fr/bases/inference-and-deployment/vllm-guide) (Optionnel)\
Vous pouvez également installer vLLM pour [l'inférence](https://unsloth.ai/docs/fr/bases/inference-and-deployment) et [l'AP](https://unsloth.ai/docs/fr/commencer/reinforcement-learning-rl-guide). Veuillez suivre [le guide de vLLM](https://docs.vllm.ai/en/latest/getting_started/installation/gpu/#intel-xpu).
{% endhint %}
{% endstep %}

{% step %}

#### Vérifiez vos environnements

```python
import torch
print(f"Version de PyTorch : {torch.__version__}")
print(f"XPU disponible : {torch.xpu.is_available()}")
print(f"Nombre de dispositifs XPU : {torch.xpu.device_count()}")
print(f"Nom du dispositif XPU : {torch.xpu.get_device_name(0)}")
```

{% endstep %}

{% step %}

#### Commencez l'affinage.

Vous pouvez utiliser directement nos [carnets](https://unsloth.ai/docs/fr/commencer/unsloth-notebooks) ou consulter notre [guide d'affinage](https://unsloth.ai/docs/fr/commencer/fine-tuning-llms-guide) ou [apprentissage par renforcement](https://unsloth.ai/docs/fr/commencer/reinforcement-learning-rl-guide) guides.
{% endstep %}
{% endstepper %}

### Windows uniquement - Configurations d'exécution

Dans l'invite de commandes avec les privilèges Administrateur, activez la prise en charge des chemins longs dans le registre Windows :

```bash
powershell -Command "Set-ItemProperty -Path "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\FileSystem" -Name "LongPathsEnabled" -Value 1
```

Cette commande n'a besoin d'être définie qu'une seule fois sur une machine. Elle n'a pas besoin d'être configurée avant chaque exécution. Ensuite :

1. Téléchargez level-zero-win-sdk-1.20.2.zip depuis [GitHub](https://github.com/oneapi-src/level-zero/releases/tag/v1.20.2)
2. Décompressez le level-zero-win-sdk-1.20.2.zip
3. Dans l'invite de commandes, sous l'environnement conda unsloth-xpu :

```bash
call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" -
set ZE_PATH=chemin\vers\le\level-zero-win-sdk-1.20.2\décompressé
```

### Exemple 1 : Affinage QLoRA avec SFT

Cet exemple montre comment affiner un modèle Qwen3-32B en utilisant QLoRA 4 bits sur un GPU Intel. QLoRA réduit considérablement les besoins en mémoire, ce qui rend possible l'affinage de grands modèles sur du matériel grand public.

{% code expandable="true" %}

```python
from unsloth import FastLanguageModel, FastModel
from trl import SFTTrainer, SFTConfig
from datasets import load_dataset
max_seq_length = 2048 # Prend en charge RoPE Scaling en interne, donc choisissez n'importe quelle valeur !
# Obtenir le dataset LAION
url = "https://huggingface.co/datasets/laion/OIG/resolve/main/unified_chip2.jsonl"
dataset = load_dataset("json", data_files = {"train" :
url}, split = "train")

# Modèles pré-quantifiés 4 bits que nous prenons en charge pour un téléchargement rapide + pas d'OOM.
fourbit_models = [
"unsloth/Qwen3-32B-bnb-4bit",
"unsloth/Qwen3-14B-bnb-4bit",
"unsloth/Qwen3-8B-bnb-4bit",
"unsloth/Qwen3-4B-bnb-4bit",
"unsloth/Qwen3-1.7B-bnb-4bit",
"unsloth/Qwen3-0.6B-bnb-4bit",
# "unsloth/Qwen2.5-32B-bnb-4bit",
# "unsloth/Qwen2.5-14B-bnb-4bit",
# "unsloth/Qwen2.5-7B-bnb-4bit",
# "unsloth/Qwen2.5-3B-bnb-4bit",
# "unsloth/Qwen2.5-1.5B-bnb-4bit",
# "unsloth/Qwen2.5-0.5B-bnb-4bit",
# "unsloth/Llama-3.2-3B-bnb-4bit",
# "unsloth/Llama-3.2-1B-bnb-4bit",
# "unsloth/Llama-3.1-8B-bnb-4bit",
# "unsloth/Llama-3.1-70B-bnb-4bit",
# "unsloth/mistral-7b-bnb-4bit",
# "unsloth/Phi-4",
# "unsloth/Phi-3.5-mini-instruct",
# "unsloth/Phi-3-medium-4k-instruct",
# "unsloth/Phi-3-mini-4k-instruct",
# "unsloth/gemma-2-9b-bnb-4bit",
# "unsloth/gemma-2-27b-bnb-4bit",
] # Plus de modèles sur https://huggingface.co/unsloth

model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/Qwen3-32B-bnb-4bit",
max_seq_length = max_seq_length,
load_in_4bit = True,
# token = "hf_...", # utilisez-en un si vous utilisez des modèles restreints comme meta-llama/Llama-2-7b-hf
)

model = FastLanguageModel.get_peft_model(
model,
r = 16, # Choisissez n'importe quel nombre > 0 ! Suggestions : 8, 16, 32, 64, 128
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
lora_alpha = 16,
lora_dropout = 0, # Prend en charge n'importe quelle valeur, mais = 0 est optimisé
bias = "none", # Prend en charge n'importe quelle valeur, mais = "none" est optimisé
use_gradient_checkpointing = "unsloth", # True ou "unsloth" pour un contexte très long
random_state = 3407,
use_rslora = False, # Nous prenons en charge LoRA stabilisé par rang
loftq_config = None, # Et LoftQ
)

trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset = dataset,
dataset_text_field = "text",
max_seq_length = max_seq_length,
dataset_num_proc = 1, # Recommandé sur Windows
packing = False, # Peut rendre l'entraînement 5x plus rapide pour des séquences courtes.
args = SFTConfig(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
warmup_steps = 5,
max_steps = 60,
learning_rate = 2e-4,
logging_steps = 1,
optim = "adamw_8bit",
weight_decay = 0.01,
lr_scheduler_type = "linear",
seed = 3407,
dataset_num_proc=1, # Recommandé sur Windows
),
)

trainer.train()
```

{% endcode %}

### Exemple 2 : Apprentissage par renforcement GRPO

GRPO est une [apprentissage par renforcement](https://unsloth.ai/docs/fr/commencer/reinforcement-learning-rl-guide) technique pour aligner les modèles de langage sur les préférences humaines. Cet exemple montre comment entraîner un modèle à suivre un format de sortie XML spécifique en utilisant plusieurs fonctions de récompense.

#### Qu'est-ce que GRPO ?

GRPO améliore le RLHF traditionnel en :

* Utilisant une normalisation basée sur des groupes pour un entraînement plus stable
* Prenant en charge plusieurs fonctions de récompense pour une optimisation multi-objectifs
* Étant plus économe en mémoire que PPO

{% code expandable="true" %}

```python
from unsloth import FastLanguageModel
import re
from trl import GRPOConfig, GRPOTrainer
from datasets import load_dataset, Dataset

max_seq_length = 1024  # Peut être augmenté pour des traces de raisonnement plus longues
lora_rank = 32  # Rang plus élevé = plus intelligent, mais plus lent
max_prompt_length = 256

# Charger et préparer le dataset
SYSTEM_PROMPT = """
Répondez dans le format suivant :
<reasoning>
...
</reasoning>
<answer>
...
</answer>
"""

XML_COT_FORMAT = """\
<reasoning>
{reasoning}
</reasoning>
<answer>
{answer}
</answer>
"""


def extract_xml_answer(text: str) -> str:
    answer = text.split("<answer>")[-1]
    answer = answer.split("</answer>")[0]
    return answer.strip()


def extract_hash_answer(text: str) -> str | None:
    if "####" not in text:
        return None
    return text.split("####")[1].strip()


# décommentez les messages du milieu pour un prompt 1-shot
def get_gsm8k_questions(split: str = "train") -> Dataset:
    data = load_dataset("openai/gsm8k", "main")[split]  # type: ignore
    data = data.map(
        lambda x: {  # type: ignore
            "prompt": [
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": x["question"]},
            ],
            "answer": extract_hash_answer(x["answer"]),
        }
    )  # type: ignore
    return data  # type: ignore


# Fonctions de récompense
def correctness_reward_func(prompts, completions, answer, **kwargs) -> list[float]:
    responses = [completion[0]["content"] for completion in completions]
    q = prompts[0][-1]["content"]
    extracted_responses = [extract_xml_answer(r) for r in responses]
    print(
        "-" * 20,
        f"Question:\n{q}",
        f"\nAnswer:\n{answer[0]}",
        f"\nResponse:\n{responses[0]}",
        f"\nExtracted:\n{extracted_responses[0]}",
    )
    return [2.0 if r == a else 0.0 for r, a in zip(extracted_responses, answer)]


def int_reward_func(completions, **kwargs) -> list[float]:
    responses = [completion[0]["content"] for completion in completions]
    extracted_responses = [extract_xml_answer(r) for r in responses]
    return [0.5 if r.isdigit() else 0.0 for r in extracted_responses]


def strict_format_reward_func(completions, **kwargs) -> list[float]:
    """Fonction de récompense qui vérifie si la complétion a un format spécifique."""
    pattern = r"^<reasoning>\n.*?\n</reasoning>\n<answer>\n.*?\n</answer>\n$"
    responses = [completion[0]["content"] for completion in completions]
    matches = [re.match(pattern, r) for r in responses]
    return [0.5 if match else 0.0 for match in matches]


def soft_format_reward_func(completions, **kwargs) -> list[float]:
    """Fonction de récompense qui vérifie si la complétion a un format spécifique."""
    pattern = r"<reasoning>.*?</reasoning>\s*<answer>.*?</answer>"
    responses = [completion[0]["content"] for completion in completions]
    matches = [re.match(pattern, r) for r in responses]
    return [0.5 if match else 0.0 for match in matches]


def count_xml(text: str) -> float:
    count = 0.0
    if text.count("<reasoning>\n") == 1:
        count += 0.125
    if text.count("\n</reasoning>\n") == 1:
        count += 0.125
    if text.count("\n<answer>\n") == 1:
        count += 0.125
    count -= len(text.split("\n</answer>\n")[-1]) * 0.001
    if text.count("\n</answer>") == 1:
        count += 0.125
    count -= (len(text.split("\n</answer>")[-1]) - 1) * 0.001
    return count


def xmlcount_reward_func(completions, **kwargs) -> list[float]:
    contents = [completion[0]["content"] for completion in completions]
    return [count_xml(c) for c in contents]


if __name__ == "__main__":
    model, tokenizer = FastLanguageModel.from_pretrained(
        model_name="unsloth/Qwen3-0.6B",
        max_seq_length=max_seq_length,
        load_in_4bit=False,  # False pour LoRA 16bit
        fast_inference=False,  # Activer l'inférence rapide vLLM
        max_lora_rank=lora_rank,
        gpu_memory_utilization=0.7,  # Réduire si manque de mémoire
        device_map="xpu:0",
    )

    model = FastLanguageModel.get_peft_model(
        model,
        r=lora_rank,  # Choisissez n'importe quel nombre > 0 ! Suggestions : 8, 16, 32, 64, 128
        target_modules=[
            "q_proj",
            "k_proj",
            "v_proj",
            "o_proj",
            "gate_proj",
            "up_proj",
            "down_proj",
        ],  # Supprimez QKVO si manque de mémoire
        lora_alpha=lora_rank,
        use_gradient_checkpointing="unsloth",  # Activer l'affinage pour contexte long
        random_state=3407,
    )

    dataset = get_gsm8k_questions()

    training_args = GRPOConfig(
        learning_rate=5e-6,
        adam_beta1=0.9,
        adam_beta2=0.99,
        weight_decay=0.1,
        warmup_ratio=0.1,
        lr_scheduler_type="cosine",
        optim="adamw_torch",
        logging_steps=1,
        per_device_train_batch_size=1,
        gradient_accumulation_steps=1,  # Augmentez à 4 pour un entraînement plus stable
        num_generations=4,  # Diminuez si manque de mémoire
        max_prompt_length=max_prompt_length,
        max_completion_length=max_seq_length - max_prompt_length,
        # num_train_epochs=1,  # Réglez sur 1 pour un entraînement complet
        max_steps=20,
        save_steps=250,
        max_grad_norm=0.1,
        report_to="none",  # Peut utiliser Weights & Biases
        output_dir="outputs",
    )

    trainer = GRPOTrainer(
        model=model,
        processing_class=tokenizer,
        reward_funcs=[
            xmlcount_reward_func,
            soft_format_reward_func,
            strict_format_reward_func,
            int_reward_func,
            correctness_reward_func,
        ],
        args=training_args,
        train_dataset=dataset,
        dataset_num_proc=1,  # Recommandé sur Windows
    )

    trainer.train()

```

{% endcode %}

## Dépannage

### Erreurs de manque de mémoire (OOM)

Si vous manquez de mémoire, essayez ces solutions :

1. **Réduire la taille du lot :** Réduire `per_device_train_batch_size`.
2. **Utiliser un modèle plus petit :** Commencez par un modèle plus petit pour réduire les besoins en mémoire.
3. **Réduire la longueur de séquence :** Réduire `max_seq_length`.
4. **Réduire le rang LoRA :** Utiliser `r=8` au lieu de `r=16` ou `r=32`.
5. **Pour GRPO, réduisez le nombre de générations :** Réduire `num_generations`.

### (Windows uniquement) Mémoire partagée iGPU Intel Ultra AIPC

Pour Intel Ultra AIPC avec des pilotes GPU récents sous Windows, la mémoire GPU partagée pour le GPU intégré est généralement définie par défaut sur **57%** de la mémoire système. Pour des modèles plus grands (par ex., **Qwen3-32B**), ou lors de l'utilisation d'une longueur de séquence maximale plus longue, d'une taille de lot plus grande, d'adaptateurs LoRA avec un rang LoRA plus élevé, etc., pendant l'affinage, vous pouvez augmenter la VRAM disponible en augmentant le pourcentage de mémoire système alloué à l'iGPU.

Vous pouvez ajuster cela en modifiant le registre :

* Chemin : `Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\MemoryManager`
* Clé à modifier :\
  `SystemPartitionCommitLimitPercentage` (définir sur un pourcentage plus élevé)


---

# 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/commencer/install/intel.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.
