Apprenez comment entraîner et affiner des modèles de langage de grande taille sur GPU Intel.
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
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 :
Téléchargez level-zero-win-sdk-1.20.2.zip depuis GitHub
Décompressez le level-zero-win-sdk-1.20.2.zip
Dans l'invite de commandes, sous l'environnement conda unsloth-xpu :
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.
Exemple 2 : Apprentissage par renforcement GRPO
GRPO est une apprentissage par renforcement 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
Dépannage
Erreurs de manque de mémoire (OOM)
Si vous manquez de mémoire, essayez ces solutions :
Réduire la taille du lot : Réduire per_device_train_batch_size.
Utiliser un modèle plus petit : Commencez par un modèle plus petit pour réduire les besoins en mémoire.
Réduire la longueur de séquence : Réduire max_seq_length.
Réduire le rang LoRA : Utiliser r=8 au lieu de r=16 ou r=32.
Pour GRPO, réduisez le nombre de générations : Réduire num_generations.
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 :
call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" -
set ZE_PATH=chemin\vers\le\level-zero-win-sdk-1.20.2\décompressé
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()
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()