Attention¶
Attention ist der Mechanismus, der Transformern erlaubt, Beziehungen zwischen allen Tokens in einer Sequenz zu lernen – unabhängig von ihrer Distanz. Er ist das Herzstück moderner LLMs.
Die Kernfrage¶
Bei der Verarbeitung eines Satzes muss das Modell wissen: Welche anderen Wörter sind für dieses Wort gerade relevant?
Attention beantwortet diese Frage, indem es Ähnlichkeiten zwischen Tokens berechnet.
Query, Key, Value¶
Die zentrale Idee: Jedes Token wird in drei Vektoren transformiert:
| Vektor | Funktion | Analogie |
|---|---|---|
| Query (Q) | "Was suche ich?" | Deine Suchanfrage |
| Key (K) | "Was biete ich?" | Titel/Tags eines Dokuments |
| Value (V) | "Was ist mein Inhalt?" | Der eigentliche Content |
Self-Attention Formel¶
Die Attention-Berechnung in einem Schritt:
Schritt für Schritt:
- Scores berechnen: \(QK^T\) – Wie ähnlich ist jede Query zu jedem Key?
- Skalieren: \(\div \sqrt{d_k}\) – Verhindert zu große Werte
- Softmax: Normalisiert zu Wahrscheinlichkeiten (summiert zu 1)
- Gewichtete Summe: Multipliziere mit Values
graph LR
Q[Query] --> Dot[Q × Kᵀ]
K[Key] --> Dot
Dot --> Scale[÷ √d_k]
Scale --> Soft[Softmax]
Soft --> Mul[× V]
V[Value] --> Mul
Mul --> Out[Output]
Beispiel: Attention visualisiert¶
Für den Satz "Die Katze schläft":
Attention Matrix nach Softmax:
→ "schläft" achtet stark auf "Katze" (0.5), weil das Verb sein Subjekt braucht.
Multi-Head Attention¶
Ein einzelner Attention-Kopf kann nur eine Art von Beziehung lernen. Multi-Head Attention verwendet mehrere parallele Attention-Köpfe:
heads = []
for i in range(num_heads):
Q_i = X @ W_q[i] # Eigene Projektion pro Head
K_i = X @ W_k[i]
V_i = X @ W_v[i]
heads.append(attention(Q_i, K_i, V_i))
output = concat(heads) @ W_o
Was lernen verschiedene Heads?
- Head 1: Syntaktische Beziehungen (Subjekt-Verb)
- Head 2: Coreference (Pronomen → Bezugswort)
- Head 3: Lokaler Kontext (benachbarte Wörter)
- ...
Masked Attention (Causal)¶
Bei der Textgenerierung darf das Modell nur auf vorherige Tokens schauen – nicht in die Zukunft:
Die Katze schläft
Die [1.0 -∞ -∞ ] ← Sieht nur sich selbst
Katze [0.3 0.7 -∞ ] ← Sieht "Die" und sich
schläft [0.1 0.5 0.4 ] ← Sieht alle vorherigen
Die \(-\infty\) Werte werden durch die Attention-Maske eingefügt und verschwinden nach dem Softmax.
Komplexität & Skalierung¶
Die Attention-Berechnung hat quadratische Komplexität:
| Sequenzlänge | Attention-Operationen |
|---|---|
| 1.000 Tokens | 1 Mio |
| 10.000 Tokens | 100 Mio |
| 100.000 Tokens | 10 Mrd |
Das ist der Grund, warum lange Context Windows so teuer sind!
Optimierungen¶
Flash Attention¶
Memory-effiziente Implementierung, die IO-Bottlenecks umgeht:
- Berechnet Attention in Blöcken
- Reduziert VRAM-Nutzung drastisch
- Standard in modernen Frameworks
Multi-Query Attention (MQA)¶
Keys und Values werden zwischen allen Heads geteilt:
→ Weniger VRAM für KV-Cache, schnellere Inferenz
Grouped-Query Attention (GQA)¶
Kompromiss: Mehrere Heads teilen sich K/V (z.B. 8 Query-Heads, 2 KV-Heads)
→ Verwendet in Llama ⅔, Mistral
Attention vs. andere Mechanismen¶
| Mechanismus | Komplexität | Globaler Kontext |
|---|---|---|
| Self-Attention | O(n²) | ✓ |
| RNN/LSTM | O(n) | Begrenzt |
| Convolution | O(n) | Lokal |
| State Space (Mamba) | O(n) | ✓ |
Code: Attention from Scratch¶
import torch
import torch.nn.functional as F
def attention(Q, K, V, mask=None):
d_k = Q.size(-1)
# Scores berechnen
scores = torch.matmul(Q, K.transpose(-2, -1)) / (d_k ** 0.5)
# Maske anwenden (für causale Attention)
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
# Softmax → Attention Weights
weights = F.softmax(scores, dim=-1)
# Gewichtete Summe der Values
return torch.matmul(weights, V)
Siehe auch¶
- Transformer – Die Gesamtarchitektur
- Embedding – Input für Attention
- KV-Cache – Attention beschleunigen
- Parameter – Wo stecken die Gewichte?