# LLM feinabstimmen

Trainieren Sie Ihr eigenes benutzerdefiniertes LLM mit effizienten Fine-Tuning-Techniken auf CLORE.AI-GPUs.

{% hint style="success" %}
Alle Beispiele können auf GPU-Servern ausgeführt werden, die über [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## Mieten auf CLORE.AI

1. Besuchen Sie [CLORE.AI Marketplace](https://clore.ai/marketplace)
2. Nach GPU-Typ, VRAM und Preis filtern
3. Wählen **On-Demand** (Festpreis) oder **Spot** (Gebotspreis)
4. Konfigurieren Sie Ihre Bestellung:
   * Docker-Image auswählen
   * Ports festlegen (TCP für SSH, HTTP für Web-UIs)
   * Gegebenenfalls Umgebungsvariablen hinzufügen
   * Startbefehl eingeben
5. Zahlung auswählen: **CLORE**, **BTC**, oder **USDT/USDC**
6. Bestellung erstellen und auf Bereitstellung warten

### Greifen Sie auf Ihren Server zu

* Verbindungsdetails finden in **Meine Bestellungen**
* Webschnittstellen: Verwenden Sie die HTTP-Port-URL
* SSH: `ssh -p <port> root@<proxy-address>`

## Was ist LoRA/QLoRA?

* **LoRA** (Low-Rank Adaptation) - Trainieren Sie kleine Adapter-Schichten statt des gesamten Modells
* **QLoRA** - LoRA mit Quantisierung für noch weniger VRAM
* Trainieren Sie ein 7B-Modell auf einer einzelnen RTX 3090
* Trainieren Sie ein 70B-Modell auf einer einzelnen A100

## Anforderungen

| Modell | Methode     | Min. VRAM | Empfohlen |
| ------ | ----------- | --------- | --------- |
| 7B     | QLoRA       | 12GB      | RTX 3090  |
| 13B    | QLoRA       | 20GB      | RTX 4090  |
| 70B    | QLoRA       | 48GB      | A100 80GB |
| 7B     | Volles LoRA | 24GB      | RTX 4090  |

## Schnelle Bereitstellung

**Docker-Image:**

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

**Ports:**

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

**Befehl:**

```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
```

## Zugriff auf Ihren Dienst

Nach der Bereitstellung finden Sie Ihre `http_pub` URL in **Meine Bestellungen**:

1. Gehen Sie zur **Meine Bestellungen** Seite
2. Klicken Sie auf Ihre Bestellung
3. Finden Sie die `http_pub` URL (z. B. `abc123.clorecloud.net`)

Verwenden Sie `https://YOUR_HTTP_PUB_URL` anstatt `localhost` in den Beispielen unten.

## Datensatzvorbereitung

### Chat-Format (empfohlen)

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

### Instruktionsformat

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

### Alpaca-Format

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

## Unterstützte moderne Modelle (2025)

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

## QLoRA Fine-Tuning-Skript

Modernes Beispiel mit PEFT 0.14+, Flash Attention 2, DoRA-Unterstützung und Qwen2.5 / DeepSeek-R1-Kompatibilität:

```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

# === Konfiguration ===
# Wählen Sie eines von: Qwen2.5, DeepSeek-R1-Distill, Llama 3.1, Mistral, usw.
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"  # oder HuggingFace-Datensatzname
OUTPUT_DIR = "./output"
MAX_SEQ_LENGTH = 4096           # Qwen2.5 unterstützt bis zu 32K Kontext
USE_DORA = True                 # DoRA verbessert die Qualität gegenüber Standard-LoRA
USE_FLASH_ATTN = True           # Flash Attention 2 spart VRAM & beschleunigt

# === Modell mit 4-Bit-Quantisierung laden ===
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,  # Erforderlich für Qwen2.5 und DeepSeek
    # Flash Attention 2: erfordert Ampere+ GPU (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"

# === LoRA mit optionalem DoRA konfigurieren ===
# DoRA (Weight-Decomposed Low-Rank Adaptation) — PEFT >= 0.14 erforderlich
# use_dora=True zerlegt Gewichte in Betrag + Richtung für bessere Qualität
lora_config = LoraConfig(
    r=64,                    # Rang (höher = mehr Kapazität, mehr VRAM)
    lora_alpha=16,           # Skalierungsfaktor (gleich oder halb von r halten)
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",  # Attention-Schichten
        "gate_proj", "up_proj", "down_proj",      # MLP-Schichten
    ],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
    use_dora=USE_DORA,        # DoRA: verbesserte Qualität (PEFT 0.14+)
    # use_rslora=True,        # Optional: Rank-Stabilized LoRA
)

# Bereiten Sie das Modell für QLoRA-Training vor
model = prepare_model_for_kbit_training(
    model,
    use_gradient_checkpointing=True,
    gradient_checkpointing_kwargs={"use_reentrant": False},
)
model = get_peft_model(model, lora_config)

# Zusammenfassung der trainierbaren Parameter ausgeben
model.print_trainable_parameters()
# Beispielausgabe: trainable params: 42,991,616 || all params: 7,284,891,648 || trainable%: 0.59

# === Datensatz laden ===
dataset = load_dataset("json", data_files=DATASET)
# Oder einen öffentlichen Datensatz verwenden:
# dataset = load_dataset("HuggingFaceH4/ultrachat_200k")

# === Datensatz für Qwen2.5 / ChatML-Format formatieren ===
def format_chat_qwen(example):
    """Format für Qwen2.5 unter Verwendung der ChatML-Vorlage."""
    messages = example.get("messages", [])
    if not messages:
        # Alpaca-ähnliche Daten behandeln
        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:
        # Nachrichtenformat (ChatML) behandeln
        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)

# === Trainingsargumente (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,         # Effektive Batch = 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,                             # Verwenden Sie bf16 für moderne GPUs (A100, RTX 30/40)
    # fp16=True,                           # Verwenden Sie fp16 für ältere GPUs
    optim="paged_adamw_8bit",
    max_grad_norm=0.3,
    group_by_length=True,
    report_to="wandb",                     # oder "tensorboard"
    # SFTConfig-spezifisch:
    max_seq_length=MAX_SEQ_LENGTH,
    dataset_text_field="text",
    packing=True,                          # Mehrere Beispiele für Effizienz bündeln
)

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

trainer.train()

# === LoRA-Adapter speichern ===
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 reduziert den VRAM-Verbrauch und beschleunigt das Training deutlich. Erfordert Ampere+ GPU (RTX 3090, RTX 4090, A100).

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

```python
# Beim Laden des Modells aktivieren:
model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    attn_implementation="flash_attention_2",  # <-- hinzufügen
    torch_dtype=torch.bfloat16,               # FA2 erfordert bf16 oder fp16
    device_map="auto",
)
```

| Einstellung               | VRAM (7B) | Geschwindigkeit |
| ------------------------- | --------- | --------------- |
| Standard-Attention (fp16) | \~22GB    | Basislinie      |
| Flash Attention 2 (bf16)  | \~16GB    | +30%            |
| Flash Attention 2 + QLoRA | \~12GB    | +30%            |

## DoRA (Weight-Decomposed LoRA)

DoRA (PEFT >= 0.14) zerlegt vortrainierte Gewichte in Betrag- und Richtungs-Komponenten. Es verbessert die Fine-Tuning-Qualität, besonders bei kleineren Rängen.

```python
from peft import LoraConfig

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

# DoRA — gleiche Parameter, bessere Qualität
lora_config = LoraConfig(r=64, lora_alpha=16, use_dora=True, ...)
# Hinweis: DoRA fügt gegenüber Standard-LoRA etwa 5–10% VRAM-Overhead hinzu
# Hinweis: Nicht in allen Fällen mit quantisierten (4-Bit/8-Bit) Modellen kompatibel
```

## Beispiele für Qwen2.5 & DeepSeek-R1-Distill

### Qwen2.5 Fine-Tuning

```python
MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
# Für 14B: "Qwen/Qwen2.5-14B-Instruct" (benötigt 20GB+ VRAM mit QLoRA)

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,          # Erforderlich für Qwen2.5
    attn_implementation="flash_attention_2",
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)

