> For the complete documentation index, see [llms.txt](https://docs.clore.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clore.ai/guides/guides_v2-fr/entrainement/finetune-llm.md).

# Fine-tune LLM

Entraînez votre propre LLM personnalisé en utilisant des techniques de fine-tuning efficaces sur les GPU CLORE.AI.

{% hint style="success" %}
Tous les exemples peuvent être exécutés sur des serveurs GPU loués via [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## Location sur CLORE.AI

1. Visitez [CLORE.AI Marketplace](https://clore.ai/marketplace)
2. Filtrez par type de GPU, VRAM et prix
3. Choisissez **À la demande** (tarif fixe) ou **Spot** (prix d’enchère)
4. Configurez votre commande :
   * Sélectionnez l’image Docker
   * Définissez les ports (TCP pour SSH, HTTP pour les interfaces web)
   * Ajoutez des variables d’environnement si nécessaire
   * Entrez la commande de démarrage
5. Sélectionnez le paiement : **CLORE**, **BTC**ou **USDT/USDC**
6. Créez la commande et attendez le déploiement

### Accédez à votre serveur

* Trouvez les détails de connexion dans **Mes commandes**
* Interfaces web : utilisez l’URL du port HTTP
* SSH : `ssh -p <port> root@<proxy-address>`

## Qu’est-ce que LoRA/QLoRA ?

* **LoRA** (Adaptation de bas rang) - Entraînez de petites couches adaptatrices au lieu du modèle complet
* **QLoRA** - LoRA avec quantification pour encore moins de VRAM
* Entraîner un modèle 7B sur un seul RTX 3090
* Entraîner un modèle 70B sur un seul A100

## Exigences

| Modèle | Méthode      | VRAM min. | Recommandé                                                                                               |
| ------ | ------------ | --------- | -------------------------------------------------------------------------------------------------------- |
| 7B     | QLoRA        | 12 Go     | [RTX 3090](https://clore.ai/rent-3090.html?utm_source=docs\&utm_medium=guide\&utm_campaign=finetune-llm) |
| 13B    | QLoRA        | 20 Go     | [RTX 4090](https://clore.ai/rent-4090.html?utm_source=docs\&utm_medium=guide\&utm_campaign=finetune-llm) |
| 70B    | QLoRA        | 48 Go     | A100 80 Go                                                                                               |
| 7B     | LoRA complet | 24 Go     | RTX 4090                                                                                                 |

## Déploiement rapide

**Image Docker :**

```
pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel
```

**Ports :**

```
22/tcp
8888/http
6006/http
```

**Commande :**

```bash
pip install "transformers>=4.45" "datasets>=2.20" accelerate "peft>=0.14" \
    bitsandbytes "trl>=0.12" wandb jupyterlab && \
jupyter lab --ip=0.0.0.0 --port=8888 --allow-root
```

## Accéder à votre service

Après le déploiement, trouvez votre `http_pub` URL dans **Mes commandes**:

1. Allez à la **Mes commandes** page
2. Cliquez sur votre commande
3. Trouvez l’ `http_pub` URL (par ex.  `abc123.clorecloud.net`)

Utilisez `https://YOUR_HTTP_PUB_URL` à la place de `localhost` dans les exemples ci-dessous.

## Préparation du jeu de données

### Format chat (recommandé)

```json
[
  {
    "messages": [
      {"role": "system", "content": "You are a helpful assistant."},
      {"role": "user", "content": "What is Python?"},
      {"role": "assistant", "content": "Python is a programming language..."}
    ]
  }
]
```

### Format d’instruction

```json
[
  {
    "instruction": "Translate to French",
    "input": "Hello, how are you?",
    "output": "Bonjour, comment allez-vous?"
  }
]
```

### Format Alpaca

```json
[
  {
    "instruction": "Give three tips for staying healthy.",
    "input": "",
    "output": "1. Eat balanced meals..."
  }
]
```

## Modèles modernes pris en charge (2025)

| Modèle                      | ID HF                                     | VRAM min. (QLoRA) |
| --------------------------- | ----------------------------------------- | ----------------- |
| Llama 3.1 / 3.3 8B          | `meta-llama/Llama-3.1-8B-Instruct`        | 12 Go             |
| Qwen 2.5 7B / 14B           | `Qwen/Qwen2.5-7B-Instruct`                | 12 Go / 20 Go     |
| DeepSeek-R1-Distill (7B/8B) | `deepseek-ai/DeepSeek-R1-Distill-Qwen-7B` | 12 Go             |
| Mistral 7B v0.3             | `mistralai/Mistral-7B-Instruct-v0.3`      | 12 Go             |
| Gemma 2 9B                  | `google/gemma-2-9b-it`                    | 14 Go             |
| Phi-4 14B                   | `microsoft/phi-4`                         | 20 Go             |

## Script de fine-tuning QLoRA

Exemple moderne avec PEFT 0.14+, Flash Attention 2, prise en charge de DoRA et compatibilité Qwen2.5 / DeepSeek-R1 :

```python
import torch
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    TrainingArguments,
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from datasets import load_dataset
from trl import SFTTrainer, SFTConfig

# === Configuration ===
# Choisissez l’un des modèles : Qwen2.5, DeepSeek-R1-Distill, Llama 3.1, Mistral, etc.
MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"
# MODEL_NAME = "meta-llama/Llama-3.1-8B-Instruct"

DATASET = "your_dataset.json"  # ou le nom d’un jeu de données HuggingFace
OUTPUT_DIR = "./output"
MAX_SEQ_LENGTH = 4096           # Qwen2.5 prend en charge jusqu’à 32K de contexte
USE_DORA = True                 # DoRA améliore la qualité par rapport au LoRA standard
USE_FLASH_ATTN = True           # Flash Attention 2 économise de la VRAM et accélère

# === Charger le modèle avec quantification en 4 bits ===
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,  # Requis pour Qwen2.5 et DeepSeek
    # Flash Attention 2 : nécessite un GPU Ampere+ (RTX 30/40, A100)
    attn_implementation="flash_attention_2" if USE_FLASH_ATTN else "eager",
)

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
if tokenizer.pad_token is None:
    tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# === Configurer LoRA avec DoRA optionnel ===
# DoRA (Adaptation de bas rang décomposée par poids) — PEFT >= 0.14 requis
# use_dora=True décompose les poids en magnitude + direction pour une meilleure qualité
lora_config = LoraConfig(
    r=64,                    # Rang (plus élevé = plus de capacité, plus de VRAM)
    lora_alpha=16,           # Facteur d’échelle (garder égal à ou à la moitié de r)
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",  # Couches d’attention
        "gate_proj", "up_proj", "down_proj",      # Couches MLP
    ],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
    use_dora=USE_DORA,        # DoRA : qualité améliorée (PEFT 0.14+)
    # use_rslora=True,        # Optionnel : LoRA à stabilité de rang
)

# Préparer le modèle pour l’entraînement QLoRA
model = prepare_model_for_kbit_training(
    model,
    use_gradient_checkpointing=True,
    gradient_checkpointing_kwargs={"use_reentrant": False},
)
model = get_peft_model(model, lora_config)

# Afficher le résumé des paramètres entraînables
model.print_trainable_parameters()
# Exemple de sortie : paramètres entraînables : 42,991,616 || tous les paramètres : 7,284,891,648 || % entraînable : 0.59

# === Charger le jeu de données ===
dataset = load_dataset("json", data_files=DATASET)
# Ou utilisez un jeu de données public :
# dataset = load_dataset("HuggingFaceH4/ultrachat_200k")

# === Formater le jeu de données au format Qwen2.5 / ChatML ===
def format_chat_qwen(example):
    """Format pour Qwen2.5 en utilisant le modèle ChatML."""
    messages = example.get("messages", [])
    if not messages:
        # Gérer les données au format alpaca
        text = f"<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n"
        text += f"<|im_start|>user\n{example['instruction']}"
        if example.get("input"):
            text += f"\n{example['input']}"
        text += f"<|im_end|>\n<|im_start|>assistant\n{example['output']}<|im_end|>"
    else:
        # Gérer le format messages (ChatML)
        text = tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=False,
        )
    return {"text": text}

dataset = dataset.map(format_chat_qwen, remove_columns=dataset["train"].column_names)

# === Arguments d’entraînement (PEFT 0.14+ / TRL 0.12+) ===
training_args = SFTConfig(
    output_dir=OUTPUT_DIR,
    num_train_epochs=3,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,         # Batch effectif = 2 * 8 = 16
    learning_rate=2e-4,
    weight_decay=0.001,
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
    logging_steps=10,
    save_steps=100,
    save_total_limit=3,
    bf16=True,                             # Utiliser bf16 pour les GPU modernes (A100, RTX 30/40)
    # fp16=True,                           # Utiliser fp16 pour les GPU plus anciens
    optim="paged_adamw_8bit",
    max_grad_norm=0.3,
    group_by_length=True,
    report_to="wandb",                     # ou "tensorboard"
    # Spécifique à SFTConfig :
    max_seq_length=MAX_SEQ_LENGTH,
    dataset_text_field="text",
    packing=True,                          # Regrouper plusieurs exemples pour l’efficacité
)

# === Entraîner ===
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset["train"],
    tokenizer=tokenizer,
    args=training_args,
)

trainer.train()

# === Enregistrer l’adaptateur LoRA ===
trainer.save_model(f"{OUTPUT_DIR}/final")
tokenizer.save_pretrained(f"{OUTPUT_DIR}/final")
print(f"Model saved to {OUTPUT_DIR}/final")
```

## Flash Attention 2

Flash Attention 2 réduit l’utilisation de la VRAM et accélère considérablement l’entraînement. Nécessite un GPU Ampere+ (RTX 3090, RTX 4090, A100).

```bash
# Installer Flash Attention 2
pip install flash-attn --no-build-isolation
```

```python
# Activer dans le chargement du modèle :
model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    attn_implementation="flash_attention_2",  # <-- ajoutez ceci
    torch_dtype=torch.bfloat16,               # FA2 nécessite bf16 ou fp16
    device_map="auto",
)
```

| Paramètre                 | VRAM (7B) | Vitesse   |
| ------------------------- | --------- | --------- |
| Attention standard (fp16) | \~22 Go   | référence |
| Flash Attention 2 (bf16)  | \~16 Go   | +30%      |
| Flash Attention 2 + QLoRA | \~12 Go   | +30%      |

## DoRA (LoRA décomposée par poids)

DoRA (PEFT >= 0.14) décompose les poids pré-entraînés en composants de magnitude et de direction. Cela améliore la qualité du fine-tuning, en particulier pour les rangs plus petits.

```python
from peft import LoraConfig

# LoRA standard
lora_config = LoraConfig(r=64, lora_alpha=16, use_dora=False, ...)

# DoRA — mêmes paramètres, meilleure qualité
lora_config = LoraConfig(r=64, lora_alpha=16, use_dora=True, ...)
# Remarque : DoRA ajoute environ 5 à 10 % de surcharge VRAM par rapport au LoRA standard
# Remarque : non compatible dans tous les cas avec les modèles quantifiés (4 bits/8 bits)
```

## Exemples Qwen2.5 et DeepSeek-R1-Distill

### Fine-tuning Qwen2.5

```python
MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
# Pour 14B : "Qwen/Qwen2.5-14B-Instruct" (nécessite 20 Go+ de VRAM avec QLoRA)

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,          # Requis pour Qwen2.5
    attn_implementation="flash_attention_2",
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)

# Qwen2.5 utilise le format ChatML — utilisez apply_chat_template
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"},
    {"role": "assistant", "content": "Hi there! How can I help?"},
]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
```

### Fine-tuning DeepSeek-R1-Distill

Les modèles DeepSeek-R1-Distill (Qwen-7B, Qwen-14B, Llama-8B, Llama-70B) sont axés sur le raisonnement. Fine-tunez-les pour adapter leur style de chaîne de pensée à votre domaine.

```python
# Variantes DeepSeek-R1-Distill
MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"   # 7B sur base Qwen2.5
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Llama-8B" # 8B sur base Llama3
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B" # 14B (nécessite A100)

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
    attn_implementation="flash_attention_2",
)

# DeepSeek-R1 utilise des balises <think>...</think> pour le raisonnement
# Conservez cela dans les données d’entraînement pour préserver la capacité de chaîne de pensée
example_format = """<|im_start|>user
Résoudre : combien font 15 * 23 ?<|im_end|>
<|im_start|>assistant
<think>
15 * 23 = 15 * 20 + 15 * 3 = 300 + 45 = 345
</think>
La réponse est 345.<|im_end|>"""

# Modules cibles LoRA pour DeepSeek-R1-Distill (base Qwen2.5)
lora_config = LoraConfig(
    r=32,
    lora_alpha=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    use_dora=True,
    task_type="CAUSAL_LM",
)
```

## Utiliser Axolotl (plus simple)

Axolotl simplifie le fine-tuning avec des configurations YAML :

```bash
pip install axolotl

# Créer la config
cat > config.yml << 'EOF'
base_model: mistralai/Mistral-7B-v0.1
model_type: MistralForCausalLM
tokenizer_type: LlamaTokenizer

load_in_4bit: true
adapter: qlora
lora_r: 32
lora_alpha: 16

datasets:
  - path: your_data.json
    type: alpaca

sequence_len: 4096
sample_packing: true

gradient_accumulation_steps: 4
micro_batch_size: 2
num_epochs: 3
learning_rate: 2e-4

output_dir: ./output
EOF

# Entraîner
accelerate launch -m axolotl.cli.train config.yml
```

## Exemples de configuration Axolotl

### Modèle de chat

```yaml
base_model: mistralai/Mistral-7B-Instruct-v0.2
load_in_4bit: true
adapter: qlora

datasets:
  - path: data.json
    type: sharegpt

chat_template: mistral
```

### Modèle de code

```yaml
base_model: codellama/CodeLlama-7b-hf
load_in_4bit: true
adapter: qlora

datasets:
  - path: code_data.json
    type: alpaca

sequence_len: 8192  # Contexte plus long pour le code
```

## Fusion des poids LoRA

Après l’entraînement, fusionnez LoRA à nouveau dans le modèle de base :

```python
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

# Charger le modèle de base
base_model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-v0.1",
    torch_dtype=torch.float16,
    device_map="auto",
)

# Charger LoRA
model = PeftModel.from_pretrained(base_model, "./output/final")

# Fusionner
merged_model = model.merge_and_unload()

# Enregistrer le modèle fusionné
merged_model.save_pretrained("./merged_model")
tokenizer.save_pretrained("./merged_model")
```

## Convertir en GGUF

Pour une utilisation avec llama.cpp/Ollama :

```bash

# Cloner llama.cpp
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp

# Convertir
python convert.py ../merged_model --outtype f16 --outfile model-f16.gguf

# Quantifier
./quantize model-f16.gguf model-q4_k_m.gguf q4_k_m
```

## Surveillance de l’entraînement

### Weights & Biases

```python
import wandb
wandb.init(project="llm-finetune", name="mistral-7b-lora")
```

### TensorBoard

```python

# Dans les arguments d’entraînement
report_to="tensorboard"
logging_dir="./logs"

# Afficher
tensorboard --logdir ./logs --port 6006 --bind_all
```

## Bonnes pratiques

### Hyperparamètres

| Paramètre   | Modèle 7B | Modèle 13B | Modèle 70B |
| ----------- | --------- | ---------- | ---------- |
| batch\_size | 4         | 2          | 1          |
| grad\_accum | 4         | 8          | 16         |
| lr          | 2e-4      | 1e-4       | 5e-5       |
| lora\_r     | 64        | 32         | 16         |
| epochs      | 3         | 2-3        | 1-2        |

### Taille du jeu de données

* Minimum : 1 000 exemples
* Bien : 10 000+ exemples
* La qualité > la quantité

### Éviter le surapprentissage

```python
training_args = TrainingArguments(
    ...
    weight_decay=0.01,
    warmup_ratio=0.03,
    save_total_limit=3,
    load_best_model_at_end=True,
    evaluation_strategy="steps",
    eval_steps=100,
)
```

## Entraînement multi-GPU

```bash

# Avec accelerate
accelerate launch --multi_gpu --num_processes 4 train.py

# Avec DeepSpeed
accelerate launch --use_deepspeed --num_processes 4 train.py
```

Configuration DeepSpeed :

```json
{
  "bf16": {"enabled": true},
  "zero_optimization": {
    "stage": 2,
    "offload_optimizer": {"device": "cpu"}
  }
}
```

## Sauvegarde et exportation

```bash

# Enregistrer l’adaptateur LoRA
trainer.save_model("./lora_adapter")

# Enregistrer le modèle fusionné
merged_model.save_pretrained("./full_model")

# Télécharger vers HuggingFace
huggingface-cli login
merged_model.push_to_hub("username/my-model")
```

## Dépannage

### Erreurs OOM

* Réduire la taille du batch
* Augmenter l’accumulation des gradients
* Utilisez `gradient_checkpointing=True`
* Réduire lora\_r

### La perte d’entraînement ne diminue pas

* Vérifier le format des données
* Augmenter le taux d’apprentissage
* Vérifier les problèmes de données

### Perte NaN

* Réduire le taux d’apprentissage
* Utiliser fp32 au lieu de fp16
* Vérifier la présence de données corrompues

## Estimation des coûts

Tarifs typiques de la place de marché CLORE.AI (en 2026) :

| GPU        | Tarif horaire | Tarif journalier | Session de 4 heures |
| ---------- | ------------- | ---------------- | ------------------- |
| RTX 3060   | \~$0.03       | \~$0.70          | \~$0.12             |
| RTX 3090   | \~$0.06       | \~$1.50          | \~$0.25             |
| RTX 4090   | \~$0.10       | \~$2.30          | \~$0.40             |
| A100 40 Go | \~$0.17       | \~$4.00          | \~$0.70             |
| A100 80 Go | \~$0.25       | \~$6.00          | \~$1.00             |

*Les prix varient selon le fournisseur et la demande. Consultez* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *les tarifs actuels.*

> 📚 Voir aussi : [Comment affiner LLaMA 3 sur un GPU cloud — Guide étape par étape](https://blog.clore.ai/how-to-fine-tune-llama-3-cloud-gpu/)

**Économisez de l’argent :**

* Utilisez **Spot** marché pour des charges de travail flexibles (souvent 30 à 50 % moins cher)
* Payer avec **CLORE** des jetons
* Comparer les prix entre différents fournisseurs


---

# 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:

```
GET https://docs.clore.ai/guides/guides_v2-fr/entrainement/finetune-llm.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.
