Diffusion-Modelle sind eine neue Klasse von generativen Modellen, die durch einen iterativen Prozess realistische Inhalte erzeugen. Im Gegensatz zu GANs oder Autoregressive Modellen brauchen sie kein adversariales Training und sind stabiler zu trainieren.

Kernidee: Noise ist invertierbar

Grundkonzept: Wenn du ein Bild mit Rauschen überschreiben kannst, kannst du Rauschen auch wieder in ein Bild zurückwandeln.

Trainingsprozess (Forward Diffusion):
Echtes Bild → (+Rauschen) → Bild mit 10% Rauschen → ... → 100% Rauschen (Gaußsches Rauschen)

Generierung (Reverse Diffusion):
100% Rauschen → (-Rauschen vorhersagen) → Bild mit 90% Rauschen → ... → Echtes Bild

Das Modell lernt, bei jedem Schritt das Rauschen vorherzusagen, das hinzugefügt wurde.


Forward Diffusion Process (Trainingsphase)

Im Forward Pass wird ein echtes Bild schrittweise mit Rauschen "zerstört".

Mathematik (vereinfacht)

x_t = sqrt(α_t) * x_0 + sqrt(1 - α_t) * ε

wobei:
- x_0 = Original-Bild
- x_t = Bild nach t Diffusionsschritten
- α_t = Schedule-Wert (kontrolliert wie viel Rauschen)
- ε = Gaußsches Rauschen ~ N(0, 1)

Praktisches Beispiel:

t=0:   Echtes Bild (klar)
t=50:  Bild mit leichtem Rauschen (noch erkennbar)
t=500: Bild mit viel Rauschen (kaum noch erkennbar)
t=999: Pur Gaußsches Rauschen (keine Information mehr)

Noise Schedule

Der Schedule definiert, wie viel Rauschen bei jedem Schritt hinzugefügt wird.

# Linear Schedule (einfach)
alphas = torch.linspace(0.999, 0.001, num_steps)

# Cosine Schedule (besser, wie in Improved DDPM)
def cosine_schedule(t, T=1000):
    return torch.cos((t / T + 0.008) / 1.008 * π / 2) ** 2

# Ergebnis: Anfangs langsam → schneller → am Ende schnell

Warum der Schedule wichtig ist:

  • Linear: Gleichmäßiges Rauschen, ineffizient
  • Cosine/Quadratic: Bessere Nutzung der Schritte, schneller
  • Custom: Für spezifische Tasks optimiert

Reverse Diffusion Process (Generierung)

Das neuronale Netz lernt, Rauschen rückwärts vorherzusagen.

Das Modell trainieren

# Training-Schleife (pseudocode)
for x_0 in real_images:
    t = random_timestep(1, T)
    ε = torch.randn_like(x_0)  # Zufälliges Rauschen

    x_t = sqrt(α_t) * x_0 + sqrt(1 - α_t) * ε

    # Netzwerk sagt Rauschen voraus
    ε_predicted = unet(x_t, t)

    # Loss: Wie nah ist die Vorhersage am echten Rauschen?
    loss = MSE(ε_predicted, ε)
    loss.backward()

Generierung aus Noise

# Sampling (Generierung)
x_T = torch.randn(batch_size, 3, 256, 256)  # Reines Rauschen

for t in range(T-1, 0, -1):  # Rückwärts durch Timesteps
    z = torch.randn_like(x_T) if t > 1 else 0  # Variance

    # Modell sagt Rauschen voraus
    ε = unet(x_T, t)

    # Entferne Rauschen
    x_T = (x_T - sqrt(1 - α_t) * ε) / sqrt(α_t)

    # Füge kontrolliertes Rauschen hinzu (für Stochastizität)
    x_T += sqrt(β_t) * z

return x_T  # Finales Bild

DDPM (Denoising Diffusion Probabilistic Models)

DDPM war die erste praktische Implementierung (Ho et al. 2020).

Charakteristiken

Aspekt DDPM
Schritte 1000 (sehr viel)
Sampling-Zeit 20-30 Sekunden pro Bild
Qualität Sehr gut
Effizienz Nicht praktisch für Real-Time
Anwendung Akademische Referenz

