Model Merging kombiniert mehrere trainierte Modelle in eines. Statt von Grund auf neu zu trainieren, nehme Features von verschiedenen spezialisierten Modellen und kombiniere sie.

Beispiel:
Model A: Gut in Code-Generierung
Model B: Gut in Kreativität
Model C: Gut in Mathematik

Merge(A, B, C) → Ein Modell mit allen Fähigkeiten!

Merge-Algorithmen

1. Linear Merge (einfach)

# Einfaches Durchschnitt der Gewichte
merged_weight = 0.5 * model_a.weight + 0.5 * model_b.weight

# Mit unterschiedlichen Proportionen
merged_weight = 0.3 * model_a.weight + 0.7 * model_b.weight

Vorteil: Einfach zu implementieren Nachteil: Oft Qualitätsverlust, Weight Space ist hochdimensional

2. SLERP (Spherical Linear Interpolation)

Standard Linear:
  x_0 = [1.0, 0.0, 0.0]
  x_1 = [0.0, 1.0, 0.0]
  Linear(0.5) = [0.5, 0.5, 0.0]  ← Mag verkürzt sein!

SLERP (Sphärisch):
  Interpoliere auf Einheitssphäre
  Erhält Magnitude des Vektors
import numpy as np

def slerp(v0, v1, t):
    """
    Spherical Linear Interpolation
    t: 0-1, wie viel von v1
    """
    # Normalize
    v0_norm = v0 / np.linalg.norm(v0)
    v1_norm = v1 / np.linalg.norm(v1)

    # Winkel zwischen Vektoren
    dot = np.clip(np.dot(v0_norm, v1_norm), -1.0, 1.0)
    omega = np.arccos(dot)

    if abs(omega) < 1e-6:
        return v0 * (1 - t) + v1 * t

    # Sphärische Interpolation
    return np.sin((1.0 - t) * omega) / np.sin(omega) * v0 + \
           np.sin(t * omega) / np.sin(omega) * v1

Anwendung auf Modell-Gewichte:

# Für jeden Layer
for layer in model_a.layers:
    merged_weight = slerp(
        model_a.layer.weight,
        model_b.layer.weight,
        t=0.5
    )

3. TIES (Task-specific Importance based Estimate of Selection)

Intelligente Auswahl: Welche Gewichte von welchem Modell?

Idee: Behalte die wichtigsten Gewichte jedes Modells

1. Berechne für jedes Modell: Welche Gewichte sind wichtig?
   (Durch Absolu
tveite oder Ablation)

2. Für jeden Weight:
   - Wenn wichtig in A und nicht in B: Nutze A
   - Wenn wichtig in B und nicht in A: Nutze B
   - Wenn wichtig in beiden: Merge mit SLERP
   - Wenn unwichtig in beiden: Ignorieren
def ties_merge(model_a, model_b, density_threshold=0.05):
    """
    model_a, model_b: PyTorch Modelle
    density_threshold: Was ist "wichtig"?
    """
    merged_state = {}

    for key in model_a.state_dict():
        w_a = model_a.state_dict()[key]
        w_b = model_b.state_dict()[key]

        # Berechne Importance als Absolutwert (vereinfacht)
        imp_a = torch.abs(w_a).flatten()
        imp_b = torch.abs(w_b).flatten()

        # Top density_threshold% Gewichte
        threshold_a = torch.quantile(imp_a, 1 - density_threshold)
        threshold_b = torch.quantile(imp_b, 1 - density_threshold)

        mask_a = (torch.abs(w_a) > threshold_a).float()
        mask_b = (torch.abs(w_b) > threshold_b).float()

        # Merge Logik
        merged = torch.zeros_like(w_a)
        both = (mask_a * mask_b)  # Wichtig in beiden
        only_a = (mask_a * (1 - mask_b))
        only_b = ((1 - mask_a) * mask_b)

        # Wo wichtig in A: Nutze A
        merged += w_a * only_a
        # Wo wichtig in B: Nutze B
        merged += w_b * only_b
        # Wo wichtig in beiden: Average (oder SLERP)
        merged += 0.5 * (w_a + w_b) * both

        merged_state[key] = merged

    return merged_state

4. DARE (Drops And REscale)

Statt Mittelwert: Drop unimportante Gewichte, rescale wichtige.

Idee: Viele Gewichte sind Rauschen
      Entferne (~90%) davon, rescale die verbleibenden

1. Pro Modell: Markiere ~10% der wichtigsten Gewichte
2. Setze den Rest auf 0
3. Rescale übrig gebliebene
4. Merge die rescaled Modelle
def dare_merge(model_a, model_b, drop_rate=0.9):
    """
    Drop unimportant weights, keep important ones
    """
    merged_state = {}

    for key in model_a.state_dict():
        w_a = model_a.state_dict()[key]
        w_b = model_b.state_dict()[key]

        # Importance: Absolutwert
        imp_a = torch.abs(w_a)
        imp_b = torch.abs(w_b)

        # Top (1-drop_rate)% Gewichte behalten
        threshold_a = torch.quantile(imp_a.flatten(), drop_rate)
        threshold_b = torch.quantile(imp_b.flatten(), drop_rate)

        mask_a = (torch.abs(w_a) > threshold_a).float()
        mask_b = (torch.abs(w_b) > threshold_b).float()

        # Rescale: Wenn 10% behalten, rescale um 10x
        w_a_masked = w_a * mask_a / (1 - drop_rate)
        w_b_masked = w_b * mask_b / (1 - drop_rate)

        # Average masked Gewichte
        merged_state[key] = 0.5 * w_a_masked + 0.5 * w_b_masked

    return merged_state

mergekit Tool (praktisch)

