<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Machine Learning on kenji.blog</title><link>http://kenji.blog/de/categories/machine-learning/</link><description>Recent content in Machine Learning on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/categories/machine-learning/index.xml" rel="self" type="application/rss+xml"/><item><title>【Für Anfänger】 Die mathematische Struktur des Transformer-Modells entschlüsseln</title><link>http://kenji.blog/de/p/transformer-mathematical-structure/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/transformer-mathematical-structure/</guid><description>&lt;img src="http://kenji.blog/p/transformer-mathematical-structure/img/eyecatch.jpg" alt="Featured image of post 【Für Anfänger】 Die mathematische Struktur des Transformer-Modells entschlüsseln" />&lt;h1 id="einführung-warum-die-mathematik-des-transformers-lernen">Einführung: Warum die Mathematik des Transformers lernen?
&lt;/h1>&lt;p>Es ist keine Übertreibung zu sagen, dass die Architektur des „Transformers“ die Geschichte der modernen natürlichen Sprachverarbeitung (NLP) und der gesamten KI neu geschrieben hat. Dieses Modell, das erstmals 2017 in dem Paper „Attention Is All You Need“ von Google-Forschern vorgestellt wurde, fungiert als Herzstück der Large Language Models (LLM), die derzeit die Welt dominieren, wie etwa die GPT-Serie von OpenAI (die Basistechnologie von ChatGPT), BERT von Google und Claude von Anthropic.&lt;/p>
&lt;p>Während man oft qualitative Erklärungen zur Funktionsweise des Transformers findet, wie etwa „den Kontext mithilfe des Attention-Mechanismus (Aufmerksamkeitsmechanismus) verstehen“, gibt es überraschenderweise nur wenige tiefgehende Erklärungen der dahinterliegenden &lt;strong>mathematischen Struktur&lt;/strong> für Anfänger. Um wirklich zu verstehen, wie die KI „Wörter“ als „mathematische Formeln“ verarbeitet und erstaunlich natürliche Texte generiert, ist es unerlässlich, ihre mathematischen Mechanismen zu entschlüsseln.&lt;/p>
&lt;p>In diesem Artikel werden wir die mathematischen Strukturen der Kernkomponenten des Transformers, wie den „Self-Attention-Mechanismus“, das „Query-Key-Value (Q/K/V)-Modell“, die „Normalisierung durch die Softmax-Funktion“ und das „Positional Encoding“, für Leser mit Grundkenntnissen in Mathematik und Programmierung (auf dem Niveau von Matrizen und Ableitungen aus der Oberstufe) gründlich und verständlich erläutern.&lt;/p>
&lt;p>Sie könnten von der Aneinanderreihung mathematischer Formeln überwältigt sein, aber jede einzelne Berechnung hat eine klare „Bedeutung“. Wenn Sie diesen Artikel zu Ende gelesen haben, sollten Sie verstehen können, dass der Transformer nicht einfach eine magische Blackbox ist, sondern ein präzise entworfenes Kristall aus Mathematik und Statistik.&lt;/p>
&lt;hr>
&lt;h1 id="1-die-grenzen-herkömmlicher-methoden-und-die-innovation-des-transformers">1. Die Grenzen herkömmlicher Methoden und die Innovation des Transformers
&lt;/h1>&lt;p>Bevor der Transformer aufkam, waren Recurrent Neural Networks (RNN) und ihre Derivate wie LSTM (Long Short-Term Memory) der Mainstream in der natürlichen Sprachverarbeitung. RNNs wurden entwickelt, um Zeitreihendaten zu verarbeiten, und lesen Texte Wort für Wort von Anfang an nacheinander ein.&lt;/p>
&lt;p>RNNs hatten jedoch zwei fatale Schwachstellen:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Schwierigkeiten beim Erlernen langfristiger Abhängigkeiten&lt;/strong>: Wenn Sätze länger werden, verblasst die Information der zuerst eingegebenen Wörter, bis sie das Ende erreichen (Problem des verschwindenden Gradienten).&lt;/li>
&lt;li>&lt;strong>Paralleles Rechnen ist unmöglich&lt;/strong>: Da die Wörter nacheinander verarbeitet werden müssen, sind groß angelegte parallele Berechnungen mithilfe von GPUs schwierig, und das Training nimmt enorm viel Zeit in Anspruch.&lt;/li>
&lt;/ol>
&lt;p>Der Transformer löste einen Paradigmenwechsel aus, indem er die RNN-Struktur komplett verwarf und den Kontext ausschließlich mithilfe von „Attention“ erfasste. Dadurch gibt es unabhängig von der Sequenzlänge keinen Informationsverlust, und Berechnungen können parallelisiert werden, um die Leistung von GPUs maximal auszuschöpfen.&lt;/p>
&lt;hr>
&lt;h1 id="2-die-gesamtarchitektur-des-transformers">2. Die Gesamtarchitektur des Transformers
&lt;/h1>&lt;p>Lassen Sie uns zunächst einen Überblick über die Gesamtarchitektur des Transformers verschaffen. Der Transformer besteht grob aus zwei Blöcken: dem „Encoder“ und dem „Decoder“. Am Beispiel einer Übersetzungsaufgabe wandelt der Encoder die Eingabesprache (z.B. Englisch) in eine mathematische Vektordarstellung um, und der Decoder generiert basierend auf dieser Vektordarstellung die Ausgabesprache (z.B. Japanisch).&lt;/p>
&lt;p>Das folgende Diagramm zeigt vereinfacht die interne Struktur des Encoder-Blocks.&lt;/p>
&lt;div class="mermaid">graph TD
A["Eingabe-Tokens"] --> B["Eingabe-Embedding"]
B --> C["Positional Encoding"]
C --> D["Multi-Head Self-Attention"]
D --> E["Add &amp; Layer Normalization"]
E --> F["Feed-Forward-Netzwerk"]
F --> G["Add &amp; Layer Normalization"]
G --> H["Ausgabe an nächste Schicht"]
C -.->|"Residual Connection"| E
E -.->|"Residual Connection"| G&lt;/div>
&lt;p>Von hier an werden wir die mathematischen Operationen in den einzelnen Komponenten Schritt für Schritt betrachten.&lt;/p>
&lt;hr>
&lt;h1 id="3-vektorisierung-von-wörtern-und-positionskodierung-positional-encoding">3. Vektorisierung von Wörtern und Positionskodierung (Positional Encoding)
&lt;/h1>&lt;p>Computer können Text nicht so verstehen, wie er ist. Der eingegebene Text wird zunächst in Einheiten namens „Tokens“ unterteilt, die jeweils in einen Vektor fester Länge umgewandelt werden. Das ist das &lt;strong>Input Embedding&lt;/strong>.&lt;/p>
&lt;h2 id="31-die-mathematik-des-input-embeddings">3.1 Die Mathematik des Input Embeddings
&lt;/h2>&lt;p>Sei $V$ die Größe des Vokabulars und $d_{model}$ die Anzahl der Dimensionen des Embedding-Vektors (im ursprünglichen Paper war $d_{model} = 512$). Jedes Wort $w_i$ wird mithilfe der Embedding-Matrix $W_E \in \mathbb{R}^{V \times d_{model}}$ in einen Vektor $x_i \in \mathbb{R}^{d_{model}}$ umgewandelt.&lt;/p>
$$ x_i = W_E \cdot \text{one\_hot}(w_i) $$
&lt;p>Dadurch wird der gesamte Satz als Matrix $X \in \mathbb{R}^{N \times d_{model}}$ dargestellt (wobei $N$ die Länge des Satzes ist).&lt;/p>
&lt;h2 id="32-die-notwendigkeit-und-formel-des-positional-encodings">3.2 Die Notwendigkeit und Formel des Positional Encodings
&lt;/h2>&lt;p>Der Transformer verarbeitet Wörter nicht nacheinander wie ein RNN, sondern alle Wörter gleichzeitig und parallel. Dies ist hinsichtlich der Berechnungsgeschwindigkeit ein großer Vorteil, verursacht aber gleichzeitig das Problem, dass &lt;strong>die wichtige Information der „Reihenfolge der Wörter (Wortstellung)“ verloren geht&lt;/strong>. Zum Beispiel sind die eingegebenen Wortmengen für „Ein Hund beißt einen Mann“ und „Ein Mann beißt einen Hund“ identisch, aber die Bedeutung ist völlig unterschiedlich.&lt;/p>
&lt;p>Um dem Modell diese Information über die Wortstellung zur Verfügung zu stellen, wurde das &lt;strong>Positional Encoding&lt;/strong> entwickelt.
Das Positional Encoding $PE$ für die $i$-te Dimension eines Wortes an der Position $pos$ wird mithilfe der folgenden trigonometrischen Funktionen berechnet.&lt;/p>
$$ PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) $$
$$ PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) $$
&lt;p>Hierbei ist $pos$ die Position des Wortes ($0, 1, 2, \dots, N-1$) und $i$ der Index der Dimension des Vektors ($0, 1, \dots, d_{model}/2 - 1$).&lt;/p>
&lt;h3 id="warum-sinus-und-kosinus-verwendet-werden">Warum Sinus und Kosinus verwendet werden
&lt;/h3>&lt;p>Auf den ersten Blick sieht es nach einer sehr komplexen und seltsamen Formel aus, aber es gibt einen tiefen mathematischen Grund dafür. Durch die Verwendung trigonometrischer Funktionen kann das Modell &lt;strong>nicht nur „absolute Positionen“, sondern auch die Differenz „relativer Positionen“&lt;/strong> leicht erlernen.&lt;/p>
&lt;p>Erinnern Sie sich an die Additionstheoreme für trigonometrische Funktionen aus der Schulmathematik.
&lt;/p>
$$ \sin(\alpha + \beta) = \sin\alpha \cos\beta + \cos\alpha \sin\beta $$
$$ \cos(\alpha + \beta) = \cos\alpha \cos\beta - \sin\alpha \sin\beta $$
&lt;p>Das Positional Encoding für eine Position $pos + k$, die um einen Offset $k$ von einer Position $pos$ entfernt ist, kann als Linearkombination des Positional Encodings der Position $pos$ dargestellt werden. Das bedeutet, es kann mithilfe einer Matrix $M_k$ wie folgt geschrieben werden:&lt;/p>
$$ PE_{pos+k} = M_k \cdot PE_{pos} $$
&lt;p>Dadurch kann der Attention-Mechanismus durch die Berechnung von Skalarprodukten leicht erkennen, „wie weit“ Wörter voneinander entfernt sind (relative Distanz). Zudem hat es den Vorteil, dass durch die Kombination mehrerer Sinus- und Kosinuswellen unterschiedlicher Wellenlängen selbst für noch so lange Sätze ein eindeutiger Positionsvektor generiert werden kann.&lt;/p>
&lt;p>Die endgültige Eingabematrix $X_{input}$ ergibt sich aus der Addition der Wort-Embedding-Vektoren und dieses Positional Encodings.&lt;/p>
$$ X_{input} = X + PE $$
&lt;hr>
&lt;h1 id="4-die-tiefgründige-mathematik-der-self-attention-selbstaufmerksamkeitsmechanismus">4. Die tiefgründige Mathematik der Self-Attention (Selbstaufmerksamkeitsmechanismus)
&lt;/h1>&lt;p>Nun dringen wir zur wichtigsten Komponente des Transformers vor: der &lt;strong>Self-Attention (Selbstaufmerksamkeitsmechanismus)&lt;/strong>. Das Ziel der Self-Attention ist es, „die Relevanz aller Wörter in einem Satz untereinander zu berechnen und den Vektor jedes Wortes zu einer reichhaltigeren Darstellung zu aktualisieren, die den Kontext berücksichtigt“.&lt;/p>
&lt;p>Hierbei wird die Analogie eines „Suchsystems“ verwendet.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Query (Q)&lt;/strong>: Suchanfrage. „Nach welchen Informationen suche ich gerade?“&lt;/li>
&lt;li>&lt;strong>Key (K)&lt;/strong>: Schlüssel (Schlagwort). „Welche Informationen habe ich?“&lt;/li>
&lt;li>&lt;strong>Value (V)&lt;/strong>: Wert (Inhalt). „Welche Informationen biete ich tatsächlich an?“&lt;/li>
&lt;/ul>
&lt;h2 id="41-generierung-der-matrizen-q-k-v">4.1 Generierung der Matrizen $Q, K, V$
&lt;/h2>&lt;p>Wir berechnen Query $Q$, Key $K$ und Value $V$, indem wir die Eingabematrix $X \in \mathbb{R}^{N \times d_{model}}$ (zur Vereinfachung ignorieren wir hier die Batch-Größe) mit den lernbaren Gewichtsmatrizen $W^Q, W^K, W^V \in \mathbb{R}^{d_{model} \times d_k}$ multiplizieren. (Normalerweise gilt $d_k = d_v = d_{model} / h$)&lt;/p>
$$ Q = X W^Q $$
$$ K = X W^K $$
$$ V = X W^V $$
&lt;p>Hier sind $Q, K, V$ alle Matrizen der Form $\mathbb{R}^{N \times d_k}$.&lt;/p>
&lt;h2 id="42-berechnung-der-attention-scores-skalarprodukt">4.2 Berechnung der Attention-Scores (Skalarprodukt)
&lt;/h2>&lt;p>Um zu messen, wie stark das Query jedes Wortes mit den Keys aller anderen Wörter in Beziehung steht, berechnen wir das &lt;strong>Skalarprodukt&lt;/strong> der Vektoren. Als Matrixoperation geschrieben, sieht das wie folgt aus:&lt;/p>
$$ \text{Scores} = Q K^T $$
&lt;p>Jedes Element $s_{ij}$ der aus dieser Berechnung resultierenden Matrix $\text{Scores} \in \mathbb{R}^{N \times N}$ repräsentiert das Skalarprodukt zwischen dem Query des $i$-ten Wortes und dem Key des $j$-ten Wortes, d. h. die „Stärke der Relevanz“.&lt;/p>
&lt;h2 id="43-skalierung-scale">4.3 Skalierung (Scale)
&lt;/h2>&lt;p>Die Score-Berechnung durch das Skalarprodukt hat ein Problem. Wenn die Dimension der Vektoren $d_k$ groß wird, werden die Werte des Skalarprodukts extrem groß oder extrem klein.&lt;/p>
&lt;p>Lassen Sie uns dies mathematisch beweisen.
Nehmen wir an, dass jedes Element des Queries $q \sim \mathcal{N}(0, 1)$ und jedes Element des Keys $k \sim \mathcal{N}(0, 1)$ einer unabhängigen Standardnormalverteilung folgt.
Wir bestimmen den Mittelwert und die Varianz des Skalarprodukts $q \cdot k = \sum_{i=1}^{d_k} q_i k_i$.
Mittelwert: Da $\mathbb{E}[q_i k_i] = \mathbb{E}[q_i] \mathbb{E}[k_i] = 0 \times 0 = 0$, ist auch der Mittelwert der Summe $0$.
Varianz: Die Varianz von $q_i k_i$ ist aufgrund der Unabhängigkeit $\text{Var}(q_i k_i) = \mathbb{E}[(q_i k_i)^2] - (\mathbb{E}[q_i k_i])^2 = 1 \times 1 - 0 = 1$.
Daher entspricht die Gesamtvarianz des Skalarprodukts der Dimensionsanzahl $d_k$.&lt;/p>
$$ \text{Var}(q \cdot k) = d_k $$
&lt;p>Wenn die Varianz groß wird, tritt bei der anschließend angewendeten Softmax-Funktion das „Problem des verschwindenden Gradienten“ auf, bei dem die Gradienten für alle Werte außer dem Maximum extrem klein werden, wodurch das Training stagniert.
Um dies zu verhindern, teilen wir die Scores durch $\sqrt{d_k}$ (Skalierung), um die Varianz stets bei $1$ zu halten.&lt;/p>
$$ \text{Scaled Scores} = \frac{Q K^T}{\sqrt{d_k}} $$
&lt;h2 id="44-umwandlung-in-wahrscheinlichkeiten-durch-die-softmax-funktion">4.4 Umwandlung in Wahrscheinlichkeiten durch die Softmax-Funktion
&lt;/h2>&lt;p>Um die erhaltenen Scores in eine Wahrscheinlichkeitsverteilung (Gewichte) umzuwandeln, deren Summe $1$ ergibt, wird die &lt;strong>Softmax-Funktion&lt;/strong> zeilenweise angewendet.&lt;/p>
$$ a_{ij} = \text{softmax}(s_i)_j = \frac{\exp(s_{ij} / \sqrt{d_k})}{\sum_{m=1}^N \exp(s_{im} / \sqrt{d_k})} $$
&lt;p>Die Matrix $A \in \mathbb{R}^{N \times N}$ wird als Attention-Weight-Matrix (Aufmerksamkeitsgewichtsmatrix) bezeichnet. Wenn wir uns jede Zeile $i$ dieser Matrix ansehen, wird durch einen Wert zwischen 0 und 1 ausgedrückt: „Wie viel Aufmerksamkeit (Attention) sollte man anderen Wörtern $j$ schenken, um das Wort $i$ zu verstehen?“.&lt;/p>
&lt;h2 id="45-gewichtete-summe-der-values">4.5 Gewichtete Summe der Values
&lt;/h2>&lt;p>Schließlich berechnen wir mithilfe der erhaltenen Attention-Weight-Matrix $A$ die gewichtete Summe der Value-Matrix $V$.&lt;/p>
$$ \text{Output} = A V = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>Die durch diese Operation ausgegebene Matrix $Z \in \mathbb{R}^{N \times d_v}$ ist eine Sammlung von „Vektordarstellungen der Wörter, die unter Berücksichtigung des Kontextes aktualisiert wurden“.
Dies ist das vollständige Bild der im Paper definierten &lt;strong>Scaled Dot-Product Attention&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="5-multi-head-attention">5. Multi-Head Attention
&lt;/h1>&lt;p>Mit nur einer einzigen Attention-Berechnung (Single-Head) besteht die Möglichkeit, dass der Kontext nur aus einer Perspektive (z. B. „grammatikalische Beziehungen“) erfasst wird. Um die vielfältigen semantischen und syntaktischen Beziehungen der Sprache („Subjekt und Prädikat“, „Pronomen und ihr Bezugswort“ usw.) gleichzeitig zu erfassen, wurde die &lt;strong>Multi-Head Attention&lt;/strong> eingeführt.&lt;/p>
&lt;p>Die Generierung von $Q, K, V$ und die Attention-Berechnung von vorhin werden $h$-mal parallel durchgeführt ($h$ ist die Anzahl der Heads; im ursprünglichen Paper war $h=8$).&lt;/p>
$$ \text{head}_i = \text{Attention}(X W_i^Q, X W_i^K, X W_i^V) $$
&lt;p>Hierbei sind $W_i^Q, W_i^K, W_i^V \in \mathbb{R}^{d_{model} \times d_k}$ die lernbaren Gewichtsmatrizen speziell für den $i$-ten Head.&lt;/p>
&lt;p>Die von jedem Head ausgegebenen Ergebnisse $\text{head}_i \in \mathbb{R}^{N \times d_v}$ werden horizontal verkettet (Concatenate).&lt;/p>
$$ \text{Concat}(\text{head}_1, \dots, \text{head}_h) \in \mathbb{R}^{N \times (h \cdot d_v)} $$
&lt;p>Normalerweise wird $h \cdot d_v = d_{model}$ so gewählt, dass die Dimension nach der Verkettung wieder auf das Eingangsmaß $d_{model}$ zurückkehrt. Schließlich wird diese Matrix mit der Gewichtsmatrix $W^O \in \mathbb{R}^{d_{model} \times d_{model}}$ multipliziert, um die endgültige Ausgabe zu erhalten.&lt;/p>
$$ \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^O $$
&lt;div class="mermaid">graph TD
X["Eingabe X"] --> Q1["Q1"]
X --> K1["K1"]
X --> V1["V1"]
Q1 &amp; K1 &amp; V1 --> H1["Head 1"]
X --> Q2["Q2"]
X --> K2["K2"]
X --> V2["V2"]
Q2 &amp; K2 &amp; V2 --> H2["Head 2"]
X --> QN["..."]
X --> KN["..."]
X --> VN["..."]
QN &amp; KN &amp; VN --> HN["Head h"]
H1 &amp; H2 &amp; HN --> C["Verketten"]
C --> WO["Mit WO multiplizieren"]
WO --> OUT["Multi-Head Ausgabe"]&lt;/div>
&lt;hr>
&lt;h1 id="6-feed-forward-neural-network-ffn">6. Feed-Forward Neural Network (FFN)
&lt;/h1>&lt;p>Die Ausgabe der Multi-Head Attention wird anschließend in das &lt;strong>Position-wise Feed-Forward Network (FFN)&lt;/strong> eingespeist.
Dies ist ein zweischichtiges, vollständig verbundenes neuronales Netzwerk, das „für jede Position (jedes Wort) in der Sequenz unabhängig“ angewendet wird.&lt;/p>
&lt;p>Als mathematische Formel ausgedrückt, sieht das so aus:&lt;/p>
$$ \text{FFN}(x) = \max(0, x W_1 + b_1) W_2 + b_2 $$
&lt;p>Hierbei repräsentiert $\max(0, z)$ die ReLU-Aktivierungsfunktion (Rectified Linear Unit) (in neueren Modellen werden oft auch GELU oder SwiGLU verwendet).&lt;/p>
&lt;p>Die Rolle dieses Netzwerks ist äußerst wichtig. Während der Attention-Mechanismus „Beziehungen zwischen Wörtern (räumliche und sequentielle Beziehungen)“ erlernt, ist das FFN für die „nichtlineare Feature-Transformation jedes einzelnen Wortvektors“ verantwortlich.
Typischerweise wird die Dimension durch die Gewichte der ersten Schicht $W_1$ vorübergehend stark erweitert (z. B. vervierfacht von $d_{model}=512$ auf $d_{ff}=2048$), um komplexe Berechnungen im Merkmalsraum durchzuführen, und dann durch die Gewichte der zweiten Schicht $W_2$ wieder auf die ursprüngliche Dimension reduziert. Durch diese „Erweiterung und Reduktion der Dimensionen“ wird die Ausdruckskraft des Modells dramatisch erhöht.&lt;/p>
&lt;hr>
&lt;h1 id="7-residual-connection-und-layer-normalization">7. Residual Connection und Layer Normalization
&lt;/h1>&lt;p>Im Deep Learning tritt bei tiefer werdenden Netzwerkschichten das Problem auf, dass Gradienten während des Trainings verschwinden oder explodieren, was ein erfolgreiches Training verhindert. Um dies zu verhindern, sind um jede Subschicht (Attention und FFN) des Transformers eine &lt;strong>Residual Connection (Restverbindung)&lt;/strong> und eine &lt;strong>Layer Normalization (Schichtnormalisierung)&lt;/strong> angeordnet.&lt;/p>
&lt;p>Als Formel geschrieben, wird die Ausgabe der Subschicht wie folgt verarbeitet:&lt;/p>
$$ \text{Output} = \text{LayerNorm}(x + \text{Sublayer}(x)) $$
&lt;h2 id="71-residual-connection-x--textsublayerx">7.1 Residual Connection ($x + \text{Sublayer}(x)$)
&lt;/h2>&lt;p>Die Eingabe $x$ wird direkt zur Ausgabe der Subschicht addiert. Dadurch wird der Gradient bei der Backpropagation direkt durch einen Shortcut in flachere Schichten weitergeleitet, wodurch das Training selbst bei tiefen Schichten stabil bleibt.&lt;/p>
&lt;h2 id="72-die-mathematik-der-layer-normalization">7.2 Die Mathematik der Layer Normalization
&lt;/h2>&lt;p>Layer Normalization ist eine Technik, die den Mittelwert und die Varianz entlang der Dimension der Merkmale berechnet und die Daten normalisiert. Bei einer Eingabe mit der Batch-Größe $B$, der Sequenzlänge $N$ und der Dimensionsanzahl $d_{model}$ wird die Normalisierung für einen einzelnen Wortvektor $x \in \mathbb{R}^{d_{model}}$ durchgeführt.&lt;/p>
&lt;p>Wir berechnen den Mittelwert $\mu$ und die Varianz $\sigma^2$.
&lt;/p>
$$ \mu = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} x_i $$
$$ \sigma^2 = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} (x_i - \mu)^2 $$
&lt;p>Dann erhalten wir die normalisierte Ausgabe $\hat{x}$.
&lt;/p>
$$ \text{LN}(x) = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta $$
&lt;p>
($\epsilon$ ist eine winzige Konstante zur Vermeidung einer Division durch null. $\gamma, \beta$ sind lernbare Skalierungs- und Verschiebungsparameter.)&lt;/p>
&lt;p>Der Grund für die Verwendung der schichtweisen Normalisierung (Layer Normalization) anstelle der Normalisierung in Batch-Richtung (Batch Normalization) liegt darin, dass bei der Verarbeitung von sequenziellen Daten mit variabler Länge, wie z.B. Sätzen, die Statistiken zwischen den Batches tendenziell instabil werden. Dank der Layer Normalization ermöglicht der Transformer ein stabiles Training unabhängig von der Batch-Größe.&lt;/p>
&lt;hr>
&lt;h1 id="8-decoderspezifische-strukturen-masked-attention-und-cross-attention">8. Decoderspezifische Strukturen: Masked Attention und Cross-Attention
&lt;/h1>&lt;p>Die bisher erläuterten Strukturen gehören zum Encoder. Beim Decoder-Block, der Sätze generiert, weicht die Struktur leicht ab.&lt;/p>
&lt;h2 id="81-masked-multi-head-attention">8.1 Masked Multi-Head Attention
&lt;/h2>&lt;p>Die Rolle des Decoders ist es, „das nächste Wort aus vergangenen Wörtern vorherzusagen“. Daher wäre es beim Training Schummeln, wenn er „zukünftige Wörter“ sehen würde. Die mathematische Operation, um dies zu verhindern, ist das &lt;strong>Masking (Maskierung)&lt;/strong>.&lt;/p>
&lt;p>Zur Score-Matrix $Q K^T$ wird eine Maskenmatrix $M$ addiert, die im oberen Dreiecksteil (was den zukünftigen Informationen entspricht) sehr kleine Werte nahe $-\infty$ setzt.&lt;/p>
$$ M_{ij} = \begin{cases} 0 &amp; (i \le j) \\ -\infty &amp; (i > j) \end{cases} $$
$$ \text{Masked Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T + M}{\sqrt{d_k}}\right) V $$
&lt;p>Bei der Berechnung der Softmax-Funktion wird $\exp(-\infty) = 0$, sodass das Attention-Weight für zukünftige Wörter komplett $0$ wird. Dadurch wird eine autoregressive Generierung unter Beibehaltung der Kausalität ermöglicht.&lt;/p>
&lt;h2 id="82-encoder-decoder-cross-attention">8.2 Encoder-Decoder Cross-Attention
&lt;/h2>&lt;p>Die zweite Subschicht des Decoders ist die &lt;strong>Cross-Attention&lt;/strong>, die auf die Ausgabe des Encoders verweist.
Hierbei wird $Q$ aus der vorherigen Decoder-Schicht generiert, während $K$ und $V$ aus der Ausgabe der letzten Encoder-Schicht generiert werden.&lt;/p>
$$ Q_{decoder} = X_{dec} W^Q $$
$$ K_{encoder} = X_{enc} W^K $$
$$ V_{encoder} = X_{enc} W^V $$
&lt;p>Durch diese Berechnung kann das Modell bei Übersetzungsaufgaben lernen, „mit welchem Teil des ursprünglichen fremdsprachigen Satzes das aktuell zu übersetzende Wort stark zusammenhängt“.&lt;/p>
&lt;hr>
&lt;h1 id="9-rechenaufwand-und-die-mathematik-der-optimierung-in-der-moderne">9. Rechenaufwand und die Mathematik der Optimierung in der Moderne
&lt;/h1>&lt;p>Der Transformer ist ein großartiges Modell, hat aber aufgrund seiner mathematischen Struktur auch „Schwachstellen“.
Achten Sie auf den Rechenaufwand der Self-Attention. Bei der Berechnung der Score-Matrix $Q K^T$ wird eine $(N \times d_k)$-Matrix mit einer $(d_k \times N)$-Matrix multipliziert, sodass der Rechenaufwand &lt;strong>$O(N^2 \cdot d_{model})$&lt;/strong> beträgt.&lt;/p>
&lt;p>Das bedeutet, dass &lt;strong>Rechenaufwand und Speicherverbrauch quadratisch zur Sequenzlänge $N$ ansteigen&lt;/strong>.
Bei kurzen Texten ist das kein Problem, aber wenn man versucht, einen extrem langen Kontext wie ein ganzes Buch in ein LLM einzuspeisen, erreicht $N$ Zehn- bis Hunderttausende, und bei herkömmlichen Attention-Berechnungen wäre der GPU-Speicher sofort erschöpft.&lt;/p>
&lt;p>Um diesen Fluch der $O(N^2)$-Komplexität zu brechen, wurden in den letzten Jahren verschiedene Optimierungen aus mathematischen und hardwaretechnischen Ansätzen vorgeschlagen.
Ein Paradebeispiel dafür ist &lt;strong>FlashAttention&lt;/strong>. FlashAttention ist ein Algorithmus, der die Attention-Berechnung in Kacheln unterteilt (Tiling), um den Datentransfer (Speicherzugriff) zwischen den Speicherhierarchien der GPU (SRAM und HBM) zu minimieren. Obwohl es mathematisch exakt das gleiche Ergebnis wie die Standard-Attention liefert (Exact Attention), erreicht es durch Optimierung auf Hardware-Ebene eine dramatische Beschleunigung und Speicherreduzierung, was die Realisierung von Modellen mit langem Kontext wie GPT-4 ermöglicht hat.&lt;/p>
&lt;p>Darüber hinaus wird intensiv an Sparse Attention, Linear Attention und Ähnlichem geforscht, die den Rechenaufwand auf $O(N \log N)$ oder $O(N)$ annähern.&lt;/p>
&lt;hr>
&lt;h1 id="10-vorstellungen-zur-implementierung-pseudocode-im-pytorch-stil">10. Vorstellungen zur Implementierung (Pseudocode im PyTorch-Stil)
&lt;/h1>&lt;p>Wenn man die bisherigen mathematischen Strukturen in tatsächlichen Programmiercode (Python / PyTorch) überträgt, stellt man fest, dass sie überraschend einfach geschrieben werden können. Hier ist der Pseudocode für den Kernteil der Self-Attention.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch.nn.functional&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">F&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">scaled_dot_product_attention&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Form von q, k, v: [batch_size, num_heads, seq_length, d_k]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d_k&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. Score-Berechnung durch Skalarprodukt: Q * K^T&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Die letzten beiden Dimensionen transponieren und Matrixprodukt berechnen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">matmul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">transpose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. Skalierung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scores&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">d_k&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. Maskierung (im Falle von Masked Attention)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">mask&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scores&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">masked_fill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mask&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mf">1e9&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. Umwandlung in Wahrscheinlichkeiten durch Softmax&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">attention_weights&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">F&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">softmax&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">scores&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dim&lt;/span>&lt;span class="o">=-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. Multiplikation mit der Value-Matrix&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">matmul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">attention_weights&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">attention_weights&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Man kann sehen, dass der mathematisch dargestellte Ausdruck $Q K^T / \sqrt{d_k}$ intuitiv als &lt;code>torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)&lt;/code> implementiert wird. Es ist ein sehr faszinierender Aspekt des Deep Learning, dass mathematische Theorien mithilfe von stark optimierten Bibliotheken in wenigen Codezeilen realisiert werden können.&lt;/p>
&lt;hr>
&lt;h1 id="fazit-die-form-der-intelligenz-wie-sie-aus-mathematischen-formeln-ersichtlich-wird">Fazit: Die Form der „Intelligenz“, wie sie aus mathematischen Formeln ersichtlich wird
&lt;/h1>&lt;p>In diesem Artikel haben wir die tiefgründigen mathematischen Strukturen des Transformer-Modells entschlüsselt.&lt;/p>
&lt;p>Das Embedding, das Wörter in einen mehrdimensionalen Vektorraum abbildet, das Positional Encoding, das Positionsinformationen durch die Synthese von Dreieckswellen ausdrückt, und der Self-Attention-Mechanismus, der aus einer Analogie zur Informationsbeschaffung entstandene Matrizenmultiplikationen verwendet. Jede dieser Komponenten ist lediglich eine Ansammlung von grundlegender Mathematik wie linearer Algebra, Differenzial- und Integralrechnung sowie Wahrscheinlichkeitsrechnung und Statistik.&lt;/p>
&lt;p>Wenn sich diese einfachen Matrixoperationen jedoch in unzähligen Schichten überlagern und Muster aus gigantischen Datensätzen durch Milliarden oder Hunderte von Milliarden an Parametern lernen, entsteht eine „Form von Intelligenz“, die unsere „Wörter“ zu verstehen, logische Schlüsse zu ziehen und manchmal kreative Ideen hervorzubringen scheint.&lt;/p>
&lt;p>Wie der provokante Titel „Attention Is All You Need“ andeutet, liegt die Schönheit dieser Architektur, die komplexe rekurrente und konvolutionale Verarbeitungen verworfen und sich auf die reinrassige Berechnung von „Attention (Relevanz)“ spezialisiert hat, gerade in ihrer mathematischen Einfachheit.&lt;/p>
&lt;p>In Zukunft könnten zwar neue Architekturen auftauchen, die den Transformer übertreffen (wie z. B. Mamba, ein State Space Model), aber der mathematische Rahmen des „Kontextverständnisses durch Attention“, den der Transformer geschaffen hat, wird für immer in der Geschichte der KI verankert bleiben.&lt;/p>
&lt;p>Wenn Sie künftig die Gelegenheit haben, LLMs wie ChatGPT oder Claude zu nutzen, stellen Sie sich vor, wie im Hintergrund jede Sekunde Billionen von Matrixmultiplikationen von $Q K^T$ berechnet werden und die Softmax-Funktion Wahrscheinlichkeiten ausspuckt. Ihr Verständnis für die Technologie wird sich vertiefen, und die Welt der KI wird Ihnen noch faszinierender erscheinen.&lt;/p>
&lt;h3 id="literaturverzeichnis">Literaturverzeichnis
&lt;/h3>&lt;ul>
&lt;li>Vaswani, A., et al. (2017). &amp;ldquo;Attention Is All You Need.&amp;rdquo; &lt;em>Advances in Neural Information Processing Systems&lt;/em>.&lt;/li>
&lt;li>Alammar, J. (2018). &amp;ldquo;The Illustrated Transformer.&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;em>Dieser Artikel wurde als Leitfaden für all jene verfasst, die die mathematischen Grundlagen der natürlichen Sprachverarbeitung und der KI erlernen möchten. Wenn Sie Fragen oder Diskussionsbedarf haben, lassen Sie es mich bitte in den Kommentaren wissen!&lt;/em>&lt;/p></description></item><item><title>Erklärung der Funktionsweise der Quantisierungstechnologie (GGUF) in llama.cpp</title><link>http://kenji.blog/de/p/llama-cpp-quantization-gguf/</link><pubDate>Fri, 11 Sep 2026 00:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/llama-cpp-quantization-gguf/</guid><description>&lt;img src="http://kenji.blog/p/llama-cpp-quantization-gguf/img/eyecatch.jpg" alt="Featured image of post Erklärung der Funktionsweise der Quantisierungstechnologie (GGUF) in llama.cpp" />&lt;h2 id="1-einführung-warum-benötigen-llms-quantisierung">1. Einführung: Warum benötigen LLMs Quantisierung?
&lt;/h2>&lt;p>Die Entwicklung von großen Sprachmodellen (LLM: Large Language Models) in den letzten Jahren war bemerkenswert, aber im Hintergrund sind ernsthafte Probleme aufgetreten: &amp;ldquo;Erschöpfung der Rechenressourcen&amp;rdquo; und &amp;ldquo;Engpässe bei der Speicherbandbreite&amp;rdquo;. Wenn beispielsweise ein Modell mit 70B (70 Milliarden) Parametern wie Llama 3 im standardmäßigen 16-Bit-Gleitkommaformat (FP16) in den Speicher geladen wird, verbrauchen allein die Parameter etwa 140 GB VRAM/RAM. Wenn der Kontext (KV-Cache) während der Inferenz hinzugefügt wird, funktioniert dies nicht, ohne mehrere High-End-GPUs für Rechenzentren (wie NVIDIA A100 80GB oder H100 80GB) in einem Cluster zusammenzufassen.&lt;/p>
&lt;p>Als Retter für die Ausführung von LLMs auf Edge-Geräten (wie MacBooks oder gängigen Gaming-PCs) für einzelne Entwickler tauchten &lt;strong>llama.cpp&lt;/strong> und seine Kerntechnologie, die &lt;strong>Quantisierung (Quantization)&lt;/strong>, auf. Insbesondere das Dateiformat &lt;strong>GGUF (GPT-Generated Unified Format)&lt;/strong> und ein fortschrittlicher blockbasierter Quantisierungsalgorithmus namens &lt;strong>k-quants&lt;/strong> sind bahnbrechende Methoden, die die Modellgröße auf einen Bruchteil komprimieren, während die Verschlechterung der Modellgenauigkeit (Perplexity) so gering wie möglich gehalten wird.&lt;/p>
&lt;p>In diesem Artikel werden wir alles vom mathematischen Hintergrund der Quantisierung in llama.cpp über die Unterschiede zum GGML-Format und die detaillierte Struktur des GGUF-Formats bis hin zu den internen Mechanismen von k-quants ausführlich erklären.&lt;/p>
&lt;hr>
&lt;h2 id="2-mathematische-grundlagen-der-quantisierung">2. Mathematische Grundlagen der Quantisierung
&lt;/h2>&lt;p>Im Kontext von LLMs bezieht sich Quantisierung auf den Vorgang, kontinuierliche Werte (oder hochpräzise Gleitkommazahlen) auf diskrete Werte mit einer geringeren Anzahl von Bits (wie INT8, INT4, INT3) abzubilden.&lt;/p>
&lt;h3 id="21-grundlegende-formeln-der-linearen-quantisierung">2.1. Grundlegende Formeln der linearen Quantisierung
&lt;/h3>&lt;p>Der einfachste Ansatz ist die lineare Quantisierung (Min-Max-Quantisierung). Sei der ursprüngliche hochpräzise Gewichtstensor $W$ und der quantisierte Ganzzahl-Tensor $W_q$.&lt;/p>
$$ W_q = \text{round}\left( \frac{W}{S} \right) + Z $$
&lt;p>Hierbei ist:&lt;/p>
&lt;ul>
&lt;li>$S$ der &lt;strong>Skalierungsfaktor (Scale Factor)&lt;/strong>, der die Schrittgröße (Auflösung) der Quantisierung bestimmt.&lt;/li>
&lt;li>$Z$ der &lt;strong>Nullpunkt (Zero-point)&lt;/strong>, ein Bias-Wert, um zu verschieben, welchem ganzzahligen Wert nach der Quantisierung die reelle Zahl $0.0$ entspricht.&lt;/li>
&lt;li>$\text{round}(\cdot)$ die Funktion zur Rundung auf die nächste Ganzzahl.&lt;/li>
&lt;/ul>
&lt;p>Durch inverse Quantisierung (Dequantization) wird während der Inferenz ein ungefähres reelles Gewicht $\tilde{W}$ wiederhergestellt.&lt;/p>
$$ \tilde{W} = S \times (W_q - Z) $$
&lt;h3 id="22-symmetrische-vs-asymmetrische-quantisierung">2.2. Symmetrische vs. asymmetrische Quantisierung
&lt;/h3>&lt;p>Abhängig von der Behandlung des Nullpunkts $Z$ gibt es im Wesentlichen zwei Methoden.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Asymmetrische Quantisierung (Asymmetric Quantization)&lt;/strong>
Mappt die Daten unter Verwendung des Minimalwerts $W_{\min}$ und des Maximalwerts $W_{\max}$.
&lt;/p>
$$ S = \frac{W_{\max} - W_{\min}}{2^b - 1}, \quad Z = \text{round}\left(-\frac{W_{\min}}{S}\right) $$
&lt;p>
Hier ist $b$ die Anzahl der Quantisierungsbits (z.B. für 4 Bit ist $2^4-1 = 15$). Da $Z$ beibehalten werden muss, erhöht sich der Rechen- und Speicher-Overhead geringfügig.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Symmetrische Quantisierung (Symmetric Quantization)&lt;/strong>
Verwendet den maximalen absoluten Wert der Daten, um sie um Null herum abzubilden ($Z=0$).
&lt;/p>
$$ S = \frac{\max(|W_{\max}|, |W_{\min}|)}{2^{b-1} - 1}, \quad Z = 0 $$
&lt;p>
Frühe Quantisierungen in llama.cpp (wie das Legacy Q4_0) verwendeten eine symmetrische Quantisierung. Da es keinen $Z$-Term gibt, hat dies den Vorteil, dass die Berechnung des inneren Produkts mit SIMD-Befehlen stark beschleunigt wird.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-entwicklung-von-ggml-zu-gguf-und-dateistruktur">3. Entwicklung von GGML zu GGUF und Dateistruktur
&lt;/h2>&lt;p>Bei der Diskussion über llama.cpp sind die in C++ geschriebene Tensor-Berechnungsbibliothek &lt;strong>GGML&lt;/strong> und das daraus abgeleitete Dateiformat &lt;strong>GGUF&lt;/strong> unerlässlich.&lt;/p>
&lt;h3 id="31-probleme-mit-ggml">3.1. Probleme mit GGML
&lt;/h3>&lt;p>Frühe Versionen von llama.cpp verwendeten das &lt;code>ggml&lt;/code>-Format (und Varianten wie &lt;code>ggjt&lt;/code>). Diese hatten jedoch die folgenden Probleme:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Fehlende Erweiterbarkeit:&lt;/strong> Magische Zahlen und Hyperparameter waren mit fester Länge und Reihenfolge hartcodiert, was bei jedem Hinzufügen einer neuen Modellarchitektur (z. B. Llama, Falcon, Mixtral usw.) oder eines neuen Tokenizers zu Breaking Changes führte.&lt;/li>
&lt;li>&lt;strong>Verlust der Abwärtskompatibilität:&lt;/strong> Formate wurden häufig aktualisiert, was oft dazu führte, dass ältere Modelldateien in neueren Versionen von llama.cpp nicht mehr geladen werden konnten.&lt;/li>
&lt;/ul>
&lt;h3 id="32-die-geburt-des-gguf-formats">3.2. Die Geburt des GGUF-Formats
&lt;/h3>&lt;p>Das im August 2023 eingeführte &lt;strong>GGUF&lt;/strong> ist ein äußerst vielseitiges Format, das zur Lösung dieser Probleme entwickelt wurde. Sein Hauptmerkmal ist die Einführung einer &lt;strong>Metadatenstruktur basierend auf Schlüssel-Wert-Paaren (Key-Value)&lt;/strong>.&lt;/p>
&lt;p>Das folgende Mermaid-Diagramm ist eine abstrahierte Darstellung der GGUF-Dateistruktur.&lt;/p>
&lt;div class="mermaid">graph TD
A["GGUF-Datei"] --> B["Header (Magic, Version)"]
A --> C["Metadaten (Schlüssel-Wert-Paare)"]
A --> D["Tensor-Info (Name, Shape, Offset)"]
A --> E["Tensor-Daten (Binäre Nutzlast)"]
C --> C1["general.architecture: llama"]
C --> C2["llama.context_length: 4096"]
C --> C3["tokenizer.ggml.tokens: [...]"]
E --> E1["Layer 0 Gewichte"]
E --> E2["Layer 1 Gewichte"]
E --> E3["..."]&lt;/div>
&lt;p>&lt;strong>Hauptvorteile von GGUF:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Flexibilität:&lt;/strong> Modell-Hyperparameter, RoPE (Rotary Positional Embedding)-Einstellungen, Tokenizer-Vokabulardaten usw. werden alle als benannte Key-Value-Paare gespeichert. Unbekannte Schlüssel werden ignoriert, was das Hinzufügen neuer Funktionen erleichtert.&lt;/li>
&lt;li>&lt;strong>Endian-Unabhängigkeit:&lt;/strong> GGUF verwendet standardmäßig Little-Endian, verfügt jedoch über ein explizites Flag, sodass es sicher portabel zwischen verschiedenen Architekturen ist.&lt;/li>
&lt;li>&lt;strong>Optimierung für mmap (Memory Mapping):&lt;/strong> Tensor-Daten werden an bestimmten Grenzen ausgerichtet (Padding) und können über den &lt;code>mmap()&lt;/code>-Systemaufruf des Betriebssystems direkt von der Festplatte in den Speicherraum abgebildet werden. Dadurch wird die Initialisierungszeit für das Laden des Modells praktisch auf Null reduziert.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-die-tiefen-von-k-quants-fortgeschrittene-blockbasierte-quantisierung">4. Die Tiefen von k-quants: Fortgeschrittene blockbasierte Quantisierung
&lt;/h2>&lt;p>Das wahre Herzstück des GGUF-Formats ist der Mechanismus &lt;strong>k-quants (K-quantization)&lt;/strong>, der für die Komprimierung der Modellgewichte verantwortlich ist.&lt;/p>
&lt;p>Die Gewichte eines normalen neuronalen Netzwerks haben eine Form, die über die gesamte Schicht hinweg fast einer Normalverteilung entspricht, aber lokal gibt es Ausreißer (Outliers). Wenn man die Gewichte der gesamten Schicht mit einem einheitlichen Skalierungsfaktor $S$ quantisiert, gehen Informationen über kleine Gewichte aufgrund des Einflusses der Ausreißer vollständig verloren.&lt;/p>
&lt;p>Um dies zu verhindern, führt llama.cpp eine &lt;strong>blockbasierte Quantisierung (Block-wise Quantization)&lt;/strong> durch. Der Gewichtstensor wird in kleine Blöcke (z.B. 32 oder 256 Elemente) unterteilt, und jeder Block hat einen eigenen spezifischen Skalierungsfaktor (und Nullpunkt).&lt;/p>
&lt;h3 id="41-grenzen-der-legacy-quantisierung-q4_0-q4_1">4.1. Grenzen der Legacy-Quantisierung (Q4_0, Q4_1)
&lt;/h3>&lt;p>Das frühe &lt;code>Q4_0&lt;/code> fasste 32 FP16-Gewichte in einem einzigen Block zusammen und teilte einen FP16-Skalierungsfaktor.&lt;/p>
&lt;ul>
&lt;li>Blockgröße: 32&lt;/li>
&lt;li>Speicher: 1 Skala (16 Bit) + 32 x 4-Bit-Gewichte (128 Bit) = 144 Bit&lt;/li>
&lt;li>Effektive Bits pro Gewicht (bpw: bits per weight): $144 / 32 = 4,5$ bpw&lt;/li>
&lt;/ul>
&lt;p>Dies ist bereits gut genug, aber die Grenzen von Genauigkeit und Kompressionsrate wurden sichtbar. Hier kam &lt;strong>k-quants&lt;/strong> mit einer komplexeren und feineren hierarchischen Struktur ins Spiel.&lt;/p>
&lt;h3 id="42-hierarchische-struktur-von-super-blöcken-und-sub-blöcken-beispiel-q4_k_m">4.2. Hierarchische Struktur von Super-Blöcken und Sub-Blöcken (Beispiel: Q4_K_M)
&lt;/h3>&lt;p>k-quants haben eine hierarchische Struktur mit großen &amp;ldquo;Super-Blöcken (Super-block)&amp;rdquo; und kleinen &amp;ldquo;Sub-Blöcken (Sub-block)&amp;rdquo; darin. Dadurch wird auch eine Quantisierung der Metadaten selbst (wie Skalierungswerte) durchgeführt, was die bpw auf das Äußerste senkt und gleichzeitig die Genauigkeit beibehält.&lt;/p>
&lt;p>Schauen wir uns die Struktur von &lt;strong>Q4_K_M&lt;/strong>, der beliebtesten Einstellung, an. Q4_K_M verwendet einen Super-Block mit 256 Elementen.&lt;/p>
&lt;div class="mermaid">graph TD
A["Super-Block (256 Gewichte)"] --> B["Skalierungs-Metadaten (FP16/INT8)"]
A --> C["Sub-Block 0 (32 Gewichte, 4-Bit)"]
A --> D["Sub-Block 1 (32 Gewichte, 4-Bit)"]
A --> E["..."]
A --> F["Sub-Block 7 (32 Gewichte, 4-Bit)"]
B --> B1["Super-Skala (FP16)"]
B --> B2["Sub-Skalen (8 x 6-Bit)"]
B --> B3["Sub-Minima (8 x 6-Bit)"]&lt;/div>
&lt;p>In C++ (GGML) ist die tatsächliche Struktur wie folgt definiert:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Konzeptionelle Struktur von block_q4_K in llama.cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#define QK_K 256
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">block_q4_K&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Super-Skala für den gesamten Super-Block (z. B. FP16 x 2)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">scales&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Gepackte Daten: 6-Bit-Skalen und 6-Bit-Minima (Nullpunkte) von 8 Sub-Blöcken (je 32 Elemente)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">qs&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">QK_K&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Auf 4-Bit quantisierte Gewichtsdaten (256 Elemente / 2 = 128 Bytes)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Mathematischer Prozess der inversen Quantisierung (Dequantization):&lt;/strong>&lt;/p>
&lt;p>Der angenäherte reelle Wert $\tilde{W}_{i, j}$ des Elements $j$ ($0 \le j &lt; 32$) im Sub-Block $i$ ($0 \le i &lt; 8$) wird wie folgt berechnet:&lt;/p>
$$ \tilde{W}_{i, j} = S_{\text{super}} \times s_i \times (w_{i, j} - m_i) $$
&lt;ul>
&lt;li>$S_{\text{super}}$: Gleitkomma-Skalierung für den gesamten Super-Block&lt;/li>
&lt;li>$s_i$: Quantisierte 6-Bit-Skala für den Sub-Block $i$&lt;/li>
&lt;li>$m_i$: Quantisiertes 6-Bit-Minimum (Nullpunkt) für den Sub-Block $i$&lt;/li>
&lt;li>$w_{i, j}$: Quantisiertes 4-Bit-Gewicht ($0 \dots 15$)&lt;/li>
&lt;/ul>
&lt;p>Durch diese hierarchische Struktur wird die Speicherbelegung durch den Skalierungsfaktor drastisch reduziert, während die Anpassungsfähigkeit an Ausreißer erhalten bleibt. Q4_K_M erreicht insgesamt etwa &lt;strong>4,8 bpw&lt;/strong>.&lt;/p>
&lt;h3 id="43-verschiedene-k-quants-optionen">4.3. Verschiedene k-quants-Optionen
&lt;/h3>&lt;p>llama.cpp bietet je nach Zweck eine Vielzahl von Variationen. Die Suffixe (S, M, L) nach dem &amp;ldquo;K&amp;rdquo; geben die Größe an.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Format&lt;/th>
&lt;th style="text-align:center">BPW (Bits pro Gewicht)&lt;/th>
&lt;th style="text-align:left">Übersicht und Eigenschaften&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q2_K&lt;/strong>&lt;/td>
&lt;td style="text-align:center">2,5–3,3&lt;/td>
&lt;td style="text-align:left">Extrem komprimiert. Die Genauigkeit nimmt erheblich ab, aber für Umgebungen mit extrem wenig VRAM gedacht.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q3_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">3,3&lt;/td>
&lt;td style="text-align:left">Standard für 3-Bit-Quantisierung. Schlechter als Q4, liegt aber oft im akzeptablen Bereich.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q4_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">4,8&lt;/td>
&lt;td style="text-align:left">&lt;strong>Empfohlener Sweet Spot&lt;/strong>. Halbierung der Modellgröße bei gleichzeitiger Beibehaltung der Genauigkeit.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q5_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">5,5&lt;/td>
&lt;td style="text-align:left">Wenn höhere Genauigkeit erforderlich ist. Zwischenposition zwischen Q4 und FP16.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q6_K&lt;/strong>&lt;/td>
&lt;td style="text-align:center">6,6&lt;/td>
&lt;td style="text-align:left">Behält fast die gleiche Perplexity wie FP16 bei, hat aber eine größere Dateigröße.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q8_0&lt;/strong>&lt;/td>
&lt;td style="text-align:center">8,5&lt;/td>
&lt;td style="text-align:left">Entspricht INT8. Wird hauptsächlich für Zwischentensoren bei der Inferenzberechnung und nur in der letzten Schicht verwendet.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>※ Die tatsächlichen BPW werden über das gesamte Modell gemittelt, da abhängig vom Tensor des Modells (z. B. Q/K/V-Projektion in der Attention oder FFN-Gewicht) eine gemischte Quantisierung (Mixed Quantization) durchgeführt wird. Wichtige Tensoren werden mit Q6 quantisiert, andere mit Q4, was intern als Optimierung stattfindet.&lt;/p>
&lt;hr>
&lt;h2 id="5-leistungsoptimierung-bei-der-inferenz-simd-und-cuda-architektur">5. Leistungsoptimierung bei der Inferenz: SIMD und CUDA-Architektur
&lt;/h2>&lt;p>Einfach das GGUF-Modell in den Speicher zu laden, macht die Inferenz noch nicht schnell. Der Großteil der LLM-Inferenz besteht aus der &amp;ldquo;Matrix-Vektor-Multiplikation&amp;rdquo; (GEMV oder Matrix-Matrix, GEMM). Der Schlüssel liegt in der Beschleunigung der Multiply-Accumulate-Operationen zwischen den quantisierten Gewichten und den in FP16 (oder FP32) gehaltenen Aktivierungen (Eingabedaten).&lt;/p>
&lt;h3 id="51-nutzung-von-simd-befehlen-in-cpu-umgebungen">5.1. Nutzung von SIMD-Befehlen in CPU-Umgebungen
&lt;/h3>&lt;p>Die erstaunliche Geschwindigkeit von llama.cpp bei der CPU-Inferenz liegt an der &lt;strong>SIMD-Optimierung (Single Instruction, Multiple Data)&lt;/strong> auf Assembler-Ebene.
Beispielsweise nutzt es die &lt;strong>AVX2&lt;/strong>- oder &lt;strong>AVX-512&lt;/strong>-Befehlssätze auf Intel/AMD-CPUs und &lt;strong>ARM NEON&lt;/strong> auf Apple Silicon vollständig aus.&lt;/p>
&lt;p>Während der Inferenz wird $W_q$ nicht explizit zurück in FP32 konvertiert (dequantisiert), bevor die Multiplikation durchgeführt wird.
Auch die Aktivierungsseite wird dynamisch blockweise quantisiert (Dynamic Quantization, normalerweise nach INT8), und die Ganzzahl-Operationen &lt;strong>INT8 $\times$ INT4&lt;/strong> werden auf einmal mithilfe spezieller SIMD-Skalarprodukt-Befehle (z. B. &lt;code>vdpaddd&lt;/code> oder &lt;code>_mm256_madd_epi16&lt;/code>) berechnet. Durch Konvertierung des endgültigen Akkumulators zurück nach FP32 und Multiplikation mit dem Skalierungsfaktor wird ein bemerkenswerter Durchsatz erzielt.&lt;/p>
&lt;h3 id="52-offloading-auf-die-gpu-umgebung-cublas--cuda">5.2. Offloading auf die GPU-Umgebung (cuBLAS / CUDA)
&lt;/h3>&lt;p>Neuere Versionen von llama.cpp unterstützen nicht nur CPUs, sondern bieten auch eine starke Unterstützung für NVIDIA-GPUs (CUBLAS / CUDA).
Es ist möglich, einen Teil oder alle Schichten der GGUF-Datei in den VRAM auszulagern (&lt;code>--n-gpu-layers&lt;/code> Option).&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant User
participant CPU_RAM as CPU &amp; RAM (mmap)
participant VRAM as GPU VRAM
participant Compute as Tensor Cores
User->>CPU_RAM: GGUF laden (mmap)
CPU_RAM->>VRAM: Schichten auslagern (z.B. 30/32 Schichten)
Note over CPU_RAM, VRAM: Daten bleiben im VRAM quantisiert
User->>Compute: Forward Pass (Eingabe-Tokens)
Compute->>VRAM: Quantisierte Gewichte abrufen
Compute->>Compute: On-the-fly im SRAM zu FP16 dequantisieren
Compute->>Compute: Matrixmultiplikation (cuBLAS / Custom Kernels)
Compute->>User: Ausgabe-Logits&lt;/div>
&lt;p>Bei Berechnungen auf der GPU wird die Speicherbandbreite (Memory Bandwidth) des VRAM zum größten Engpass. Da die Gewichte mit k-quants komprimiert sind, reduziert sich die Datenübertragungsmenge vom VRAM zu den Recheneinheiten der GPU (SM: Streaming Multiprocessor oder Tensor Cores) auf 1/3 bis 1/4. In dem Moment, in dem die Gewichte die Recheneinheit erreichen, werden sie &amp;ldquo;on-the-fly&amp;rdquo; (im laufenden Betrieb) zu FP16 dequantisiert (entpackt), und die Matrixmultiplikation wird mithilfe von Tensor Cores extrem schnell durchgeführt.
Mit anderen Worten: Die Quantisierung erfolgt &lt;strong>nicht &amp;ldquo;um die Rechenmenge zu reduzieren&amp;rdquo;, sondern &amp;ldquo;um die Speicherübertragungsmenge zu reduzieren&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="6-spezifisches-beispiel-für-den-kompromiss-zwischen-speichernutzung-und-leistung">6. Spezifisches Beispiel für den Kompromiss zwischen Speichernutzung und Leistung
&lt;/h2>&lt;p>Lassen Sie uns anhand des Modells Llama 3 8B die erforderlichen Spezifikationen für verschiedene Quantisierungsstufen in GGUF betrachten. (Die Zahlen sind ungefähre Richtwerte.)&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Modell / Quantisierung&lt;/th>
&lt;th style="text-align:left">Dateigröße&lt;/th>
&lt;th style="text-align:left">Benötigter VRAM/RAM&lt;/th>
&lt;th style="text-align:left">Inferenzgeschwindigkeit (Schätzung)&lt;/th>
&lt;th style="text-align:left">Perplexity-Verschlechterung&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (FP16)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Ca. 16 GB&lt;/td>
&lt;td style="text-align:left">18 GB oder mehr&lt;/td>
&lt;td style="text-align:left">Basislinie&lt;/td>
&lt;td style="text-align:left">Keine (Base)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q8_0)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Ca. 8,5 GB&lt;/td>
&lt;td style="text-align:left">10 GB oder mehr&lt;/td>
&lt;td style="text-align:left">Schnell&lt;/td>
&lt;td style="text-align:left">Fast null&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q6_K)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Ca. 6,6 GB&lt;/td>
&lt;td style="text-align:left">8 GB oder mehr&lt;/td>
&lt;td style="text-align:left">Sehr schnell&lt;/td>
&lt;td style="text-align:left">Sehr klein&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q4_K_M)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Ca. 4,9 GB&lt;/td>
&lt;td style="text-align:left">6,5 GB oder mehr&lt;/td>
&lt;td style="text-align:left">Am schnellsten / Optimal&lt;/td>
&lt;td style="text-align:left">Akzeptabel / Gering&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q3_K_M)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Ca. 3,9 GB&lt;/td>
&lt;td style="text-align:left">5,5 GB oder mehr&lt;/td>
&lt;td style="text-align:left">Am schnellsten&lt;/td>
&lt;td style="text-align:left">Etwas auffällig&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q2_K)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Ca. 3,0 GB&lt;/td>
&lt;td style="text-align:left">4,5 GB oder mehr&lt;/td>
&lt;td style="text-align:left">Schnell&lt;/td>
&lt;td style="text-align:left">Deutliche Verschlechterung&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Hinweis (Einfluss des KV-Caches):&lt;/strong>
Bei der Inferenz mit LLMs nimmt der Speicherverbrauch des &lt;strong>KV-Caches&lt;/strong>, der die vergangenen Attention-Zustände speichert, bei zunehmender Kontextlänge (Anzahl der Tokens in der Eingabeaufforderung) explosionsartig zu, nicht nur die Gewichte des Modells.
Wenn der Kontext beispielsweise 8192 Token beträgt, verbraucht allein der KV-Cache mehrere GB. Daher muss in der Praxis ein Spielraum (Headroom) von &lt;code>Dateigröße des Modells + ca. 1,5 GB bis 3 GB&lt;/code> vorgesehen werden. Der Grund, warum Q4_K_M empfohlen wird, liegt darin, dass es genau die richtige Balance bietet, um sicher auf einer GPU mit 8 GB VRAM (wie RTX 3060 / 4060) zu laufen, selbst wenn dieser KV-Cache gesichert ist.&lt;/p>
&lt;p>In den neueren Versionen von llama.cpp wurde auch eine Funktion zur &lt;strong>Quantisierung des KV-Caches selbst in Q8_0 oder Q4_0&lt;/strong> hinzugefügt, und es werden kontinuierliche Anstrengungen unternommen, um die Kontextlänge weiter zu erhöhen.&lt;/p>
&lt;hr>
&lt;h2 id="7-zusammenfassung">7. Zusammenfassung
&lt;/h2>&lt;p>In diesem Artikel haben wir uns eingehend mit der internen Struktur des GGUF-Formats, dem Herzstück von llama.cpp, und der k-quants-Quantisierungstechnologie befasst.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Flexibilität von GGUF:&lt;/strong> Durch eine Metadatenstruktur vom Typ Schlüssel-Wert wurde ein robustes Ökosystem aufgebaut, das selbst bei schnellen Entwicklungen von LLMs (wie der Einführung neuer Modellarchitekturen) ohne Breaking Changes mithalten kann.&lt;/li>
&lt;li>&lt;strong>Extreme Komprimierung durch k-quants:&lt;/strong> Durch die hierarchische Verwaltung der Skalierungsfaktoren in Super-Blöcken und Sub-Blöcken wurde eine erstaunliche Komprimierung von durchschnittlich 4,8 Bit pro Gewicht (Q4_K_M) erreicht, während die Informationen der Ausreißer erhalten blieben.&lt;/li>
&lt;li>&lt;strong>Behebung des Engpasses bei der Speicherbandbreite:&lt;/strong> Durch die Reduzierung der VRAM-Übertragungsmenge durch &amp;ldquo;On-the-fly&amp;rdquo;-Dequantisierung und -Berechnung, ermöglicht durch fortschrittliche Kernel-Implementierungen in SIMD und CUDA, wurde die Inferenzgeschwindigkeit drastisch erhöht.&lt;/li>
&lt;/ol>
&lt;p>Die technologischen Fähigkeiten von llama.cpp, das die Demokratisierung der KI vorantreibt, sprengen den Rahmen eines bloßen Werkzeugs, und es ist keine Übertreibung zu sagen, dass es heute einen der Höhepunkte der Softwareentwicklung darstellt. Das Verständnis des Quantisierungsalgorithmus und der Mechanismen des GGUF-Formats wird Ihnen helfen, das optimale Modell für Ihre Umgebung genauer auszuwählen und das Performance-Tuning effizienter durchzuführen.&lt;/p>
&lt;h3 id="referenz-links">Referenz-Links
&lt;/h3>&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noopener"
>llama.cpp GitHub Repository&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/ggml/blob/master/docs/gguf.md" target="_blank" rel="noopener"
>GGUF Format Specification&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp/pull/1684" target="_blank" rel="noopener"
>K-quants Implementation PR&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>(Ende)&lt;/p></description></item></channel></rss>