DDPM Architektur

Input: Rauschen x_t + Timestep t
  ↓
Sinusoidal Timestep Embedding (zeitbewusst)
  ↓
U-Net mit ResNet Blöcken
  ↓
Attention (Self-Attention bei kleineren Features)
  ↓
Rauschen-Vorhersage ε

DDIM (Denoising Diffusion Implicit Models)

DDIM beschleunigt die Generierung, ohne Qualität zu opfern (Song et al. 2021).

Idee: Überschreite weniger Schritte

DDPM:  1000 → 999 → 998 → ... → 1 → 0  (1000 Schritte!)
DDIM:  1000 → 900 → 800 → ... → 100 → 0  (100 Schritte, 10x schneller!)

DDIM Sampling

# DDIM-Schritte (deterministisch)
def ddim_step(x_t, ε_t, t, t_prev):
    # Vorhergesagtes ursprüngliches Bild
    x_0_pred = (x_t - sqrt(1 - α_t) * ε_t) / sqrt(α_t)

    # DDIM-Übergänge (implizit, kein Rauschen nötig)
    x_t_prev = sqrt(α_t_prev) * x_0_pred + sqrt(1 - α_t_prev) * ε_t

    return x_t_prev

DDIM vs DDPM

DDPM:  Sampelt stochastisch, braucht viele Schritte
DDIM:  Deterministisch, weniger Schritte nötig (50 reichen meist)

Speed-Vergleich:
  DDPM 1000 Schritte: 30 Sekunden
  DDIM 50 Schritte:   1-2 Sekunden (15-30x schneller!)

Latent Diffusion Models (Stable Diffusion)

Latent Diffusion arbeitet nicht auf Pixel-Ebene, sondern im komprimierten Latent-Space — daher viel schneller.

Architektur

Echtes Bild (512x512)
  ↓
VAE Encoder (komprimieren)
  ↓
Latent-Space (64x64) — 8x Kompression
  ↓
Diffusion im Latent-Space (schnell!)
  ↓
VAE Decoder (dekomprimieren)
  ↓
Generiertes Bild (512x512)

Warum das schneller ist

Pixel-Level Diffusion:  512x512 = 262.144 Pixel pro Schritt
Latent Diffusion:       64x64 = 4.096 Dimensionen pro Schritt

Speedup: ~64x schneller bei gleicher Qualität

Training Latent Diffusion

# VAE - trainiert separat
encoder = VAE_Encoder()
decoder = VAE_Decoder()

# Forward Diffusion im Latent Space
z_0 = encoder(image)  # Beispiel: [1, 4, 64, 64]
z_t = apply_diffusion(z_0, t)  # Gleiches Rauschen-Prinzip

# U-Net operiert auf Latents
ε = unet(z_t, t, text_embedding)

Stable Diffusion Pipeline

Text: "Ein weißes Kaninchen sitzt auf einer Blume"
  ↓
CLIP Text Encoder → Text-Embedding (768d)
  ↓
U-Net (Cross-Attention mit Text)
  ↓
VAE Decoder
  ↓
Bild

Classifier-Free Guidance (CFG)

Guidance kontrolliert, wie stark das Modell dem Text-Prompt folgt.

Problem ohne Guidance

Das Modell muss zwischen "befolge Text" und "ignoriere Text" wechseln. Das führt zu Qualitätsverlust.

Lösung: CFG

# Training mit Classifier-Free Guidance
# 10% der Zeit: Text-Embedding = NULL (unbedingte Vorhersage)
# 90% der Zeit: Normal trainieren (bedingte Vorhersage)

# Sampling mit Guidance
ε_uncond = unet(z_t, t, embedding=None)  # Ohne Bedingung
ε_cond = unet(z_t, t, embedding=text_emb)  # Mit Bedingung

# Guidance-Anwendung
ε = ε_uncond + guidance_scale * (ε_cond - ε_uncond)

# guidance_scale:
#   1.0  = ignoriere Text völlig
#   7.5  = Standard (gutes Gleichgewicht)
#   15.0 = sehr stark Text folgen (weniger Vielfalt)