Populäres Open-Source Tool zum Mergen von Modellen.

# Installation
pip install mergekit

# Konfiguration: merge_config.yaml
models:
  - model_name: model_a_hf_path
    parameters:
      weight: 0.5
  - model_name: model_b_hf_path
    parameters:
      weight: 0.5

merge_method: ties
base_model: model_a_hf_path
parameters:
  normalize_weights: true
  int8_mask: true
# Merge durchführen
mergekit-cai --copy-tokenizer --allow-patterns "*.safetensors" \
  --cuda --low-ram merge_config.yaml ./output

Praktische Merge-Rezepte

Rezept 1: Chat + Coding Modelle

# Code Llama + ChatGLM Merge
models:
  - model_name: codellama/CodeLlama-7b-Instruct-hf
    parameters:
      weight: 0.6
  - model_name: THUDM/chatglm2-6b
    parameters:
      weight: 0.4

merge_method: slerp
base_model: codellama/CodeLlama-7b-Instruct-hf
parameters:
  t: 0.5

Ergebnis: Modell mit Code-Skill (60%) + Chat-Fähigkeiten (40%)

Rezept 2: Multiple Task Experts

# 3-Way Merge: Math + Code + Chat
models:
  - model_name: math_expert_7b  # Gemalt vom Math-Tuning
    parameters:
      weight: 0.33
  - model_name: code_expert_7b
    parameters:
      weight: 0.33
  - model_name: chat_base_7b
    parameters:
      weight: 0.34

merge_method: ties
parameters:
  density: 0.1  # Behalte nur 10% wichtigster Gewichte

Rezept 3: LoRA Merge vor Mergen

# Schritt 1: LoRA in Basis-Modell mergen
python merge_lora.py \
  --base_model meta-llama/Llama-2-7b \
  --lora_model your_lora_checkpoint \
  --output_dir ./merged_base

# Schritt 2: Merged Modelle kombinieren
mergekit-cai merge_config.yaml ./final_output

Wann Merging funktioniert / nicht funktioniert

✅ Merging funktioniert gut

1. Diverse Modelle (unterschiedliche Tasks)
   Code + Chat + Math → Gutes Ergebnis
   Grund: Weniger Konflikt zwischen Gewichten

2. Ähnliche Architektur
   Llama-7b + Llama-7b → Perfekt
   Reason: Gleiche Netzwerk-Struktur

3. Ähnliche Größe
   7B + 7B → Gut
   7B + 13B → Schlecht (unterschiedliche Dimensionen)

4. Fine-tuned auf Basis
   Base Model (Pretrain)
   + Model A (Fine-tune auf Base)
   + Model B (Fine-tune auf Base)
   → Gutes Ergebnis

❌ Merging funktioniert schlecht

1. Zu ähnliche Modelle (redundant)
   Llama Chat v1 + Llama Chat v2 → Nur marginal besser
   Grund: Zu viel Überlap, Merging macht keinen Sinn

2. Gegensätzliche Ziele
   Instruction-tuned (Chat) + Uncensored → Konflikt
   Result: Unpredictable Behavior

3. Sehr unterschiedliche Größen
   3B + 70B → Funktioniert nicht (dimensionale Mismatches)

4. Keine gemeinsame Base
   RandomModel A + RandomModel B → Chaos

Evaluierung nach Merge

from datasets import load_dataset
from transformers import pipeline

# Merged Model testen
merged = pipeline("text-generation", model="./merged_model")

# Test 1: Code
code_test = "def quicksort"
result = merged(code_test, max_length=50)
print("Code Quality:", result)

# Test 2: Math
math_test = "Was ist 2**10?"
result = merged(math_test, max_length=20)
print("Math Quality:", result)

# Test 3: Chat
chat_test = "Hallo, wie heißt du?"
result = merged(chat_test, max_length=30)
print("Chat Quality:", result)

Metriken-Basierte Evaluation

# Auf Standard Benchmarks testen
from lm_eval.evaluator import evaluate

results = evaluate(
    model="hf",
    model_args=f"pretrained=./merged_model",
    tasks=["hellaswag", "arc_easy", "truthfulqa_mc"],
    num_fewshot=0
)

print(results)
# Vergleiche mit Base Modellen

Best Practices

1. Merge mit ähnlichen Modellen

✅ Llama-7b mit anderem Llama-7b
✅ Mistral-7b mit anderem Mistral-7b
❌ Llama-7b mit Falcon-7b (unterschiedliche Architekturen)

2. Einige Gewichte frieren

# Nicht alle Gewichte mergen, nur bestimmte Layer
# z.B. nur Attention-Layer mergen, FFN frozenhalten

for name, param in merged_model.named_parameters():
    if "mlp" in name:
        param.requires_grad = False  # Freeze
    elif "self_attn" in name:
        param.requires_grad = True   # Merge

3. Post-Merge Fine-tuning

# Nach dem Merge: Fine-tune auf Mix-Daten
# 30% Math, 30% Code, 40% Chat

merged_model.train()
optimizer = torch.optim.AdamW(merged_model.parameters())

for batch in mixed_dataset:
    outputs = merged_model(**batch)
    loss = outputs.loss
    loss.backward()
    optimizer.step()

Häufige Fehler

1. Zu viele Modelle mergen

❌ Merge von 5+ Modellen → Qualitätsverlust
✅ 2-3 Modelle → Balance

2. Falsche Gewichte-Verhältnisse

❌ 0.95 + 0.05 → Effektiv nur ein Modell
✅ 0.5 + 0.5 oder 0.6 + 0.4 → Guter Balance

3. Keine Evaluation

❌ Merge durchführen, hoffen dass es gut ist
✅ Auf Benchmarks testen, mit Base vergleichen