<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AI on kenji.blog</title><link>http://kenji.blog/de/categories/ai/</link><description>Recent content in AI on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 18:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/categories/ai/index.xml" rel="self" type="application/rss+xml"/><item><title>Microsoft.Windows.AI: Neueste API-Anwendungsfälle und Beispielcode</title><link>http://kenji.blog/de/p/microsoft-windows-ai-api-guide/</link><pubDate>Fri, 11 Sep 2026 18:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/microsoft-windows-ai-api-guide/</guid><description>&lt;img src="http://kenji.blog/p/microsoft-windows-ai-api-guide/img/eyecatch.jpg" alt="Featured image of post Microsoft.Windows.AI: Neueste API-Anwendungsfälle und Beispielcode" />&lt;h1 id="microsoftwindowsai-neueste-api-anwendungsfälle-und-beispielcode--die-tiefen-der-windows-copilot-runtime-erkunden">Microsoft.Windows.AI: Neueste API-Anwendungsfälle und Beispielcode – Die Tiefen der Windows Copilot Runtime erkunden
&lt;/h1>&lt;h2 id="1-einführung-eine-neue-ära-für-windows-mit-nativer-ki-integration">1. Einführung: Eine neue Ära für Windows mit nativer KI-Integration
&lt;/h2>&lt;p>In den letzten Jahren hat sich die KI-Technologie bemerkenswert weiterentwickelt, was zu einem schnellen Paradigmenwechsel von der Nutzung großer Sprachmodelle (LLMs) in der Cloud hin zu KI-Inferenzen auf Edge-Geräten (lokalen PCs) geführt hat. Das Herzstück dieser Entwicklung sind die von Microsoft für Windows 11 bereitgestellte &amp;ldquo;Windows Copilot Runtime&amp;rdquo; und die &amp;ldquo;Microsoft.Windows.AI&amp;rdquo;-API zu deren Steuerung.&lt;/p>
&lt;p>Die Entwicklung von Anwendungen mithilfe von Cloud-APIs (wie OpenAI oder Azure OpenAI) ist zwar einfach, bringt jedoch Herausforderungen in Bezug auf Latenz, Datenschutz und laufende Kosten mit sich. Durch die lokale Ausführung von KI-Modellen können hingegen extrem latenzarme Anwendungen realisiert werden, die auch offline funktionieren, ohne dass sensible Daten das Gerät verlassen.&lt;/p>
&lt;p>Dieser Artikel bietet eine äußerst detaillierte Erklärung zur Implementierung lokaler KI-Funktionen, die für die zukünftige Entwicklung von Windows-Anwendungen unerlässlich sind. Anhand praktischer Beispielcodes in C# und C++ werden Aspekte von der Architektur bis hin zum Performance-Tuning umfassend behandelt. Wir gehen dabei tief auf technische Details ein, wie die Nutzung der zugrunde liegenden Hardware (NPU und GPU) und die Integration mit DirectML, anstatt nur API-Aufrufe zu demonstrieren.&lt;/p>
&lt;h2 id="2-windows-copilot-runtime-und-der-architekturüberblick">2. Windows Copilot Runtime und der Architekturüberblick
&lt;/h2>&lt;p>Die Windows Copilot Runtime ist ein KI-Stack, der so konzipiert ist, dass Entwickler KI-Modelle problemlos in Windows integrieren und gleichzeitig die beste Leistung erzielen können. Diese Laufzeitumgebung abstrahiert die Hardwarebeschleunigung auf Betriebssystemebene und bietet Entwicklern eine einheitliche Schnittstelle.&lt;/p>
&lt;div class="mermaid">graph TD
App["Windows-Anwendung (C# / C++)"] --> API["Microsoft.Windows.AI APIs"]
App --> ORT["ONNX Runtime"]
API --> WCR["Windows Copilot Runtime (OS-Schicht)"]
WCR --> SLM["Lokale Modelle (Phi-Silica, etc.)"]
ORT --> DML["DirectML Execution Provider"]
SLM --> DML
DML --> DXCore["DXCore / DirectX 12"]
DXCore --> NPU["NPU (Neural Processing Unit)"]
DXCore --> GPU["GPU (Graphics Processing Unit)"]
DXCore --> CPU["CPU"]&lt;/div>
&lt;p>Wie das obige Architekturdiagramm zeigt, können Anwendungen über die High-Level-API &lt;code>Microsoft.Windows.AI&lt;/code> direkt auf Small Language Models (SLMs wie Phi-Silica) zugreifen, die im Betriebssystem integriert sind. Bei der Verwendung benutzerdefinierter Modelle ist es zudem möglich, die Hardwarebeschleunigung explizit über die ONNX Runtime und DirectML zu nutzen. Da die Betriebssystemschicht die Verteilung der Arbeitslast auf CPU, GPU und NPU optimiert, können Entwickler hochleistungsfähige KI-Anwendungen erstellen, ohne sich tiefgreifend um Hardwareunterschiede kümmern zu müssen.&lt;/p>
&lt;h2 id="3-hardwarebeschleunigung-und-mathematische-bewertung-der-npu">3. Hardwarebeschleunigung und mathematische Bewertung der NPU
&lt;/h2>&lt;p>Die neuesten Copilot+ PCs sind mit NPUs (Neural Processing Units) ausgestattet, Prozessoren, die speziell auf KI-Verarbeitung zugeschnitten sind. Die Leistung von NPUs wird im Allgemeinen in TOPS (Tera Operations Per Second) gemessen.&lt;/p>
&lt;p>Bei der Inferenz von KI-Modellen bestimmt insbesondere die Rechenleistung bei der Matrixmultiplikation (GEMM: General Matrix Multiply) den Durchsatz. Die theoretische maximale Leistung der Hardware $P_{\text{peak}}$ kann mit der folgenden Formel geschätzt werden:&lt;/p>
$$
P_{\text{peak}} = f \times N_{\text{cores}} \times N_{\text{MACs/core}} \times 2
$$
&lt;p>Hierbei ist:&lt;/p>
&lt;ul>
&lt;li>$f$ die Taktfrequenz der NPU (Hz)&lt;/li>
&lt;li>$N_{\text{cores}}$ die Anzahl der Kerne in der NPU&lt;/li>
&lt;li>$N_{\text{MACs/core}}$ die Anzahl der MAC-Einheiten (Multiply-Accumulate) pro Kern&lt;/li>
&lt;li>Die abschließende $2$ steht dafür, dass eine MAC-Operation als zwei Operationen (Multiplikation und Addition, FLOPs/OPs) gezählt wird.&lt;/li>
&lt;/ul>
&lt;p>Für eine NPU mit einer Frequenz von 1,5 GHz, 4 Kernen und 4096 MACs pro Kern ergibt sich beispielsweise:
&lt;/p>
$$
P_{\text{peak}} = 1.5 \times 10^9 \times 4 \times 4096 \times 2 \approx 49.15 \text{ TOPS}
$$
&lt;p>
Dies zeigt mathematisch, dass die Leistung die Anforderung von 40 TOPS für Copilot+ PCs in Windows 11 erfüllt.&lt;/p>
&lt;p>Darüber hinaus ist die Inferenz von KI-Modellen, insbesondere von LLMs (Dekodierungsphase), oft &lt;strong>speichergebunden (Memory-Bound)&lt;/strong>. Die theoretische Bandbreite des Systemspeichers $BW$ wird wie folgt berechnet:&lt;/p>
$$
BW = f_{\text{mem}} \times W_{\text{bus}} \times \frac{2}{8}
$$
&lt;p>Bei LPDDR5x-8533-Speicher ($f_{\text{mem}} = 8533 \text{ MT/s}$) und einem 128-Bit-Bus ($W_{\text{bus}} = 128$) beträgt die Bandbreite etwa $136 \text{ GB/s}$. Bei der Optimierung von KI-Anwendungen ist es entscheidend, wie diese Bandbreite eingespart werden kann, weshalb die später erläuterte Modellquantisierung (Quantization) unerlässlich ist.&lt;/p>
&lt;h2 id="4-einrichtung-der-entwicklungsumgebung">4. Einrichtung der Entwicklungsumgebung
&lt;/h2>&lt;p>Um die neuesten Windows AI APIs zu nutzen, müssen folgende Umgebung und Toolchains eingerichtet werden:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>OS&lt;/strong>: Windows 11 Version 24H2 oder neuer (Geräte mit NPU, die die Anforderungen für Copilot+ PCs erfüllen, werden dringend empfohlen)&lt;/li>
&lt;li>&lt;strong>SDK&lt;/strong>: Windows App SDK (Version 1.5 oder neuer mit KI-Erweiterungsunterstützung)&lt;/li>
&lt;li>&lt;strong>Entwicklungsumgebung&lt;/strong>: Visual Studio 2022 (v17.10 oder neuer), Workloads für native C++-Entwicklung und .NET-Desktopentwicklung&lt;/li>
&lt;li>&lt;strong>Pakete&lt;/strong>: Installation von &lt;code>Microsoft.Windows.AI&lt;/code> und &lt;code>Microsoft.ML.OnnxRuntime.DirectML&lt;/code> über NuGet&lt;/li>
&lt;/ol>
&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Beispiel für die .csproj-Konfiguration --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;ItemGroup&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;PackageReference&lt;/span> &lt;span class="na">Include=&lt;/span>&lt;span class="s">&amp;#34;Microsoft.Windows.AI&amp;#34;&lt;/span> &lt;span class="na">Version=&lt;/span>&lt;span class="s">&amp;#34;1.0.0-preview1&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;PackageReference&lt;/span> &lt;span class="na">Include=&lt;/span>&lt;span class="s">&amp;#34;Microsoft.WindowsAppSDK&amp;#34;&lt;/span> &lt;span class="na">Version=&lt;/span>&lt;span class="s">&amp;#34;1.5.240311000&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;PackageReference&lt;/span> &lt;span class="na">Include=&lt;/span>&lt;span class="s">&amp;#34;Microsoft.ML.OnnxRuntime.DirectML&amp;#34;&lt;/span> &lt;span class="na">Version=&lt;/span>&lt;span class="s">&amp;#34;1.17.1&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/ItemGroup&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="5-deep-dive-1nutzung-lokaler-sprachmodelle-phi-silica-mit-c">5. 【Deep Dive 1】Nutzung lokaler Sprachmodelle (Phi-Silica) mit C#
&lt;/h2>&lt;p>Die Windows Copilot Runtime enthält als standardmäßige Betriebssystemkomponente das von Microsoft entwickelte, hocheffiziente kleine Sprachmodell &amp;ldquo;Phi-Silica&amp;rdquo;. Dadurch wird eine fortschrittliche Verarbeitung natürlicher Sprache (Zusammenfassung von Texten, Codegenerierung, Chatbots) in Offline-Umgebungen ermöglicht, ohne dass gigabytegroße Modelle aus dem Netzwerk heruntergeladen werden müssen.&lt;/p>
&lt;p>Im Folgenden finden Sie einen fortgeschrittenen Beispielcode in C#, der den Namensraum &lt;code>Microsoft.Windows.AI.Generative&lt;/code> verwendet, um eine Chat-KI zu erstellen. Er unterstützt Streaming-Antworten und generiert Text in Echtzeit, ohne den UI-Thread zu blockieren.&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System.Text&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System.Threading&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System.Threading.Tasks&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Microsoft.Windows.AI.Generative&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">namespace&lt;/span> &lt;span class="nn">WindowsAI.Sample&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">LocalLanguageModelService&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="n">LanguageModel&lt;/span> &lt;span class="n">_languageModel&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="n">_isInitialized&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">false&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="cs">/// &amp;lt;summary&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cs">/// Initialisiert das Sprachmodell. Überprüft die Verfügbarkeit der NPU und lädt das Modell auf das optimale Gerät.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cs">/// &amp;lt;/summary&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">async&lt;/span> &lt;span class="n">Task&lt;/span> &lt;span class="n">InitializeAsync&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">_isInitialized&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&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="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Systemanforderungen und Verfügbarkeit des lokalen KI-Modells (Phi-Silica) werden überprüft...&amp;#34;&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">// Überprüfen, ob das Modell auf dem System verfügbar ist (falls nicht unterstützt, kann ein Download angefordert werden)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">availability&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">LanguageModel&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">CheckAvailabilityAsync&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">availability&lt;/span> &lt;span class="p">!=&lt;/span> &lt;span class="n">LanguageModelAvailability&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Available&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">InvalidOperationException&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">$&amp;#34;Das lokale KI-Modell ist derzeit nicht verfügbar. Status: {availability}&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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">// Erstellen der Modellinstanz (Zu diesem Zeitpunkt erfolgen das Mapping in den Speicher und die NPU-Initialisierung)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_languageModel&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">LanguageModel&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">CreateAsync&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_isInitialized&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&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="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Initialisierung des Sprachmodells abgeschlossen. Hardwarebeschleunigung über DirectML ist aktiv.&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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="cs">/// &amp;lt;summary&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cs">/// Nimmt die Benutzereingabe (Prompt) entgegen und generiert die Antwort als Stream.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cs">/// &amp;lt;/summary&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">async&lt;/span> &lt;span class="n">Task&lt;/span> &lt;span class="n">GenerateResponseStreamAsync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">string&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">CancellationToken&lt;/span> &lt;span class="n">cancellationToken&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(!&lt;/span>&lt;span class="n">_isInitialized&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">InitializeAsync&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="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">$&amp;#34;\n[Benutzereingabe]: {prompt}\n[KI-Assistent]: &amp;#34;&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">// Hyperparameter für die Generierung festlegen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">options&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">LanguageModelOptions&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Temperature&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">0.7f&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TopP&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">0.9f&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">MaxTokens&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">2048&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">RepetitionPenalty&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">1.1f&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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">// Aufbau des Konversationskontexts&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">context&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">LanguageModelContext&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">context&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">AddSystemMessage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Du bist ein hochentwickelter KI-Assistent, der direkt auf der lokalen NPU von Windows läuft. Denke logisch Schritt für Schritt und antworte prägnant.&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">context&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">AddUserMessage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&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">try&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Aufruf der Streaming-Inferenz-API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">responseStream&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">_languageModel&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">GenerateResponseStreamAsync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">options&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">// Asynchrones Iterieren über die Chunks, die als IAsyncEnumerable zurückgegeben werden&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">var&lt;/span> &lt;span class="n">chunk&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="n">responseStream&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WithCancellation&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cancellationToken&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Generierte Token (Chunks) in Echtzeit in der Konsole ausgeben&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// In einer UI-Anwendung würde hier der DispatcherQueue verwendet werden, um z. B. eine TextBox zu aktualisieren&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunk&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Text&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">OperationCanceledException&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;\n[Generierung wurde vom Benutzer oder System abgebrochen]&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Exception&lt;/span> &lt;span class="n">ex&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">$&amp;#34;\n[Ein schwerwiegender Fehler ist aufgetreten: {ex.Message}]&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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;h3 id="51-architektur-erklärung-der-c-implementierung">5.1 Architektur-Erklärung der C#-Implementierung
&lt;/h3>&lt;p>Der Kern dieses Codes liegt in der Vorabprüfung durch &lt;code>LanguageModel.CheckAvailabilityAsync()&lt;/code> und dem asynchronen Streaming durch &lt;code>GenerateResponseStreamAsync&lt;/code>. Wenn die im Hintergrund des Betriebssystems laufende Copilot Runtime diesen API-Aufruf empfängt, startet sie intern die ONNX Runtime und wählt den optimalen Execution Provider (bei vielen modernen PCs DirectML + NPU) basierend auf der Systemkonfiguration aus.&lt;/p>
&lt;p>Entwickler können modernste KI-Inferenzpipelines mit nur wenigen Zeilen C#-Code in ihre Anwendungen integrieren, ohne sich um die Tensorform des Modells, die Implementierung des Tokenizers oder die Speicherverwaltung des KV-Caches kümmern zu müssen.&lt;/p>
&lt;h2 id="6-deep-dive-2schnelle-inferenz-benutzerdefinierter-modelle-mit-c-und-directml">6. 【Deep Dive 2】Schnelle Inferenz benutzerdefinierter Modelle mit C++ und DirectML
&lt;/h2>&lt;p>Bei der Arbeit mit spezifischen Domänen (wie etwa eigene Bildsegmentierung, Spracherkennung oder benutzerdefinierte Objekterkennungsmodelle), die von den standardmäßigen Sprachmodellen des Betriebssystems nicht abgedeckt werden, müssen Entwickler direkt mit der ONNX Runtime und DirectML interagieren, die in den unteren Schichten von &lt;code>Microsoft.Windows.AI&lt;/code> angesiedelt sind.&lt;/p>
&lt;p>Durch die Verwendung von C++ kann die Speicherzuweisung extrem optimiert werden, um die Spitzenleistung der NPU/GPU abzurufen. Im Folgenden sehen Sie eine Kernimplementierung einer fortschrittlichen Initialisierungs- und Inferenzpipeline für die Ausführung eines benutzerdefinierten Modells im ONNX-Format (z. B. YOLOv8) mit DirectML in C++.&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;span class="lnt">90
&lt;/span>&lt;span class="lnt">91
&lt;/span>&lt;span class="lnt">92
&lt;/span>&lt;span class="lnt">93
&lt;/span>&lt;span class="lnt">94
&lt;/span>&lt;span class="lnt">95
&lt;/span>&lt;span class="lnt">96
&lt;/span>&lt;span class="lnt">97
&lt;/span>&lt;span class="lnt">98
&lt;/span>&lt;span class="lnt">99
&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="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;onnxruntime_cxx_api.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;dml_provider_factory.h&amp;gt;&lt;/span>&lt;span class="cp">
&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">class&lt;/span> &lt;span class="nc">CustomVisionAIProcessor&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Env&lt;/span> &lt;span class="n">env&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Session&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="k">nullptr&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">AllocatorWithDefaultOptions&lt;/span> &lt;span class="n">allocator&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">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CustomVisionAIProcessor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">modelPath&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">:&lt;/span> &lt;span class="n">env&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ORT_LOGGING_LEVEL_WARNING&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;VisionAIProcessor&amp;#34;&lt;/span>&lt;span class="p">)&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="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">SessionOptions&lt;/span> &lt;span class="n">sessionOptions&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Optimierung der Thread-Anzahl
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">sessionOptions&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">SetIntraOpNumThreads&lt;/span>&lt;span class="p">(&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 class="c1">// Maximale Graphenoptimierungsstufe festlegen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">sessionOptions&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">SetGraphOptimizationLevel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">GraphOptimizationLevel&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">ORT_ENABLE_ALL&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. Hinzufügen des DirectML Execution Providers (DML EP)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// device_id = 0 ist der vom System empfohlene Standardadapter (NPU oder Hochleistungs-GPU)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">OrtApi&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">ortApi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">GetApi&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">OrtDmlApi&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">dmlApi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">OrtStatus&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">status&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ortApi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">GetExecutionProviderApi&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;DML&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ORT_API_VERSION&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">reinterpret_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="o">**&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">dmlApi&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">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">dmlApi&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">ThrowOnError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dmlApi&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">SessionOptionsAppendExecutionProvider_DML&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sessionOptions&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Info] DirectML Execution Provider wurde erfolgreich angehängt.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Warning] DirectML API konnte nicht abgerufen werden. Ausführung im CPU-Fallback-Modus.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">ortApi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ReleaseStatus&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">status&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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. Laden des Modells und Erstellen der Session
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Session&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">env&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">modelPath&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">sessionOptions&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Info] ONNX-Modell erfolgreich geladen und Berechnungsgraph kompiliert.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Exception&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Error] Fehler beim Laden des Modells: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">what&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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="kt">void&lt;/span> &lt;span class="nf">RunInference&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">float&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">imageTensor&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int64_t&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">inputShape&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. Puffer für den Eingabetensor erstellen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">MemoryInfo&lt;/span> &lt;span class="n">memoryInfo&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">MemoryInfo&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">CreateCpu&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrtArenaAllocator&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">OrtMemTypeDefault&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Value&lt;/span> &lt;span class="n">inputTensor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Value&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">CreateTensor&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">float&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">memoryInfo&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">float&lt;/span>&lt;span class="o">*&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">imageTensor&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">()),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">imageTensor&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">inputShape&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">inputShape&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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. Dynamisches Abrufen der Ein- und Ausgabeknotennamen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">auto&lt;/span> &lt;span class="n">inputNamePtr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">GetInputNameAllocated&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">allocator&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">outputNamePtr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">GetOutputNameAllocated&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">allocator&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const&lt;/span> &lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">inputNames&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">inputNamePtr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const&lt;/span> &lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">outputNames&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">outputNamePtr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">()&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. Inferenz ausführen (wird über DirectML an die NPU/GPU ausgelagert)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Info] Ausführung der Inferenz-Engine gestartet...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">startTime&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">high_resolution_clock&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">now&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">auto&lt;/span> &lt;span class="n">outputTensors&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Ort&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">RunOptions&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="k">nullptr&lt;/span>&lt;span class="p">},&lt;/span> &lt;span class="n">inputNames&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">inputTensor&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">outputNames&lt;/span>&lt;span class="p">,&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="k">auto&lt;/span> &lt;span class="n">endTime&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">high_resolution_clock&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">duration&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">duration_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">milliseconds&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">endTime&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">startTime&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">// 6. Ergebnistensor abrufen und analysieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">outputData&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">outputTensors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">front&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">GetTensorMutableData&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">float&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size_t&lt;/span> &lt;span class="n">outputSize&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">outputTensors&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">front&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">GetTensorTypeAndShapeInfo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">GetElementCount&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="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Result] Inferenz abgeschlossen: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">duration&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; ms&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Result] Anzahl der Elemente im Ausgabetensor: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">outputSize&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// * Anschließend werden NMS (Non-Maximum Suppression) oder das Zeichnen von Bounding-Boxen für den Ausgabetensor implementiert
&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;span class="line">&lt;span class="cl">&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="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Pfad zum auszuführenden ONNX-Modell
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">CustomVisionAIProcessor&lt;/span> &lt;span class="n">processor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;models/yolov8n_quantized.onnx&amp;#34;&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">// Dummy-Bilddaten für die Inferenz (Batch-Größe 1 x 3 Kanäle x 640 x 640)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int64_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">inputShape&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">640&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">640&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">float&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">dummyImage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">640&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">640&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.5f&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="n">processor&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">RunInference&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dummyImage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">inputShape&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">exception&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Das Programm wurde unerwartet beendet: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">what&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&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 class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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;h3 id="61-die-bedeutung-von-speicherverwaltung-und-zero-copy-inferenz-in-c">6.1 Die Bedeutung von Speicherverwaltung und Zero-Copy-Inferenz in C++
&lt;/h3>&lt;p>Der größte Vorteil der Verwendung von DirectML in C++ ist die enge Integration mit DirectX 12 (DX12). Während der obige Code aus pädagogischen Gründen ein standardmäßiges Kopieren von Daten aus dem CPU-Speicher enthält, ist es in realen Spiel-Engines oder Videoverarbeitungsanwendungen oft der Fall, dass Bilder (Texturen) mithilfe von DX12 bereits im Speicher der GPU oder NPU vorgehalten werden.&lt;/p>
&lt;p>In solchen Fällen können die erweiterten Bindungsfunktionen der &lt;code>OrtDmlApi&lt;/code> genutzt werden, um DX12-Ressourcen direkt als Tensoren der ONNX Runtime abzubilden, wodurch eine &amp;ldquo;&lt;strong>Zero-Copy Inference&lt;/strong>&amp;rdquo; (Inferenz ohne Kopiervorgänge) realisiert wird. Dadurch entfällt der Overhead der Datenübertragung über den PCIe-Bus (der Verbrauch der oben erwähnten Bandbreite $BW$) vollständig, und die Bildrate bei der Echtzeit-Videoverarbeitung wird drastisch verbessert.&lt;/p>
&lt;h2 id="7-leistungsoptimierung-und-best-practices">7. Leistungsoptimierung und Best Practices
&lt;/h2>&lt;p>Im Folgenden werden unverzichtbare Optimierungsstrategien für die Entwicklung erstklassiger KI-Anwendungen unter Verwendung der Windows AI API und DirectML zusammengefasst.&lt;/p>
&lt;h3 id="71-modellquantisierung-quantization-und-das-olive-toolkit">7.1 Modellquantisierung (Quantization) und das Olive Toolkit
&lt;/h3>&lt;p>Um das wahre Potenzial der NPU zu entfalten, ist es absolut notwendig, die Gewichte und Aktivierungen von KI-Modellen von FP32 (einfache Genauigkeit) zu INT8 oder INT4 zu &lt;strong>quantisieren (Quantization)&lt;/strong>. Die NPU-Architektur ist auf Ganzzahloperationen spezialisiert und bietet mit INT8 im Vergleich zu FP32 theoretisch den vierfachen Durchsatz und massive Energieeinsparungen.&lt;/p>
&lt;p>Durch die Verwendung der von Microsoft bereitgestellten Toolchain &lt;code>Olive (ONNX Live)&lt;/code> können Modelle aus PyTorch und anderen Frameworks automatisch für Windows-Umgebungen optimiert werden. Olive bietet starke Unterstützung für spezielle Aufmerksamkeitsoptimierungen (Attention-Optimierungen) in Transformer-Modellen und die hardwarebezogene Kompilierung von Graphen.&lt;/p>
&lt;h3 id="72-der-kompromiss-batch-verarbeitung-vs-interaktives-streaming">7.2 Der Kompromiss: Batch-Verarbeitung vs. interaktives Streaming
&lt;/h3>&lt;p>Bei API-Aufrufen kann die Auslastung der NPU (Compute Utilization) durch das Zusammenfassen mehrerer Inferenzanforderungen in einer Batch-Verarbeitung (Stapelverarbeitung) erhöht werden. Bei einer interaktiven Benutzeroberfläche wie einem Chatbot bestimmt jedoch die Zeit, bis das erste Token angezeigt wird (TTFT: Time To First Token), das Benutzererlebnis (UX) mehr als der bloße Durchsatz.
Daher besteht die Best Practice für interaktive UIs darin, die Batch-Größe auf 1 zu setzen und der Streaming-Generierung Vorrang zu geben.&lt;/p>
&lt;h3 id="73-hintergrundaufgaben-und-zusammenarbeit-mit-dem-betriebssystem">7.3 Hintergrundaufgaben und Zusammenarbeit mit dem Betriebssystem
&lt;/h3>&lt;p>KI-Inferenzen verbrauchen lokal große Mengen an Strom und Systemressourcen. Durch die Integration mit der Windows &lt;code>App Lifecycle API&lt;/code> wird erwartet, dass Inferenzaufgaben mit niedriger Priorität angehalten (Suspend) oder der Ressourcenverbrauch gedrosselt wird, wenn die Anwendung in den Hintergrund tritt.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant User as "Benutzer"
participant App as "Windows-Anwendung (C#)"
participant API as "Microsoft.Windows.AI"
participant OS as "Windows Copilot Runtime"
participant ORT as "ONNX Runtime (DML)"
participant NPU as "NPU-Hardware"
User->>App: "Prompt eingeben"
App->>API: "GenerateResponseStreamAsync()"
API->>OS: "Dispatch des Inferenzjobs"
OS->>ORT: "Graph-Ausführungsanforderung"
ORT->>NPU: "Ausführen der Befehlsliste via DirectML"
NPU-->>ORT: "Berechnung abgeschlossen (1 Token generiert)"
ORT-->>OS: "Tensorergebnis"
OS-->>API: "Dekodierter Text"
API-->>App: "IAsyncEnumerable&lt;string> Chunk"
App-->>User: "Echtzeit-Zeichenausgabe in der UI"
Note over ORT,NPU: "Diese Schleife wird schnell wiederholt, bis sie abgeschlossen ist"&lt;/div>
&lt;p>Dieses Sequenzdiagramm veranschaulicht die Eleganz der asynchronen Verarbeitung, bei der Daten von der untersten NPU-Hardwareschicht bis zur Präsentationsschicht der Anwendung fließen, ohne dass der UI-Thread jemals blockiert wird.&lt;/p>
&lt;h2 id="8-zukunftsausblick-und-die-evolution-von-windows-ai">8. Zukunftsausblick und die Evolution von Windows AI
&lt;/h2>&lt;p>Die &lt;code>Microsoft.Windows.AI&lt;/code>-API und die Copilot Runtime entwickeln sich rasant weiter. Zukünftige Updates für Entwickler lassen folgende Paradigmenwechsel erwarten:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OS-native Integration multimodaler APIs&lt;/strong>: Nahtlose, gleichzeitige Verarbeitung nicht nur von Text, sondern auch von Audio, Bildern und sogar Live-Video-Feeds, wodurch cross-modale KI-Inferenzen standardmäßig auf OS-Ebene bereitgestellt werden.&lt;/li>
&lt;li>&lt;strong>RAG (Retrieval-Augmented Generation) auf Systemebene&lt;/strong>: Die Verknüpfung persönlicher Dokumente und des Windows-Suchindex auf dem lokalen PC mit KI-Modellen innerhalb der sicheren OS-Sandbox. Dies ermöglicht den Aufbau hochentwickelter, persönlicher KI-Assistenten, die die Privatsphäre des Benutzers vollständig wahren.&lt;/li>
&lt;li>&lt;strong>Dynamische Ressourcenskalierung der NPU&lt;/strong>: Ein Mechanismus, bei dem der Windows-Kernel-Scheduler den Ausführungskontext der NPU dynamisch umschaltet, um QoS (Quality of Service) zu gewährleisten, wenn mehrere KI-Anwendungen (z. B. Rauschunterdrückung im Hintergrund und Codegenerierung im Vordergrund) gleichzeitig ausgeführt werden.&lt;/li>
&lt;/ul>
&lt;h2 id="9-fazit-die-zukunft-von-anwendungen-durch-lokale-ki">9. Fazit: Die Zukunft von Anwendungen durch lokale KI
&lt;/h2>&lt;p>Die Copilot Runtime in Windows 11 und die &lt;code>Microsoft.Windows.AI&lt;/code>-API haben allen Windows-Entwicklern die extrem mächtige Waffe der &amp;ldquo;lokalen KI&amp;rdquo; an die Hand gegeben. Es besteht keine absolute Abhängigkeit mehr von Cloud-APIs. Sie können den Benutzern KI-Erlebnisse der nächsten Generation bieten, die Latenzen eliminieren, den Datenschutz strikt wahren und auch offline vollständig funktionieren.&lt;/p>
&lt;p>Nutzen Sie das Wissen aus diesem Artikel – von der Integration standardmäßiger Sprachmodelle des Betriebssystems mit C# über mathematische Leistungsbewertungen bis hin zu extremer Hardwareoptimierung mithilfe von C++ und DirectML –, um eigenhändig &amp;ldquo;KI-native&amp;rdquo; Windows-Anwendungen der nächsten Generation zu erschaffen. Die unbegrenzten Möglichkeiten, die KI bietet, liegen direkt vor dem Code, den Sie schreiben.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Hinweis: Dieser Artikel basiert auf den Preview-APIs und den neuesten Spezifikationen mit Stand September 2026. Da sich API-Spezifikationen und Hardwareanforderungen aufgrund von Windows-Updates ändern können, konsultieren Sie bei der Implementierung immer auch die offizielle Dokumentation von Microsoft Learn.&lt;/em>&lt;/p></description></item><item><title>Python nicht nötig! Ich habe eine AI-Inferenz-Engine nur mit C++ aufgebaut</title><link>http://kenji.blog/de/p/building-ai-inference-engine-cpp-only/</link><pubDate>Fri, 11 Sep 2026 17:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/building-ai-inference-engine-cpp-only/</guid><description>&lt;img src="http://kenji.blog/p/building-ai-inference-engine-cpp-only/img/eyecatch.jpg" alt="Featured image of post Python nicht nötig! Ich habe eine AI-Inferenz-Engine nur mit C++ aufgebaut" />&lt;h2 id="1-einleitung-warum-python-aufgeben-und-eine-ki-inferenz-engine-in-c-schreiben">1. Einleitung: Warum Python aufgeben und eine KI-Inferenz-Engine in C++ schreiben?
&lt;/h2>&lt;p>In der modernen KI-Entwicklung ist Python der De-facto-Standard. Dank leistungsstarker Frameworks wie PyTorch und TensorFlow können komplexe neuronale Netze mit nur wenigen Codezeilen aufgebaut, trainiert und für die Inferenz genutzt werden. Hinter den Kulissen dieser Frameworks übernehmen jedoch Low-Level-Sprachen wie C++ und CUDA die rechenintensiven Aufgaben. Python fungiert hier lediglich als &amp;ldquo;Klebstoff&amp;rdquo; (Glue).&lt;/p>
&lt;p>Warum sollte man also Python explizit ausschließen und eine KI-Inferenz-Engine ausschließlich mit C++ erstellen? Dafür gibt es einige triftige Gründe:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Extreme Leistung und niedrige Latenz&lt;/strong>: Der Overhead durch Pythons GIL (Global Interpreter Lock) und die dynamische Typisierung kann vollständig eliminiert werden. Besonders bei Systemen, die Echtzeitfähigkeit erfordern, können Verzögerungen im Millisekundenbereich fatal sein.&lt;/li>
&lt;li>&lt;strong>Einfaches Deployment&lt;/strong>: Der Aufbau einer Python-Umgebung (riesige Bibliotheken, Abhängigkeitshölle) auf dem System des Endbenutzers ist äußerst schwierig. Mit C++ reicht es aus, eine einzige statisch verlinkte ausführbare Binärdatei (&lt;code>.exe&lt;/code> oder ELF-Binärdatei) zu verteilen.&lt;/li>
&lt;li>&lt;strong>Unterstützung für Edge-Geräte&lt;/strong>: In ressourcenbeschränkten Umgebungen wie Smartphones, eingebetteten Geräten oder dem Raspberry Pi gibt es keinen Spielraum, um eine Python-Laufzeitumgebung auszuführen, die mehrere Gigabyte an Speicher verbraucht.&lt;/li>
&lt;li>&lt;strong>Direkte Hardwaresteuerung&lt;/strong>: Low-Level-Steuerungen wie das Timing der Speicherzuweisung, die explizite Nutzung von SIMD-Befehlen und die Optimierung des Speichertransfers mit der GPU sind mit C++ möglich.&lt;/li>
&lt;/ol>
&lt;p>In diesem Artikel werden wir den Prozess des Aufbaus einer Inferenz-Engine für Large Language Models (LLMs) und andere Modelle komplett von Grund auf in C++ tiefgreifend und technisch erklären, stark inspiriert von der Architektur der Bibliothek &amp;ldquo;GGML&amp;rdquo;, die von Georgi Gerganov entwickelt wurde.&lt;/p>
&lt;hr>
&lt;h2 id="2-gesamtarchitektur-der-inferenz-engine">2. Gesamtarchitektur der Inferenz-Engine
&lt;/h2>&lt;p>KI-Inferenzprozesse sind im Wesentlichen &amp;ldquo;eine Reihe gigantischer Matrixberechnungen&amp;rdquo;. Um diese effizient auszuführen, muss eine Inferenz-Engine aus den folgenden Komponenten bestehen:&lt;/p>
&lt;div class="mermaid">graph TD
A["Eingabedaten (Tokens/Bilder)"] --> B["Tensor-Management"]
B --> C["Berechnungsgraph (DAG)"]
C --> D["Memory Arena &amp; Allocator"]
C --> E["Scheduler &amp; Thread-Pool"]
E --> F["CPU-Backend (AVX2/ARM NEON)"]
E --> G["GPU-Backend (CUDA/Metal)"]
F --> H["Ausgabeergebnisse"]
G --> H&lt;/div>
&lt;ol>
&lt;li>&lt;strong>Tensor-Management&lt;/strong>: Verwaltet mehrdimensionale Array-Datenstrukturen und die Strides pro Dimension.&lt;/li>
&lt;li>&lt;strong>Berechnungsgraph (Computation Graph)&lt;/strong>: Repräsentiert die Operationen jeder Schicht des neuronalen Netzes als gerichteten azyklischen Graphen (DAG).&lt;/li>
&lt;li>&lt;strong>Memory Arena&lt;/strong>: Ein Mechanismus zur vorab allokierten Speicherverwaltung, um den Overhead der dynamischen Speicherzuweisung (&lt;code>malloc&lt;/code> oder &lt;code>new&lt;/code>) zu vermeiden.&lt;/li>
&lt;li>&lt;strong>Backend&lt;/strong>: Für bestimmte Hardware wie CPU oder GPU optimierte Implementierungen der Operationen (Kernel).&lt;/li>
&lt;/ol>
&lt;p>Wir werden diese Komponenten unter Verwendung der mächtigen Funktionen von C++ (Templates, Zeigerarithmetik, RAII usw.) zusammensetzen.&lt;/p>
&lt;hr>
&lt;h2 id="3-das-geheimnis-der-speicherverwaltung-memory-arena-und-simd-alignment">3. Das Geheimnis der Speicherverwaltung: Memory Arena und SIMD-Alignment
&lt;/h2>&lt;p>Die Speicherverwaltung in einer Inferenz-Engine ist einer der wichtigsten Faktoren, der sich direkt auf die Leistung auswirkt. Während der Inferenz, insbesondere beim Durchlaufen der einzelnen Schichten eines Transformer-Modells, wird eine enorme Anzahl von Zwischen-Tensoren generiert. Wenn diese jedes Mal mit dem standardmäßigen &lt;code>malloc&lt;/code> zugewiesen und freigegeben werden, führt dies aufgrund von Heap-Fragmentierung und OS-Kontextwechseln zu massiven Leistungseinbußen.&lt;/p>
&lt;p>Daher verwenden wir den Ansatz einer &amp;ldquo;&lt;strong>Memory Arena&lt;/strong>&amp;rdquo;. Bei dieser Methode wird die maximale Speichermenge, die zu Beginn der Inferenz benötigt wird, berechnet (oder vorgegeben) und auf einmal zugewiesen. Der Speicher wird dann einfach durch das Inkrementieren eines Zeigers reserviert.&lt;/p>
&lt;h3 id="31-die-bedeutung-des-alignments">3.1 Die Bedeutung des Alignments
&lt;/h3>&lt;p>Moderne CPUs unterstützen SIMD-Befehle (Single Instruction, Multiple Data), wie AVX2/AVX-512 von Intel/AMD oder NEON von ARM. Diese Befehle verarbeiten 256 Bit (32 Byte) oder 512 Bit (64 Byte) Daten auf einmal, erfordern aber, dass der zu verarbeitende Datenspeicher an bestimmten Byte-Grenzen (normalerweise 32 Byte oder 64 Byte) ausgerichtet (aligned) ist.&lt;/p>
&lt;p>Hier ist ein C++-Implementierungsbeispiel für eine Memory Arena, die das Alignment berücksichtigt.&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&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="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cstdint&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cstddef&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&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">MemoryArena&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size_t&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size_t&lt;/span> &lt;span class="n">offset&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="o">*&lt;/span> &lt;span class="n">data&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="n">MemoryArena&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">offset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Bei POSIX-Systemen posix_memalign verwenden, bei Windows _aligned_malloc
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#ifdef _WIN32
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">static_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint8_t&lt;/span>&lt;span class="o">*&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_aligned_malloc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">64&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#else
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">posix_memalign&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">reinterpret_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="o">**&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">64&lt;/span>&lt;span class="p">,&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">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">bad_alloc&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#endif
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&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="o">~&lt;/span>&lt;span class="n">MemoryArena&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#ifdef _WIN32
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span> &lt;span class="n">_aligned_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#else
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span> &lt;span class="n">free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#endif
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&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="kt">void&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="nf">allocate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span> &lt;span class="n">bytes&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size_t&lt;/span> &lt;span class="n">alignment&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">64&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Berechnung des Alignments (Bestimmung des Paddings)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">size_t&lt;/span> &lt;span class="n">pad&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">alignment&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">offset&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">alignment&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">alignment&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">offset&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">pad&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">bytes&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;OOM: MemoryArena out of memory&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">offset&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">pad&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">offset&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">offset&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">bytes&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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="kt">void&lt;/span> &lt;span class="nf">reset&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">offset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Speicherfreigabe erfolgt nur durch Rücksetzen des Zeigers (O(1))
&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;span class="line">&lt;span class="cl">&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>Auf diese Weise wird der Speicher beim Erstellen von Tensoren immer über diese Arena zugewiesen. Durch einfaches Aufrufen von &lt;code>reset()&lt;/code> am Ende jedes Inferenzschritts (z. B. nach jeder Token-Generierung) kann der Speicher sofort wiederverwendet werden.&lt;/p>
&lt;hr>
&lt;h2 id="4-tensor-datenstrukturen-und-die-magie-des-strides">4. Tensor-Datenstrukturen und die Magie des Strides
&lt;/h2>&lt;p>Ein Tensor ist ein generalisiertes Konzept von Skalaren, Vektoren und Matrizen. Bei der Implementierung ist es wichtig, das Konzept des &amp;ldquo;Strides&amp;rdquo; zu berücksichtigen, das es ermöglicht, die eigentlichen Daten, die als &lt;strong>eindimensionales fortlaufendes Array&lt;/strong> im Speicher liegen, als mehrdimensional zu interpretieren.&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;/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="k">enum&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">DataType&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">FP32&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">FP16&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">INT8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// Für Quantisierung
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">INT4&lt;/span> &lt;span class="c1">// Für Quantisierung
&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;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Tensor&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_dims&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Anzahl der Dimensionen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int64_t&lt;/span> &lt;span class="n">ne&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Anzahl der Elemente pro Dimension (Number of Elements)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">size_t&lt;/span> &lt;span class="n">nb&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Stride pro Dimension (Number of Bytes)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">DataType&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Datentyp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">void&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Zeiger auf die Nutzdaten (Payload)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Für den Berechnungsgraphen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">enum&lt;/span> &lt;span class="nc">OpType&lt;/span> &lt;span class="n">op&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">src0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">src1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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>Der Stride &lt;code>nb[i]&lt;/code> repräsentiert den Byte-Abstand im Speicher zwischen benachbarten Elementen in der Dimension &lt;code>i&lt;/code>.
Zum Beispiel sieht der Stride für eine Matrix mit $M \times N$ Elementen (FP32, 4 Bytes pro Element), die in Row-Major-Reihenfolge (zeilenweise) gespeichert ist, wie folgt aus:&lt;/p>
&lt;ul>
&lt;li>&lt;code>nb[0]&lt;/code> = 4 (Bytes): Bewegung in Spaltenrichtung&lt;/li>
&lt;li>&lt;code>nb[1]&lt;/code> = $N \times 4$ (Bytes): Bewegung in Zeilenrichtung&lt;/li>
&lt;/ul>
&lt;p>Durch die Nutzung dieses Konzepts können Operationen wie &amp;ldquo;Transponieren&amp;rdquo; (Transpose) oder &amp;ldquo;Ansicht&amp;rdquo; (View) durchgeführt werden, ohne Speicher zu kopieren, indem man lediglich die Stride-Werte austauscht. Das ist sehr elegant und schnell.&lt;/p>
&lt;hr>
&lt;h2 id="5-aufbau-des-berechnungsgraphen-dag-und-lazy-evaluation">5. Aufbau des Berechnungsgraphen (DAG) und Lazy Evaluation
&lt;/h2>&lt;p>Ähnlich wie PyTorch verwendet auch unsere Inferenz-Engine eine verzögerte Auswertung (Lazy Evaluation), die dem &amp;ldquo;Define-by-Run&amp;rdquo;-Konzept ähnelt. Das bedeutet, dass zum Zeitpunkt des Aufrufs einer mathematischen Funktion keine Berechnungen durchgeführt werden, sondern nur der Graph (die Abhängigkeiten zwischen den Knoten) aufgebaut wird.&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;/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="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="nf">tensor_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">MemoryArena&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">arena&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">out&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_tensor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arena&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">type&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">n_dims&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">ne&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">out&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">op&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OpType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">ADD&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">out&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">src0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">out&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">src1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">out&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="nf">tensor_mul_mat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">MemoryArena&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">arena&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// b ist meistens transponiert
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int64_t&lt;/span> &lt;span class="n">ne&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">ne&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">ne&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">out&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_tensor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arena&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">type&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ne&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">out&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">op&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OpType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">MUL_MAT&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">out&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">src0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">out&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">src1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">out&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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>Der Ablauf des Inferenzprozesses ist wie folgt:&lt;/p>
&lt;div class="mermaid">graph LR
A["Tensoren definieren"] --> B["Graph über Ops erstellen"]
B --> C["Topologische Sortierung"]
C --> D["Speicher für Ausgaben reservieren"]
D --> E["Knoten der Reihe nach ausführen"]&lt;/div>
&lt;p>Bei der Auswertung des Graphen (Vorwärtspass) wird eine topologische Sortierung verwendet, um Knoten ohne Abhängigkeiten nacheinander auszuführen. Da wir bei reiner Inferenz keine Gradienten für die Backpropagation speichern müssen, bleibt die Speicherverwaltung sehr einfach.&lt;/p>
&lt;hr>
&lt;h2 id="6-der-kern-von-mathematik-und-optimierung-matrixmultiplikation-gemm">6. Der Kern von Mathematik und Optimierung: Matrixmultiplikation (GEMM)
&lt;/h2>&lt;p>Mehr als 90 % der Rechenleistung bei der KI-Inferenz werden für Matrixmultiplikationen (GEMM: General Matrix Multiply) aufgewendet. Der Kern von Transformer-Modellen, der Attention-Mechanismus und das Feed-Forward Network (FFN), sind letztlich gigantische Matrixmultiplikationen.&lt;/p>
&lt;p>Das Produkt $C = A B$ (Größe $M \times N$) von zwei Matrizen $A$ (Größe $M \times K$) und $B$ (Größe $K \times N$) wird mathematisch wie folgt ausgedrückt:&lt;/p>
$$
C_{i,j} = \sum_{k=0}^{K-1} A_{i,k} \cdot B_{k,j}
$$
&lt;p>Wenn dies mit einer naiven dreifachen Schleife implementiert wird, treten häufig Cache-Misses auf, und es wird kaum Leistung erbracht.&lt;/p>
&lt;h3 id="61-cache-blocking-auf-der-cpu-und-simd-optimierung">6.1 Cache-Blocking auf der CPU und SIMD-Optimierung
&lt;/h3>&lt;p>Die grundlegende Strategie zur Beschleunigung von GEMM auf der CPU sieht folgendermaßen aus:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Loop-Tiling (Cache-Blocking)&lt;/strong>: Die Matrix wird in kleine Blöcke unterteilt, die in den L1/L2-Cache passen, und blockweise berechnet.&lt;/li>
&lt;li>&lt;strong>Daten-Packing&lt;/strong>: Daten werden intern neu angeordnet, um kontinuierliche Speicherzugriffsmuster zu gewährleisten.&lt;/li>
&lt;li>&lt;strong>Nutzung von SIMD&lt;/strong>: Durch die Verwendung von FMA-Befehlen (Fused Multiply-Add) wie &lt;code>_mm512_fmadd_ps&lt;/code> in AVX-512 können in einem einzigen Taktzyklus viele Multiplikations-Additions-Operationen durchgeführt werden.&lt;/li>
&lt;/ol>
&lt;p>Hier ist ein Beispiel für ein vereinfachtes Vektor-Skalarprodukt (Dot Product) unter Verwendung von C++ und SIMD Intrinsics.&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;span class="lnt">27
&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="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;immintrin.h&amp;gt;&lt;/span>&lt;span class="cp"> &lt;/span>&lt;span class="c1">// Für AVX-Befehle
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Schnelles FP32-Skalarprodukt mit AVX2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">float&lt;/span> &lt;span class="nf">dot_product_avx2&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">__m256&lt;/span> &lt;span class="n">sum256&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_mm256_setzero_ps&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&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">// Verarbeite 8 Elemente auf einmal (256 Bit = 32 Byte = 8 * 4 Byte)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">__m256&lt;/span> &lt;span class="n">va&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_mm256_loadu_ps&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">__m256&lt;/span> &lt;span class="n">vb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_mm256_loadu_ps&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// FMA-Befehl: sum256 = va * vb + sum256
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">sum256&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_mm256_fmadd_ps&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">va&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">vb&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">sum256&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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">// Horizontale Addition der Werte im SIMD-Register
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">float&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_mm256_storeu_ps&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">sum256&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">float&lt;/span> &lt;span class="n">dot&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">7&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">// Verarbeitung des Rests
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dot&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dot&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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>Schon dieser kleine Trick kann im Vergleich zu einer naiven Implementierung zu einer mehrfachen bis zu über zehnfachen Geschwindigkeitssteigerung führen.&lt;/p>
&lt;hr>
&lt;h2 id="7-hardwaregrenzen-überwinden-integration-von-cuda--und-metal-backends">7. Hardwaregrenzen überwinden: Integration von CUDA- und Metal-Backends
&lt;/h2>&lt;p>Eine reine C++-Implementierung läuft auf der CPU zwar einigermaßen gut, aber um riesige Modelle wie LLMs mit praktischer Geschwindigkeit auszuführen (z. B. mehr als 20 Tokens pro Sekunde), ist die parallele Rechenleistung einer GPU unerlässlich. Daher führen wir eine Backend-Abstraktionsschicht in unsere Engine ein.&lt;/p>
&lt;h3 id="71-backend-abstraktion">7.1 Backend-Abstraktion
&lt;/h3>&lt;p>Wir nutzen den C++-Polymorphismus, um die Ausführungseinheit (Executor) für die Berechnungen wechseln zu können.&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;/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="k">class&lt;/span> &lt;span class="nc">Backend&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="o">~&lt;/span>&lt;span class="n">Backend&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">default&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">alloc_buffer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">free_buffer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">copy_to_device&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">copy_to_host&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&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">// Ausführung verschiedener Operationen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">virtual&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">compute_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">src0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">src1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">dst&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">compute_mul_mat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">src0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">src1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">dst&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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;h3 id="72-implementierung-des-nvidia-cuda-backends">7.2 Implementierung des NVIDIA CUDA-Backends
&lt;/h3>&lt;p>Um NVIDIA-GPUs zu nutzen, implementieren wir das Backend mit CUDA-C++-Erweiterungen. Obwohl es möglich ist, eigene Kernel zu schreiben, ist es bei Matrixmultiplikationen am besten, &amp;ldquo;cuBLAS&amp;rdquo;, die erstklassige Bibliothek von NVIDIA, zu verwenden.&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&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="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cublas_v2.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cuda_runtime.h&amp;gt;&lt;/span>&lt;span class="cp">
&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">class&lt;/span> &lt;span class="nc">CUDABackend&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">Backend&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cublasHandle_t&lt;/span> &lt;span class="n">handle&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">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CUDABackend&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cublasCreate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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="o">~&lt;/span>&lt;span class="n">CUDABackend&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cublasDestroy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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="kt">void&lt;/span> &lt;span class="nf">compute_mul_mat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">src0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">src1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Tensor&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">dst&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">override&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Bei CUDA ist Column-Major der Standard, daher muss man auf die Parameter achten
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">float&lt;/span> &lt;span class="n">alpha&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">1.0f&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const&lt;/span> &lt;span class="kt">float&lt;/span> &lt;span class="n">beta&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.0f&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="kt">int&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">src0&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">ne&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">k&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">src0&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">ne&lt;/span>&lt;span class="p">[&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 class="kt">int&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">src1&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">ne&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// src1 wird als transponiert vorausgesetzt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cublasSgemm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">CUBLAS_OP_T&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">CUBLAS_OP_N&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">alpha&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">src0&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">src1&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">beta&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">dst&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cudaDeviceSynchronize&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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>Da die Datenübertragung (&lt;code>cudaMemcpy&lt;/code>) zwischen CUDA-Speicher und Host-(CPU)-Speicher sehr ressourcenintensiv ist, ist es wichtig, die Engine so zu entwerfen, dass alle Gewichte (Gewichtstensoren) und Zwischentensoren während der Inferenz so weit wie möglich im VRAM verbleiben.&lt;/p>
&lt;h3 id="73-apple-silicon-metal-backend">7.3 Apple Silicon (Metal) Backend
&lt;/h3>&lt;p>In den letzten Jahren haben sich Macs mit M1/M2/M3-Chips (Apple Silicon) als hervorragende Maschinen für die KI-Inferenz erwiesen. Der Grund dafür ist der &amp;ldquo;Unified Memory&amp;rdquo;. Da sich CPU und GPU denselben Speicherbereich teilen, entfallen die teuren Host-Device-Speichertransfers über den PCIe-Bus, wie sie bei CUDA erforderlich sind, komplett.&lt;/p>
&lt;p>Um Metal von C++ aus aufzurufen, verwendet man entweder Objective-C++ (&lt;code>.mm&lt;/code>-Dateien) als Brücke oder die Bibliothek &lt;code>metal-cpp&lt;/code>.
Kernel werden mithilfe von Metal Compute-Shadern (in &lt;code>.metal&lt;/code>-Dateien C++-ähnlich geschrieben) implementiert.&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;/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">// Metal-Shader (kernel.metal)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;metal_stdlib&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">metal&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="n">kernel&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">mul_mat_kernel&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">A&lt;/span> &lt;span class="p">[[&lt;/span>&lt;span class="n">buffer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)]],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">B&lt;/span> &lt;span class="na">[[buffer(1)]]&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device&lt;/span> &lt;span class="kt">float&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">C&lt;/span> &lt;span class="na">[[buffer(2)]]&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">constant&lt;/span> &lt;span class="n">uint3&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">dims&lt;/span> &lt;span class="na">[[buffer(3)]]&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uint2&lt;/span> &lt;span class="n">gid&lt;/span> &lt;span class="na">[[thread_position_in_grid]]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uint&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dims&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">uint&lt;/span> &lt;span class="n">k&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dims&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">uint&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dims&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">z&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uint&lt;/span> &lt;span class="n">row&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gid&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">uint&lt;/span> &lt;span class="n">col&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gid&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&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">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">row&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">col&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">float&lt;/span> &lt;span class="n">sum&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">uint&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sum&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">A&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">row&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">k&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">B&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">col&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Vereinfacht
&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;span class="line">&lt;span class="cl"> &lt;span class="n">C&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">row&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">col&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sum&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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>In Apple Silicon-Umgebungen steht auch eine optimierte Bibliothek für Matrixmultiplikationen namens MPS (Metal Performance Shaders) zur Verfügung. Wenn man diese in der Praxis nutzt, lassen sich beeindruckende Inferenzgeschwindigkeiten erzielen.&lt;/p>
&lt;hr>
&lt;h2 id="8-spezifische-verarbeitung-für-transformer-modelle-attention-und-kv-cache">8. Spezifische Verarbeitung für Transformer-Modelle: Attention und KV-Cache
&lt;/h2>&lt;p>Hochmoderne LLMs wie LLaMA 2/3 oder GPT basieren auf der Transformer-Architektur. Um dies in C++ zu implementieren, ist es unerlässlich, die &amp;ldquo;Scaled Dot-Product Attention&amp;rdquo;, ausgedrückt durch folgende mathematische Formel, aufzubauen:&lt;/p>
$$
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
&lt;p>Zudem müssen bei der autoregressiven Token-Generierung die Berechnungsergebnisse (Key und Value) vergangener Tokens aufbewahrt werden. Dies nennt man &amp;ldquo;&lt;strong>KV-Cache (Key-Value Cache)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">graph TD
T["Aktuelles Token"] --> Q["Query"]
T --> K["Key"]
T --> V["Value"]
K --> KCache["An KV-Cache anhängen"]
V --> VCache["An KV-Cache anhängen"]
Q --> Dot1["Q * K_Cache^T"]
KCache --> Dot1
Dot1 --> Scale["Skalieren (1/sqrt(d))"]
Scale --> Softmax["Softmax"]
Softmax --> Dot2["SoftmaxOut * V_Cache"]
VCache --> Dot2
Dot2 --> Out["Kontextvektor"]&lt;/div>
&lt;p>Auch für den KV-Cache wird der Speicher im Voraus reserviert. Dies erfolgt ähnlich wie bei einem Ringpuffer, indem man in der Arena Platz für die maximale Kontextlänge (z. B. 4096 oder 8192 Tokens) allokiert. Dadurch können Neuallokationen bei jedem Generierungsschritt vermieden werden.&lt;/p>
&lt;p>Für die Positionscodierung (Positional Encoding) implementieren wir &amp;ldquo;RoPE (Rotary Position Embedding)&amp;rdquo;, was sich in den letzten Jahren durchgesetzt hat. Dies ist eine Methode, bei der Positionsinformationen als Rotationsvektoren im komplexen Raum eingebettet werden. Die Optimierung der Aufrufe von &lt;code>sin&lt;/code>- und &lt;code>cos&lt;/code>-Funktionen in C++ (z. B. durch Look-up-Tabellen) ist hier der Schlüssel zur Leistung.&lt;/p>
&lt;hr>
&lt;h2 id="9-extreme-optimierung-durch-modellquantisierung-quantization">9. Extreme Optimierung durch Modellquantisierung (Quantization)
&lt;/h2>&lt;p>Wenn ein großes Modell (beispielsweise ein LLaMA-Modell mit 7 Milliarden Parametern) als FP32 (32-Bit-Fließkommazahl) geladen wird, verbrauchen allein die Gewichte etwa 28 GB Speicher (VRAM). Nimmt man den KV-Cache und die Inferenzpuffer hinzu, übersteigt der Verbrauch leicht 30 GB, was eine Ausführung auf normalen Consumer-GPUs unmöglich macht.&lt;/p>
&lt;p>Hier kommt die &amp;ldquo;&lt;strong>Quantisierung (Quantization)&lt;/strong>&amp;rdquo; ins Spiel. Sie ist auch die wahre Stärke des GGML-Formats.&lt;/p>
&lt;p>Bei der Quantisierung wird die Genauigkeit der Gewichte bewusst verringert.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>FP16 (16-bit)&lt;/strong>: Größe halbiert. Nahezu kein Genauigkeitsverlust.&lt;/li>
&lt;li>&lt;strong>INT8 (8-bit)&lt;/strong>: Ein Viertel der Größe. Leichte Verschlechterung.&lt;/li>
&lt;li>&lt;strong>INT4 (4-bit)&lt;/strong>: Ein Achtel der Größe. Bei Verwendung von eigenem Blocking und Skalierungsfaktoren ist eine praktische Inferenz möglich.&lt;/li>
&lt;/ul>
&lt;p>Auf der Seite der Inferenz-Engine werden die als INT4 (oder INT8) komprimierten Gewichte aus dem Speicher gelesen und &lt;strong>unmittelbar nach dem Laden in die CPU- oder GPU-Register auf FP16 oder FP32 entpackt (dequantisiert)&lt;/strong>, bevor die Berechnung erfolgt.&lt;/p>
&lt;p>Erstaunlicherweise ist es schneller, das aus dem Speicher gelesene Datenvolumen zu reduzieren, selbst wenn dies die Berechnungsmenge erhöht. Dies liegt daran, dass bei moderner Hardware der Engpass bei Inferenzaufgaben nicht in der &amp;ldquo;Rechenleistung (Compute Bound)&amp;rdquo;, sondern in der &amp;ldquo;&lt;strong>Speicherbandbreite (Memory Bandwidth Bound)&lt;/strong>&amp;rdquo; liegt. Mit einer in C++ implementierten Engine, die INT4-Quantisierung nutzt, ist es möglich, lokale LLMs selbst auf einem MacBook Air mit 8 GB VRAM flüssig auszuführen.&lt;/p>
&lt;hr>
&lt;h2 id="10-performance-tuning-numa-architektur-und-thread-pools">10. Performance-Tuning: NUMA-Architektur und Thread-Pools
&lt;/h2>&lt;p>Bei der Inferenz auf einer CPU ist Multithreading unerlässlich. Es ist jedoch nicht optimal, einfach viele &lt;code>std::thread&lt;/code>s zu starten.&lt;/p>
&lt;p>In modernen Multi-Socket-Servern oder High-End-CPUs wie dem Ryzen Threadripper wird eine &lt;strong>NUMA (Non-Uniform Memory Access)&lt;/strong>-Architektur verwendet. Der Zugriff auf physisch nahegelegenen Speicher (lokalen Speicher) von einem bestimmten CPU-Kern aus ist schnell, während der Zugriff auf Speicher, der mit einem anderen Prozessor verbunden ist, extrem langsam ist.&lt;/p>
&lt;p>Fortgeschrittene C++-Inferenz-Engines nutzen die folgenden Techniken:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Thread-Pinning&lt;/strong>: Jeder Thread wird an einen bestimmten CPU-Kern gebunden (Festlegen der Affinity), um zu verhindern, dass Caches durch Kontextwechsel verworfen werden.&lt;/li>
&lt;li>&lt;strong>NUMA-Aware Allocation&lt;/strong>: Der Speicher wird auf demselben NUMA-Knoten zugewiesen wie der Thread, der die Daten verarbeitet.&lt;/li>
&lt;li>&lt;strong>Work-Stealing Thread-Pool&lt;/strong>: Implementierung eines effizienten Schedulers, der jeden Knoten des Berechnungsgraphen in kleinere Aufgaben unterteilt. Freie Threads &amp;ldquo;stehlen&amp;rdquo; sich dann automatisch Aufgaben und führen diese aus.&lt;/li>
&lt;/ol>
&lt;p>Indem man all dies einsetzt, kann die CPU-Auslastung konstant nahe an 100 % gehalten und ein Durchsatz erreicht werden, der nah am theoretischen Maximum liegt.&lt;/p>
&lt;hr>
&lt;h2 id="11-fazit-der-spaß-daran-ki-mit-c-muskeln-anzutreiben">11. Fazit: Der Spaß daran, KI mit C++-&amp;ldquo;Muskeln&amp;rdquo; anzutreiben
&lt;/h2>&lt;p>Python ist zweifellos praktisch. In der Forschung, Entwicklung und beim Prototyping gibt es keine Sprache, die an seine Produktivität heranreicht. Wenn man jedoch in die Phase übergeht, in der man ein fertiges Modell &amp;ldquo;in der realen Welt, effizient und auf jedem Gerät ausführen&amp;rdquo; möchte, schlägt die Stunde von C++.&lt;/p>
&lt;p>Das Erfolgserlebnis, das man verspürt, wenn die eigens entwickelte Inferenz-Engine – erschaffen durch das direkte Manipulieren von Speicher-Bytefolgen, das Ausreizen von Registern durch SIMD-Befehle und den Kampf mit der VRAM-Bandbreite der GPU – nacheinander natürliche japanische (oder deutsche) Text-Tokens in der Konsole generiert, bietet eine &amp;ldquo;reine Ingenieursfreude&amp;rdquo;, die man beim Aufrufen von &lt;code>model.generate()&lt;/code> in einem Python-Framework niemals erleben wird.&lt;/p>
&lt;p>KI-Technologie neigt dazu, eine &amp;ldquo;Black Box&amp;rdquo; zu sein. Doch indem man von Tensor-Operationen bis hin zur Speicherverwaltung alles selbst in C++ schreibt, kann man ein tiefes Verständnis für die wahren Mechanismen erlangen und begreifen, wie ein LLM &amp;ldquo;denkt&amp;rdquo;.&lt;/p>
&lt;p>Wenn Sie über Grundkenntnisse in C++ verfügen und ein starkes Interesse an der aktuellen KI-Technologie haben, sollten Sie unbedingt versuchen, eine eigene Inferenz-Engine zu entwickeln. Die Quellcodes von GGML und llama.cpp werden Ihnen dabei als die besten &amp;ldquo;lebenden Lehrbücher&amp;rdquo; dienen.&lt;/p>
&lt;p>&lt;strong>Also, lassen Sie die schwere Python-Laufzeitumgebung hinter sich und treiben Sie modernste KI mit den Muskeln von C++ an!&lt;/strong>&lt;/p></description></item><item><title>Wie man TinyLLaMA in einer On-Premises-Umgebung am schnellsten feinabstimmt</title><link>http://kenji.blog/de/p/tinyllama-on-premises-fast-tuning-guide/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/tinyllama-on-premises-fast-tuning-guide/</guid><description>&lt;img src="http://kenji.blog/p/tinyllama-on-premises-fast-tuning-guide/img/eyecatch.jpg" alt="Featured image of post Wie man TinyLLaMA in einer On-Premises-Umgebung am schnellsten feinabstimmt" />&lt;h2 id="1-einführung-warum-gerade-jetzt-tinyllama-und-on-premises">1. Einführung: Warum gerade jetzt TinyLLaMA und On-Premises?
&lt;/h2>&lt;p>Die Entwicklung von Large Language Models (LLM) schreitet mit enormer Geschwindigkeit voran, und dementsprechend wächst auch die Anzahl der Modellparameter stetig in die Hunderte von Milliarden. Während gigantische Modelle wie GPT-4 und Claude 3 eine beispiellose Leistung aufweisen, stellen die Rechenkosten für Inferenz und Training sowie Sicherheits- und Datenschutzbedenken bei der Nutzung externer APIs große Hürden für Unternehmen dar. Insbesondere in Geschäftsbereichen, die mit hochsensiblen internen Daten oder persönlichen Informationen umgehen, ist das Senden von Daten an öffentliche LLM-APIs in der Cloud aus Compliance-Gründen (wie DSGVO oder APPI) oft nicht zulässig.&lt;/p>
&lt;p>Daher rücken &lt;strong>Small Language Models (SLM)&lt;/strong> und der &lt;strong>lokale Betrieb in On-Premises-Umgebungen&lt;/strong> ins Rampenlicht. Unter diesen zeichnet sich &amp;ldquo;&lt;strong>TinyLLaMA&lt;/strong>&amp;rdquo; durch seine kompakte Größe von nur 1,1B (1,1 Milliarden) Parametern aus, während es mit einem riesigen Datensatz von etwa 3 Billionen Token vortrainiert wurde. Es zeigt im Vergleich zu Modellen derselben Klasse eine erstaunliche Leistung.&lt;/p>
&lt;p>Dieser Artikel bietet einen vollständigen Leitfaden, wie Sie TinyLLaMA in einer On-Premises-Umgebung (lokaler Server oder Workstation) &amp;ldquo;am schnellsten und effizientesten&amp;rdquo; für Ihre eigenen spezifischen Aufgaben feinabstimmen (Fine-Tuning) können. Wir werden alles umfassend abdecken, von den mathematischen Grundlagen über die neuesten Optimierungstechnologien bis hin zum konkreten PyTorch-Implementierungscode.&lt;/p>
&lt;hr>
&lt;h2 id="2-architektur-und-eigenschaften-von-tinyllama">2. Architektur und Eigenschaften von TinyLLaMA
&lt;/h2>&lt;p>TinyLLaMA folgt der von Meta entwickelten LLaMA (Large Language Model Meta AI)-Architektur. Obwohl die Anzahl der Parameter auf 1,1B begrenzt ist, verwendet es denselben Technologie-Stack wie LLaMA 2, was zu einer extrem hohen Ökosystem-Kompatibilität führt.&lt;/p>
&lt;h3 id="hauptkomponenten-der-architektur">Hauptkomponenten der Architektur
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>RMSNorm (Root Mean Square Normalization):&lt;/strong>
Eine Normalisierungsmethode, die die Subtraktion des Mittelwerts aus der herkömmlichen LayerNorm-Berechnung weglässt und so die Recheneffizienz verbessert. Sie erhöht den Durchsatz, während die Stabilität des Trainings erhalten bleibt.&lt;/li>
&lt;li>&lt;strong>SwiGLU-Aktivierungsfunktion:&lt;/strong>
Im Feed Forward Network (FFN) wird SwiGLU anstelle von herkömmlichem ReLU oder GELU verwendet. Dies wird mathematisch wie folgt ausgedrückt:
$$ \text{SwiGLU}(x, W, V) = \text{Swish}(xW) \otimes (xV) $$
Hierbei steht $\otimes$ für das elementweise Produkt (Hadamard-Produkt) und die Swish-Funktion ist $\text{Swish}(z) = z \cdot \sigma(\beta z)$. Dadurch wird die Ausdruckskraft deutlich erhöht.&lt;/li>
&lt;li>&lt;strong>RoPE (Rotary Position Embedding):&lt;/strong>
Eine Methode, die die Vorteile von absoluter und relativer Positionskodierung kombiniert. Sie bietet eine hohe Generalisierungsleistung, auch wenn die Sequenzlänge erweitert wird.&lt;/li>
&lt;li>&lt;strong>Grouped Query Attention (GQA):&lt;/strong>
Ein Ansatz, der zwischen Multi-Head Attention (MHA) und Multi-Query Attention (MQA) liegt. Durch die Gruppierung von Key- und Value-Heads wird Speicherbandbreite gespart und die Inferenzgeschwindigkeit drastisch verbessert.&lt;/li>
&lt;/ol>
&lt;p>Das folgende Mermaid-Diagramm zeigt den allgemeinen Datenfluss und die Struktur der Transformer-Blöcke von TinyLLaMA.&lt;/p>
&lt;div class="mermaid">graph TD
A["Eingabetext"] --> B["Tokenizer (BPE)"]
B --> C["Embedding-Schicht"]
C --> D["Transformer-Blöcke (x22 Schichten für TinyLLaMA)"]
D --> E["RMSNorm (Final)"]
E --> F["Lineare Projektion (Vokabulargröße)"]
F --> G["Ausgabewahrscheinlichkeiten (Softmax)"]
subgraph "Aufbau des Transformer-Blocks"
D1["Eingabe Hidden State"] --> D2["RMSNorm"]
D2 --> D3["Grouped Query Attention (GQA)"]
D3 --> D4["Residuales Hinzufügen"]
D4 --> D5["RMSNorm"]
D5 --> D6["SwiGLU FFN"]
D6 --> D7["Residuales Hinzufügen"]
D7 --> D8["Ausgabe zur nächsten Schicht"]
D1 -.-> D4
D4 -.-> D7
end&lt;/div>
&lt;hr>
&lt;h2 id="3-durchbruch-beim-fine-tuning-lora-und-qlora">3. Durchbruch beim Fine-Tuning: LoRA und QLoRA
&lt;/h2>&lt;p>Die Feinabstimmung aller Parameter in einer On-Premises-Umgebung würde selbst für ein 1,1B-Modell Dutzende Gigabyte an VRAM (Videospeicher) verbrauchen, um die Optimizer-Zustände und Gradienten zu speichern. Um mit begrenzten Ressourcen effizient trainieren zu können, ist der Einsatz von &lt;strong>PEFT (Parameter-Efficient Fine-Tuning)&lt;/strong>-Methoden wie &amp;ldquo;&lt;strong>LoRA&lt;/strong>&amp;rdquo; und dessen quantisierter Erweiterung &amp;ldquo;&lt;strong>QLoRA&lt;/strong>&amp;rdquo; unerlässlich.&lt;/p>
&lt;h3 id="31-mathematischer-hintergrund-von-lora-low-rank-adaptation">3.1 Mathematischer Hintergrund von LoRA (Low-Rank Adaptation)
&lt;/h3>&lt;p>LoRA ist eine Methode, bei der die vortrainierte Gewichtsmatrix fixiert (eingefroren) wird und der Aktualisierungsbetrag dieser Gewichte ($\Delta W$) durch das Produkt von zwei kleinen Matrizen mit niedrigem Rang (Low-Rank) angenähert wird.&lt;/p>
&lt;p>Sei das vortrainierte Gewicht $W_0 \in \mathbb{R}^{d \times k}$. Beim vollständigen Fine-Tuning wird $W_0$ selbst aktualisiert zu $W_0 + \Delta W$, aber bei LoRA wird die Aktualisierungsmatrix $\Delta W$ wie folgt zerlegt:&lt;/p>
$$ \Delta W = B \times A $$
&lt;p>Hierbei sind $B \in \mathbb{R}^{d \times r}$ und $A \in \mathbb{R}^{r \times k}$, und $r$ ist ein Hyperparameter namens Rang (Rank), der ein sehr kleiner Wert ist (typischerweise 8, 16, 32 usw.), der $r \ll \min(d, k)$ erfüllt.&lt;/p>
&lt;p>Die Berechnung des Vorwärtsdurchlaufs (Forward Pass) sieht wie folgt aus:&lt;/p>
$$ h = W_0 x + \Delta W x = W_0 x + B A x $$
&lt;p>Im Initialzustand wird die Matrix $A$ zufällig mit einer Normalverteilung (Gauß-Verteilung) initialisiert, und die Matrix $B$ wird als Nullmatrix initialisiert. Dadurch ist $\Delta W$ zu Beginn des Trainings null, sodass das Training in einem Zustand gestartet werden kann, in dem die Ausgabe des Basismodells vollständig erhalten bleibt.&lt;/p>
&lt;div class="mermaid">graph LR
X["Eingabevektor x"] --> W0["Eingefrorenes vortrainiertes Gewicht (W_0)"]
X --> A["Trainierbare LoRA-Matrix A (r x k)"]
A --> B["Trainierbare LoRA-Matrix B (d x r)"]
W0 --> Add["Vektoraddition"]
B --> Add
Add --> Y["Ausgabevektor h"]&lt;/div>
&lt;h3 id="32-die-innovation-von-qlora-quantized-lora">3.2 Die Innovation von QLoRA (Quantized LoRA)
&lt;/h3>&lt;p>QLoRA treibt den Ansatz von LoRA weiter voran, indem das Basismodell $W_0$ in 4-Bit-Präzision (NormalFloat 4, NF4) quantisiert und in den Speicher geladen wird. Dies reduziert den VRAM-Verbrauch drastisch.&lt;/p>
&lt;p>In QLoRA sind drei wichtige Technologien integriert:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>4-bit NormalFloat (NF4) Quantisierung:&lt;/strong> Ein theoretisch optimaler Datentyp, der für normalverteilte Gewichte optimiert ist.&lt;/li>
&lt;li>&lt;strong>Double Quantization (Doppelte Quantisierung):&lt;/strong> Spart noch mehr Speicherplatz, indem die Quantisierungskonstante (Skalierungsfaktor) selbst quantisiert wird.&lt;/li>
&lt;li>&lt;strong>Paged Optimizers:&lt;/strong> Ein Mechanismus, der die Unified-Memory-Funktion von NVIDIA nutzt, um Optimizer-Statusse bei VRAM-Mangel vorübergehend in den RAM der CPU auszulagern.&lt;/li>
&lt;/ol>
&lt;p>Dadurch kann ein Tuning, das normalerweise 16 GB bis 24 GB VRAM benötigt, selbst auf Consumer-GPUs (wie RTX 3060 12 GB oder RTX 4070) mühelos durchgeführt werden.&lt;/p>
&lt;hr>
&lt;h2 id="4-hardwareanforderungen-und-einrichtung-in-der-on-premises-umgebung">4. Hardwareanforderungen und Einrichtung in der On-Premises-Umgebung
&lt;/h2>&lt;p>Die Hardwareanforderungen für die Feinabstimmung von TinyLLaMA (1,1B) mit QLoRA können sehr niedrig gehalten werden.&lt;/p>
&lt;h3 id="empfohlene-hardwarespezifikationen">Empfohlene Hardwarespezifikationen
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>GPU:&lt;/strong> NVIDIA RTX 3060 (12GB), RTX 3090/4090 (24GB) oder NVIDIA A10G/A100 usw. Ein Minimum von 8 GB VRAM ist für den Betrieb ausreichend, aber 12 GB oder mehr werden empfohlen, um größere Batch-Größen zu ermöglichen.&lt;/li>
&lt;li>&lt;strong>CPU:&lt;/strong> Moderne CPU mit 8 oder mehr Kernen (Intel Core i7/i9, AMD Ryzen 7/9)&lt;/li>
&lt;li>&lt;strong>RAM:&lt;/strong> 32 GB oder mehr (Wichtig als Auslagerungsziel für den VRAM bei Verwendung von Paged Optimizers)&lt;/li>
&lt;li>&lt;strong>Speicher:&lt;/strong> NVMe SSD (Zur Beschleunigung des Ladens von Datensätzen und des Speicherns von Modellen)&lt;/li>
&lt;/ul>
&lt;h3 id="einrichtung-der-softwareumgebung">Einrichtung der Softwareumgebung
&lt;/h3>&lt;p>Dies ist ein Einrichtungsprozess, der für eine Ubuntu 22.04 LTS-Umgebung vorgesehen ist. Python 3.10 oder höher wird verwendet.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Virtuelle Umgebung erstellen und aktivieren&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">python3 -m venv tinyllama_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">source&lt;/span> tinyllama_env/bin/activate
&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"># PyTorch installieren (für CUDA 12.1)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
&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"># Transformer-bezogene Bibliotheken installieren&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install transformers datasets peft trl accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="5-optimierungstechnologien-für-schnellstes-tuning">5. Optimierungstechnologien für schnellstes Tuning
&lt;/h2>&lt;p>Um das Tuning nicht nur einfach durchzuführen, sondern &amp;ldquo;am schnellsten&amp;rdquo; abzuschließen, müssen die folgenden Optimierungsmethoden kombiniert werden.&lt;/p>
&lt;h3 id="51-flash-attention-2">5.1 Flash Attention 2
&lt;/h3>&lt;p>Der Standard-Attention-Mechanismus hat eine Zeit- und Raumkomplexität von $O(N^2)$ für die Sequenzlänge $N$. Flash Attention 2 optimiert die Speicherzugriffe zwischen dem SRAM der GPU und dem HBM (High Bandwidth Memory), wodurch E/A-Engpässe ohne Reduzierung der Berechnungskomplexität beseitigt werden. Dies beschleunigt das Training um ein Vielfaches und reduziert den Speicherverbrauch drastisch.&lt;/p>
&lt;h3 id="52-gradient-checkpointing-gradienten-checkpointing">5.2 Gradient Checkpointing (Gradienten-Checkpointing)
&lt;/h3>&lt;p>Hierbei werden nicht alle im Vorwärtsdurchlauf (Forward Pass) berechneten Zwischenaktivierungen im VRAM gespeichert, sondern nur ein Teil davon. Diese werden dann bei Bedarf im Rückwärtsdurchlauf (Backward Pass) neu berechnet. Die Berechnungszeit erhöht sich zwar um etwa 20 %, aber der Speicherverbrauch kann drastisch gesenkt werden, was letztendlich die Einstellung größerer Batch-Größen und eine Erhöhung des Gesamtdurchsatzes ermöglicht.&lt;/p>
&lt;h3 id="53-mixed-precision-training-gemischte-genauigkeit-und-bfloat16">5.3 Mixed Precision Training (Gemischte Genauigkeit) und Bfloat16
&lt;/h3>&lt;p>Um die Tensor Cores der GPU optimal zu nutzen, werden die Trainingsberechnungen in &lt;code>bfloat16&lt;/code> (Brain Floating Point) durchgeführt. Im Vergleich zu &lt;code>float16&lt;/code> ist die Bitlänge des Exponenten dieselbe wie bei &lt;code>float32&lt;/code>, sodass das Risiko von Overflows und Underflows extrem gering ist, was zu einem stabileren Training führt.&lt;/p>
&lt;hr>
&lt;h2 id="6-praxis-qlora-fine-tuning-code-für-tinyllama">6. Praxis: QLoRA Fine-Tuning Code für TinyLLaMA
&lt;/h2>&lt;p>Lassen Sie uns nun das PyTorch-Skript für das schnellste Tuning erläutern, das alle oben genannten Optimierungen enthält. Hier verwenden wir den &lt;code>SFTTrainer&lt;/code> aus der Bibliothek &lt;code>trl&lt;/code> (Transformer Reinforcement Learning) von Hugging Face.&lt;/p>
&lt;h3 id="61-vorbereiten-des-datensatzes-und-laden-des-modells">6.1 Vorbereiten des Datensatzes und Laden des Modells
&lt;/h3>&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&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">from&lt;/span> &lt;span class="nn">datasets&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">load_dataset&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TrainingArguments&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">trl&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">SFTTrainer&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. Spezifikation von Modell und Tokenizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;TinyLlama/TinyLlama-1.1B-Chat-v1.0&amp;#34;&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. 4-Bit-Quantisierungseinstellungen für QLoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bnb_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">load_in_4bit&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_use_double_quant&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_quant_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;nf4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_compute_dtype&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">bfloat16&lt;/span> &lt;span class="c1"># Berechnungen in bfloat16 durchführen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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. Laden des Modells (Flash Attention 2 aktivieren)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Loading model...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantization_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">bnb_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">use_flash_attention_2&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span> &lt;span class="c1"># Schlüssel zur maximalen Geschwindigkeit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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. Laden des Tokenizers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">trust_remote_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pad_token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">eos_token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">padding_side&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;right&amp;#34;&lt;/span> &lt;span class="c1"># Auf right setzen, um Bugs während fp16/bf16-Trainings zu vermeiden&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-anwendung-des-lora-adapters-und-formatierung-des-datensatzes">6.2 Anwendung des LoRA-Adapters und Formatierung des Datensatzes
&lt;/h3>&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&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="c1"># 5. Vorbereitung auf k-Bit-Training und Aktivierung des Gradient Checkpointings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gradient_checkpointing_enable&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&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"># 6. LoRA-Konfiguration&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">peft_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Rang&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_alpha&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Skalierungsfaktor&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_dropout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.05&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bias&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;none&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;CAUSAL_LM&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_modules&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;q_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;k_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;v_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;o_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;gate_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;up_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;down_proj&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># Die Einbeziehung aller linearen Schichten verbessert die Leistung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">peft_config&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">print_trainable_parameters&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ausgabebeispiel: trainable params: 14,286,848 || all params: 1,114,335,232 || trainable%: 1.282%&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"># 7. Laden des Datensatzes (Hier verwenden wir als Beispiel einen japanischen Instruction-Datensatz)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># In der Praxis laden Sie z.B. private JSONL-Dateien aus der On-Premises-Umgebung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">load_dataset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kunishou/databricks-dolly-15k-ja&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">split&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;train&amp;#34;&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">def&lt;/span> &lt;span class="nf">format_instruction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Formatiert den String so, dass er zum ChatML-Format oder Prompt-Template passt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_start|&amp;gt;user&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;instruction&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&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">sample&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;input&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;input&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_end|&amp;gt;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;lt;|im_start|&amp;gt;assistant&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;output&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;lt;|im_end|&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&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="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dataset&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">format_instruction&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;h3 id="63-ausführung-des-trainings">6.3 Ausführung des Trainings
&lt;/h3>&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&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="c1"># 8. Einstellen der Trainingsargumente&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">training_args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TrainingArguments&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-output&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">per_device_train_batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Erhöhen, falls noch VRAM verfügbar ist&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">gradient_accumulation_steps&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"># Effektive Batch-Größe = 8 * 2 = 16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">optim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;paged_adamw_32bit&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># VRAM-Einsparung durch Paged Optimizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">save_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logging_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">learning_rate&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">2e-4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fp16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bf16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Gemischte Genauigkeit (bfloat16)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_grad_norm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 500 Schritte zu Testzwecken. In der Produktion durch Epochenanzahl angeben&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">warmup_ratio&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.03&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">group_by_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lr_scheduler_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;cosine&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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"># 9. Starten des Trainings mit SFTTrainer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SFTTrainer&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">train_dataset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">peft_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">peft_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dataset_text_field&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_seq_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Anpassen an die erwartete Eingabelänge&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">tokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">training_args&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Starting training...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">train&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"># 10. Speichern des LoRA-Adapters&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Training complete and model saved.&amp;#34;&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;hr>
&lt;h2 id="7-leistungsbewertung-und-fehlerbehebung">7. Leistungsbewertung und Fehlerbehebung
&lt;/h2>&lt;p>Dies sind häufig auftretende Probleme und deren Lösungen beim Training in On-Premises-Umgebungen.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>OOM (Out Of Memory) tritt auf:&lt;/strong>
&lt;ul>
&lt;li>Senken Sie &lt;code>per_device_train_batch_size&lt;/code> auf &lt;code>1&lt;/code>.&lt;/li>
&lt;li>Erhöhen Sie &lt;code>gradient_accumulation_steps&lt;/code>, um die effektive Batch-Größe beizubehalten.&lt;/li>
&lt;li>Verkürzen Sie &lt;code>max_seq_length&lt;/code> von &lt;code>2048&lt;/code> auf &lt;code>1024&lt;/code> oder &lt;code>512&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Loss sinkt nicht oder divergiert:&lt;/strong>
&lt;ul>
&lt;li>Möglicherweise ist die Lernrate (&lt;code>learning_rate&lt;/code>) zu hoch. Versuchen Sie, sie von &lt;code>2e-4&lt;/code> auf etwa &lt;code>5e-5&lt;/code> zu senken.&lt;/li>
&lt;li>Wenn Float16 anstelle von Bfloat16 verwendet wird, könnte ein Gradienten-Underflow auftreten. Stellen Sie sicher, dass &lt;code>bf16=True&lt;/code> gesetzt ist.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Bei der Inferenz werden mysteriöse Zeichenketten generiert:&lt;/strong>
&lt;ul>
&lt;li>Stellen Sie sicher, dass &lt;code>padding_side=&amp;quot;right&amp;quot;&lt;/code> korrekt eingestellt ist. Darüber hinaus muss überprüft werden, ob das Datensatzformat (Spezial-Token wie &lt;code>&amp;lt;|im_start|&amp;gt;&lt;/code>) mit dem des Basismodells beim Vortraining übereinstimmt.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-modellbereitstellung-deployment-nach-dem-tuning">8. Modellbereitstellung (Deployment) nach dem Tuning
&lt;/h2>&lt;p>Wenn das Tuning abgeschlossen ist, wird nicht das &amp;ldquo;gesamte Basismodell&amp;rdquo; gespeichert, sondern nur der wenige MB bis Dutzende MB große &amp;ldquo;&lt;strong>LoRA-Adapter (Differenzgewichte)&lt;/strong>&amp;rdquo;. Um eine schnelle Inferenz durchzuführen, müssen diese LoRA-Gewichte mit dem ursprünglichen Basismodell zusammengeführt (gemergt) und als einzelnes Modell exportiert werden.&lt;/p>
&lt;h3 id="skript-zum-mergen-des-modells">Skript zum Mergen des Modells
&lt;/h3>&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;/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">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoTokenizer&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="n">output_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&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"># Laden von Modell und Adapter in FP16/BF16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">torch_dtype&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">bfloat16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output_dir&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"># Gewichte zusammenführen und speichern&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">merge_and_unload&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">safe_serialization&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Model merged and saved successfully!&amp;#34;&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;h3 id="aufbau-eines-extrem-schnellen-inferenzservers-mit-vllm">Aufbau eines extrem schnellen Inferenzservers mit vLLM
&lt;/h3>&lt;p>Um den Inferenzdurchsatz (Tokens per second) in On-Premises-Umgebungen zu maximieren, wird dringend empfohlen, &lt;strong>vLLM&lt;/strong> oder &lt;strong>TGI (Text Generation Inference)&lt;/strong> anstelle der Standard-&lt;code>pipeline&lt;/code> von Hugging Face zu verwenden. vLLM verwendet die PagedAttention-Technologie, um Speicherfragmentierung der GPU zu verhindern und die Verarbeitungskapazität für gleichzeitige Anfragen drastisch zu verbessern.&lt;/p>
&lt;p>Das folgende Mermaid-Diagramm zeigt die Pipeline vom Training bis zur Bereitstellung auf dem Inferenzserver.&lt;/p>
&lt;div class="mermaid">graph TD
A["Rohe private Daten"] --> B["Vorverarbeitung &amp; Formatierung (JSONL)"]
B --> C["QLoRA Fine-Tuning (SFTTrainer)"]
C --> D["LoRA-Adaptergewichte (.safetensors)"]
D --> E["Zusammenführung mit Basis-TinyLLaMA 1,1B"]
E --> F["Zusammengeführtes Modell"]
F --> G["Bereitstellung über vLLM-Server"]
G --> H["API-Endpunkt / UI (z. B. Chatbot)"]&lt;/div>
&lt;p>Das Starten des API-Servers mit vLLM ist mit folgendem Einzelbefehl erledigt:&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">python -m vllm.entrypoints.openai.api_server &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --model ./tinyllama-merged &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --host 0.0.0.0 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --port &lt;span class="m">8000&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --max-model-len &lt;span class="m">2048&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --dtype bfloat16
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Damit ist ein mit der OpenAI-API kompatibler Endpunkt in der On-Premises-Umgebung eingerichtet, wodurch die lokale KI sicher und mit hoher Geschwindigkeit genutzt werden kann.&lt;/p>
&lt;hr>
&lt;h2 id="9-fazit">9. Fazit
&lt;/h2>&lt;p>Dieser Artikel erläuterte Methoden zur schnellsten und speichereffizientesten Feinabstimmung von &amp;ldquo;TinyLLaMA&amp;rdquo;, einem Modell, das trotz seiner kompakten Größe von 1,1B Parametern eine hohe Leistung bietet, in einer On-Premises-Umgebung.&lt;/p>
&lt;ul>
&lt;li>Durch &lt;strong>LoRA / QLoRA&lt;/strong> ist ein vollwertiges LLM-Tuning auch auf Consumer-GPUs möglich.&lt;/li>
&lt;li>Die Nutzung von &lt;strong>Flash Attention 2&lt;/strong> und &lt;strong>Gradient Checkpointing&lt;/strong> optimiert die Trainingszeit und den VRAM-Verbrauch auf das Äußerste.&lt;/li>
&lt;li>Durch die Bereitstellung mit &lt;strong>vLLM&lt;/strong> wird auch in Produktionsumgebungen ein hoher Durchsatz erzielt.&lt;/li>
&lt;/ul>
&lt;p>Der lokale Betrieb von LLMs vor Ort schützt nicht nur die Datenvertraulichkeit, sondern ist auch die stärkste Waffe zum Aufbau spezialisierter KI für bestimmte Domänen (wie Recht, Medizin, interne Vorschriften usw.) zu geringen Kosten. Nutzen Sie diesen Leitfaden gerne als Referenz, um Ihr eigenes unternehmensspezifisches TinyLLaMA zu entwickeln.&lt;/p></description></item><item><title>Wie sollten Programmierer im KI-Zeitalter überleben?</title><link>http://kenji.blog/de/p/how-programmers-survive-in-ai-era/</link><pubDate>Fri, 11 Sep 2026 15:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/how-programmers-survive-in-ai-era/</guid><description>&lt;img src="http://kenji.blog/p/how-programmers-survive-in-ai-era/img/eyecatch.jpg" alt="Featured image of post Wie sollten Programmierer im KI-Zeitalter überleben?" />&lt;h1 id="wie-sollten-programmierer-im-ki-zeitalter-überleben-das-ende-des-codings-und-der-beginn-eines-neuen-engineerings">Wie sollten Programmierer im KI-Zeitalter überleben? Das Ende des Codings und der Beginn eines neuen Engineerings
&lt;/h1>&lt;p>Im Jahr 2026 befindet sich die Softwareentwicklung in einer beispiellosen Phase des Umbruchs. Bis vor wenigen Jahren beschränkte sich das Konzept &amp;ldquo;KI schreibt Code&amp;rdquo; bestenfalls auf die Generierung von Boilerplate-Code (Standardcode) und die automatische Vervollständigung von Funktionen – als &amp;ldquo;Hilfswerkzeug&amp;rdquo; für Programmierer. Doch durch die erstaunliche Entwicklung von Large Language Models (LLMs) hat sich die Situation grundlegend geändert. Die moderne KI ist nicht mehr nur eine &amp;ldquo;schlaue Schreibmaschine&amp;rdquo;, sondern hat sich zu einem &amp;ldquo;autonomen Junior-Engineer&amp;rdquo; entwickelt: Wenn man ihr ein Anforderungsdokument gibt, ist sie in der Lage, autonom und in Sekundenschnelle ein komplettes System aufzubauen – von der Frontend- und Backend-Logik über das Datenbankschema-Design bis hin zur Einrichtung von CI/CD-Pipelines.&lt;/p>
&lt;p>Wie sollten wir &amp;ldquo;Programmierer&amp;rdquo; und &amp;ldquo;Software-Ingenieure&amp;rdquo; in einem solchen Zeitalter überleben? Während der wirtschaftliche Wert des bloßen &amp;ldquo;Code-Schreibens&amp;rdquo; rapide abnimmt, werden &amp;ldquo;Coder&amp;rdquo;, die lediglich die Syntax einer bestimmten Programmiersprache kennen und mit der API eines bestimmten Frameworks vertraut sind, schnell vom Markt verdrängt.&lt;/p>
&lt;p>In diesem Artikel werden wir die Überlebensstrategien für Programmierer im KI-Zeitalter aus technischen, mathematischen und philosophischen Perspektiven sehr detailliert untersuchen. Dies ist nicht nur eine Karrieredebatte, sondern eine Neudefinition der Disziplin des Software Engineerings selbst.&lt;/p>
&lt;hr>
&lt;h2 id="1-die-geschichte-der-abstraktion-und-die-neudefinition-des-programmierens">1. Die Geschichte der Abstraktion und die Neudefinition des &amp;ldquo;Programmierens&amp;rdquo;
&lt;/h2>&lt;p>Wenn wir auf die Geschichte des Software Engineerings zurückblicken, erkennen wir, dass es immer eine Geschichte der &amp;ldquo;Abstraktion&amp;rdquo; war. Wir haben stets Schichten (Layer) aufgebaut, um komplexere Systeme in einer menschenähnlicheren Sprache beschreiben zu können.&lt;/p>
&lt;p>Frühe Informatiker verwendeten Lochkarten, um physische Hardware-Schalter direkt zu bedienen, und gaben dem Computer Anweisungen in Maschinensprache (einer Reihe von 0en und 1en). Später erschien die Assemblersprache, die es ermöglichte, Hardware mit menschenlesbaren Mnemonics zu steuern. Im Laufe der Zeit kamen höhere Programmiersprachen wie C und Fortran auf, denen es gelang, komplexe Hardware-Details wie Speicherverwaltung und CPU-Register zu kapseln. Moderne Sprachen wie Java, Python, Ruby und TypeScript ermöglichten es Programmierern schließlich, sich mehr darauf zu konzentrieren, &amp;ldquo;was der Computer tun soll (What)&amp;rdquo;, anstatt &amp;ldquo;wie der Computer es tun soll (How)&amp;rdquo;.&lt;/p>
&lt;p>Das Aufkommen von KI (LLMs) ist der neueste und größte Paradigmenwechsel in dieser Geschichte der Abstraktion. Wenn die Evolution von Programmiersprachen das &amp;ldquo;Verbergen von Hardware&amp;rdquo; war, dann ist die Evolution von LLMs das &amp;ldquo;Verbergen von Syntax (Grammatik)&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">graph TD
A["Maschinencode / Lochkarten (1940er)"] --> B["Assemblersprache (1950er)"]
B --> C["Kompilierte Hochsprachen (1970er)"]
C --> D["Managed / Skriptsprachen (1990er)"]
D --> E["Natürliche Sprache via LLMs (2020er)"]
E --> F["Autonome KI-Agenten (2026-)"]
style E fill:#f9f,stroke:#333,stroke-width:2px
style F fill:#fbb,stroke:#333,stroke-width:2px&lt;/div>
&lt;p>Die Zeit, in der Entwickler sich um Speicherlecks sorgen, Zeiger manipulieren oder Hunderte von Zeilen Standardcode für das Parsen von JSON schreiben mussten, ist vorbei. Die Verwendung natürlicher Sprache (wie Deutsch oder Englisch) – der für die Menschheit am höchsten abstrahierten Sprache – zur Definition von Systemen ist zum Standard des &amp;ldquo;Programmierens&amp;rdquo; im Jahr 2026 geworden.&lt;/p>
&lt;hr>
&lt;h2 id="2-das-mathematische-modell-der-produktivität-auf-der-welle-des-exponentiellen-wachstums-reiten">2. Das mathematische Modell der Produktivität: Auf der Welle des exponentiellen Wachstums reiten
&lt;/h2>&lt;p>Lassen Sie uns die durch KI bedingte Produktivitätssteigerung quantitativ anhand eines mathematischen Modells bewerten.
Die individuelle Produktivität in der traditionellen Softwareentwicklung $P_{traditional}$ konnte als lineare Kombination aus individuellem Qualifikationsniveau $S$, Domänenerfahrung $E$ und Werkzeugeffizienz $T$ modelliert werden.&lt;/p>
$$ P_{traditional} = c_1 \cdot S + c_2 \cdot E + c_3 \cdot T $$
&lt;p>In der modernen, KI-gestützten Entwicklung wirkt die Fähigkeit der KI $A(t)$ jedoch als &amp;ldquo;starker Hebel (Multiplier)&amp;rdquo;, der die menschlichen Fähigkeiten verstärkt. Da die Fähigkeiten der KI im Laufe der Zeit $t$ exponentiell wachsen (eine KI-Version des mooreschen Gesetzes), kann die Produktivität im KI-Zeitalter $P_{AI}(t)$ durch die folgende Gleichung dargestellt werden:&lt;/p>
$$ P_{AI}(t) = \alpha \cdot S_{core} \cdot e^{\beta \cdot A(t)} $$
&lt;p>Hierbei haben die Variablen folgende Bedeutung:&lt;/p>
&lt;ul>
&lt;li>$\alpha$: Basiskoeffizient der menschlichen Produktivität&lt;/li>
&lt;li>$S_{core}$: &amp;ldquo;Menschliche Kernkompetenzen&amp;rdquo;, die nicht durch KI ersetzt werden können (z.B. Architekturdesign, Verständnis von Geschäftsanforderungen, ethisches Urteilsvermögen)&lt;/li>
&lt;li>$A(t)$: Absolute Leistungsfähigkeit des KI-Modells zum Zeitpunkt $t$ (Parameteranzahl, Kontextfenster, Schlussfolgerungsfähigkeit)&lt;/li>
&lt;li>$\beta$: Ein Koeffizient, der angibt, wie effektiv KI-Werkzeuge genutzt werden können (Qualität des Prompt-Engineerings, Raffinesse des kollaborativen Workflows mit der KI)&lt;/li>
&lt;/ul>
&lt;p>Eine wichtige Erkenntnis aus dieser Formel ist: &lt;strong>In einer Welt, in der $A(t)$ exponentiell zunimmt, haben traditionelle Fähigkeiten wie bloße Tippgeschwindigkeit oder das Auswendiglernen einer bestimmten Sprache nur noch einen sehr geringen Einfluss auf die Gesamtproduktivität.&lt;/strong> Stattdessen werden der Multiplikator $\beta$, um auf dem exponentiellen KI-Wachstum aufzubauen, und der von der KI nicht abdeckbare Bereich $S_{core}$ zu den dominierenden Faktoren, die den Marktwert eines Entwicklers bestimmen.&lt;/p>
&lt;hr>
&lt;h2 id="3-wahrscheinlichkeit-der-aufgabenautomatisierung-probability-of-automation">3. Wahrscheinlichkeit der Aufgabenautomatisierung (Probability of Automation)
&lt;/h2>&lt;p>Welche Aufgaben werden also automatisiert und welche bleiben in menschlicher Hand?
Die Wahrscheinlichkeit $P_{auto}(T)$, dass eine bestimmte Aufgabe $T$ vollständig von einer KI automatisiert wird, lässt sich wie folgt formulieren:&lt;/p>
$$ P_{auto}(T) = 1 - \exp\left(-\lambda \cdot \frac{\text{Predictability}(T)}{\text{Complexity}(T) \times \text{Context Dependency}(T)}\right) $$
&lt;ul>
&lt;li>$\text{Predictability}(T)$: Vorhersehbarkeit der Aufgabe (wie viele Muster in historischen Daten vorhanden sind)&lt;/li>
&lt;li>$\text{Complexity}(T)$: Komplexität der Aufgabe&lt;/li>
&lt;li>$\text{Context Dependency}(T)$: Stärke des &amp;ldquo;impliziten Kontexts&amp;rdquo; (domänenspezifisches Wissen oder menschliche Beziehungen), von dem die Aufgabe abhängt&lt;/li>
&lt;li>$\lambda$: Technologische Fortschrittsrate der KI&lt;/li>
&lt;/ul>
&lt;p>Aufgaben mit hoher Vorhersehbarkeit und geringer Kontextabhängigkeit, wie das Schreiben von API-Routings oder das Erstellen einfacher CRUD-Bildschirme, haben ein $P_{auto} \approx 1$ und werden fast vollständig automatisiert. Andererseits sind Aufgaben mit extrem hoher Kontextabhängigkeit schwer zu automatisieren, wie zum Beispiel &amp;ldquo;Wie integriert man ein bestehendes Legacy-System sicher mit neuen Microservices?&amp;rdquo; oder &amp;ldquo;Wie gestaltet man einen Authentifizierungsfluss, der die Anforderungen der Rechtsabteilung erfüllt, ohne die Benutzererfahrung zu beeinträchtigen?&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="4-rückkehr-von-der-syntax-grammatik-zur-architektur-struktur">4. Rückkehr von der Syntax (Grammatik) zur Architektur (Struktur)
&lt;/h2>&lt;p>Eine klare Trennung zwischen dem, worin die KI gut ist, und dem, worin der Mensch gut ist, ist eine absolute Überlebensbedingung.&lt;/p>
&lt;div class="mermaid">graph LR
Sub1["Exzellenzbereiche der KI"]
Sub2["Exzellenzbereiche des Menschen"]
A["Codegenerierung nach Spezifikation"] --> Sub1
B["Syntaxfehler &amp; Fehlerbehebung"] --> Sub1
C["Boilerplate / Testgenerierung"] --> Sub1
D["Log-Analyse &amp; Mustererkennung"] --> Sub1
E["Systemarchitektur-Design"] --> Sub2
F["Lösung mehrdeutiger Anforderungen"] --> Sub2
G["Teamübergreifende Verhandlung"] --> Sub2
H["Ethisches Urteil / Verantwortung"] --> Sub2&lt;/div>
&lt;p>Die KI übertrifft den Menschen bei der &amp;ldquo;lokalen Optimierung&amp;rdquo;. Wenn es um die Geschwindigkeit und Genauigkeit beim Schreiben einer einzigen Funktion, einer einzigen Klasse oder eines einzelnen Moduls geht, hat der Mensch keine Chance. Allerdings ist die KI sehr anfällig, wenn es um &amp;ldquo;globale Optimierung&amp;rdquo; oder &amp;ldquo;fehlenden Kontext (Missing Context)&amp;rdquo; geht.&lt;/p>
&lt;p>Programmierer der Zukunft müssen ihre Rolle von &amp;ldquo;Code schreibenden Arbeitern&amp;rdquo; zu &amp;ldquo;Architekten, die unzählige von der KI generierte Komponenten orchestrieren&amp;rdquo; wandeln. Das gesamte System überblicken, entscheiden, wo die Grenzen von Microservices gezogen werden, wie der Kompromiss zwischen Verfügbarkeit und Konsistenz im CAP-Theorem im geschäftlichen Kontext gelöst wird, oder wie man technische Schulden kontrolliert: Dies sind hochgradig intellektuelle Aufgaben, die nur von Menschen ausgeführt werden können, die das Gesamtbild und die Geschäftsziele verstehen.&lt;/p>
&lt;hr>
&lt;h2 id="5-anforderungsdefinition-ist-das-wahre-prompt-engineering">5. Anforderungsdefinition ist das &amp;ldquo;wahre Prompt-Engineering&amp;rdquo;
&lt;/h2>&lt;p>Der Begriff &amp;ldquo;Prompt-Engineering&amp;rdquo;, den man in letzter Zeit oft hört, wird häufig fälschlicherweise als &amp;ldquo;Hack, um die KI auszutricksen und die gewünschte Ausgabe zu erhalten&amp;rdquo; missverstanden. Das Wesen des Prompt-Engineerings in der Softwareentwicklung ist jedoch zweifellos &lt;strong>&amp;ldquo;fortgeschrittene Anforderungsdefinition (Requirements Engineering)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Um der KI Anweisungen in natürlicher Sprache zu geben und sie dazu zu bringen, genau die beabsichtigte Software auszugeben, müssen die folgenden Elemente strikt verbalisiert werden:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Zweck (Why)&lt;/strong>: Warum wird diese Funktion benötigt? Was ist der geschäftliche Wert?&lt;/li>
&lt;li>&lt;strong>Einschränkungen (Constraints)&lt;/strong>: Leistungsanforderungen (Latenz, Durchsatz), Sicherheitsanforderungen, Kostenbeschränkungen.&lt;/li>
&lt;li>&lt;strong>Sonderfälle (Edge Cases)&lt;/strong>: Fallback-Verarbeitung, wenn der Benutzer unerwartete Eingaben vornimmt.&lt;/li>
&lt;li>&lt;strong>Schnittstellen (Interfaces)&lt;/strong>: Spezifikationen für die Integration in bestehende Systeme.&lt;/li>
&lt;/ol>
&lt;p>Aus vagen Anweisungen (Prompts) entstehen nur vage und anfällige Systeme. Die Fähigkeit, &amp;ldquo;was der Kunde wirklich wollte&amp;rdquo; tiefgehend zu erfragen, widersprüchliche Anforderungen zu ordnen und eine logisch fehlerfreie Spezifikation (Prompt) zu erstellen – das ist die stärkste &amp;ldquo;Coding-Fähigkeit&amp;rdquo; im KI-Zeitalter. Programmierer werden mehr Zeit damit verbringen, vor Notion- oder Markdown-Dateien anstatt vor Code-Editoren zu sitzen, und in Textform präzise beschreiben, wie das System idealerweise sein sollte.&lt;/p>
&lt;hr>
&lt;h2 id="6-die-überwältigende-überlegenheit-von-domänenwissen-domain-knowledge">6. Die überwältigende Überlegenheit von Domänenwissen (Domain Knowledge)
&lt;/h2>&lt;p>Da die KI auf Open-Source-Code und öffentlichen Dokumenten aus der ganzen Welt trainiert wurde, ist sie mit allgemeinen Webtechnologien und Algorithmen bestens vertraut. Es gibt jedoch Daten, auf die die KI keinen Zugriff hat: &amp;ldquo;die spezifischen Geschäftsregeln Ihres Unternehmens&amp;rdquo; und &amp;ldquo;Domänenwissen, das tief in bestimmten Branchen (wie Medizin, Finanzen, Fertigung usw.) verwurzelt ist&amp;rdquo;.&lt;/p>
&lt;p>Angenommen, ein medizinisches Startup entwickelt ein System für elektronische Patientenakten. Die KI weiß &amp;ldquo;wie man mit React ein tabellarisches UI erstellt&amp;rdquo; oder &amp;ldquo;die allgemeine Datenstruktur von HL7 FHIR&amp;rdquo;. Sie hat jedoch nicht das implizite Wissen darüber gelernt, &amp;ldquo;in welcher Reihenfolge Ärzte in einer bestimmten Fachabteilung von Krankenhaus A die Patientendaten einsehen und wie eine Benutzeroberfläche gestaltet sein muss, um das Risiko von medizinischen Fehlern zu minimieren&amp;rdquo;.&lt;/p>
&lt;p>In einer Welt, in der Technologie selbst zur Commodity (Massenware) wird, entsteht der wahre Wert eines Ingenieurs an der Schnittstelle von &amp;ldquo;Technologie&amp;rdquo; und &amp;ldquo;Business-Domäne&amp;rdquo;. Nicht diejenigen, die nur mit technischem Können konkurrieren, werden den zukünftigen Markt anführen, sondern diejenigen, die über tiefes Fachwissen in einer bestimmten Domäne wie Medizin, Finanzen, Logistik oder Unterhaltung verfügen und deren Herausforderungen mit dem mächtigen Werkzeug der KI lösen können.&lt;/p>
&lt;hr>
&lt;h2 id="7-das-trolley-problem-der-softwareentwicklung-wer-übernimmt-die-verantwortung">7. Das &amp;ldquo;Trolley-Problem&amp;rdquo; der Softwareentwicklung: Wer übernimmt die Verantwortung?
&lt;/h2>&lt;p>Mit zunehmender Abhängigkeit von KI stehen wir vor schwerwiegenden philosophischen und ethischen Problemen. Es geht um die Frage der &amp;ldquo;Verantwortung&amp;rdquo; in der Softwareentwicklung.&lt;/p>
&lt;p>Wenn von einer KI autonom generierter Code in einer Produktionsumgebung einen schweren Bug verursacht und einem Unternehmen Verluste in Millionenhöhe beschert, oder wenn er in einem lebenswichtigen medizinischen System eine Fehlfunktion auslöst – wer übernimmt dann die Verantwortung? Das Unternehmen, das das KI-Modell entwickelt hat? Oder der Ingenieur, der den Prompt eingegeben hat? Man kann eine KI weder &amp;ldquo;entlassen&amp;rdquo; noch &amp;ldquo;verhaften&amp;rdquo;.&lt;/p>
&lt;p>Die Rolle des &amp;ldquo;Menschen&amp;rdquo; als Instanz, die die &amp;ldquo;rechtliche und ethische Verantwortung (Accountability)&amp;rdquo; für die Auswirkungen eines Systems auf die Gesellschaft übernimmt, wird niemals verschwinden, egal wie weit die Technologie fortschreitet. Im Gegenteil: Je mehr der Prozess der Codegenerierung zur Blackbox wird, desto größere Verantwortung trägt der Mensch als &amp;ldquo;letzter Genehmiger (Approver)&amp;rdquo; und &amp;ldquo;Überwacher (Supervisor)&amp;rdquo; für das System.&lt;/p>
&lt;p>Die Überprüfung, ob die von der KI vorgeschlagene Architektur und der Code die Sicherheitsstandards erfüllen, ethisch unbedenklich sind (keine Verzerrungen/Bias enthalten) und die Compliance-Richtlinien einhalten, um letztendlich grünes Licht zu geben – dieser Akt des &amp;ldquo;Verantwortung-Übernehmens&amp;rdquo; selbst wird zu einem wichtigen Teil der Arbeit eines Ingenieurs.&lt;/p>
&lt;hr>
&lt;h2 id="8-ki-pair-programming-und-das-management-der-kognitiven-belastung-cognitive-load">8. KI-Pair-Programming und das Management der kognitiven Belastung (Cognitive Load)
&lt;/h2>&lt;p>In der Zusammenarbeit mit der KI verändert sich auch die Natur der &amp;ldquo;kognitiven Belastung&amp;rdquo; (Cognitive Load) des Menschen. Die kognitive Belastung beim Schreiben von Code von Grund auf ist völlig anders als die kognitive Belastung beim &amp;ldquo;Lesen und Überprüfen&amp;rdquo; von Hunderten Zeilen unbekannten, von einer KI generierten Codes.&lt;/p>
&lt;p>Nach der Theorie der kognitiven Belastung aus der Psychologie erschöpft sich das Arbeitsgedächtnis des Menschen sehr schnell, wenn es komplexe Informationen verarbeiten muss, die nicht mit bestehenden Schemata (der Wissensstruktur im Kopf) übereinstimmen. Von KI generierter Code enthält manchmal hochgradige Optimierungen, auf die ein Mensch niemals kommen würde, kann aber gleichzeitig kontextignorierende &amp;ldquo;Halluzinationen&amp;rdquo; enthalten.&lt;/p>
&lt;p>Um dies zu verhindern, muss der Überprüfungsprozess für die KI systematisiert werden.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant H as "Menschlicher Ingenieur (Architekt)"
participant A as "KI-Agent"
participant S as "CI/CD &amp; Testing"
H->>A: "Definition strikter Anforderungen &amp; Einschränkungen"
A->>H: "Vorschlag für Architektur &amp; Initialen Code"
Note over H,A: Überprüfungsphase: Hohe kognitive Belastung
H->>A: "Kritik an Designentscheidungen, Bitte um Refactoring"
A->>S: "Generierung des finalen Codes &amp; Push"
S-->>H: "Automatisierte Testergebnisse &amp; Statische Analyse"
H->>H: "Finale Genehmigung &amp; Übernahme der Verantwortung"&lt;/div>
&lt;p>Der Mensch muss seine Fähigkeiten im &amp;ldquo;schnellen Lesen und sofortigen Erkennen logischer Fehler (Code Reading &amp;amp; Auditing)&amp;rdquo; noch stärker perfektionieren als seine Fähigkeiten im &amp;ldquo;Schreiben&amp;rdquo;. Die Bedeutung der testgetriebenen Entwicklung (TDD) nimmt im KI-Zeitalter noch weiter zu. Der Ansatz, bei dem ein Mensch oder eine andere KI strenge Testcodes schreibt, bevor die KI den eigentlichen Code schreiben darf, und die KI den Code so lange korrigieren lässt, bis er diese Tests besteht, wird sich durchsetzen.&lt;/p>
&lt;hr>
&lt;h2 id="9-konkrete-überlebensstrategien-was-sie-ab-morgen-lernen-sollten">9. Konkrete Überlebensstrategien: Was Sie ab morgen lernen sollten
&lt;/h2>&lt;p>Basierend auf der bisherigen Analyse präsentieren wir einen konkreten Aktionsplan, wie Programmierer im KI-Zeitalter überleben können.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Die &amp;ldquo;Grundlagen&amp;rdquo; der Technologie von Grund auf neu lernen&lt;/strong>: Die Verwendung von Frameworks kann man der KI überlassen. Ein tiefgreifendes Verständnis der Funktionsweise von Betriebssystemen, Netzwerkprotokollen (TCP/IP, HTTP/3), internen Datenbankstrukturen (B-Tree, Transaktionsisolationsstufen) sowie Datenstrukturen und Algorithmen ist jedoch absolut notwendig. Ein solides Fundament in der Informatik ist unerlässlich, um zu beurteilen, ob die Ausgabe der KI korrekt ist.&lt;/li>
&lt;li>&lt;strong>Cloud-Architekturen und verteilte Systeme meistern&lt;/strong>: Anstatt sich auf einzelnen Code zu konzentrieren, sollten Sie sich darauf fokussieren, wie Sie Cloud-Ressourcen wie AWS, GCP und Azure kombinieren können, um skalierbare Systeme aufzubauen. Verstehen Sie Konzepte von IaC (Infrastructure as Code) wie Terraform und entwickeln Sie die Fähigkeit, ganze Systeme als Code zu entwerfen.&lt;/li>
&lt;li>&lt;strong>Ein Experte für Geschäftsdomänen werden&lt;/strong>: Lernen Sie das Geschäftsmodell, die rechtlichen Rahmenbedingungen und die Verhaltenspsychologie der Benutzer in Ihrer Branche intensiv kennen. Gehen Sie über die Grenzen eines Ingenieurs hinaus und nehmen Sie eine Perspektive ein, die der eines Produktmanagers (PM) nahekommt.&lt;/li>
&lt;li>&lt;strong>Kommunikations- und Moderationsfähigkeiten verbessern&lt;/strong>: Der Prozess der Lösung von &amp;ldquo;Mehrdeutigkeiten&amp;rdquo; zwischen Menschen und der Konsensbildung kann nicht durch KI ersetzt werden. Soft Skills im Dialog mit Stakeholdern und zur Identifizierung der wahren Probleme werden zu den wertvollsten Fähigkeiten.&lt;/li>
&lt;li>&lt;strong>KI als &amp;ldquo;Kollegen&amp;rdquo; voll ausschöpfen&lt;/strong>: Anstatt sich vor der Entwicklung von KI-Werkzeugen zu fürchten, nutzen Sie sie als Ihre stärkste Waffe. Verwenden Sie im Alltag die neuesten LLMs und KI-Coding-Agenten und sammeln Sie das &amp;ldquo;implizite Wissen&amp;rdquo; darüber, wo die KI scheitert und wie Sie Prompts gestalten müssen, um die beste Leistung aus ihr herauszuholen.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="fazit-keine-angst-reiten-sie-die-welle">Fazit: Keine Angst, reiten Sie die Welle
&lt;/h2>&lt;p>Die Automatisierung des Programmierens durch KI bedeutet nicht den &amp;ldquo;Tod&amp;rdquo; des Berufs des Programmierers. Vielmehr ist es eine &lt;strong>&amp;ldquo;Renaissance&amp;rdquo;&lt;/strong>, die uns von der &amp;ldquo;unwesentlichen Arbeit&amp;rdquo; in der Softwareentwicklung befreit – wie dem Korrigieren von Tippfehlern, dem Beheben von Problemen bei der Einrichtung von Umgebungen und dem Schreiben langweiligen Boilerplate-Codes.&lt;/p>
&lt;p>Historisch gesehen verbreitete sich Pessimismus über das Verschwinden von Arbeitsplätzen sowohl bei der Einführung des mechanischen Webstuhls als auch bei der Einführung von Tabellenkalkulationssoftware (Excel). In der Realität wurden jedoch durch die dramatische Steigerung der Produktivität neue Bedürfnisse geweckt und höherwertige Arbeitsplätze geschaffen. Dasselbe wird in der Welt der Software geschehen. Da Systeme &amp;ldquo;kostengünstiger erstellt werden können&amp;rdquo;, wird Software in alle Bereiche vordringen, die bisher aufgrund von unzureichender Rentabilität nicht digitalisiert wurden. Die Probleme, die Ingenieure lösen müssen (What), werden sich ins Unendliche ausweiten.&lt;/p>
&lt;p>Uns Programmierern bietet sich nun die Chance, uns von handwerklichen Code-Schreibern zu &amp;ldquo;Orchesterdirigenten&amp;rdquo; zu entwickeln, die die mächtige Intelligenz der KI leiten. Anstatt aus Angst vor der technologischen Welle am Ufer zu bleiben, sollten wir sie als Erste reiten und uns auf die Reise begeben, um größere und wertvollere Systeme zu erschaffen. Das KI-Zeitalter ist die Ära, in der &amp;ldquo;Engineering&amp;rdquo; im wahrsten Sinne des Wortes beginnt.&lt;/p></description></item><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><item><title>Ein umfassender Vergleich der APIs von ChatGPT, Gemini und Claude: Welche sollten Sie wählen?</title><link>http://kenji.blog/de/p/chatgpt-gemini-claude-api-comparison/</link><pubDate>Fri, 11 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/chatgpt-gemini-claude-api-comparison/</guid><description>&lt;img src="http://kenji.blog/p/chatgpt-gemini-claude-api-comparison/img/eyecatch.jpg" alt="Featured image of post Ein umfassender Vergleich der APIs von ChatGPT, Gemini und Claude: Welche sollten Sie wählen?" />&lt;h1 id="ein-umfassender-vergleich-der-apis-von-chatgpt-gemini-und-claude-welche-sollten-sie-wählen">Ein umfassender Vergleich der APIs von ChatGPT, Gemini und Claude: Welche sollten Sie wählen?
&lt;/h1>&lt;p>Die Entwicklung der KI-Technologie ist bemerkenswert, insbesondere im Bereich der großen Sprachmodelle (LLM: Large Language Model). Hier liefern sich OpenAIs ChatGPT (GPT-Serie), Googles Gemini und Anthropics Claude einen erbitterten Dreikampf um die Vorherrschaft. Im Jahr 2026 veröffentlichen diese Unternehmen im Monats-, wenn nicht gar Wochentakt, neue Modelle und API-Funktionen. Für Entwickler und IT-Architekten von Unternehmen ist die Frage, „welche API in das Produkt integriert werden soll“, zu einer äußerst wichtigen Entscheidung geworden, die über den Erfolg eines Projekts bestimmen kann.&lt;/p>
&lt;p>In diesem Artikel werden wir die APIs dieser drei großen KI-Anbieter nicht nur durch eine bloße Aufzählung von Spezifikationen vergleichen und erläutern, sondern auch aus der Perspektive von Entwicklern tiefgreifend auf Aspekte wie Architekturdesign, detaillierte Preisstrukturen, mathematische Analyse der Latenz (Verzögerung), konkrete Implementierungsbeispiele in Python und Node.js sowie die neuesten Methoden zur Kostenoptimierung wie Prompt Caching eingehen.&lt;/p>
&lt;p>Wir hoffen, dass dieser Artikel ein vollständiger Leitfaden für Sie als Leser wird, um die optimale LLM-API für Ihren speziellen Anwendungsfall auszuwählen und skalierbare, kosteneffiziente KI-Anwendungen zu entwickeln.&lt;/p>
&lt;hr>
&lt;h2 id="1-philosophie-und-designkonzept-der-einzelnen-llm-apis">1. Philosophie und Designkonzept der einzelnen LLM-APIs
&lt;/h2>&lt;p>Bei der Auswahl der Technologie ist es zunächst von entscheidender Bedeutung zu verstehen, mit welcher Philosophie die einzelnen Unternehmen ihre Modelle und APIs entwickeln.&lt;/p>
&lt;h3 id="11-openai-chatgpt">1.1 OpenAI (ChatGPT)
&lt;/h3>&lt;p>OpenAI verfolgt die Mission, „Künstliche Allgemeine Intelligenz (AGI) zu verwirklichen“, und treibt stets den De-facto-Standard der Branche voran. Sie bieten vielfältige Modelle, die auf verschiedene Anwendungsfälle zugeschnitten sind, wie z. B. GPT-4o, GPT-4o-mini und die auf Inferenzen spezialisierten o1-Modelle. Das Ökosystem ist am ausgereiftesten und verfügt über die größte Fülle an offiziellen und inoffiziellen Bibliotheken und Dokumentationen.&lt;/p>
&lt;h3 id="12-google-gemini">1.2 Google (Gemini)
&lt;/h3>&lt;p>Google vertritt den „AI First“-Ansatz und nutzt die Skalierbarkeit seiner eigenen Infrastruktur (TPU-Netzwerk) als seine stärkste Waffe. Gemini 1.5 Pro/Flash zeichnet sich vor allem durch sein überwältigendes Kontextfenster (Kontextlänge) von bis zu 2 Millionen Token aus, mit dem es lange Dokumente und mehrstündige Videos oder Audios in einem Durchgang verarbeiten kann. Die starke Integration mit der Google Cloud (Vertex AI) ist auch für Unternehmen äußerst attraktiv.&lt;/p>
&lt;h3 id="13-anthropic-claude">1.3 Anthropic (Claude)
&lt;/h3>&lt;p>Anthropic ist ein von ehemaligen OpenAI-Mitgliedern gegründetes Unternehmen, das einen einzigartigen Sicherheitsansatz namens „Constitutional AI (Verfassungsgemäße KI)“ anwendet. Claude 3.5 Sonnet und Opus erfreuen sich aufgrund ihrer hohen Schlussfolgerungsfähigkeit, ihrer Fähigkeiten zur Codegenerierung und vor allem wegen ihrer „menschenähnlichen, natürlichen Konversation“ und dem „Mangel an Halluzinationen“ bei vielen Entwicklern begeisterter Unterstützung.&lt;/p>
&lt;hr>
&lt;h2 id="2-ein-detaillierter-spezifikationsvergleich-der-modellfamilien">2. Ein detaillierter Spezifikationsvergleich der Modellfamilien
&lt;/h2>&lt;p>Wir vergleichen die Spezifikationen der wichtigsten Modelle im Jahr 2026.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Anbieter&lt;/th>
&lt;th>Hauptmodell&lt;/th>
&lt;th>Maximale Kontextlänge&lt;/th>
&lt;th>Hauptstärken&lt;/th>
&lt;th>Empfohlene Anwendungsfälle&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>OpenAI&lt;/strong>&lt;/td>
&lt;td>GPT-4o&lt;/td>
&lt;td>128K&lt;/td>
&lt;td>Geschwindigkeit, visuelle Erkennung, Sprachunterstützung&lt;/td>
&lt;td>Interaktive Apps, allgemeine Aufgaben&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenAI&lt;/strong>&lt;/td>
&lt;td>o1-preview&lt;/td>
&lt;td>128K&lt;/td>
&lt;td>Fortgeschrittenes logisches Denken, Mathematik, Programmieren&lt;/td>
&lt;td>Erstellung komplexer Algorithmen, Forschungszwecke&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Google&lt;/strong>&lt;/td>
&lt;td>Gemini 1.5 Pro&lt;/td>
&lt;td>2.000K&lt;/td>
&lt;td>Verarbeitung sehr langer Texte, Multimodal (Video/Audio)&lt;/td>
&lt;td>Analyse riesiger Codebasen, Videozusammenfassung&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Google&lt;/strong>&lt;/td>
&lt;td>Gemini 1.5 Flash&lt;/td>
&lt;td>2.000K&lt;/td>
&lt;td>Geringe Latenz, hoher Durchsatz, extrem niedrige Kosten&lt;/td>
&lt;td>Echtzeitverarbeitung, Stapelverarbeitung riesiger Datenmengen&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Anthropic&lt;/strong>&lt;/td>
&lt;td>Claude 3.5 Sonnet&lt;/td>
&lt;td>200K&lt;/td>
&lt;td>Programmierfähigkeiten, natürliche Textgenerierung&lt;/td>
&lt;td>Unterstützung bei der Softwareentwicklung, fortschrittlicher Kundensupport&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Anthropic&lt;/strong>&lt;/td>
&lt;td>Claude 3.5 Haiku&lt;/td>
&lt;td>200K&lt;/td>
&lt;td>Ultraschnelle Reaktion, Kosteneffizienz&lt;/td>
&lt;td>Edge AI, Echtzeit-Chatbots&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="3-ein-tieferer-blick-in-die-architektur-hinter-den-kulissen-von-api-anfragen">3. Ein tieferer Blick in die Architektur: Hinter den Kulissen von API-Anfragen
&lt;/h2>&lt;p>Welche Prozesse laufen im Backend ab, wenn ein API-Aufruf für ein LLM getätigt wird? Um die Leistung zu optimieren, muss man diese Architektur verstehen.&lt;/p>
&lt;p>Das folgende Mermaid-Diagramm zeigt das Gesamtbild vom Senden einer API-Anfrage durch den Client bis zur Rückgabe der Token im Streaming-Verfahren.&lt;/p>
&lt;div class="mermaid">graph TD
A["Client-Anwendung"] -->|HTTP/REST oder gRPC| B["API-Gateway"]
B --> C["Load Balancer"]
C --> D["Inferenz-Cluster"]
D --> E["Tokenizer (BPE / SentencePiece)"]
E --> F["KV Cache &amp; Attention-Mechanismus"]
F --> G["Transformer-Blöcke (Forward Pass)"]
G --> H["Output-Layer (Logits)"]
H --> I["Sampler (Temperature, Top-p, Top-k)"]
I --> J["Detokenizer"]
J -->|Streaming-Antwort (Chunk)| A&lt;/div>
&lt;h3 id="31-tokenisierungs-algorithmen-tokenization">3.1 Tokenisierungs-Algorithmen (Tokenization)
&lt;/h3>&lt;p>Der in die API eingegebene Text wird intern in Einheiten namens „Token“ unterteilt.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OpenAI (tiktoken)&lt;/strong>: Verwendet Byte-Pair Encoding (BPE). Es komprimiert besonders im Englischen äußerst effizient, aber bei nicht-alphabetischen Sprachen wie Japanisch neigt die Anzahl der Token dazu, stark anzusteigen.&lt;/li>
&lt;li>&lt;strong>Google (Gemini)&lt;/strong>: Verwendet SentencePiece (Unigram Language Model). Es ist stark in Mehrsprachigkeit und neigt dazu, selbst japanische Texte mit einer relativ geringen Anzahl von Token darstellen zu können.&lt;/li>
&lt;li>&lt;strong>Anthropic (Claude)&lt;/strong>: Verwendet eine angepasste Version von BPE. Die Mehrsprachigkeit wurde verbessert, und ab Claude 3 hat sich die Token-Effizienz für Japanisch ebenfalls drastisch verbessert.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="4-mathematische-analyse-von-latenz-und-leistung">4. Mathematische Analyse von Latenz und Leistung
&lt;/h2>&lt;p>In Echtzeitanwendungen wirkt sich die Latenz direkt auf das Benutzererlebnis (UX) aus. Die Latenz einer LLM-API, $T_{total}$, lässt sich mathematisch wie folgt modellieren:&lt;/p>
$$ T_{total} = T_{network} + T_{TTFT} + (N \times T_{TPOT}) $$
&lt;p>Hier haben die einzelnen Variablen die folgenden Bedeutungen:&lt;/p>
&lt;ul>
&lt;li>$T_{network}$: Die Round-Trip-Time (RTT) des Netzwerks.&lt;/li>
&lt;li>$T_{TTFT}$ (Time To First Token): Die Zeit, bis das erste Zeichen generiert wird. Sie hängt stark von den Berechnungskosten der Attention ab, die proportional zum Quadrat der Prompt-Länge (Anzahl der Eingabe-Token) steigen.&lt;/li>
&lt;li>$N$: Die Gesamtzahl der ausgegebenen Token.&lt;/li>
&lt;li>$T_{TPOT}$ (Time Per Output Token): Die Generierungszeit pro Token. Da es sich um ein autoregressives Modell handelt, wird es seriell in Abhängigkeit von der vorherigen Ausgabe berechnet.&lt;/li>
&lt;/ul>
&lt;h3 id="41-berechnungskomplexität-des-self-attention-mechanismus">4.1 Berechnungskomplexität des Self-Attention-Mechanismus
&lt;/h3>&lt;p>Die Berechnungskomplexität der Self-Attention in der Transformer-Architektur steigt quadratisch mit der Eingabesequenzlänge $L$.&lt;/p>
$$ \text{Complexity} = O(L^2 \cdot d) $$
&lt;p>Hierbei ist $d$ die Dimensionalität des Einbettungsvektors (Embedding Vector). Aufgrund dieser Einschränkung verschlechtert sich $T_{TTFT}$ normalerweise drastisch, wenn der Prompt länger wird.
Googles Gemini 1.5 hat jedoch innovative Optimierungsarchitekturen wie „Ring Attention“ und „Block-wise Compute“ eingeführt, wodurch es gelingt, das erste Token in einer realistischen Zeit (wenige Sekunden bis Dutzende von Sekunden) zu generieren, selbst wenn ein langer Text von 2 Millionen Token eingegeben wird.&lt;/p>
&lt;hr>
&lt;h2 id="5-preisstrukturen-und-strategien-zur-kostenoptimierung">5. Preisstrukturen und Strategien zur Kostenoptimierung
&lt;/h2>&lt;p>Die API-Kosten werden grundsätzlich basierend auf der Anzahl der Eingabe- und Ausgabe-Token berechnet.&lt;/p>
$$ Cost = (Tokens_{in} \times Rate_{in}) + (Tokens_{out} \times Rate_{out}) $$
&lt;p>Allerdings haben die neuesten APIs neue Mechanismen eingeführt, um die Kosten drastisch zu senken.&lt;/p>
&lt;h3 id="51-prompt-caching-prompt-caching">5.1 Prompt-Caching (Prompt Caching)
&lt;/h3>&lt;p>Es verursacht enorme Kosten, wenn man jedes Mal extrem lange System-Prompts oder riesige Mengen an Dokumenten, die über RAG (Retrieval-Augmented Generation) abgerufen wurden, sendet. Um dem entgegenzuwirken, bieten die Anbieter eine Caching-Funktion an.&lt;/p>
&lt;p>Bei Anthropic (Claude) und Google (Gemini) können durch das Caching bestimmter Textblöcke die Eingabekosten erheblich (um bis zu 90 %) gesenkt werden.&lt;/p>
&lt;p>Das Kostenmodell bei Verwendung von Cache sieht wie folgt aus:&lt;/p>
$$ Cost_{cached} = (Tokens_{cache\_write} \times Rate_{cache\_write}) + (Tokens_{cache\_read} \times Rate_{cache\_read}) + (Tokens_{out} \times Rate_{out}) $$
&lt;p>Hierbei ist $Rate_{cache\_read}$ auf etwa 10 % bis 25 % des normalen $Rate_{in}$ festgelegt. Dadurch wurde es möglich, einen Chatbot kostengünstig zu betreiben, während ihm eine Codebasis von Zehntausenden von Zeilen permanent als Hintergrundwissen zur Verfügung steht.&lt;/p>
&lt;h3 id="52-batch-api-batch-api">5.2 Batch-API (Batch API)
&lt;/h3>&lt;p>Für Aufgaben, bei denen keine Echtzeitfähigkeit erforderlich ist (z. B. Log-Analyse, massenhafte Datenklassifizierung), bieten OpenAI und Anthropic eine Batch-API an. Dies ist ein leistungsstarker Mechanismus, bei dem Anfragen gebündelt gesendet werden und man die Ergebnisse innerhalb von 24 Stunden erhält, dafür aber nur den halben Preis (50 % Rabatt) der normalen API-Kosten extrinsisch zahlt.&lt;/p>
&lt;hr>
&lt;h2 id="6-entwicklererfahrung-dx-und-sdk-vergleich">6. Entwicklererfahrung (DX) und SDK-Vergleich
&lt;/h2>&lt;p>Wir vergleichen die von den einzelnen Unternehmen angebotenen SDKs (Software Development Kits) unter dem Gesichtspunkt der Entwicklungseffizienz.&lt;/p>
&lt;h3 id="61-openai-api">6.1 OpenAI API
&lt;/h3>&lt;p>Es ist am weitesten verbreitet und auch die Unterstützung durch Bibliotheken von Drittanbietern (LangChain, LlamaIndex usw.) ist am schnellsten. Darüber hinaus garantiert die Funktion „Structured Outputs“ (strukturierte Ausgaben), dass Antworten zu 100 % konform mit einem JSON-Schema zurückgegeben werden, was die Systemintegration extrem vereinfacht.&lt;/p>
&lt;h3 id="62-anthropic-api-claude">6.2 Anthropic API (Claude)
&lt;/h3>&lt;p>Die SDK-Schnittstelle ist sehr ausgereift und Typdefinitionen in TypeScript sind beispielsweise äußerst benutzerfreundlich. Insbesondere die Struktur der Message-API ist intuitiv, und auch multimodale Anfragen, die mehrere Bilder enthalten, lassen sich einfach implementieren.&lt;/p>
&lt;h3 id="63-google-gemini-api">6.3 Google Gemini API
&lt;/h3>&lt;p>Es gibt zwei Zugangswege: über Google Cloud Vertex AI und über AI Studio (Google Gen AI SDK), was Anfänger möglicherweise etwas verwirren kann. Das Vertex AI SDK für Unternehmen ist jedoch vollständig in das IAM (Identitäts- und Zugriffsmanagement) der GCP integriert und ermöglicht den Aufbau einer sicheren Entwicklungsumgebung.&lt;/p>
&lt;hr>
&lt;h2 id="7-praxis-implementierung-eines-integrationstests-mehrerer-apis-mit-python">7. Praxis! Implementierung eines Integrationstests mehrerer APIs mit Python
&lt;/h2>&lt;p>Hier werden wir mit Python ein Skript implementieren, das gleichzeitig asynchrone Anfragen an die drei APIs von OpenAI, Anthropic und Gemini sendet und deren Latenz vergleicht.&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&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">asyncio&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">time&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">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">openai&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AsyncOpenAI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">anthropic&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AsyncAnthropic&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">google.generativeai&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">genai&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"># Initialisierung der Clients&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">openai_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AsyncOpenAI&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;OPENAI_API_KEY&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">anthropic_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AsyncAnthropic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;ANTHROPIC_API_KEY&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">genai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">configure&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;GEMINI_API_KEY&amp;#34;&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="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Bitte erklären Sie für Anfänger verständlich die Grundlagen von Quantencomputern und deren Auswirkungen auf aktuelle Kryptographietechnologien.&amp;#34;&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">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_openai&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">openai_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chat&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">completions&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;gpt-4o&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_tokens&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;OpenAI (GPT-4o)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&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">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_anthropic&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">anthropic_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">messages&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;claude-3-5-sonnet-20240620&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_tokens&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;Anthropic (Claude 3.5 Sonnet)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&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">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_gemini&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">genai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">GenerativeModel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;gemini-1.5-pro&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Nutzung der asynchronen Methode des Gemini Python SDKs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate_content_async&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;Google (Gemini 1.5 Pro)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&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">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Sende Anfragen an die jeweiligen LLM-APIs...&amp;#34;&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"># Ausführung der drei APIs parallel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gather&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_openai&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_anthropic&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_gemini&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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">for&lt;/span> &lt;span class="n">provider&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">latency&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">text&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">results&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;--- &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">provider&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Latency: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">latency&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> seconds&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Response (Excerpt): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&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">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">main&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>Durch Ausführen dieses Skripts können Sie in einer realen Netzwerkumgebung leicht messen, welches Modell am schnellsten (bei Minimierung von $T_{total}$) antwortet.&lt;/p>
&lt;hr>
&lt;h2 id="8-implementierung-von-tool-calling-function-calling-mit-nodejs">8. Implementierung von Tool Calling (Function Calling) mit Node.js
&lt;/h2>&lt;p>Um ein LLM nicht nur als simplen Chatbot, sondern als „KI-Agenten“ fungieren zu lassen, der mit externen Systemen interagiert, ist Tool Calling (oder Function Calling) unerlässlich. Das folgende Beispiel zeigt, wie man mit Node.js (TypeScript) die OpenAI-API dazu bringt, eine Wetter-API aufzurufen.&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">import&lt;/span> &lt;span class="nx">OpenAI&lt;/span> &lt;span class="kr">from&lt;/span> &lt;span class="s2">&amp;#34;openai&amp;#34;&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="kr">const&lt;/span> &lt;span class="nx">openai&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">OpenAI&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">apiKey&lt;/span>: &lt;span class="kt">process.env.OPENAI_API_KEY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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="kr">async&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nx">runAgent() {&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">tools&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;function&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;get_weather&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">description&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Ruft das aktuelle Wetter für die angegebene Stadt ab.&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parameters&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;object&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">properties&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">location&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">description&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Name der Stadt (z. B. Tokio, New York)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">required&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;location&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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="kr">const&lt;/span> &lt;span class="nx">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="nx">openai&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">chat&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">completions&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">model&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;gpt-4o&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">messages&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nx">role&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Wie ist das Wetter heute in Tokio? Brauche ich einen Regenschirm?&amp;#34;&lt;/span> &lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tools&lt;/span>: &lt;span class="kt">tools&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tool_choice&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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="kr">const&lt;/span> &lt;span class="nx">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">response&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">choices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">message&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">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">message&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tool_calls&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">toolCall&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">message&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tool_calls&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`Das LLM hat einen Tool-Aufruf angefordert: Funktionsname = &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">toolCall&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&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="kr">const&lt;/span> &lt;span class="nx">args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">JSON&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">parse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">toolCall&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">arguments&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`Argumente: &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">args&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">location&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&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">// Hier wird der Prozess zum Aufrufen der eigentlichen Wetter-API (z. B. OpenWeatherMap) implementiert
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// const weather = await fetchWeatherFromAPI(args.location);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Das abgerufene Ergebnis wird wieder an das LLM übergeben, um die endgültige Antwort generieren zu lassen
&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;span class="line">&lt;span class="cl">&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="nx">runAgent&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="k">catch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&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>Claude 3.5 Sonnet und Gemini 1.5 Pro verfügen ebenfalls über gleichwertige Tool-Calling-Funktionen, und obwohl es leichte Unterschiede in der Art und Weise gibt, wie Schemata definiert werden, ist der grundlegende Ablauf derselbe.&lt;/p>
&lt;hr>
&lt;h2 id="9-rag-vs-long-context-window-welches-sollte-verwendet-werden">9. RAG vs. Long Context Window: Welches sollte verwendet werden?
&lt;/h2>&lt;p>Eine der größten Debatten in der Enterprise-KI-Architektur ist derzeit die Frage, „ob man RAG (Retrieval-Augmented Generation) nutzen sollte, um externes Wissen einzubeziehen, oder ob man alles einem riesigen Kontextfenster (Long Context) überlassen sollte.“&lt;/p>
&lt;h3 id="vorteile-und-herausforderungen-von-rag-retrieval-augmented-generation">Vorteile und Herausforderungen von RAG (Retrieval-Augmented Generation)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Vorteile&lt;/strong>: Die Kosten sind niedrig (da nur die benötigten Chunks in den Prompt eingefügt werden) und die Quelle der Antwort lässt sich leicht identifizieren.&lt;/li>
&lt;li>&lt;strong>Herausforderungen&lt;/strong>: Da es auf der Genauigkeit der semantischen Suche beruht, eignet es sich nicht für komplexe Schlussfolgerungsaufgaben, bei denen der Kontext über mehrere Dokumente verstreut ist (z. B. „Analysieren Sie chronologisch die Grundursache für die Verzögerung von Projekt A anhand aller Besprechungsprotokolle des letzten Jahres“).&lt;/li>
&lt;/ul>
&lt;h3 id="long-context-z-b-2-millionen-token-von-gemini-15-pro">Long Context (z. B. 2 Millionen Token von Gemini 1.5 Pro)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Vorteile&lt;/strong>: Kein Informationsverlust durch die Suche. Selbst im „Needle In A Haystack (NIAH)“-Test (Die Nadel im Heuhaufen suchen) können Modelle wie Gemini 1.5 Pro oder Claude 3.5 Sonnet Informationen mit einer Genauigkeit von über 99 % extrahieren.&lt;/li>
&lt;li>&lt;strong>Herausforderungen&lt;/strong>: Der Token-Verbrauch ist enorm, was die Kosten in die Höhe treibt, und die Latenz ($T_{TTFT}$) nimmt zu.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Fazit&lt;/strong>: Die Best Practice für das Jahr 2026 ist ein &lt;strong>„Hybrid-Ansatz“&lt;/strong>. Für alltägliche Q&amp;amp;As wird RAG mit einer Vektordatenbank eingesetzt. Für spezialisierte Aufgaben, die komplexe Analysen oder Code-Reviews des gesamten Systems erfordern, wird hingegen Long Context in Kombination mit Prompt-Caching verwendet. Dieses Design ist heute der Mainstream.&lt;/p>
&lt;hr>
&lt;h2 id="10-vergleich-der-multimodalen-verarbeitungsfähigkeiten">10. Vergleich der multimodalen Verarbeitungsfähigkeiten
&lt;/h2>&lt;p>KI-Anwendungen der nächsten Generation erfordern die Fähigkeit, nicht nur Text, sondern auch Bilder, Audiodaten und Videos direkt zu verstehen.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant User as "Benutzer"
participant Client as "Frontend-App"
participant API as "LLM-API (Multimodal)"
User->>Client: Video &amp; Text-Prompt hochladen
Client->>API: Video Bytes/URI + Text senden
Note over API: Video aufteilen &amp; Audio trennen
Note over API: Multimodales Embedding-Modell
API-->>Client: Textzusammenfassung &amp; Zeitstempel zurückgeben
Client-->>User: Erkenntnisse anzeigen&lt;/div>
&lt;ul>
&lt;li>&lt;strong>OpenAI (GPT-4o)&lt;/strong>: Bietet eine extrem hohe Bilderkennungsgenauigkeit und eignet sich hervorragend zum Lesen von handgezeichneten Skizzen oder komplexen Graphen. Die native Sprachinteraktion mit extrem geringer Latenz (einige hundert Millisekunden) über die Realtime-API ist ebenfalls sehr leistungsstark.&lt;/li>
&lt;li>&lt;strong>Google (Gemini 1.5 Pro)&lt;/strong>: &lt;strong>Ist bei der Videoanalyse unübertroffen.&lt;/strong> Man kann eine einstündige Videodatei (Frames + Audio) direkt eingeben und punktgenaue Fragen stellen wie: „Wie lautet der Titel des Dokuments, das die Person am rechten Bildschirmrand bei Minute 12:45 in der Hand hält?“.&lt;/li>
&lt;li>&lt;strong>Anthropic (Claude 3.5 Sonnet)&lt;/strong>: Die Fähigkeiten zur Bilderkennung (Vision) sind auf dem gleichen Niveau wie bei GPT-4o und äußerst beeindruckend. Es zeigt eine beispiellose Stärke bei der Unterstützung der Frontend-Entwicklung, etwa wenn man einen Screenshot einer Benutzeroberfläche übergibt und anfordert: „Generiere den React-Komponentencode für diesen Bildschirm“.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="11-sicherheit-und-compliance-auf-unternehmensniveau">11. Sicherheit und Compliance auf Unternehmensniveau
&lt;/h2>&lt;p>Wenn Unternehmen LLM-APIs in Produktionsumgebungen einsetzen, sind die größten Bedenken: „Werden unsere Daten zum Trainieren der KI verwendet?“ und „Werden Compliance-Anforderungen erfüllt?“.&lt;/p>
&lt;p>Alle drei Unternehmen haben klar erklärt, dass die über die API gesendeten Daten (Prompts und Antworten) &lt;strong>nicht zum Trainieren der Modelle verwendet werden (Zero Data Retention / No Training on Customer Data)&lt;/strong> (*Dies gilt nicht für die kostenlosen Web-Chat-UIs für Verbraucher).&lt;/p>
&lt;p>Wenn ein noch höheres Sicherheitsniveau erforderlich ist:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OpenAI&lt;/strong>: Durch die Nutzung des Azure OpenAI Service stehen die Enterprise-Grade-Sicherheit von Microsoft, SLAs und geschlossene Netzwerkverbindungen über Azure Private Link zur Verfügung.&lt;/li>
&lt;li>&lt;strong>Google&lt;/strong>: Durch die Nutzung von Google Cloud Vertex AI sind eine strikte Netzwerktrennung mithilfe von VPC Service Controls und der Datenschutz durch CMEK (Customer-Managed Encryption Keys) möglich.&lt;/li>
&lt;li>&lt;strong>Anthropic&lt;/strong>: Durch die Nutzung über AWS Bedrock oder Google Cloud Vertex AI kann man von der robusten Sicherheitsinfrastruktur der Cloud-Anbieter profitieren.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="12-fazit-der-ultimative-leitfaden-zur-auswahl-nach-anwendungsfall">12. Fazit: Der ultimative Leitfaden zur Auswahl nach Anwendungsfall
&lt;/h2>&lt;p>Wir haben bisher einen vielseitigen Vergleich angestellt, aber die endgültige Antwort auf die Frage „Welche API sollte man wählen?“ hängt letztendlich vom Anwendungsfall ab.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Komplexe Softwareentwicklung / Codegenerierung / Fortgeschrittenes logisches Denken&lt;/strong>:
&lt;strong>👑 Gewinner: Claude 3.5 Sonnet (Anthropic)&lt;/strong>
Es bietet derzeit die beste Leistung beim Verstehen von Code-Kontexten, beim Refactoring und bei der Erstellung von natürlichem, menschenähnlichem Text. Auch die Benutzerfreundlichkeit der API und die Kosteneffizienz durch Prompt-Caching sind hervorragend.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Analyse von extrem langen Dokumenten / Stapelverarbeitung von Video und Audio&lt;/strong>:
&lt;strong>👑 Gewinner: Gemini 1.5 Pro (Google)&lt;/strong>
Das Kontextfenster von 2 Millionen Token ist eine einzigartige Waffe. Bei Aufgaben, die ein Verständnis des Gesamtbildes der Daten erfordern, wie z. B. die Analyse von Hunderten Seiten langen PDF-Handbüchern oder die Zusammenfassung von stundenlangen Besprechungsaufzeichnungen, ist Gemini unübertroffen.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Vielseitigkeit / Ausführungsgeschwindigkeit / Stabile strukturierte Ausgaben (JSON)&lt;/strong>:
&lt;strong>👑 Gewinner: GPT-4o / GPT-4o-mini (OpenAI)&lt;/strong>
Es erledigt alle Aufgaben einwandfrei und bietet die umfangreichste Unterstützung für Tools von Drittanbietern. Das OpenAI-Ökosystem ist unverzichtbar, wenn man ein zuverlässiges JSON-Parsing mithilfe von Structured Outputs benötigt oder extrem fortgeschrittenes logisches Denken mit dem o1-Modell erfordert.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="empfehlung-für-multimodell-routing">Empfehlung für Multimodell-Routing
&lt;/h3>&lt;p>Anstatt sich auf eine einzige API zu verlassen (Vendor-Lock-in), ist die zukünftige Richtung eine Architektur des &lt;strong>„LLM-Routings“&lt;/strong>, bei der Modelle je nach Schwierigkeitsgrad und Wichtigkeit der Aufgabe dynamisch umgeschaltet werden.
Beispielsweise kann man auf einfache Fragen von Benutzern mit dem kostengünstigen und schnellen &lt;code>GPT-4o-mini&lt;/code> oder &lt;code>Gemini 1.5 Flash&lt;/code> antworten. Nur wenn festgestellt wird, dass eine komplexe Verarbeitung erforderlich ist, greift man als Fallback für die Aufgabe auf &lt;code>Claude 3.5 Sonnet&lt;/code> zurück. So lässt sich das optimale Gleichgewicht zwischen Kosten und Leistung erreichen.&lt;/p>
&lt;p>Die Entwicklung der KI ist unaufhaltsam. Verstehen Sie die Stärken und Schwächen der einzelnen APIs sowie die Besonderheiten ihrer Architektur genau, um flexible und flexibel skalierbare KI-Anwendungen zu entwickeln.&lt;/p></description></item><item><title>Einführung in die Nutzung und C++-Anpassung von llama.cpp</title><link>http://kenji.blog/de/p/llama-cpp-cxx-customization/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/llama-cpp-cxx-customization/</guid><description>&lt;img src="http://kenji.blog/p/llama-cpp-cxx-customization/img/eyecatch.jpg" alt="Featured image of post Einführung in die Nutzung und C++-Anpassung von llama.cpp" />&lt;p>In den letzten Jahren war die Entwicklung von Large Language Models (LLMs) enorm und ihre Anwendungsbereiche erweitern sich täglich. Um jedoch Modelle mit Milliarden oder zig Milliarden Parametern in einer lokalen Umgebung auszuführen, benötigt man normalerweise eine High-End-GPU mit enorm viel VRAM. &lt;strong>llama.cpp&lt;/strong> hat diese „Hardware-Barriere“ durchbrochen und ermöglicht praktische LLM-Inferenz auf gewöhnlichen PCs, Macs und sogar auf Geräten wie dem Raspberry Pi.&lt;/p>
&lt;p>In diesem Artikel erklären wir nicht nur die Nutzung als reines Kommandozeilentool, sondern gehen für Entwickler äußerst detailliert auf die zugrunde liegende &lt;code>ggml&lt;/code>-Architektur, den mathematischen Hintergrund von Transformern und Quantisierung sowie die Nutzung der C++-API ein, um LLMs in eigene Anwendungen zu integrieren und anzupassen.&lt;/p>
&lt;hr>
&lt;h2 id="1-übersicht-über-llamacpp-und-ggml">1. Übersicht über llama.cpp und ggml
&lt;/h2>&lt;p>&lt;code>llama.cpp&lt;/code> ist eine von Georgi Gerganov in C/C++ geschriebene, leichtgewichtige LLM-Inferenz-Engine. Ursprünglich wurde sie entwickelt, um Metas LLaMA-Modelle auf Apple Silicon (M1/M2 Macs) mit hoher Geschwindigkeit auszuführen, unterstützt aber mittlerweile verschiedene Architekturen und Modelle.&lt;/p>
&lt;p>Das größte Merkmal ist, dass es sich um eine &lt;strong>reine C/C++-Implementierung ohne externe Abhängigkeiten&lt;/strong> handelt. Da kein riesiges Ökosystem wie Python oder PyTorch benötigt wird und es als einzelne ausführbare Datei kompiliert werden kann, ist die Bereitstellung extrem einfach.&lt;/p>
&lt;p>Das Herzstück von &lt;code>llama.cpp&lt;/code> ist die Tensor-Berechnungsbibliothek &lt;strong>ggml&lt;/strong>. ggml wurde von Grund auf neu entwickelt, um Matrixoperationen für maschinelles Lernen auf der CPU (und teilweise GPU) bis zum Äußersten zu optimieren.&lt;/p>
&lt;h3 id="11-warum-ist-llamacpp-so-schnell">1.1 Warum ist llama.cpp so schnell?
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Nutzung von Memory Mapping (mmap)&lt;/strong>: Beim Laden der Modellgewichte in den Speicher wird durch die Nutzung der &lt;code>mmap&lt;/code>-Funktion des Betriebssystems das vollständige Laden in den RAM vermieden, was zu einem schnellen Start und Speicherplatzeinsparungen führt.&lt;/li>
&lt;li>&lt;strong>Umfassende Optimierung von SIMD-Befehlen&lt;/strong>: CPU-spezifische Befehlssätze wie AVX2, AVX-512, ARM NEON und Apple AMX werden genutzt, um Matrixmultiplikationen extrem zu beschleunigen.&lt;/li>
&lt;li>&lt;strong>Quantisierung (Quantization)&lt;/strong>: Die Gewichte in 16-Bit-Gleitkommazahlen (FP16) werden in 4-Bit-, 5-Bit- oder 8-Bit-Ganzzahlen komprimiert, um Engpässe in der Speicherbandbreite zu beseitigen (Details siehe unten).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-mathematischer-hintergrund-transformer-und-quantisierung">2. Mathematischer Hintergrund: Transformer und Quantisierung
&lt;/h2>&lt;p>Um llama.cpp tiefgreifend zu verstehen, muss man die mathematischen Formeln kennen, die es berechnet, und wissen, wie es diese Berechnungen annähert.&lt;/p>
&lt;h3 id="21-transformer-inferenzprozess">2.1 Transformer-Inferenzprozess
&lt;/h3>&lt;p>Modelle wie LLaMA verwenden eine autoregressive (Auto-regressive) Transformer-Decoder-Architektur. Der Kern der Textgenerierung ist der &lt;strong>Self-Attention&lt;/strong>-Mechanismus.&lt;/p>
&lt;p>Für eine Eingabematrix von verborgenen Zuständen $X \in \mathbb{R}^{N \times d}$ werden Query $Q$, Key $K$ und Value $V$ durch Multiplikation mit Gewichtsmatrizen berechnet:&lt;/p>
$$
Q = X W_Q, \quad K = X W_K, \quad V = X W_V
$$
&lt;p>Hierbei ist die Ausgabe der Attention wie folgt definiert:&lt;/p>
$$
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
&lt;p>In der Inferenzschleife von llama.cpp liegt der Engpass in der Multiplikation dieser riesigen Matrizen $W_Q, W_K, W_V$ und der Gewichtsmatrizen des Feed-Forward-Networks (FFN) mit dem Vektor $X$ (da in der Generierungsphase Token für Token verarbeitet wird, ist $N=1$), also &lt;strong>GEMV (General Matrix-Vector Multiplication)&lt;/strong>.&lt;/p>
&lt;h3 id="22-mathematische-grundlagen-der-quantisierung">2.2 Mathematische Grundlagen der Quantisierung
&lt;/h3>&lt;p>In der Inferenz, bei der die Speicherzugriffsbandbreite der Engpass ist, ist die Quantisierung, bei der Gewichtsparameter mit einer kleinen Anzahl von Bits dargestellt werden, unerlässlich. Wir erklären das Grundprinzip der in llama.cpp weit verbreiteten blockweisen Quantisierung (z. B. &lt;code>Q4_K&lt;/code> oder &lt;code>Q4_0&lt;/code>).&lt;/p>
&lt;p>Betrachten wir zum Beispiel einen Block $w = [w_1, w_2, \dots, w_B]$ der Länge $B$ (normalerweise 32 oder 64), der Teil der FP16-Gewichtsmatrix $W$ ist. Dieser Block wird durch eine 4-Bit-Ganzzahl $q_i \in [-8, 7]$ und einen einzelnen Skalierungsfaktor $\Delta$ (FP16 oder FP32) angenähert.&lt;/p>
$$
w_i \approx \Delta \times q_i
$$
&lt;p>$\Delta$ wird basierend auf dem maximalen Absolutwert innerhalb des Blocks bestimmt.&lt;/p>
$$
\Delta = \frac{\max_i |w_i|}{7}
$$
&lt;p>Wenn das Skalarprodukt $y = w \cdot x$ unter Verwendung der quantisierten Gewichte berechnet wird und der Eingabevektor $x$ ebenfalls quantisiert wird, sodass $x_i \approx \Delta_x \times q_{x, i}$, gilt:&lt;/p>
$$
y = \sum_{i=1}^{B} w_i x_i \approx \Delta \Delta_x \sum_{i=1}^{B} q_i q_{x, i}
$$
&lt;p>Dieser Teil $\sum q_i q_{x, i}$ ist eine &lt;strong>reine Ganzzahloperation&lt;/strong> und kann mithilfe von SIMD-Befehlen extrem schnell parallel berechnet werden. Das ist der mathematische Trick, der llama.cpp auf CPUs atemberaubende Geschwindigkeiten erreichen lässt.&lt;/p>
&lt;hr>
&lt;h2 id="3-architektur-und-inferenzfluss">3. Architektur und Inferenzfluss
&lt;/h2>&lt;p>Um die interne Funktionsweise von llama.cpp zu verstehen, zeigt das folgende Mermaid-Diagramm die Gesamtsystemarchitektur und den Datenfluss.&lt;/p>
&lt;div class="mermaid">graph TD
A["Benutzereingabe (String)"] --> B["llama.cpp Tokenizer"]
B --> C["Token-IDs (int32-Array)"]
C --> D["Kontextpuffer (KV Cache)"]
D --> E["ggml-Berechnungsgraph"]
E --> F["Transformer-Schichten"]
subgraph "ggml Engine"
F --> G["Self-Attention (RoPE)"]
G --> H["Feed Forward Network"]
H --> F
end
F --> I["Logits (Vokabulargröße)"]
I --> J["Sampler (Temperature, Top-K, Top-P)"]
J --> K["Ausgewählte Token-ID"]
K --> L["llama.cpp Detokenizer"]
L --> M["Ausgabe-String"]
K -. "Autoregressive Schleife" .-> D&lt;/div>
&lt;p>Die Textgenerierung ist eine autoregressive Schleife, bei der jedes ausgegebene Token als nächste Eingabe in den KV-Cache aufgenommen wird und den Berechnungsgraphen erneut durchläuft.&lt;/p>
&lt;hr>
&lt;h2 id="4-einrichtung-der-umgebung-und-build-methode">4. Einrichtung der Umgebung und Build-Methode
&lt;/h2>&lt;p>Bevor wir llama.cpp in ein C++-Projekt integrieren, lassen Sie uns zunächst den Quellcode kompilieren (builden).&lt;/p>
&lt;h3 id="41-klonen-des-repositorys">4.1 Klonen des Repositorys
&lt;/h3>&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git clone https://github.com/ggerganov/llama.cpp.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> llama.cpp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="42-build-mit-cmake">4.2 Build mit CMake
&lt;/h3>&lt;p>Wenn Sie es als C++-Projekt in andere Anwendungen integrieren möchten, ist die Verwendung von CMake der Standardweg. Durch die Aktivierung von plattformspezifischen Beschleunigern (Backends) können Berechnungen beschleunigt werden.&lt;/p>
&lt;p>&lt;strong>Nur CPU (Basis-Build):&lt;/strong>&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Bei Verwendung einer NVIDIA-GPU (CUDA):&lt;/strong>&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake .. -DGGML_CUDA&lt;span class="o">=&lt;/span>ON
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Bei Verwendung von Apple Silicon (Metal):&lt;/strong>&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake .. -DGGML_METAL&lt;span class="o">=&lt;/span>ON
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Bei einem erfolgreichen Build werden ausführbare Dateien wie &lt;code>llama-cli&lt;/code> und die &lt;code>llama&lt;/code>-Bibliothek (sowie die &lt;code>ggml&lt;/code>-Bibliothek) zur Verlinkung mit der unten beschriebenen C++-API im Verzeichnis &lt;code>build/bin/&lt;/code> generiert.&lt;/p>
&lt;hr>
&lt;h2 id="5-einführung-in-die-c-anpassung-nutzung-der-llamacpp-api">5. Einführung in die C++-Anpassung: Nutzung der llama.cpp API
&lt;/h2>&lt;p>Von hier an behandeln wir das Hauptthema: die Steuerung von llama.cpp aus C++-Code.
Um ein LLM in Ihre eigenen Anwendungen (z. B. Spiel-Engines, Desktop-Apps, eingebettete Systeme usw.) zu integrieren, anstatt nur das Kommandozeilentool zu verwenden, müssen Sie die C++-API direkt aufrufen.&lt;/p>
&lt;p>llama.cpp bietet hauptsächlich eine C-Schnittstelle über eine Header-Datei namens &lt;code>llama.h&lt;/code>. Auch beim Aufruf aus C++ wird diese Schnittstelle verwendet.&lt;/p>
&lt;h3 id="51-nötigste-includes-und-einstellungen">5.1 Nötigste Includes und Einstellungen
&lt;/h3>&lt;p>Wenn Sie llama.cpp in Ihrem eigenen Projekt verwenden, inkludieren Sie Folgendes:&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;/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="cp">#include&lt;/span> &lt;span class="cpf">&amp;#34;llama.h&amp;#34;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&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="c1">// Makro zur Fehlerbehandlung
&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 LLAMA_ASSERT(x) \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> do { \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> if (!(x)) { \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> std::cerr &amp;lt;&amp;lt; &amp;#34;Assertion failed: &amp;#34; &amp;lt;&amp;lt; #x &amp;lt;&amp;lt; std::endl; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> std::terminate(); \
&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="cp"> } while (0)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="52-modell-laden-und-kontext-initialisieren">5.2 Modell laden und Kontext initialisieren
&lt;/h3>&lt;p>Zuerst laden wir die Modelldatei im &lt;code>.gguf&lt;/code>-Format und reservieren den Kontext (Speicherplatz und KV-Cache) für die Inferenz.&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&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="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">argc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">argc&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Usage: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; &amp;lt;model.gguf&amp;gt;&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&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 class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">model_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">[&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. Initialisierung des Backends (Umgebungs-Setup wie CPU/GPU)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_backend_init&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. Standardeinstellungen für Modellparameter abrufen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_model_params&lt;/span> &lt;span class="n">model_params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_model_default_params&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_gpu_layers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">35&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Anzahl der auf die GPU ausgelagerten Schichten
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. Modell laden
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_model&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_load_model_from_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">model_params&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to load model&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&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 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. Kontextparameter einstellen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_context_params&lt;/span> &lt;span class="n">ctx_params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_context_default_params&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2048&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Maximale Kontextgröße (Anzahl der Tokens)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_threads&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Anzahl der für die Inferenz verwendeten CPU-Threads
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. Kontext erstellen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_context&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_new_context_with_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to create context&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&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 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="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Model and context loaded successfully!&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ... folgende Verarbeitung
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-tokenisierung-des-prompts-tokenization">5.3 Tokenisierung des Prompts (Tokenization)
&lt;/h3>&lt;p>LLMs verstehen Text nicht direkt, sondern verarbeiten ihn als eine Reihe von ganzzahligen IDs (Tokens). Die Eingabezeichenfolge muss in Tokens umgewandelt werden.&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;/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="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Q: Was ist die Hauptstadt von Japan?&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">A:&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">llama_token&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Puffergröße mit etwas Spielraum
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Ob spezielle Token (BOS: Begin of Sequence etc.) am Anfang hinzugefügt werden sollen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="n">add_special&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Zeichenfolge in ein Array von Token-IDs umwandeln
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_tokenize&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">add_special&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">false&lt;/span> &lt;span class="c1">// parse_special
&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;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Logik für Neuallokation und Wiederholung erforderlich, wenn der Puffer nicht ausreicht (hier zur Vereinfachung weggelassen)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to tokenize prompt&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&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 class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_tokens&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;h3 id="54-inferenzschleife-und-sampling">5.4 Inferenzschleife und Sampling
&lt;/h3>&lt;p>Wir erstellen eine Schleife, in der Tokens in das Modell eingespeist werden, die Wahrscheinlichkeitsverteilung (Logits) für das nächste Token abgerufen wird, und dann durch Sampling das nächste Token bestimmt wird.&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;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&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">// Maximale Anzahl der zu generierenden Tokens
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">max_gen_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&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">// Struktur für die Batch-Evaluierung initialisieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_batch&lt;/span> &lt;span class="n">batch&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_batch_init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">512&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&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">// Prompt-Tokens zum Batch hinzufügen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// So einstellen, dass Logits (Vorhersageergebnisse) nur für das letzte Token des Prompts ausgegeben werden
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">logits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&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">// Erste Evaluierung (Modell mit Prompt füttern)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;llama_decode() failed&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&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 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="kt">int&lt;/span> &lt;span class="n">n_cur&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Aktuelle Kontextlänge
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_decode&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&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="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">Output: &amp;#34;&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">// Sampler-Kontext initialisieren (Einstellungen wie Temperature, Top-K, Top-P etc.)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_sampler&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">smpl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_sampler_chain_init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">llama_sampler_chain_default_params&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_top_k&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_top_p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.9f&lt;/span>&lt;span class="p">,&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 class="n">llama_sampler_chain_add_temp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.7f&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_dist&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1234&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Seed-Wert
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_decode&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">max_gen_tokens&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. Sampling: Vorhersage des nächsten Tokens basierend auf dem aktuellen Kontext
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_token&lt;/span> &lt;span class="n">new_token_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_sampler_sample&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ctx&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. Wenn das Token EOS (End of Sequence) ist, Schleife beenden
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_token_is_eog&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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. Token in einen String (Text) dekodieren und anzeigen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">128&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_chars&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_token_to_piece&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_chars&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_chars&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">flush&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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. Das neu generierte Token als nächsten Batch vorbereiten
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_batch_clear&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_cur&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="nb">true&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. Modellevaluierung (KV-Cache aktualisieren und nächstes vorhersagen)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to evaluate&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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="n">n_cur&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 class="n">n_decode&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 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="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&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">// Bereinigung
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_sampler_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_backend_free&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="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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>Dieser Code implementiert eine eigene Inferenzschleife mit der Basis-API von llama.cpp.
Er verwendet die &lt;code>llama_batch&lt;/code>-Struktur zur Verwaltung der Tokengruppen und führt mit &lt;code>llama_decode&lt;/code> einen Forward-Pass (Vorwärtsausbreitung) des neuronalen Netzwerks aus.&lt;/p>
&lt;hr>
&lt;h2 id="6-fortgeschrittenes-anpassungsbeispiel-logit-manipulation-und-penalty-steuerung-mit-c">6. Fortgeschrittenes Anpassungsbeispiel: Logit-Manipulation und Penalty-Steuerung mit C++
&lt;/h2>&lt;p>Wenn Sie nicht nur einfachen Text generieren, sondern eine Ausgabe in einem bestimmten Format (z. B. nur JSON) erzwingen oder die Ausgabe bestimmter verbotener Wörter verhindern möchten, können Sie die &lt;strong>Logits&lt;/strong> vor dem Sampling direkt in C++ manipulieren.&lt;/p>
&lt;p>Sie können das Array der rohen Scores (Werte vor der Umwandlung in Wahrscheinlichkeiten) kurz vor der Ausgabe jedes Tokens durch das Modell abrufen.&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;/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">// Rufen Sie das Array der rohen Logits direkt nach der Inferenz und vor dem Sampling ab
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">float&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">logits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_get_logits_ith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&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 class="kt">int&lt;/span> &lt;span class="n">n_vocab&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_n_vocab&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&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">// Liste der IDs verbotener Tokens (Beispiel: 1234, 5678)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">llama_token&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">forbidden_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">1234&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5678&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">// Setzen Sie die Auftrittswahrscheinlichkeit verbotener Tokens auf 0 (Logit auf minus unendlich)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_token&lt;/span> &lt;span class="nl">bad_tok&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">forbidden_tokens&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">bad_tok&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">INFINITY&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&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>Durch die direkte Nutzung der C++-API werden &lt;strong>„Eingriffe im Mikrosekundenbereich pro Inferenzzyklus“&lt;/strong> möglich, die über LangChain oder Python nur schwer zu realisieren wären oder mit großem Overhead verbunden sind.&lt;/p>
&lt;hr>
&lt;h2 id="7-die-geheimnisse-der-leistungsoptimierung-performance-tuning">7. Die Geheimnisse der Leistungsoptimierung (Performance Tuning)
&lt;/h2>&lt;p>Nach Abschluss der C++-Implementierung finden Sie hier einige Kontrollpunkte, um die Geschwindigkeit für den praktischen Einsatz auf das Maximum zu steigern.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Optimierung der Batch-Verarbeitung:&lt;/strong> Bei der gleichzeitigen Verarbeitung von Anfragen mehrerer Benutzer können Sie mehrere Sequenzen in einen &lt;code>llama_batch&lt;/code> aufnehmen und &lt;code>llama_decode&lt;/code> einmalig aufrufen (Continuous Batching). Dies bündelt Speicherzugriffe und kann den Durchsatz drastisch verbessern.&lt;/li>
&lt;li>&lt;strong>Flash Attention aktivieren:&lt;/strong>
Durch Setzen von &lt;code>ctx_params.flash_attn = true;&lt;/code> in den Kontextparametern können Sie die Attention-Berechnung beschleunigen und gleichzeitig den Speicherverbrauch reduzieren. Bei der Arbeit mit langen Kontexten (Zehntausende von Tokens) ist diese Einstellung zwingend erforderlich.&lt;/li>
&lt;li>&lt;strong>NUMA-Unterstützung:&lt;/strong>
In Multi-Socket-Serverumgebungen kann die Speicherzugriffslatenz reduziert werden, indem NUMA vor dem Aufruf von &lt;code>llama_backend_init()&lt;/code> entsprechend konfiguriert wird.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-fazit">8. Fazit
&lt;/h2>&lt;p>In diesem Artikel haben wir detailliert alles vom mathematischen Hintergrund von &lt;code>llama.cpp&lt;/code> über die Erklärung seiner Architektur bis hin zur Erstellung einer benutzerdefinierten Inferenz-Engine mithilfe der C++-API behandelt.&lt;/p>
&lt;p>Während das Python-Ökosystem sehr nützlich für Prototyping ist, zeigt die direkte Steuerung des C/C++-basierten &lt;code>llama.cpp&lt;/code> in Produktionsumgebungen, die Deployments auf Edge-Geräten, Integrationen in Spiele und Echtzeitverarbeitung erfordern, ihre überwältigende Stärke.&lt;/p>
&lt;p>Wir laden Sie ein, eigenen C++-Code zu schreiben und den Spaß zu erleben, LLMs in Ihrer lokalen Umgebung frei zu steuern.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Referenzlinks&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noopener"
>llama.cpp Official Repository&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/ggml" target="_blank" rel="noopener"
>ggml - Tensor Library&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://arxiv.org/abs/1706.03762" target="_blank" rel="noopener"
>Attention Is All You Need (Vaswani et al., 2017)&lt;/a>&lt;/li>
&lt;/ul>
&lt;/blockquote></description></item><item><title>【2026 Aktuell】Der ultimative Leitfaden zur Ausführung von lokalen LLMs unter Windows</title><link>http://kenji.blog/de/p/local-llm-windows-2026/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/local-llm-windows-2026/</guid><description>&lt;img src="http://kenji.blog/p/local-llm-windows-2026/img/eyecatch.jpg" alt="Featured image of post 【2026 Aktuell】Der ultimative Leitfaden zur Ausführung von lokalen LLMs unter Windows" />&lt;h1 id="1-einführung-warum-gerade-jetzt-lokale-llms-unter-windows">1. Einführung: Warum gerade jetzt lokale LLMs unter Windows?
&lt;/h1>&lt;p>Im Jahr 2026 hat die Entwicklung generativer KI und großer Sprachmodelle (LLMs) einen gewaltigen Paradigmenwechsel vollzogen – von riesigen API-Diensten in der Cloud hin zu &amp;ldquo;lokalen LLMs&amp;rdquo;, die auf privaten PCs oder in On-Premise-Umgebungen laufen. Cloud-KIs wie GPT-5 von OpenAI und Claude 3.5 von Anthropic sind extrem leistungsstark, aber Unternehmen und Privatpersonen können nicht all ihre Daten in die Cloud senden. Aus Gründen des Datenschutzes, der Sicherheit, der Latenzzeit sowie der langfristigen und nachhaltigen Kosten ist die Nachfrage nach lokalen LLMs so explosionsartig gestiegen wie nie zuvor.&lt;/p>
&lt;p>Besonders im Windows-Umfeld ist die Entwicklung des Ökosystems für lokale LLMs bemerkenswert. Noch vor einigen Jahren galt &amp;ldquo;KI-Entwicklung und -Ausführung gleich Linux&amp;rdquo; als gängige Regel, doch im Jahr 2026 hat sich Windows zu einer äußerst leistungsstarken und zugänglichen KI-Plattform gewandelt.&lt;/p>
&lt;p>In diesem Artikel bieten wir einen vollständigen Leitfaden zur Einrichtung, zum Betrieb und zur Optimierung lokaler LLMs in einer Windows-Umgebung, basierend auf den neuesten Technologietrends von 2026. Von der einfachen Einrichtung für Anfänger mit Ollama über die extreme Optimierung für Fortgeschrittene mithilfe von llama.cpp bis hin zu tiefergehenden mathematischen Ansätzen zur VRAM-Berechnung, dem Verständnis der Architektur und lokalem Fine-Tuning – wir erklären alles ausführlich und in gewaltigem Umfang.&lt;/p>
&lt;h2 id="11-technologietrends-rund-um-lokale-llms-im-jahr-2026">1.1 Technologietrends rund um lokale LLMs im Jahr 2026
&lt;/h2>&lt;p>Die wichtigsten Trends, die das aktuelle Ökosystem für lokale LLMs prägen, sind:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vollständige Verbreitung des GGUF-Formats&lt;/strong>: GGUF (GPT-Generated Unified Format), das Metadaten und Tensoren in einer einzigen Datei vereint, hat sich vollständig als De-facto-Standard etabliert. Dadurch genügt es, eine einzige Datei von Hugging Face herunterzuladen, um sie in beliebigen Umgebungen auszuführen.&lt;/li>
&lt;li>&lt;strong>Demokratisierung der MoE-Architektur (Mixture of Experts)&lt;/strong>: Es wurden zahlreiche kleine, aber leistungsstarke MoE-Modelle veröffentlicht. Indem während der Inferenz nur ein Teil der Experten aktiviert wird, erreichen sie die Leistung riesiger Modelle, während die Rechenlast für Consumer-PCs gering gehalten wird.&lt;/li>
&lt;li>&lt;strong>Fortgeschrittene Abstraktion und Optimierung von Inferenz-Engines&lt;/strong>: Tools wie Ollama, LM Studio und AnythingLLM wurden so verfeinert, dass sich der Benutzer nicht mehr um komplexe Abhängigkeiten wie die Installation von CUDA-Treibern kümmern muss. Zudem hat die native Windows-Unterstützung von FlashAttention 3 die Inferenzgeschwindigkeit drastisch erhöht.&lt;/li>
&lt;li>&lt;strong>Nutzung von NPUs und der Aufstieg von Windows Copilot+ PCs&lt;/strong>: Die Technologie zur Ausführung kleiner LLMs (SLM: Small Language Models) mit geringem Stromverbrauch unter Nutzung der verbauten NPU (Neural Processing Unit) hat auch bei Laptops ohne GPU die Praxisreife erreicht.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-hardwareanforderungen-und-os-vorbereitung">2. Hardwareanforderungen und OS-Vorbereitung
&lt;/h1>&lt;p>Um ein lokales LLM mit praktikabler Geschwindigkeit (15 bis 30 Token pro Sekunde oder mehr) auszuführen, ist die Wahl der Hardware von entscheidender Bedeutung.&lt;/p>
&lt;h2 id="21-empfohlene-hardwarekonfiguration">2.1 Empfohlene Hardwarekonfiguration
&lt;/h2>&lt;p>Mit der Weiterentwicklung von AI-PCs haben sich auch die Spezifikationsanforderungen geändert.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OS&lt;/strong>: Windows 11 Pro (24H2 oder neuer). Zwingend erforderlich für die volle Funktionalität von WSL2, erweitertes Speichermanagement sowie die Nutzung der neuesten APIs von DirectML.&lt;/li>
&lt;li>&lt;strong>CPU&lt;/strong>: Intel Core Ultra 200 Serie oder neuer, bzw. AMD Ryzen 9000 Serie oder neuer. Bei gleichzeitiger Nutzung der CPU-Inferenz ist eine hohe Speicherbandbreite unerlässlich.&lt;/li>
&lt;li>&lt;strong>RAM&lt;/strong>: Mindestens 32 GB, empfohlen 64 GB oder mehr. Die Bandbreite des Hauptspeichers (MB/s) wird zum entscheidenden Flaschenhals bei CPU-Inferenz oder Offloading. Schneller DDR5-6000 Speicher oder höher ist ideal.&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong>: NVIDIA RTX 4000/5000 Serie. Bei lokalen LLMs ist nicht die Rechenleistung, sondern die &amp;ldquo;VRAM-Kapazität&amp;rdquo; das Wichtigste.
&lt;ul>
&lt;li>&lt;strong>Einsteiger&lt;/strong>: RTX 4060 Ti (16GB-Version) - Bestes Preis-Leistungs-Verhältnis. Ideal für Modelle der 8B- bis 14B-Klasse.&lt;/li>
&lt;li>&lt;strong>Mittelklasse&lt;/strong>: RTX 4070 Ti SUPER (16GB) / RTX 4080 SUPER (16GB)&lt;/li>
&lt;li>&lt;strong>High-End&lt;/strong>: RTX 4090 (24GB) / RTX 5090 (32GB) - Erforderlich für die Ausführung quantisierter Modelle der 30B- bis 70B-Klasse.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Speicher&lt;/strong>: PCIe Gen4 oder Gen5 NVMe SSD. Reduziert die Ladezeiten für zig Gigabyte große Modelle drastisch.&lt;/li>
&lt;/ul>
&lt;h2 id="22-einrichtung-von-wsl2-windows-subsystem-for-linux-2">2.2 Einrichtung von WSL2 (Windows Subsystem for Linux 2)
&lt;/h2>&lt;p>Viele GUI-Tools laufen nativ unter Windows, aber für die Python-Entwicklung, das Kompilieren neuester Tools und das spätere LoRA-Fine-Tuning ist WSL2 äußerst praktisch. In den neuesten Windows 11-Umgebungen muss lediglich der NVIDIA-Treiber auf dem Host installiert werden, um die GPU (CUDA) transparent aus WSL2 heraus nutzen zu können.&lt;/p>
&lt;p>Öffnen Sie PowerShell mit Administratorrechten und führen Sie Folgendes aus:&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;/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="c"># Installation von WSL2 und dem neuesten Ubuntu&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span> &lt;span class="n">-d&lt;/span> &lt;span class="n">Ubuntu&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">24.04&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="c"># Kernel-Update&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-update&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Führen Sie nach der Installation &lt;code>nvidia-smi&lt;/code> im WSL2-Terminal aus. Wenn die GPU korrekt erkannt wird, war die Einrichtung erfolgreich.&lt;/p>
&lt;hr>
&lt;h1 id="3-architektur-lokaler-llms-und-inferenzmechanismus">3. Architektur lokaler LLMs und Inferenzmechanismus
&lt;/h1>&lt;p>Das Verständnis der internen Struktur, wie ein Modell in einer lokalen Umgebung Text generiert, ist für die Fehlerbehebung und Optimierung äußerst nützlich.&lt;/p>
&lt;p>Das folgende Mermaid-Diagramm zeigt eine typische Inferenz-Pipeline eines lokalen LLMs.&lt;/p>
&lt;div class="mermaid">graph TD
User["Benutzereingabe (Prompt)"] --> Tokenizer["Tokenizer (Tokenizer)"]
Tokenizer --> Embedding["Embedding-Schicht (Embedding)"]
subgraph "Transformer Block (x Layers)"
Embedding --> Attn["Selbst-Aufmerksamkeit (Self-Attention)"]
Attn --> KVCache["KV-Cache (Key/Value-Erhalt)"]
Attn --> FFN["Feed-Forward-Netzwerk (FFN)"]
end
FFN --> Logits["Logit-Berechnung (Logits)"]
Logits --> Sampler["Sampler (Temperature, Top-K, Top-P)"]
Sampler --> OutputToken["Ausgabe-Token"]
OutputToken --> |"Autoregressive Generierung"| Tokenizer
OutputToken --> Decoder["Detokenizer (Detokenizer)"]
Decoder --> FinalOutput["Finaler Ausgabetext"]&lt;/div>
&lt;h2 id="31-zwei-phasen-prefill-und-decode">3.1 Zwei Phasen: Prefill und Decode
&lt;/h2>&lt;p>Die Textgenerierung bei LLMs unterteilt sich in zwei Phasen mit unterschiedlichen Berechnungseigenschaften.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Prefill-Phase (Prompt-Verarbeitung)&lt;/strong>: In dieser Phase wird der gesamte eingegebene Prompt auf einmal verarbeitet und verstanden. Da parallele Berechnungen möglich sind, steht die Rechenleistung der GPU (FLOPS) in direktem Zusammenhang mit der Geschwindigkeit. Bei langen Prompts kann diese Phase mehrere Sekunden dauern.&lt;/li>
&lt;li>&lt;strong>Decode-Phase (Token-Generierung)&lt;/strong>: In dieser Phase wird iterativ ein Token vorhergesagt und als nächste Eingabe zurückgeführt (autoregressiv). Da hier parallele Berechnungen eingeschränkt sind, wird die VRAM-Bandbreite (Memory Bandwidth) der GPU zum entscheidenden Flaschenhals.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="4-berechnung-des-vram-verbrauchs-und-mathematisches-verständnis-der-modellgröße">4. Berechnung des VRAM-Verbrauchs und mathematisches Verständnis der Modellgröße
&lt;/h1>&lt;p>Um richtig einschätzen zu können, &amp;ldquo;welches Modell auf meinem PC läuft&amp;rdquo;, muss man die Berechnungsformel für den VRAM verstehen. Ein Fallback auf den Systemspeicher (RAM) aufgrund von VRAM-Mangel macht die Inferenzgeschwindigkeit 10- bis 100-mal langsamer.&lt;/p>
&lt;h2 id="41-basis-vram-basierend-auf-der-parametergröße">4.1 Basis-VRAM basierend auf der Parametergröße
&lt;/h2>&lt;p>Dies ist die Speichermenge, die benötigt wird, um die Gewichte (Weights) des Modells in den VRAM zu laden.
Sie wird anhand der Modellgröße $P$ (Anzahl der Parameter, Einheit: 1 Milliarde = 1B) und der Anzahl der Bytes pro Parameter $B$ berechnet.&lt;/p>
$$
V_{base} = P \times B \quad \text{(GB)}
$$
&lt;p>Wenn Sie beispielsweise ein 8B (8 Milliarden) Parameter-Modell in FP16 (Halbgenauigkeits-Gleitkommazahl, 16 Bit = 2 Byte) laden:&lt;/p>
$$
V_{base} = 8 \times 2 = 16 \text{ GB}
$$
&lt;p>Das bedeutet, selbst wenn Ihre GPU 16 GB VRAM hat, ist allein durch das Laden des Modells das Limit fast erreicht.&lt;/p>
&lt;h2 id="42-die-magie-der-quantisierung-quantization">4.2 Die Magie der Quantisierung (Quantization)
&lt;/h2>&lt;p>Hier kommt die &amp;ldquo;Quantisierung&amp;rdquo; ins Spiel. Durch Verringern der Parametergenauigkeit wird die Modellgröße drastisch reduziert. Bei der gängigsten 4-Bit-Quantisierung (z. B. Q4_K_M) beträgt ein Parameter im Durchschnitt etwa 0,55 Byte.&lt;/p>
$$
V_{base\_4bit} = 8 \times 0.55 = 4.4 \text{ GB}
$$
&lt;p>Dadurch können Sie mit 16 GB VRAM problemlos ein 8B-Modell mit ausreichend Spielraum ausführen.&lt;/p>
&lt;h2 id="43-berechnung-des-kv-caches-gqa-unterstützte-version">4.3 Berechnung des KV-Caches (GQA-unterstützte Version)
&lt;/h2>&lt;p>Während der Inferenz verbraucht der &amp;ldquo;KV-Cache&amp;rdquo;, der den bisherigen Kontext speichert, VRAM. In neuesten Modellen wie Llama 3 wird GQA (Grouped Query Attention) eingesetzt, um Speicher zu sparen.&lt;/p>
&lt;p>Der Verbrauch des KV-Caches $V_{kv}$ (in Gigabyte) lässt sich durch folgende Formel darstellen:&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times \left( \frac{h_{kv}}{h_q} \right) \times h_q \times d \times B_{kv} \div 10^9
$$
&lt;p>Vereinfacht ausgedrückt, kann es mithilfe der Anzahl der Key- und Value-Köpfe $h_{kv}$ einfach berechnet werden:&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times h_{kv} \times d \times B_{kv} \div 10^9
$$
&lt;p>Hierbei ist:&lt;/p>
&lt;ul>
&lt;li>$b$: Batch-Größe (bei lokaler Einzelnutzung meist 1)&lt;/li>
&lt;li>$s$: Sequenzlänge (Kontextlänge, z. B. 8192)&lt;/li>
&lt;li>$l$: Anzahl der Schichten (Layer, z. B. 32)&lt;/li>
&lt;li>$h_{kv}$: Anzahl der KV-Köpfe (KV-Heads, z. B. 8)&lt;/li>
&lt;li>$d$: Dimensionalität pro Kopf (z. B. 128)&lt;/li>
&lt;li>$B_{kv}$: Bytegröße des KV-Caches (2 für FP16)&lt;/li>
&lt;/ul>
&lt;p>Berechnungsbeispiel (Llama 3 8B, Kontext 8192, FP16 Cache):
$V_{kv} = 2 \times 1 \times 8192 \times 32 \times 8 \times 128 \times 2 \div 10^9 \approx 1.07 \text{ GB}$&lt;/p>
&lt;p>Beachten Sie, dass der erforderliche VRAM linear ansteigt, je länger die Kontextlänge $s$ gewählt wird.&lt;/p>
&lt;hr>
&lt;h1 id="5-praxis-1-schnellstes-und-kürzestes-setup-mit-ollama">5. Praxis 1: Schnellstes und kürzestes Setup mit Ollama
&lt;/h1>&lt;p>Da wir nun die Theorie verstehen, lassen Sie uns ein LLM tatsächlich in einer Windows-Umgebung ausführen.
Im Jahr 2026 ist das benutzerfreundlichste Tool &amp;ldquo;Ollama&amp;rdquo;. Es bietet ein Docker-ähnliches, intuitives CLI.&lt;/p>
&lt;h2 id="51-installation-und-ausführung">5.1 Installation und Ausführung
&lt;/h2>&lt;ol>
&lt;li>Laden Sie den Windows-Installer von der &lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"
>offiziellen Ollama-Website&lt;/a> herunter und führen Sie ihn aus.&lt;/li>
&lt;li>Öffnen Sie PowerShell und geben Sie den folgenden Befehl ein. Hier verwenden wir das japanischsprachige &lt;code>llama3:8b&lt;/code>.&lt;/li>
&lt;/ol>
&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;/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">ollama&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">llama3&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="n">8b&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Beim ersten Ausführen wird das Modell heruntergeladen. Sobald dies abgeschlossen ist, können Sie direkt im Terminal chatten.&lt;/p>
&lt;h2 id="52-erstellen-einer-benutzerdefinierten-ki-mit-modelfile">5.2 Erstellen einer benutzerdefinierten KI mit Modelfile
&lt;/h2>&lt;p>Sie können ganz einfach eine KI mit einer bestimmten Persona erstellen. Erstellen Sie ein &lt;code>Modelfile&lt;/code> an einem beliebigen Ort.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">FROM llama3:8b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SYSTEM &amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Sie sind ein hervorragender Senior-Software-Ingenieur.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Beantworten Sie Benutzerfragen stets mit Codebeispielen, logisch und präzise.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">PARAMETER temperature 0.3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">PARAMETER num_ctx 8192
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Erstellen und starten Sie Ihr eigenes Modell mit den folgenden Befehlen:&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;/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">ollama&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="n">SeniorDev&lt;/span> &lt;span class="o">-f&lt;/span> &lt;span class="p">./&lt;/span>&lt;span class="n">Modelfile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">SeniorDev&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="53-nutzung-über-externe-apps-ki-editoren">5.3 Nutzung über externe Apps (KI-Editoren)
&lt;/h2>&lt;p>Ollama stellt einen OpenAI-kompatiblen API-Endpunkt unter &lt;code>http://localhost:11434&lt;/code> zur Verfügung.
Indem Sie diese URL in den Backend-Einstellungen von VS-Code-Erweiterungen wie Cursor oder Continue.dev angeben und als Modellnamen z.B. &lt;code>SeniorDev&lt;/code> festlegen, erhalten Sie kostenlos einen leistungsstarken lokalen Coding-Assistenten.&lt;/p>
&lt;hr>
&lt;h1 id="6-praxis-2-extreme-leistungsoptimierung-mit-llamacpp">6. Praxis 2: Extreme Leistungsoptimierung mit llama.cpp
&lt;/h1>&lt;p>Wenn Sie feinkörnige Speicherverwaltung wünschen oder die neuesten Formate (wie EXL2 oder IQ-Quantisierung) schnell ausprobieren möchten, steuern Sie die Kern-Engine &lt;code>llama.cpp&lt;/code> direkt.&lt;/p>
&lt;h2 id="61-schritte-zum-kompilieren-von-llamacpp">6.1 Schritte zum Kompilieren von llama.cpp
&lt;/h2>&lt;p>In einer Windows-Umgebung ist es am besten, mithilfe von CUDA Toolkit und CMake aus dem Quellcode zu kompilieren.&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-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">git&lt;/span> &lt;span class="n">clone&lt;/span> &lt;span class="n">https&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="p">//&lt;/span>&lt;span class="n">github&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">ggerganov&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">llama&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">cpp
&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">llama&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">&lt;/span>&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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Für CUDA konfigurieren und kompilieren&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">-DLLAMA_CUBLAS&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="n">ON&lt;/span> &lt;span class="n">-DBUILD_SHARED_LIBS&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="n">OFF&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 class="n">-j&lt;/span> &lt;span class="mf">16&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="62-fortgeschrittener-start-im-server-modus">6.2 Fortgeschrittener Start im Server-Modus
&lt;/h2>&lt;p>Verwenden Sie die kompilierte &lt;code>llama-server.exe&lt;/code>, um das Modell zu hosten.&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;/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="p">.\&lt;/span>&lt;span class="n">bin&lt;/span>&lt;span class="p">\&lt;/span>&lt;span class="n">Release&lt;/span>&lt;span class="p">\&lt;/span>&lt;span class="nb">llama-server&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">exe&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-model&lt;/span> &lt;span class="s2">&amp;#34;C:\models\Llama-3-8B-Instruct.Q4_K_M.gguf&amp;#34;&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-ctx-size&lt;/span> &lt;span class="mf">8192&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-n-gpu-layers&lt;/span> &lt;span class="mf">99&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-threads&lt;/span> &lt;span class="mf">8&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-flash-attn&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-port&lt;/span> &lt;span class="mf">8080&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>&lt;code>--n-gpu-layers 99&lt;/code>: Verlagert so viele Layer wie möglich auf den GPU VRAM.&lt;/li>
&lt;li>&lt;code>--flash-attn&lt;/code>: Aktiviert FlashAttention 3, um die Inferenzgeschwindigkeit zu erhöhen und den VRAM-Verbrauch des KV-Caches zu senken.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="7-gui-frontends-lm-studio-und-aufbau-lokaler-rags">7. GUI-Frontends: LM Studio und Aufbau lokaler RAGs
&lt;/h1>&lt;p>Wenn Sie die Kommandozeile meiden möchten oder RAG (Retrieval-Augmented Generation) intuitiv umsetzen wollen, nutzen Sie eine GUI.&lt;/p>
&lt;h2 id="71-lm-studio">7.1 LM Studio
&lt;/h2>&lt;p>LM Studio ist eine fantastische Anwendung, die Modellsuche, Download, Überprüfung der Systemanforderungen und eine Chat-UI in einem vereint. Durch einfaches Klicken auf den Button &amp;ldquo;Local Server&amp;rdquo; in der App wird eine OpenAI-kompatible API gestartet.&lt;/p>
&lt;h2 id="72-rag-architektur-mit-anythingllm">7.2 RAG-Architektur mit AnythingLLM
&lt;/h2>&lt;p>Hier ist das Architekturdiagramm einer RAG-Umgebung zum Einlesen interner Dokumente oder privater Notizen.&lt;/p>
&lt;div class="mermaid">graph LR
Document["Dokument (PDF, MD)"] --> Chunking["Chunk-Aufteilung"]
Chunking --> EmbedModel["Embedding-Modell"]
EmbedModel --> VectorDB["Vektordatenbank"]
UserQuery["Benutzeranfrage"] --> EmbedQuery["Anfrage-Embedding"]
EmbedQuery --> VectorDB
VectorDB --> |"Ähnlichkeitssuche"| RetrievedDocs["Extrahierte relevante Dokumente"]
UserQuery --> PromptBuilder["Prompt-Generierung"]
RetrievedDocs --> PromptBuilder
PromptBuilder --> LocalLLM["Lokales LLM"]
LocalLLM --> Answer["Finale Antwort"]&lt;/div>
&lt;p>Mit der Desktop-Version von AnythingLLM (für Windows) können Sie diese Architektur in wenigen Minuten aufbauen, indem Sie in den Einstellungen Ollama (für LLM und Embedding) auswählen und eine lokale Vektor-DB (LanceDB) festlegen. Dies ist die Geburtsstunde einer privaten KI, die keinerlei Daten nach außen sendet.&lt;/p>
&lt;hr>
&lt;h1 id="8-fine-tuning-lora-auf-windows-wsl2">8. Fine-Tuning (LoRA) auf Windows WSL2
&lt;/h1>&lt;p>Wenn Sie Modelle nicht nur lokal ausführen, sondern mit Ihren eigenen Daten intelligenter machen wollen, ist ein Fine-Tuning mit LoRA (Low-Rank Adaptation) möglich. Im Jahr 2026 können Sie mit der Bibliothek &amp;ldquo;Unsloth&amp;rdquo; in einer Windows WSL2-Umgebung das Training eines 8B-Modells mit 16 GB VRAM in wenigen Stunden abschließen.&lt;/p>
&lt;p>Richten Sie die Umgebung ein, indem Sie Folgendes in WSL2 Ubuntu ausführen:&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-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">conda create --name unsloth_env &lt;span class="nv">python&lt;/span>&lt;span class="o">=&lt;/span>3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">conda activate unsloth_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install &lt;span class="s2">&amp;#34;unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install --no-deps trl peft accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Unsloth optimiert CUDA-Kernel bis zum Äußersten, verdoppelt die Trainingsgeschwindigkeit im Vergleich zu Standard-Hugging-Face-Bibliotheken und halbiert den VRAM-Verbrauch. Starten Sie einfach ein Jupyter Notebook, laden Sie Ihren Datensatz (im JSONL-Format) ein, und schon ist ein Training über mehrere Epochen selbst auf einer RTX 4060 Ti mit 12 GB bis 16 GB VRAM möglich.&lt;/p>
&lt;hr>
&lt;h1 id="9-leistungs-fehlerbehebung-troubleshooting">9. Leistungs-Fehlerbehebung (Troubleshooting)
&lt;/h1>&lt;p>Häufig auftretende Probleme und deren Lösungen.&lt;/p>
&lt;h3 id="1-inferenzgeschwindigkeit-ist-extrem-langsam-1-2-tokenss">1. Inferenzgeschwindigkeit ist extrem langsam (1-2 tokens/s)
&lt;/h3>&lt;p>&lt;strong>Ursache&lt;/strong>: Das Modell passt nicht in den VRAM und wird auf den Systemspeicher (RAM) ausgelagert.
&lt;strong>Lösung&lt;/strong>: Überprüfen Sie den &amp;ldquo;Dedizierten GPU-Speicher&amp;rdquo; im Task-Manager. Wenn das Limit erreicht ist, verringern Sie die Kontextgröße (&lt;code>-c&lt;/code>) oder verwenden Sie ein quantisiertes Modell mit niedrigerer Bitrate (z. B. Q4_K_M).&lt;/p>
&lt;h3 id="2-cuda-out-of-memory-fehler">2. &amp;ldquo;CUDA out of memory&amp;rdquo; Fehler
&lt;/h3>&lt;p>&lt;strong>Ursache&lt;/strong>: Der VRAM ist vollständig erschöpft. Tritt besonders dann auf, wenn der Dialog lang wird und der KV-Cache anwächst.
&lt;strong>Lösung&lt;/strong>: Begrenzen Sie bewusst die Werte für &lt;code>num_ctx&lt;/code> bei Ollama oder &lt;code>-c&lt;/code> bei llama.cpp.&lt;/p>
&lt;h3 id="3-japanische-oder-eine-andere-generierung-ist-seltsam">3. Japanische (oder eine andere) Generierung ist seltsam
&lt;/h3>&lt;p>&lt;strong>Ursache&lt;/strong>: Falsches Prompt-Template oder inkompatibles Modell.
&lt;strong>Lösung&lt;/strong>: Verwenden Sie Modelle, die &lt;code>Instruct&lt;/code> im Namen tragen, und stellen Sie sicher, dass das vom Modellautor angegebene korrekte Template (wie ChatML oder Llama3-Format) im Tool ausgewählt ist.&lt;/p>
&lt;hr>
&lt;h1 id="10-zusammenfassung-und-zukünftige-aussichten">10. Zusammenfassung und zukünftige Aussichten
&lt;/h1>&lt;p>Im Jahr 2026 ist der Aufbau lokaler LLMs unter Windows kein Privileg mehr für eine kleine Gruppe von Ingenieuren. Durch den De-facto-Standard des GGUF-Formats, das Erscheinen ausgereifter Ökosysteme wie Ollama und LM Studio und Hardware-Optimierungen wie FlashAttention kann heute jeder ganz einfach eine KI-Umgebung auf Unternehmensniveau einrichten.&lt;/p>
&lt;p>Bitte nutzen Sie die in diesem Artikel erläuterten Punkte:&lt;/p>
&lt;ol>
&lt;li>Wählen Sie durch &lt;strong>mathematische VRAM-Berechnungen&lt;/strong> logisch die optimale Modellgröße und Quantisierungsstufe für die Spezifikationen Ihres PCs aus.&lt;/li>
&lt;li>Bauen Sie mit &lt;strong>Ollama&lt;/strong> in kürzester Zeit eine Umgebung auf und steigern Sie die Produktivität drastisch durch die Integration mit einem KI-Editor.&lt;/li>
&lt;li>Holen Sie durch erweiterte Parametersteuerung mit &lt;strong>llama.cpp&lt;/strong> die maximale Leistung aus Ihrer Hardware heraus.&lt;/li>
&lt;li>Errichten Sie mit &lt;strong>AnythingLLM&lt;/strong> ein sicheres lokales RAG-System, das auch vertrauliche Daten verarbeiten kann.&lt;/li>
&lt;li>Nutzen Sie &lt;strong>Unsloth (WSL2)&lt;/strong>, um Ihre eigene benutzerdefinierte KI mit Fachwissen zu trainieren.&lt;/li>
&lt;/ol>
&lt;p>Die &amp;ldquo;Demokratisierung&amp;rdquo; der KI ist nicht länger nur ein Schlagwort, sondern ein reales System, das auf Ihrem Windows-Desktop läuft. Befreien Sie sich von Cloud-API-Kosten sowie Risiken von Informationslecks und treten Sie noch heute in die freie und mächtige Welt der privaten KI ein.&lt;/p></description></item></channel></rss>