Positional Encoding
Eine Technik, die Transformern die Position von Tokens in einer Sequenz mitteilt – notwendig, weil Attention allein keine Reihenfolge kennt.
Eine Methode zur Positionskodierung in Transformern, die relative Positionen durch Rotation im Embedding-Raum kodiert – Standard in modernen LLMs.
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
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
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.
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)
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):
| 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 |
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
}
) RoPE ist wie eine Uhr mit rotierenden Zeigern: Die Position eines Tokens wird durch seinen Winkel dargestellt. Der Abstand zwischen zwei Tokens ergibt sich aus der Differenz ihrer Winkel – egal wo sie absolut stehen.
Kodiert relative Positionen statt absoluter
Ermöglicht Extrapolation auf längere Kontexte als trainiert
Standard in LLaMA, Mistral, GPT-NeoX und vielen modernen LLMs
Lange Kontexte
Modelle können auf längere Sequenzen extrapolieren
Effiziente Attention
Relative Positionen ohne zusätzliche Parameter
Context Extension
Basis für Techniken wie YaRN, NTK-aware Scaling
Absolute Encodings (wie in GPT-2) sind auf trainierte Länge begrenzt. RoPE kodiert relative Abstände, was Extrapolation auf längere Sequenzen ermöglicht.
Techniken wie YaRN oder NTK-aware Scaling modifizieren die Rotationsfrequenzen, um längere Kontexte zu unterstützen ohne volles Retraining.
LLaMA 1/2/3, Mistral, Mixtral, Qwen, Falcon, GPT-NeoX, und viele andere. Es ist der De-facto-Standard für moderne Open-Source LLMs.
Bei sehr langen Kontexten (>100k) kann die Qualität abnehmen. Außerdem: Etwas mehr Compute als keine Positional Encoding, aber vernachlässigbar.