Zum Hauptinhalt springen

Fine-Tuning

Wie du KI-Modelle für deine spezifischen Anforderungen anpasst

Was ist Fine-Tuning?

Fine-Tuning ist der Prozess, bei dem ein bereits vortrainiertes KI-Modell (wie GPT oder LLaMA) auf spezifische Daten oder Aufgaben weiter trainiert wird. Statt ein Modell von Grund auf zu trainieren, nutzt man das vorhandene Wissen und passt es gezielt an neue Anforderungen an.

💡 Analogie: Fine-Tuning ist wie ein Aufbaustudium – du baust auf vorhandenem Wissen auf und spezialisierst dich in einem bestimmten Bereich.

Fine-Tuning Methoden

Full Fine-Tuning

Alle Parameter des Modells werden angepasst

Vorteile:

  • Maximale Anpassungsfähigkeit
  • Beste Ergebnisse für spezifische Domänen

Nachteile:

  • Hoher Rechenaufwand
  • Risiko von Overfitting

Ideal für: Wenn du viele Daten und Rechenkapazität hast

LoRA (Low-Rank Adaptation)

Nur kleine Adapter-Schichten werden trainiert

Vorteile:

  • Sehr effizient
  • Weniger Speicherbedarf
  • Schnelles Training

Nachteile:

  • Etwas geringere Flexibilität

Ideal für: Ideale Balance zwischen Effizienz und Leistung

Prompt Tuning

Nur Prompt-Embeddings werden optimiert

Vorteile:

  • Minimal invasiv
  • Sehr schnell
  • Günstig

Nachteile:

  • Begrenzte Anpassungsmöglichkeiten

Ideal für: Für einfache Anpassungen mit wenig Ressourcen

Praktische Anleitung: Fine-Tuning Schritt für Schritt

1Umgebung einrichten

Installiere die erforderlichen Bibliotheken für modernes Fine-Tuning:

# Grundlegende Bibliotheken installieren
pip install transformers==4.40.0
pip install peft==0.11.0
pip install bitsandbytes==0.43.0
pip install accelerate==0.30.0
pip install trl==0.8.6
pip install datasets==2.19.0

# Für bessere Performance (optional)
pip install unsloth[cu121]  # CUDA 12.1
pip install flash-attn --no-build-isolation

2Daten vorbereiten

Erstelle ein Dataset im ChatML-Format für optimale Ergebnisse:

import json
from datasets import Dataset

def prepare_dataset(data_file):
    """Bereite Dataset für Fine-Tuning vor"""
    conversations = []
    
    with open(data_file, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    for item in data:
        conversation = [
            {"role": "system", "content": "Du bist ein hilfreicher Assistent."},
            {"role": "user", "content": item["instruction"]},
            {"role": "assistant", "content": item["response"]}
        ]
        conversations.append({"messages": conversation})
    
    return Dataset.from_list(conversations)

3Modell konfigurieren

Lade das Basismodell mit QLoRA-Quantisierung:

from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    TrainingArguments
)
from peft import LoraConfig, get_peft_model
import torch

# QLoRA Konfiguration für 4-bit Training
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16
)

# Modell laden
model_name = "meta-llama/Llama-3.2-8B"
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    quantization_config=bnb_config,
    device_map="auto",
    torch_dtype=torch.bfloat16,
    attn_implementation="flash_attention_2"
)

# Tokenizer vorbereiten
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

4LoRA konfigurieren

Optimale LoRA-Einstellungen für 2025:

from peft import LoraConfig, TaskType

# Moderne LoRA Konfiguration
peft_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    inference_mode=False,
    r=16,  # Rank - höher für komplexere Aufgaben
    lora_alpha=16,  # Alpha scaling parameter
    lora_dropout=0.1,
    # Alle linearen Schichten anvisieren
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj"
    ],
    bias="none",
    use_rslora=True,  # 2025 Verbesserung
    use_dora=False    # Alternative zu LoRA
)

# LoRA auf Modell anwenden
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
# Ausgabe: trainable params: 6,738,432 || all params: 8,030,261,248 || trainable%: 0.08

