tomczak.dev
Zurück zur Übersicht
25. Januar 20264 min7 ViewsKI-Entwicklung

LLM Fine-Tuning auf dem eigenen PC: Kostenlos mit Unsloth

Fine-Tuning lokaler KI-Modelle mit nur 8GB VRAM! Lerne wie du Llama, Mistral & Co. auf deiner GPU trainierst – kostenlos, privat und ohne Cloud-Abo.

MT

Martin Tomczak

Senior Full Stack Architect mit 10+ Jahren Erfahrung

LLM Fine-Tuning auf dem eigenen PC: Kostenlos mit Unsloth

Fine-Tuning lokaler KI-Modelle mit nur 8GB VRAM! Lerne wie du Llama, Mistral & Co. auf deiner GPU trainierst – kostenlos, privat und ohne Cloud-Abo.

⚡ TL;DR – Das Wichtigste in 30 Sekunden

  • Fine-Tuning auf Consumer-Hardware ist 2026 dank Unsloth 2.0 mit nur 8GB VRAM möglich
  • Kostenersparnis: ~0,54€ vs. 15-50€ pro Training-Run in der Cloud
  • Volle Datenkontrolle: DSGVO-konform, keine externen API-Calls
  • Performance: 2x schneller als Standard-PyTorch durch optimierte Kernel

Hardware-Anforderungen 2026

Die gute Nachricht: Du brauchst keine teure Datacenter-GPU. Mit den richtigen Tools und Quantisierungstechniken reicht eine Consumer-Grafikkarte ab 8GB VRAM für die meisten Fine-Tuning-Aufgaben.

Minimum vs. Empfohlen

Komponente

Minimum

Empfohlen

Optimal

GPU

RTX 3060 12GB

RTX 4070 Ti 16GB

RTX 4090 24GB

VRAM

8GB (mit QLoRA)

16GB

24GB+

RAM

16GB

32GB

64GB

Storage

100GB SSD

500GB NVMe

1TB+ NVMe

Modellgröße

7B Parameter

13B Parameter

70B Parameter

💡 Pro-Tipp: Mit Unsloth 2.0 und 4-bit QLoRA kannst du ein 7B-Modell auf nur 6GB VRAM fine-tunen. Die RTX 3060 12GB ist damit das beste Preis-Leistungs-Verhältnis für Einsteiger.

NVIDIA DGX Spark: Die Zukunft?

NVIDIA hat mit dem DGX Spark (angekündigt CES 2025, verfügbar ab Mai 2026) eine kompakte Workstation vorgestellt, die speziell für lokales LLM-Training konzipiert ist. Mit 128GB unified Memory und GB10 Grace Blackwell Chip für ~3.000€ könnte das die Demokratisierung des KI-Trainings einläuten.

Daten vorbereiten & Qualität sichern

Die Qualität deines Fine-Tunings steht und fällt mit der Qualität deiner Trainingsdaten. Hier ist mein bewährter Workflow:

Datensatz-Struktur (JSONL Format)

{"conversations": [
  {"role": "system", "content": "Du bist ein hilfreicher Assistent."},
  {"role": "user", "content": "Was ist Machine Learning?"},
  {"role": "assistant", "content": "Machine Learning ist ein Teilbereich..."}
]}
{"conversations": [
  {"role": "system", "content": "Du bist ein hilfreicher Assistent."},
  {"role": "user", "content": "Erkläre neuronale Netze."},
  {"role": "assistant", "content": "Neuronale Netze sind..."}
]}

Datensatz-Qualität prüfen

import json
from collections import Counter