Praktischer Effekt

Prompt: "Katze"
CFG 1.0:  Zufälliges Bild (ignoriert Prompt)
CFG 7.5:  Katze mit etwas Vielfalt
CFG 15.0: Sehr stark erkennbare Katze (aber weniger kreativ)

Praktische Implementierung

Stable Diffusion mit Diffusers (Hugging Face)

from diffusers import StableDiffusionPipeline
import torch

# Modell laden
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16
)
pipe = pipe.to("cuda")

# Text → Bild
prompt = "Ein futuristisches Schloss auf einem Berggipfel"
image = pipe(
    prompt,
    height=512,
    width=512,
    num_inference_steps=50,  # DDIM Schritte
    guidance_scale=7.5,       # CFG Stärke
    generator=torch.Generator().manual_seed(42)
).images[0]

image.save("output.png")

DDIM vs DDPM in Praxis

from diffusers import DDIMScheduler, PNDMScheduler

# DDIM (schnell, 50 Schritte)
pipe.scheduler = DDIMScheduler.from_config(
    pipe.scheduler.config
)

# DDPM (langsam, aber original, 1000 Schritte)
pipe.scheduler = DDPMScheduler.from_config(
    pipe.scheduler.config
)

LoRA Fine-Tuning (für Custom Styles)

# Diffusers mit LoRA
from diffusers import StableDiffusionPipeline
from peft import get_peft_model, LoraConfig

# LoRA auf U-Net anwenden (nur 1% der Parameter trainieren)
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["to_k", "to_v"],
    lora_dropout=0.05
)

unet = get_peft_model(pipe.unet, lora_config)

# Trainieren auf Custom Dataset
# ... Training Loop ...

# Speichern und Laden
unet.save_pretrained("custom_lora")
pipe.load_lora_weights("custom_lora")

Vergleich: Diffusion vs Andere

Modell Speed Qualität Stabilität Training
Diffusion Mittel (DDIM) ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ Stabil
GAN Schnell ⭐⭐⭐⭐ ⭐⭐⭐ Schwierig
Autoregressive Langsam ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ Sehr langsam
Flow-basiert Mittel ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ Komplex

Use Cases und Recommendations

✅ Wann Diffusion verwenden

  • Text-to-Image (Stable Diffusion)
  • Image-to-Image (Inpainting)
  • Style Transfer
  • Upscaling
  • Video-Generierung
  • Super-Resolution

⚠️ Wann etwas Anderes verwenden

  • Real-Time Anwendungen ohne DDIM → dann GAN
  • Extrem große Bilder (>1024x1024) → weniger praktisch
  • Audio-Generierung → Diffusion ok, aber andere Modelle auch
  • Wenn Latency < 100ms kritisch → nicht geeignet

Neueste Entwicklungen (2024-2026)

Flux.1 (Black Forest Labs)

- Transformer-basiert statt U-Net
- Noch schneller (30-50 Schritte)
- Bessere Text-Treue
- Verwendet DiT (Diffusion Transformer)

Consistency Models

- Direktes Sampling in 1-2 Schritten
- Trainiert auf Diffusion-Modellen
- Trade-Off: Speed vs Quality

ControlNet und T2I Adapters

- Struktur-Kontrolle über Edges/Poses/Depth
- Composable Guidance
- Mehrere Bedingungen gleichzeitig

Häufige Fehler

1. Guidance Scale zu hoch

❌ CFG 30+: Artefakte, verfälschte Farben
✅ CFG 7-10: Gutes Gleichgewicht

2. Zu wenige Schritte

❌ 10 Schritte: Körnig, unfertig
✅ 50 Schritte (DDIM): Gute Balance
✅ 100+ Schritte: Maximum Qualität

3. Memory Overflow

# ❌ Zu viel RAM
image = pipe("prompt", height=2048, width=2048)

# ✅ Mit Optimierungen
pipe.enable_attention_slicing()
pipe.enable_memory_efficient_attention()
image = pipe("prompt", height=768, width=768)