5Training konfigurieren

Optimale Hyperparameter für verschiedene Hardware-Setups:

from trl import SFTTrainer, DataCollatorForCompletionOnlyLM

# Training Argumente - optimiert für RTX 4090/24GB
training_args = TrainingArguments(
    output_dir="./llama-3.2-8b-fine-tuned",
    per_device_train_batch_size=1,
    gradient_accumulation_steps=8,
    num_train_epochs=3,
    learning_rate=2e-4,
    lr_scheduler_type="cosine",
    warmup_ratio=0.1,
    logging_steps=10,
    save_strategy="epoch",
    evaluation_strategy="epoch",
    save_total_limit=2,
    bf16=True,
    gradient_checkpointing=True,
    dataloader_pin_memory=False,
    max_grad_norm=1.0,
    group_by_length=True,
    ddp_find_unused_parameters=False
)

6Training ausführen

Vollständiges Training-Skript:

def format_chat_template(row):
    """Formatiere Daten für Chat-Template"""
    messages = row['messages']
    return tokenizer.apply_chat_template(messages, tokenize=False)

def main():
    # Dataset laden
    train_dataset = prepare_dataset("train_data.json")
    eval_dataset = prepare_dataset("eval_data.json")
    
    # Trainer initialisieren
    trainer = SFTTrainer(
        model=model,
        train_dataset=train_dataset,
        eval_dataset=eval_dataset,
        peft_config=peft_config,
        tokenizer=tokenizer,
        args=training_args,
        max_seq_length=2048,
        packing=True,  # Effizientere GPU-Nutzung
        formatting_func=format_chat_template
    )
    
    # Training starten
    print("Training läuft...")
    trainer.train()
    
    # Modell speichern
    trainer.save_model()
    tokenizer.save_pretrained("./llama-3.2-8b-fine-tuned")
    print("Training abgeschlossen!")

if __name__ == "__main__":
    main()

7Evaluation und Test

Teste dein fine-getuntes Modell:

from peft import AutoPeftModelForCausalLM
import torch

# Fine-getuntes Modell laden
model = AutoPeftModelForCausalLM.from_pretrained(
    "./llama-3.2-8b-fine-tuned",
    device_map="auto",
    torch_dtype=torch.bfloat16
)

tokenizer = AutoTokenizer.from_pretrained("./llama-3.2-8b-fine-tuned")

def generate_response(prompt, max_length=512):
    """Generiere Antwort mit fine-getunetem Modell"""
    messages = [
        {"role": "system", "content": "Du bist ein hilfreicher Assistent."},
        {"role": "user", "content": prompt}
    ]
    
    # Formatiere mit Chat-Template
    formatted_prompt = tokenizer.apply_chat_template(
        messages, 
        tokenize=False, 
        add_generation_prompt=True
    )
    
    # Tokenisiere und generiere
    inputs = tokenizer(formatted_prompt, return_tensors="pt").to(model.device)
    
    with torch.no_grad():
        outputs = model.generate(
            **inputs,
            max_new_tokens=max_length,
            temperature=0.7,
            do_sample=True,
            top_p=0.95,
            pad_token_id=tokenizer.eos_token_id
        )
    
    # Dekodiere Antwort
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return response.split("assistant")[-1].strip()

# Teste verschiedene Prompts
test_prompts = [
    "Erkläre mir künstliche Intelligenz in einfachen Worten.",
    "Was sind die Vorteile von Fine-Tuning?",
    "Wie funktioniert LoRA?"
]

for prompt in test_prompts:
    print(f"\nPrompt: {prompt}")
    response = generate_response(prompt)
    print(f"Antwort: {response}")

Hardware-Anforderungen (2025)

ModellgrößeMinimale GPUEmpfohlene GPUTrainingsdauer
7B ParameterRTX 3090 (24GB)RTX 4090 (24GB)2-6 Stunden
13B ParameterA100 (40GB)H100 (80GB)4-12 Stunden
70B Parameter2x A100 (80GB)4x H100 (80GB)1-3 Tage
Quellen und Referenzen