Sofortantwort
RoPE einfach erklärt
Positionskodierung durch Rotation – ermöglicht längere Kontexte.
- Kurz gesagt
- Kodiert relative Positionen statt absoluter
- Typischer Einsatz
- Lange Kontexte, Effiziente Attention, Context Extension
- Wichtig zu wissen
- Standard in LLaMA, Mistral, GPT-NeoX und vielen modernen LLMs
RoPE im Überblick
RoPE (Rotary Position Embedding) ist eine Methode, um Transformern beizubringen, wo Tokens in einer Sequenz stehen. Statt absolute Positionen zu lernen, kodiert RoPE relative Abstände durch Rotation.
Das Problem mit absoluten Positionen:
Training: Sequenzen bis 2048 Tokens
Position 1, 2, 3, ... 2048 gelernt
Inference: Sequenz mit 4096 Tokens
Position 2049, 2050, ... ???
→ Modell hat diese nie gesehen!
RoPE-Lösung:
Statt: "Token an Position 5"
"Token an Position 10"
RoPE: "Token 10 ist 5 Positionen nach Token 5"
→ Relative Beziehung, nicht absolute Position
→ Funktioniert auch für ungesehene Positionen
Visualisierung:
Embedding-Raum (2D vereinfacht):
Position 1: ──→ (Winkel 0°)
Position 2: ╲ (Winkel 36°)
Position 3: ╲ (Winkel 72°)
...
Abstand = Winkeldifferenz
→ Unabhängig von absoluter Position
Technisch betrachtet
Mathematische Grundlage
Rotation im 2D-Raum:
R(θ) = [cos(θ) -sin(θ)]
[sin(θ) cos(θ)]
RoPE wendet Rotation auf Query/Key an:
def apply_rope(x, position, dim):
"""
x: Embedding [batch, seq_len, dim]
position: Position in Sequenz
"""
# Frequenzen für verschiedene Dimensionen
freqs = 1.0 / (10000 ** (torch.arange(0, dim, 2) / dim))
# Winkel = Position × Frequenz
angles = position * freqs
# Rotation anwenden (paarweise auf Dimensionen)
x_rotated = torch.zeros_like(x)
x_rotated[..., 0::2] = x[..., 0::2] * cos(angles) - x[..., 1::2] * sin(angles)
x_rotated[..., 1::2] = x[..., 0::2] * sin(angles) + x[..., 1::2] * cos(angles)
return x_rotated
Warum Rotation funktioniert
Attention Score:
score(q, k) = q · k
Mit RoPE:
score(q_m, k_n) = R(m·θ)q · R(n·θ)k
= q · R((n-m)·θ)k
→ Hängt nur von (n-m) ab, nicht von m oder n einzeln!
Die relative Position (n-m) ist im Score kodiert, nicht die absoluten Positionen.
Implementierung in Transformers
class RotaryEmbedding(nn.Module):
def __init__(self, dim, max_seq_len=2048, base=10000):
super().__init__()
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
self.register_buffer("inv_freq", inv_freq)
# Precompute für Effizienz
t = torch.arange(max_seq_len)
freqs = torch.einsum("i,j->ij", t, self.inv_freq)
self.register_buffer("cos_cached", freqs.cos())
self.register_buffer("sin_cached", freqs.sin())
def forward(self, x, seq_len):
cos = self.cos_cached[:seq_len]
sin = self.sin_cached[:seq_len]
return apply_rotary_pos_emb(x, cos, sin)
Context Extension
Problem: Modell auf 4k trainiert, soll 32k verarbeiten.
NTK-aware Scaling:
# Basis-Frequenz anpassen
base_scaled = base * (target_len / trained_len) ** (dim / (dim - 2))
# Neue Frequenzen
inv_freq = 1.0 / (base_scaled ** (torch.arange(0, dim, 2) / dim))
YaRN (Yet another RoPE extensioN):
- Kombiniert NTK-Scaling mit Interpolation
- Unterschiedliche Skalierung für verschiedene Frequenzen
- Aktuell beste Methode für Context Extension
Vergleich Positional Encodings
| Methode | Extrapolation | Effizienz | Modelle |
|---|---|---|---|
| Sinusoidal (Original) | Begrenzt | Gut | GPT-2 |
| Learned Absolute | Keine | Gut | BERT |
| ALiBi | Gut | Sehr gut | BLOOM |
| RoPE | Sehr gut | Gut | LLaMA, Mistral |
Praktische Tipps
Für Inference mit langen Kontexten:
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3-8B",
rope_scaling={
"type": "yarn",
"factor": 4.0, # 4x längerer Kontext
}
)