<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Development on kenji.blog</title><link>http://kenji.blog/de/tags/development/</link><description>Recent content in Development on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 14:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/tags/development/index.xml" rel="self" type="application/rss+xml"/><item><title>Entwicklungsschritte für kleine KI-Modelle (wie TinyLLaMA) mit C++</title><link>http://kenji.blog/de/p/cpp-small-ai-model-tinyllama-dev-guide/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/cpp-small-ai-model-tinyllama-dev-guide/</guid><description>&lt;img src="http://kenji.blog/p/cpp-small-ai-model-tinyllama-dev-guide/img/eyecatch.jpg" alt="Featured image of post Entwicklungsschritte für kleine KI-Modelle (wie TinyLLaMA) mit C++" />&lt;h1 id="entwicklungsschritte-für-kleine-ki-modelle-wie-tinyllama-mit-c">Entwicklungsschritte für kleine KI-Modelle (wie TinyLLaMA) mit C++
&lt;/h1>&lt;p>In den letzten Jahren ist das Interesse an der Ausführung von Large Language Models (LLMs) in lokalen Umgebungen rasant gestiegen. Insbesondere kleine Modelle wie TinyLLaMA (1,1B Parameter) können selbst auf Edge-Geräten mit begrenzten Ressourcen oder herkömmlichen Laptops (einschließlich Windows-Umgebungen) mit praktischer Geschwindigkeit für Inferenzen genutzt werden. Während die Entwicklung hauptsächlich mit Python und PyTorch erfolgt, ist die Kombination aus C++ und „ggml“, einer C-basierten Tensor-Bibliothek, zum De-facto-Standard geworden, wenn es darum geht, die ultimative Leistung und Speichereffizienz zu erreichen.&lt;/p>
&lt;p>In diesem Artikel werden wir die detaillierten Entwicklungsschritte erläutern, um eine Inferenz-Engine von Grund auf aufzubauen (oder die interne Struktur der bestehenden llama.cpp tiefgehend zu verstehen), mit der TinyLLaMA in C++ geladen und Text generiert wird.&lt;/p>
&lt;hr>
&lt;h2 id="1-warum-c-und-ggml">1. Warum C++ und ggml?
&lt;/h2>&lt;p>In der Trainingsphase von KI ist Python mit seiner Flexibilität und seinem umfangreichen Ökosystem überwältigend im Vorteil. In der Bereitstellungs- oder „Inferenz“-Phase wird C++ jedoch aus den folgenden Gründen zu einer leistungsstarken Option.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Reduzierung von Overhead&lt;/strong>: Das Global Interpreter Lock (GIL) von Python und der Runtime-Overhead können vollständig eliminiert werden.&lt;/li>
&lt;li>&lt;strong>Speichereffizienz und Arena-Allokation&lt;/strong>: Da die Zuweisung und Freigabe von Speicher manuell gesteuert werden können, lassen sich unvorhersehbare Spitzen (Spikes) durch die Garbage Collection verhindern.&lt;/li>
&lt;li>&lt;strong>Direkter Zugriff auf die Hardware&lt;/strong>: SIMD-Intrinsics wie AVX-512, AVX2 und ARM NEON können direkt aufgerufen werden, um die Rechenleistung der CPU zu maximieren.&lt;/li>
&lt;li>&lt;strong>Keine Abhängigkeiten&lt;/strong>: ggml ist eine C/C++-Bibliothek ohne Abhängigkeiten (Zero dependencies) und kann problemlos auf Windows-Umgebungen mit MSVC kompiliert werden, solange ein Compiler vorhanden ist.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-gesamtbild-der-architektur">2. Gesamtbild der Architektur
&lt;/h2>&lt;p>Der Fluss der gesamten Inferenz-Pipeline ist im folgenden Mermaid-Diagramm dargestellt. Dies ist der Prozess vom Eingabetext des Benutzers bis zur endgültigen Generierung des nächsten Tokens.&lt;/p>
&lt;div class="mermaid">graph TD
A["Benutzereingabetext"] --> B["BPE Tokenizer"]
B --> C["Token-IDs Array"]
C --> D["Embedding Layer Lookup"]
D --> E["Transformer Blocks"]
E --> F["RMSNorm"]
F --> G["LM Head Layer"]
G --> H["Logits Array"]
H --> I["Sampler-Modul"]
I --> J["Nächste Token-ID"]
J --> K["Detokenizer"]
K --> L["Ausgabetext-Chunk"]
J -.-> |"Zum Kontext hinzufügen"| C&lt;/div>
&lt;p>Da es sich um ein autoregressives Modell handelt, wird das ausgegebene Token wieder dem Kontext hinzugefügt und als Eingabe für die Vorhersage des nächsten Tokens zyklisch verwendet (gestrichelte Linie im Diagramm).&lt;/p>
&lt;hr>
&lt;h2 id="3-modellformat-und-memory-mapping-mmap">3. Modellformat und Memory Mapping (mmap)
&lt;/h2>&lt;p>Das größte Hindernis beim Umgang mit den Gewichten riesiger neuronaler Netze sind Festplatten-I/O und Speicherverbrauch. In der C++-Implementierung wird dies durch &lt;strong>Memory Mapping (mmap)&lt;/strong> gelöst.&lt;/p>
&lt;h3 id="31-funktionsweise-von-memory-mapping-und-implementierung-in-windows">3.1 Funktionsweise von Memory Mapping und Implementierung in Windows
&lt;/h3>&lt;p>Mit mmap kann der Inhalt einer Datei direkt in den virtuellen Adressraum des Prozesses abgebildet (gemappt) werden.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Zero-copy&lt;/strong>: Die Daten werden von der Festplatte direkt in den Page-Cache des Kernels geladen, ohne dass eine zusätzliche Kopie in den Userspace erfolgt.&lt;/li>
&lt;li>&lt;strong>On-Demand-Laden (Page Fault)&lt;/strong>: In dem Moment, in dem die CPU tatsächlich auf diese Speicheradresse zugreift, tritt ein Page Fault (Seitenfehler) auf, und nur der benötigte Chunk (normalerweise 4 KB) wird in den physischen Speicher geladen.&lt;/li>
&lt;/ul>
&lt;p>In Windows-Umgebungen werden anstelle des POSIX &lt;code>mmap&lt;/code> die Win32-APIs &lt;code>CreateFileMapping&lt;/code> und &lt;code>MapViewOfFile&lt;/code> verwendet.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant OS["Windows OS"]
participant RAM["Physischer Speicher"]
participant App["C++ Anwendung"]
App->>OS: "CreateFileMapping / MapViewOfFile"
OS-->>App: "Zeiger auf virtuelle Speicheradresse"
App->>App: "Tensor-Daten am Zeiger lesen"
OS->>RAM: "Page Fault / Seite von der Festplatte laden"
RAM-->>App: "Daten bereit für SIMD-Berechnung"&lt;/div>
&lt;h3 id="32-binäre-struktur-des-gguf-formats">3.2 Binäre Struktur des GGUF-Formats
&lt;/h3>&lt;p>Das aus Formaten wie &lt;code>.safetensors&lt;/code> von Hugging Face konvertierte &lt;strong>GGUF (GPT-Generated Unified Format)&lt;/strong> ist das ultimative Format für Inferenzen. Es verfügt über das folgende strikte binäre Layout.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Magic Bytes&lt;/strong>: &lt;code>0x46554747&lt;/code> (GGUF).&lt;/li>
&lt;li>&lt;strong>Version&lt;/strong>: Die Versionsnummer des Formats.&lt;/li>
&lt;li>&lt;strong>Tensor Count &amp;amp; Metadata Count&lt;/strong>: Anzahl der Tensoren und der Metadaten-Schlüssel-Wert-Paare.&lt;/li>
&lt;li>&lt;strong>Metadata (Key-Value Pairs)&lt;/strong>: Schlüssel mit Präfix für die Zeichenfolgenlänge und typisierte Werte.&lt;/li>
&lt;li>&lt;strong>Tensor Info&lt;/strong>: Name, Dimensionen, Datentyp (FP16, Q4_K usw.) jedes Tensors und die Offset-Position in der Datei.&lt;/li>
&lt;li>&lt;strong>Padding&lt;/strong>: Polsterung (Padding), die eingefügt wird, damit die Tensordaten an bestimmten Grenzen (normalerweise 32 oder 64 Byte) ausgerichtet (aligned) werden. Dies ist entscheidend für den schnellen Speicherzugriff mit SIMD-Befehlen (insbesondere AVX).&lt;/li>
&lt;li>&lt;strong>Tensor Data&lt;/strong>: Das eigentliche Array der ausgerichteten Gewichtsdaten.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-mathematische-grundlagen-von-tinyllama-und-c-algorithmen">4. Mathematische Grundlagen von TinyLLaMA und C++-Algorithmen
&lt;/h2>&lt;p>TinyLLaMA beinhaltet einige fortgeschrittene architektonische Tricks zur Effizienzsteigerung. Die mathematischen Ausdrücke zur korrekten Implementierung in C++ werden hier erläutert.&lt;/p>
&lt;h3 id="41-rmsnorm-root-mean-square-normalization">4.1 RMSNorm (Root Mean Square Normalization)
&lt;/h3>&lt;p>Die Rechenkosten werden reduziert, indem die Mittelwert-Zentrierung aus LayerNorm weggelassen und nur die Varianz-Skalierung durchgeführt wird.&lt;/p>
$$ \text{RMSNorm}(x) = \frac{x}{\sqrt{\frac{1}{d}\sum_{i=1}^{d} x_i^2 + \epsilon}} \odot \gamma $$
&lt;p>$d$ ist die Anzahl der Dimensionen, $\gamma$ ist der gelernte Skalierungstensor.
Bei der Implementierung in C++ wird dies optimiert, indem zunächst die Summe der Quadrate des Arrays schnell mit AVX2s &lt;code>_mm256_fmadd_ps&lt;/code> etc. berechnet wird und dann mit der inversen Quadratwurzel (z. B. &lt;code>_mm256_rsqrt_ps&lt;/code> Befehl) multipliziert wird.&lt;/p>
&lt;h3 id="42-rope-rotary-position-embedding">4.2 RoPE (Rotary Position Embedding)
&lt;/h3>&lt;p>Eine Technik, um die Positionsinformationen von Tokens als Rotation im Tensorraum anzuwenden. Es kann als Rotation auf einer komplexen Ebene betrachtet werden, wobei für benachbarte Dimensionspaare $(x_1, x_2)$ des Vektors $x$ die folgende Rotation angewendet wird.&lt;/p>
$$ \text{RoPE}(x, m) = \begin{pmatrix} x_{1} \cos(m\theta) - x_{2} \sin(m\theta) \\ x_{1} \sin(m\theta) + x_{2} \cos(m\theta) \end{pmatrix} $$
&lt;p>Hier ist $m$ der absolute Positionsindex des Tokens und $\theta$ die vorberechnete Grundfrequenz. In ggml wird es parallel ausgeführt, indem einfach der &lt;code>ggml_rope&lt;/code>-Operator während der Konstruktion des Inferenzgraphen hinzugefügt wird.&lt;/p>
&lt;h3 id="43-grouped-query-attention-gqa">4.3 Grouped-Query Attention (GQA)
&lt;/h3>&lt;p>Bei der normalen Multi-Head Attention (MHA) gibt es die gleiche Anzahl von Heads für Query, Key und Value. TinyLLaMA verwendet jedoch &lt;strong>Grouped-Query Attention (GQA)&lt;/strong>, um die Speicherbandbreite und den KV-Cache-Verbrauch drastisch zu reduzieren.&lt;/p>
$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>Bei GQA teilen sich mehrere Query-Heads einen Key/Value-Head. In der C++-Implementierung ist es erforderlich, den KV-Tensor so zu broadcasten (zu replizieren), dass er der Anzahl der Queries entspricht, bevor die Matrixmultiplikation &lt;code>ggml_mul_mat&lt;/code> ausgeführt wird.&lt;/p>
&lt;h3 id="44-swiglu-aktivierungsfunktion">4.4 SwiGLU-Aktivierungsfunktion
&lt;/h3>&lt;p>Im Feed-Forward Network (FFN)-Layer wird anstelle von GELU SwiGLU verwendet.&lt;/p>
$$ \text{SwiGLU}(x) = \text{Swish}(x W_{\text{gate}}) \otimes (x W_{\text{up}}) $$
$$ \text{Swish}(z) = z \cdot \sigma(z) = z \cdot \frac{1}{1 + e^{-z}} $$
&lt;p>Im Berechnungsgraphen wird dies durch eine Kombination aus dem &lt;code>ggml_silu&lt;/code>-Operator und &lt;code>ggml_mul&lt;/code> dargestellt.&lt;/p>
&lt;hr>
&lt;h2 id="5-konstruktion-des-berechnungsgraphen-mit-ggml-und-speicherverwaltung">5. Konstruktion des Berechnungsgraphen mit ggml und Speicherverwaltung
&lt;/h2>&lt;p>ggml verfolgt einen „Define-and-Run“-Ansatz, bei dem ein statischer Berechnungsgraph für die Inferenz konstruiert und anschließend evaluiert wird.&lt;/p>
&lt;h3 id="51-ggml_context-und-arena-allocator">5.1 ggml_context und Arena-Allocator
&lt;/h3>&lt;p>Die einzigartigste Eigenschaft von ggml ist die „Arena-Allokation“, bei der in der Inferenzschleife keinerlei dynamische Speicherzuweisungen (&lt;code>malloc&lt;/code> oder &lt;code>new&lt;/code>) stattfinden.
Bei der Initialisierung wird ein riesiger zusammenhängender Speicherbereich (die Arena) reserviert, und bei jedem Aufruf von z. B. &lt;code>ggml_new_tensor&lt;/code> wird der Zeiger dieses Bereichs inkrementiert. Sobald ein Inferenzschritt abgeschlossen ist, wird der Allokationszeiger einfach auf seine Ausgangsposition zurückgesetzt, wodurch die Speicherzuweisung für den nächsten Inferenzschritt sofort abgeschlossen ist.&lt;/p>
&lt;h3 id="52-konkretes-beispiel-für-die-konstruktion-eines-graphen">5.2 Konkretes Beispiel für die Konstruktion eines Graphen
&lt;/h3>&lt;p>Für jeden Inferenzschritt wird der folgende Berechnungsgraph im Speicher aufgebaut.&lt;/p>
&lt;div class="mermaid">graph TD
A["Eingabe-Token-ID"] --> B["Embed Lookup"]
B --> C["ggml_rms_norm"]
C --> D["Q / K / V Projektionen"]
D --> E["ggml_rope Positional"]
E --> F["KV Cache Speichern"]
E --> G["KV Cache Laden"]
G --> H["Self Attention"]
H --> I["Skalierung &amp; Softmax"]
I --> J["Attention Ausgabe"]
J --> K["Out Projektion"]
K --> L["Residual Hinzufügen"]&lt;/div>
&lt;hr>
&lt;h2 id="6-quantisierung-quantization-und-windows--simd-optimierung">6. Quantisierung (Quantization) und Windows / SIMD-Optimierung
&lt;/h2>&lt;p>Wenn TinyLLaMA (1,1B) in FP16 verwendet wird, werden etwa 2,2 GB Speicher benötigt, aber durch 4-Bit-Quantisierung (wie Q4_K) kann dies drastisch auf etwa 600 MB komprimiert werden.&lt;/p>
&lt;h3 id="61-block-quantisierungsarchitektur">6.1 Block-Quantisierungsarchitektur
&lt;/h3>&lt;p>ggml quantisiert nicht den gesamten Tensor einheitlich, sondern in „Blöcken“.
Im &lt;code>Q4_0&lt;/code>-Format werden 32 FP16-Werte in einem Block zusammengefasst.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Skalierungsfaktor (Scale Factor)&lt;/strong>: Ein FP16-Wert (2 Byte)&lt;/li>
&lt;li>&lt;strong>Quantisierte Daten&lt;/strong>: 32 4-Bit-Werte (16 Byte)
Dadurch wird der Einfluss von lokalen Ausreißern (Outliers) minimiert.&lt;/li>
&lt;/ul>
&lt;h3 id="62-beschleunigung-des-skalarprodukts-durch-avx2">6.2 Beschleunigung des Skalarprodukts durch AVX2
&lt;/h3>&lt;p>Beim Kompilieren für die neuesten x86-CPUs in einer Windows-Umgebung werden Compiler-Flags wie &lt;code>/arch:AVX2&lt;/code> verwendet und die SIMD-Verarbeitung läuft im folgenden Fluss ab:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Laden&lt;/strong>: Die quantisierten 4-Bit-Daten werden aus dem Speicher in ein 256-Bit-AVX-Register geladen.&lt;/li>
&lt;li>&lt;strong>Entpacken (Unpack)&lt;/strong>: Die 4-Bit-Werte werden durch Bitmasken- und Shift-Operationen in Int8 oder Int16 entpackt.&lt;/li>
&lt;li>&lt;strong>Dequantisierung&lt;/strong>: Multiplikation mit dem Skalierungsfaktor zur Umwandlung in Gleitkommazahlen.&lt;/li>
&lt;li>&lt;strong>FMA-Berechnung&lt;/strong>: Parallele Ausführung der Multiply-Add-Operation mit den Aktivierungswerten über &lt;code>_mm256_fmadd_ps&lt;/code> (Fused Multiply-Add).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="7-details-zur-implementierung-des-kv-caches">7. Details zur Implementierung des KV-Caches
&lt;/h2>&lt;p>Bei der autoregressiven Generierung ist ein „KV-Cache“, der die Berechnung von Key und Value vergangener Tokens überspringt, eine zwingend erforderliche Funktion.&lt;/p>
&lt;p>Bei der Implementierung in C++ sind die folgenden Punkte wichtig:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vorabreservierung des Tensors&lt;/strong>: Ein riesiger Tensor für die maximale Kontextlänge (z. B. 2048 Tokens) wird für den KV-Cache initialisiert (FP16 wird empfohlen).&lt;/li>
&lt;li>&lt;strong>Offset-Kopie&lt;/strong>: Wenn die Berechnung für die Token-Position $N$ durchgeführt wird, werden die in diesem Schritt erhaltenen K- und V-Vektoren in der $N$-ten Zeile des KV-Cache-Tensors mithilfe von &lt;code>ggml_cpy&lt;/code> o. Ä. gespeichert.&lt;/li>
&lt;li>&lt;strong>Erstellung eines Views bei der Attention&lt;/strong>: Bei der Berechnung der Attention wird ein „View“ (Ansicht) erstellt, der nur auf den Bereich der Tokens 0 bis $N$ verweist, und dieser View wird an die Matrixmultiplikation übergeben.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-bpe-tokenizer-und-dekodierung">8. BPE Tokenizer und Dekodierung
&lt;/h2>&lt;p>Der Eingabe-String wird als Bytefolge in UTF-8 behandelt und mit einem vordefinierten Vokabular abgeglichen. Um die Vokabularsuche in C++ zu beschleunigen, werden Algorithmen implementiert, die &lt;strong>Trie-Bäume (Präfixbäume)&lt;/strong> oder Prioritätswarteschlangen verwenden.&lt;/p>
&lt;p>Die vom LM Head ausgegebenen Logits werden mithilfe des Temperature-Parameters skaliert, um Wahrscheinlichkeiten zu erhalten. Die Kandidaten werden durch Top-K-Extraktion oder Top-P-Methoden (Nucleus Sampling) eingegrenzt, und das endgültige nächste Token wird mithilfe von Zufallszahlen bestimmt.&lt;/p>
&lt;hr>
&lt;h2 id="9-aufbau-eines-c-projekts-windows--powershell-umgebung">9. Aufbau eines C++-Projekts (Windows / PowerShell-Umgebung)
&lt;/h2>&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.14&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">TinyLLaMACpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">17&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Optimierungs- und AVX2-Flags für Windows (MSVC)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MSVC&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">/O2&lt;/span> &lt;span class="s">/arch:AVX2&lt;/span> &lt;span class="s">/fp:fast&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_link_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">/STACK:8388608&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">else&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">-O3&lt;/span> &lt;span class="s">-march=native&lt;/span> &lt;span class="s">-ffast-math&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_library&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ggml&lt;/span> &lt;span class="s">OBJECT&lt;/span> &lt;span class="s">ggml/ggml.c&lt;/span> &lt;span class="s">ggml/ggml-alloc.c&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_compile_definitions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ggml&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">GGML_USE_AVX2&lt;/span> &lt;span class="s">GGML_USE_F16C&lt;/span> &lt;span class="s">GGML_USE_FMA&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">main&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">main&lt;/span> &lt;span class="s">ggml&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Beispiel für einen Build-Befehl in PowerShell:&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">mkdir&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">..&lt;/span> &lt;span class="n">-G&lt;/span> &lt;span class="s2">&amp;#34;Visual Studio 17 2022&amp;#34;&lt;/span> &lt;span class="n">-A&lt;/span> &lt;span class="n">x64&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-build&lt;/span> &lt;span class="p">.&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-config&lt;/span> &lt;span class="n">Release&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="10-zusammenfassung">10. Zusammenfassung
&lt;/h2>&lt;p>Die Implementierung einer Inferenz-Engine für kleine KI-Modelle wie TinyLLaMA von Grund auf mit C++ und ggml ist eine hervorragende Gelegenheit, die Blackbox des Deep Learning zu entschlüsseln und die Schönheit der Low-Level-Hardwaresteuerung kennenzulernen. Durch den Einsatz von Zero-Copy-Laden mithilfe von Memory Mapping, SIMD-Optimierung und dem Aufbau von KV-Caches können Sie das Wesentliche der Systemprogrammierung in vollen Zügen genießen und gleichzeitig die Zukunft der Edge-KI mitgestalten.&lt;/p></description></item></channel></rss>