# Qwen2.5 verwendet ChatML-Format — verwenden Sie 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)
```

### DeepSeek-R1-Distill Fine-Tuning

DeepSeek-R1-Distill-Modelle (Qwen-7B, Qwen-14B, Llama-8B, Llama-70B) sind auf Reasoning ausgerichtet. Feinabstimmung, um ihren Chain-of-Thought-Stil an Ihre Domäne anzupassen.

```python
# DeepSeek-R1-Distinct-Varianten
MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"   # 7B auf Qwen2.5-Basis
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Llama-8B" # 8B auf Llama3-Basis
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B" # 14B (benötigt 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 verwendet <think>...</think>-Tags für Reasoning
# Bewahren Sie diese im Trainingsdatensatz, um die Chain-of-Thought-Fähigkeit zu erhalten
example_format = """<|im_start|>user
Solve: What is 15 * 23?<|im_end|>
<|im_start|>assistant
<think>
15 * 23 = 15 * 20 + 15 * 3 = 300 + 45 = 345
</think>
The answer is 345.<|im_end|>"""

# LoRA-Zielmodule für DeepSeek-R1-Distill (Qwen2.5-Basis)
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",
)
```

## Verwendung von Axolotl (einfacher)

Axolotl vereinfacht das Fine-Tuning mit YAML-Konfigurationen:

```bash
pip install axolotl