def analyze_dataset(jsonl_path):
    """
    Analysiere Trainingsdaten auf häufige Probleme
    """
    with open(jsonl_path, 'r') as f:
        data = [json.loads(line) for line in f]
    
    # Statistiken
    print(f"📊 Gesamt-Beispiele: {len(data)}")
    
    # Token-Längen (approximiert)
    lengths = []
    for example in data:
        text = ' '.join([msg['content'] for msg in example['conversations']])
        lengths.append(len(text.split()))
    
    print(f"📏 Durchschnittliche Länge: {sum(lengths)/len(lengths):.0f} Wörter")
    print(f"📏 Min: {min(lengths)}, Max: {max(lengths)}")
    
    # Duplikate prüfen
    user_prompts = [ex['conversations'][1]['content'] for ex in data]
    duplicates = len(user_prompts) - len(set(user_prompts))
    print(f"⚠️  Duplikate: {duplicates} ({duplicates/len(data)*100:.1f}%)")
    
    # Empfehlungen
    if duplicates > len(data) * 0.1:
        print("❌ WARNUNG: >10% Duplikate - Datensatz bereinigen!")
    if max(lengths) > 4000:
        print("⚠️  Einige Beispiele sehr lang - Context-Window beachten!")
    
analyze_dataset('training_data.jsonl')

⚠️ Häufige Fehler: Zu wenige Beispiele (<100), zu viele Duplikate, inkonsistente Formatierung. Starte mit 500-1000 hochwertigen Beispielen für erste Tests.

Fine-Tuning mit Unsloth: Schritt-für-Schritt Tutorial

Jetzt wird's praktisch. Hier ist mein bewährtes Setup mit allen optimierten Hyperparametern.

1. Environment Setup

# Conda Environment erstellen
conda create -n unsloth python=3.11 -y
conda activate unsloth

# PyTorch mit CUDA
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124

# Unsloth installieren (2026 Version)
pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
pip install --no-deps trl peft accelerate bitsandbytes triton xformers

2. Komplettes Training-Script

import torch
from unsloth import FastLanguageModel
from trl import SFTTrainer
from transformers import TrainingArguments
from datasets import load_dataset

# ═══════════════════════════════════════════════════════════
# 1. MODELL LADEN (4-bit Quantisierung für weniger VRAM)
# ═══════════════════════════════════════════════════════════
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/Llama-3.2-3B-Instruct",  # oder: mistralai/Mistral-7B-v0.3
    max_seq_length=2048,
    dtype=None,  # Auto-detect
    load_in_4bit=True,  # Reduziert VRAM um ~75%
)

# ═══════════════════════════════════════════════════════════
# 2. LoRA ADAPTER KONFIGURIEREN
# ═══════════════════════════════════════════════════════════
model = FastLanguageModel.get_peft_model(
    model,
    r=16,                # LoRA Rank (8-64, höher = mehr Kapazität)
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    lora_alpha=16,
    lora_dropout=0,      # Optimiert für Unsloth
    bias="none",
    use_gradient_checkpointing="unsloth",  # 30% weniger VRAM
    random_state=42,
)

# ═══════════════════════════════════════════════════════════
# 3. DATENSATZ LADEN
# ═══════════════════════════════════════════════════════════
dataset = load_dataset("json", data_files="training_data.jsonl", split="train")

def format_prompts(examples):
    texts = []
    for conv in examples['conversations']:
        text = tokenizer.apply_chat_template(conv, tokenize=False)
        texts.append(text)
    return {"text": texts}

dataset = dataset.map(format_prompts, batched=True)

# ═══════════════════════════════════════════════════════════
# 4. TRAINING STARTEN
# ═══════════════════════════════════════════════════════════
trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=2048,
    args=TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,  # Effektive Batch Size: 8
        warmup_steps=10,
        num_train_epochs=3,
        learning_rate=2e-4,
        fp16=not torch.cuda.is_bf16_supported(),
        bf16=torch.cuda.is_bf16_supported(),
        logging_steps=10,
        output_dir="outputs",
        optim="adamw_8bit",
        seed=42,
    ),
)

# Training starten
trainer_stats = trainer.train()
print(f"✅ Training abgeschlossen in {trainer_stats.metrics['train_runtime']:.0f}s")

3. Modell speichern & exportieren

# Als LoRA Adapter speichern (klein, ~50MB)
model.save_pretrained("lora_model")
tokenizer.save_pretrained("lora_model")

# Für Ollama: Als GGUF exportieren
model.save_pretrained_gguf(
    "model_gguf",
    tokenizer,
    quantization_method="q4_k_m"  # Beste Balance: Qualität/Größe
)

Deployment mit Ollama

Nach dem Training willst du dein Modell natürlich nutzen. Ollama macht das Deployment zum Kinderspiel.

Modelfile erstellen

# Modelfile
FROM ./model_gguf/unsloth.Q4_K_M.gguf

PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER num_ctx 4096

SYSTEM """Du bist ein hilfreicher KI-Assistent, spezialisiert auf 
technische Fragen rund um Webentwicklung und Machine Learning."""

In Ollama registrieren

# Modell erstellen
ollama create mein-modell -f Modelfile

# Testen
ollama run mein-modell "Erkläre mir Docker in 3 Sätzen"

# API verfügbar unter
curl http://localhost:11434/api/generate -d '{
  "model": "mein-modell",
  "prompt": "Hallo!",
  "stream": false
}'

Integration in deine Anwendung (TypeScript)

// lib/ollama.ts
interface OllamaResponse {
  response: string;
  done: boolean;
}

export async function generateText(prompt: string): Promise<string> {
  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'mein-modell',
      prompt,
      stream: false,
      options: {
        temperature: 0.7,
        num_predict: 500,
      }
    })
  });
  
  const data: OllamaResponse = await response.json();
  return data.response;
}

// Verwendung
const antwort = await generateText('Was ist TypeScript?');
console.log(antwort);

Kostenvergleich: Lokal vs. Cloud

Hier der ehrliche Kostenvergleich basierend auf realen Benchmarks:

Methode

Kosten/Training

Geschwindigkeit

Datenschutz

Lokal (RTX 4090)

~0,54€ (Strom)

~45 Min/1000 Samples

✅ Vollständig

Google Colab Pro

~12€/Monat

~60 Min/1000 Samples

⚠️ Cloud-Upload

AWS SageMaker

~25-50€/Training

~30 Min/1000 Samples

⚠️ AWS-Infrastruktur

OpenAI Fine-Tuning

~75€/Training

~20 Min/1000 Samples

❌ Daten bei OpenAI

📊 ROI-Rechnung: Bei 10 Training-Runs pro Monat amortisiert sich eine RTX 4090 (1.599€) gegenüber Cloud-Lösungen bereits nach 3-4 Monaten.

FAQ & Troubleshooting

Kann ich mit AMD-Grafikkarten fine-tunen?

Ja, aber mit Einschränkungen. ROCm unterstützt seit 2025 die meisten PyTorch-Operationen. Unsloth hat jedoch noch keine offizielle AMD-Unterstützung. Alternative: DirectML auf Windows oder das neue AMD AI Stack (seit Q4 2025).

Wie viele Trainingsdaten brauche ich?

Für erste Tests: 100-500 Beispiele. Für produktionsreife Modelle: 1.000-10.000 hochwertige Beispiele. Qualität schlägt Quantität! 500 perfekte Beispiele sind besser als 5.000 mittelmäßige.

Ist lokales Fine-Tuning DSGVO-konform?

Ja, wenn: Training & Inference vollständig lokal erfolgen (keine Cloud-APIs), keine personenbezogenen Daten im Trainingsdatensatz sind (oder Einwilligung eingeholt wurde), und Logs/Telemetrie deaktiviert sind.

Welches Modell soll ich wählen?

Für Deutsche Texte: Llama 3.2 oder Mistral (bessere multilinguale Fähigkeiten). Für Code: CodeLlama oder DeepSeek Coder. Für Chat: Llama 3.2 Instruct Varianten.

CUDA Out of Memory – was tun?

  1. load_in_4bit=True aktivieren
  2. Batch Size auf 1 reduzieren
  3. gradient_accumulation_steps erhöhen
  4. max_seq_length auf 1024 reduzieren
  5. Anderen Browser/Anwendungen schließen (VRAM-Konkurrenz)

Über den Autor

Senior Full Stack Developer & KI-Engineer mit Fokus auf Next.js, React und lokales LLM Fine-Tuning für deutschsprachige B2B-Anwendungen. Experimentiert seit 2023 mit lokalen KI-Modellen.

Zuletzt aktualisiert: Januar 2026 · Alle Code-Beispiele getestet mit Unsloth 2.0 & Ollama

Interessiert an einer Zusammenarbeit?

Lassen Sie uns darüber sprechen, wie ich Ihnen helfen kann.

Kostenlose Beratung anfragen →