# Konfiguration erstellen
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

# Trainieren
accelerate launch -m axolotl.cli.train config.yml
```

## Axolotl Config-Beispiele

### Chat-Modell

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

datasets:
  - path: data.json
    type: sharegpt

chat_template: mistral
```

### Code-Modell

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

datasets:
  - path: code_data.json
    type: alpaca

sequence_len: 8192  # Längerer Kontext für Code
```

## LoRA-Gewichte zusammenführen

Nach dem Training LoRA zurück in das Basismodell mergen:

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

# Basismodell laden
base_model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-v0.1",
    torch_dtype=torch.float16,
    device_map="auto",
)

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

# Mergen
merged_model = model.merge_and_unload()

# Gemergtes Modell speichern
merged_model.save_pretrained("./merged_model")
tokenizer.save_pretrained("./merged_model")
```

## In GGUF konvertieren

Zur Verwendung mit llama.cpp/Ollama:

```bash

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

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

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

## Training überwachen

### Weights & Biases

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

### TensorBoard

```python

# In den Trainingsargumenten
report_to="tensorboard"
logging_dir="./logs"

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

## Best Practices

### Hyperparameter

| Parameter   | 7B-Modell | 13B-Modell | 70B-Modell |
| ----------- | --------- | ---------- | ---------- |
| batch\_size | 4         | 2          | 1          |
| grad\_accum | 4         | 8          | 16         |
| lr          | 2e-4      | 1e-4       | 5e-5       |
| lora\_r     | 64        | 32         | 16         |
| Epochen     | 3         | 2-3        | 1-2        |

### Datensatzgröße

* Minimum: 1.000 Beispiele
* Gut: 10.000+ Beispiele
* Qualität > Quantität

### Überanpassung vermeiden

```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,
)
```

## Multi-GPU-Training

```bash

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

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

DeepSpeed-Konfiguration:

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

## Speichern & Exportieren

```bash

# LoRA-Adapter speichern
trainer.save_model("./lora_adapter")

# Gemergtes Modell speichern
merged_model.save_pretrained("./full_model")

# Auf HuggingFace hochladen
huggingface-cli login
merged_model.push_to_hub("username/my-model")
```

## Fehlerbehebung

### OOM-Fehler

* Batch-Größe reduzieren
* Gradient Accumulation erhöhen
* Verwenden Sie `gradient_checkpointing=True`
* lora\_r reduzieren

### Trainingsverlust sinkt nicht

* Datenformat überprüfen
* Lernrate erhöhen
* Auf Datenprobleme prüfen

### NaN-Verlust

* Lernrate reduzieren
* fp32 statt fp16 verwenden
* Auf korrupte Daten prüfen

## Kostenabschätzung

Typische CLORE.AI-Marktplatzpreise (Stand 2024):

| GPU       | Stundenpreis | Tagespreis | 4-Stunden-Sitzung |
| --------- | ------------ | ---------- | ----------------- |
| 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 40GB | \~$0.17      | \~$4.00    | \~$0.70           |
| A100 80GB | \~$0.25      | \~$6.00    | \~$1.00           |

*Preise variieren je nach Anbieter und Nachfrage. Prüfen* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *für aktuelle Preise.*

> 📚 Siehe auch: [Wie man LLaMA 3 auf einer Cloud-GPU feintuned — Schritt-für-Schritt-Anleitung](https://blog.clore.ai/how-to-fine-tune-llama-3-cloud-gpu/)

**Geld sparen:**

* Verwenden Sie **Spot** Markt für flexible Workloads (oft 30–50% günstiger)
* Bezahlen mit **CLORE** Token
* Preise bei verschiedenen Anbietern vergleichen
