<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Local AI on kenji.blog</title><link>http://kenji.blog/tags/local-ai/</link><description>Recent content in Local AI on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ja</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/tags/local-ai/index.xml" rel="self" type="application/rss+xml"/><item><title>TinyLLaMAをオンプレミス環境で最速チューニングする方法</title><link>http://kenji.blog/p/tinyllama-on-premises-fast-tuning-guide/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/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 TinyLLaMAをオンプレミス環境で最速チューニングする方法" />&lt;h2 id="1-はじめになぜ今tinyllamaとオンプレミスなのか">1. はじめに：なぜ今、TinyLLaMAとオンプレミスなのか？
&lt;/h2>&lt;p>大規模言語モデル（LLM）の進化は凄まじいスピードで進んでいますが、それに伴いモデルのパラメータ数も数千億規模へと膨張し続けています。GPT-4やClaude 3のような超巨大モデルは比類なき性能を誇る一方で、推論や学習にかかる計算コスト、そして外部APIを利用する際のセキュリティやデータプライバシーの懸念が企業にとって大きなハードルとなっています。特に機密性の高い社内データや個人情報を扱う業務においては、クラウド上のパブリックなLLM APIへデータを送信することは、コンプライアンス（GDPRやAPPIなど）の観点から許容されないケースが多々あります。&lt;/p>
&lt;p>そこで脚光を浴びているのが、&lt;strong>小規模言語モデル（SLM: Small Language Models）&lt;/strong> と &lt;strong>オンプレミス環境でのローカル運用&lt;/strong> です。その中でも「&lt;strong>TinyLLaMA&lt;/strong>」は、わずか1.1B（11億）パラメータというコンパクトなサイズでありながら、約3兆トークンという膨大なデータセットで事前学習されており、同クラスのモデルと比較して驚異的な性能を発揮します。&lt;/p>
&lt;p>本記事では、このTinyLLaMAをオンプレミス環境（ローカルサーバーやワークステーション）で、自社専用のタスクに向けて「最速かつ高効率」にファインチューニング（微調整）するための完全ガイドを提供します。数学的な背景から、最新の最適化技術、そして具体的なPyTorchの実装コードまで、網羅的に解説していきます。&lt;/p>
&lt;hr>
&lt;h2 id="2-tinyllamaのアーキテクチャと特徴">2. TinyLLaMAのアーキテクチャと特徴
&lt;/h2>&lt;p>TinyLLaMAは、Meta社が開発したLLaMA（Large Language Model Meta AI）アーキテクチャを踏襲しています。パラメータ数を1.1Bに抑えつつも、LLaMA 2と同じ技術スタックを利用しているため、エコシステムの互換性が非常に高いのが特徴です。&lt;/p>
&lt;h3 id="主要なアーキテクチャコンポーネント">主要なアーキテクチャコンポーネント
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>RMSNorm (Root Mean Square Normalization):&lt;/strong>
従来のLayerNormの計算から平均の減算を省略し、計算効率を向上させた正規化手法です。学習の安定性を保ちながらスループットを向上させます。&lt;/li>
&lt;li>&lt;strong>SwiGLU活性化関数:&lt;/strong>
Feed Forward Network (FFN) において、従来のReLUやGELUの代わりにSwiGLUを採用しています。これは数学的には以下のように表されます。
$$ \text{SwiGLU}(x, W, V) = \text{Swish}(xW) \otimes (xV) $$
ここで、$\otimes$ は要素ごとの積（Hadamard積）を表し、Swish関数は $\text{Swish}(z) = z \cdot \sigma(\beta z)$ です。これにより表現力が大幅に向上します。&lt;/li>
&lt;li>&lt;strong>RoPE (Rotary Position Embedding):&lt;/strong>
絶対的な位置エンコーディングと相対的な位置エンコーディングの利点を組み合わせた手法です。シーケンス長が拡張された際にも高い汎化性能を持ちます。&lt;/li>
&lt;li>&lt;strong>Grouped Query Attention (GQA):&lt;/strong>
Multi-Head Attention (MHA) と Multi-Query Attention (MQA) の中間的なアプローチであり、キーとバリューのヘッドをグループ化することで、メモリ帯域幅を節約し推論速度を劇的に向上させます。&lt;/li>
&lt;/ol>
&lt;p>以下のMermaid図は、TinyLLaMAの全体的なデータフローとTransformerブロックの構造を示しています。&lt;/p>
&lt;div class="mermaid">graph TD
A["Input Text"] --> B["Tokenizer (BPE)"]
B --> C["Embedding Layer"]
C --> D["Transformer Blocks (x22 Layers for TinyLLaMA)"]
D --> E["RMSNorm (Final)"]
E --> F["Linear Projection (Vocab Size)"]
F --> G["Output Probabilities (Softmax)"]
subgraph "Transformer Block Anatomy"
D1["Input Hidden State"] --> D2["RMSNorm"]
D2 --> D3["Grouped Query Attention (GQA)"]
D3 --> D4["Residual Add"]
D4 --> D5["RMSNorm"]
D5 --> D6["SwiGLU FFN"]
D6 --> D7["Residual Add"]
D7 --> D8["Output to Next Layer"]
D1 -.-> D4
D4 -.-> D7
end&lt;/div>
&lt;hr>
&lt;h2 id="3-ファインチューニングのブレイクスルーloraとqlora">3. ファインチューニングのブレイクスルー：LoRAとQLoRA
&lt;/h2>&lt;p>オンプレミス環境でフルパラメータのファインチューニングを行うには、1.1Bモデルであってもオプティマイザのステートや勾配を保持するために数十GBのVRAM（ビデオメモリ）を消費します。限られたリソースで効率的に学習を行うために必須となるのが、&lt;strong>PEFT (Parameter-Efficient Fine-Tuning)&lt;/strong> 手法である「&lt;strong>LoRA&lt;/strong>」とその量子化拡張である「&lt;strong>QLoRA&lt;/strong>」です。&lt;/p>
&lt;h3 id="31-lora-low-rank-adaptation-の数学的背景">3.1 LoRA (Low-Rank Adaptation) の数学的背景
&lt;/h3>&lt;p>LoRAは、事前学習済みの重み行列を固定（フリーズ）し、その重みの更新量（$\Delta W$）を低ランクの2つの小さな行列の積として近似する手法です。&lt;/p>
&lt;p>事前学習済みの重みを $W_0 \in \mathbb{R}^{d \times k}$ とします。フルファインチューニングでは、$W_0$ 自体を更新して $W_0 + \Delta W$ としますが、LoRAでは更新行列 $\Delta W$ を以下のように分解します。&lt;/p>
$$ \Delta W = B \times A $$
&lt;p>ここで、$B \in \mathbb{R}^{d \times r}$、$A \in \mathbb{R}^{r \times k}$ であり、$r$ はランク（Rank）と呼ばれるハイパーパラメータで、$r \ll \min(d, k)$ を満たす非常に小さな値（通常は8, 16, 32など）です。&lt;/p>
&lt;p>フォワードパスの計算は以下のようになります。&lt;/p>
$$ h = W_0 x + \Delta W x = W_0 x + B A x $$
&lt;p>初期状態において、行列 $A$ は正規分布（ガウス分布）でランダムに初期化され、行列 $B$ はゼロ行列で初期化されます。これにより、学習開始時の $\Delta W$ はゼロとなり、ベースモデルの出力を完全に保持した状態から学習をスタートできます。&lt;/p>
&lt;div class="mermaid">graph LR
X["Input Vector x"] --> W0["Frozen Pre-trained Weight (W_0)"]
X --> A["Trainable LoRA Matrix A (r x k)"]
A --> B["Trainable LoRA Matrix B (d x r)"]
W0 --> Add["Vector Addition"]
B --> Add
Add --> Y["Output Vector h"]&lt;/div>
&lt;h3 id="32-qlora-quantized-lora-の革新性">3.2 QLoRA (Quantized LoRA) の革新性
&lt;/h3>&lt;p>QLoRAは、LoRAのアプローチをさらに推し進め、ベースモデル $W_0$ を4-bit精度（NormalFloat 4, NF4）で量子化してメモリにロードする手法です。これにより、VRAM消費量を劇的に削減します。&lt;/p>
&lt;p>QLoRAには3つの重要な技術が組み込まれています。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>4-bit NormalFloat (NF4) 量子化:&lt;/strong> 正規分布に従う重みに最適化された理論的に最適なデータ型。&lt;/li>
&lt;li>&lt;strong>Double Quantization (二重量子化):&lt;/strong> 量子化定数（スケールファクタ）自体も量子化することで、さらにメモリを節約。&lt;/li>
&lt;li>&lt;strong>Paged Optimizers:&lt;/strong> NVIDIAの統合メモリ機能を利用し、VRAMが不足した際にオプティマイザのステータスをCPUのRAMへ一時的に退避させる仕組み。&lt;/li>
&lt;/ol>
&lt;p>これにより、通常はVRAMが16GB〜24GB必要なチューニングが、コンシューマー向けのGPU（RTX 3060 12GBやRTX 4070など）でも余裕を持って実行可能になります。&lt;/p>
&lt;hr>
&lt;h2 id="4-オンプレミス環境におけるハードウェア要件とセットアップ">4. オンプレミス環境におけるハードウェア要件とセットアップ
&lt;/h2>&lt;p>TinyLLaMA (1.1B) をQLoRAでチューニングする場合のハードウェア要件は非常に低く抑えられます。&lt;/p>
&lt;h3 id="推奨ハードウェアスペック">推奨ハードウェアスペック
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>GPU:&lt;/strong> NVIDIA RTX 3060 (12GB), RTX 3090/4090 (24GB), または NVIDIA A10G/A100 など。VRAMは最低8GBあれば動作しますが、バッチサイズを稼ぐためには12GB以上を推奨します。&lt;/li>
&lt;li>&lt;strong>CPU:&lt;/strong> 8コア以上のモダンなCPU（Intel Core i7/i9, AMD Ryzen 7/9）&lt;/li>
&lt;li>&lt;strong>RAM:&lt;/strong> 32GB以上（Paged Optimizersを利用する場合、VRAMからの退避先として重要）&lt;/li>
&lt;li>&lt;strong>ストレージ:&lt;/strong> NVMe SSD（データセットの読み込みやモデルの保存を高速化するため）&lt;/li>
&lt;/ul>
&lt;h3 id="ソフトウェア環境の構築">ソフトウェア環境の構築
&lt;/h3>&lt;p>Ubuntu 22.04 LTS環境を想定したセットアップ手順です。Python 3.10以降を使用します。&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"># 仮想環境の作成とアクティベート&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のインストール (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"># トランスフォーマー関連ライブラリのインストール&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-最速チューニングのための最適化技術">5. 最速チューニングのための最適化技術
&lt;/h2>&lt;p>ただスクリプトを回すだけでなく、「最速」でチューニングを完了させるためには、以下の最適化手法を組み合わせる必要があります。&lt;/p>
&lt;h3 id="51-flash-attention-2">5.1 Flash Attention 2
&lt;/h3>&lt;p>標準的なAttentionメカニズムは、シーケンス長 $N$ に対して時間・空間計算量が $O(N^2)$ となります。Flash Attention 2は、GPUのSRAMとHBM（High Bandwidth Memory）間のメモリアクセスを最適化することで、計算量を削減せずにIOネックを解消し、学習速度を数倍に引き上げ、メモリ消費を激減させます。&lt;/p>
&lt;h3 id="52-gradient-checkpointing-勾配チェックポイント">5.2 Gradient Checkpointing (勾配チェックポイント)
&lt;/h3>&lt;p>フォワードパスで計算された中間アクティベーションをすべてVRAMに保存するのではなく、一部のみを保存し、バックワードパスで必要になった際に再計算する手法です。計算時間は約20%増加しますが、メモリ消費量を劇的に削減できるため、結果としてより大きなバッチサイズを設定でき、スループット全体が向上します。&lt;/p>
&lt;h3 id="53-mixed-precision-training-混合精度学習-と-bfloat16">5.3 Mixed Precision Training (混合精度学習) と Bfloat16
&lt;/h3>&lt;p>GPUのTensor Coreを最大限に活用するため、学習時の計算を &lt;code>bfloat16&lt;/code> (Brain Floating Point) で行います。&lt;code>float16&lt;/code> と比較して指数部のビット長が &lt;code>float32&lt;/code> と同じであるため、オーバーフロー・アンダーフローのリスクが極めて低く、学習が安定します。&lt;/p>
&lt;hr>
&lt;h2 id="6-実践tinyllamaのqloraファインチューニングコード">6. 実践：TinyLLaMAのQLoRAファインチューニングコード
&lt;/h2>&lt;p>それでは、上記すべての最適化を盛り込んだ最速チューニング用のPyTorchスクリプトを解説します。ここではHugging Faceの &lt;code>trl&lt;/code> (Transformer Reinforcement Learning) ライブラリの &lt;code>SFTTrainer&lt;/code> を利用します。&lt;/p>
&lt;h3 id="61-データセットの準備とモデルのロード">6.1 データセットの準備とモデルのロード
&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. モデルとトークナイザーの指定&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. QLoRA用の4-bit量子化設定&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"># 計算は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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. モデルのロード (Flash Attention 2を有効化)&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"># 最速化の鍵&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. トークナイザーのロード&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"># fp16/bf16トレーニング時のバグ回避のためrightに設定&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-loraアダプタの適用とデータセットの整形">6.2 LoRAアダプタの適用とデータセットの整形
&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. k-bit学習の準備と勾配チェックポイントの有効化&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の設定&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"># ランク&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"># スケーリングファクタ&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"># 全てのLinear層をターゲットにすると性能が向上&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"># 出力例: 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. データセットのロード (ここでは例として日本語Instructionデータセットを使用)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 実際にはオンプレミスのプライベートJSONLファイルなどをロードします&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"> ChatMLフォーマットやプロンプトテンプレートに合わせて文字列を成形します
&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-トレーニングの実行">6.3 トレーニングの実行
&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. トレーニング引数の設定&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"># VRAMに余裕があれば上げる&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"># 実質的なバッチサイズ = 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"># Paged OptimizerによるVRAM節約&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"># 混合精度学習 (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ステップ。本番はエポック数で指定&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. 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"># 想定する入力長に合わせて調整&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. LoRAアダプタの保存&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-パフォーマンス評価とトラブルシューティング">7. パフォーマンス評価とトラブルシューティング
&lt;/h2>&lt;p>オンプレミス環境で学習を回す際、よく直面する問題とその解決策です。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>OOM (Out Of Memory) が発生する:&lt;/strong>
&lt;ul>
&lt;li>&lt;code>per_device_train_batch_size&lt;/code> を &lt;code>1&lt;/code> に下げる。&lt;/li>
&lt;li>&lt;code>gradient_accumulation_steps&lt;/code> を増やして実質バッチサイズを維持する。&lt;/li>
&lt;li>&lt;code>max_seq_length&lt;/code> を &lt;code>2048&lt;/code> から &lt;code>1024&lt;/code> や &lt;code>512&lt;/code> に短縮する。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Lossが下がらない・発散する:&lt;/strong>
&lt;ul>
&lt;li>学習率 (&lt;code>learning_rate&lt;/code>) が大きすぎる可能性があります。&lt;code>2e-4&lt;/code> から &lt;code>5e-5&lt;/code> 程度まで下げてみてください。&lt;/li>
&lt;li>Bfloat16ではなくFloat16を使用している場合、勾配のアンダーフローが起きている可能性があります。&lt;code>bf16=True&lt;/code> を確認してください。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>推論時に謎の文字列が生成される:&lt;/strong>
&lt;ul>
&lt;li>&lt;code>padding_side=&amp;quot;right&amp;quot;&lt;/code> が正しく設定されているか確認してください。また、データセットのフォーマット（&lt;code>&amp;lt;|im_start|&amp;gt;&lt;/code> などの特殊トークン）がベースモデルの事前学習時と整合しているか確認が必要です。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-チューニング後のモデル展開-deployment">8. チューニング後のモデル展開 (Deployment)
&lt;/h2>&lt;p>チューニングが完了すると、保存されるのは「ベースモデル全体」ではなく、数MB〜数十MBの「&lt;strong>LoRAアダプタ（差分ウェイト）&lt;/strong>」のみです。推論を高速に行うためには、このLoRAウェイトを元のベースモデルにマージ（統合）し、単一のモデルとして書き出す必要があります。&lt;/p>
&lt;h3 id="モデルのマージスクリプト">モデルのマージスクリプト
&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"># 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"># ウェイトをマージして保存&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="vllmによる爆速推論サーバーの立ち上げ">vLLMによる爆速推論サーバーの立ち上げ
&lt;/h3>&lt;p>オンプレミス環境での展開において、推論速度（Tokens per second）を最大化するためには、Hugging Faceの標準の &lt;code>pipeline&lt;/code> ではなく、&lt;strong>vLLM&lt;/strong> や &lt;strong>TGI (Text Generation Inference)&lt;/strong> の使用を強く推奨します。vLLMはPagedAttention技術を用いて、GPUメモリの断片化を防ぎ、並行リクエストの処理能力を劇的に向上させます。&lt;/p>
&lt;p>以下のMermaid図は、学習から推論サーバー展開までのパイプラインを示しています。&lt;/p>
&lt;div class="mermaid">graph TD
A["Raw Private Data"] --> B["Preprocessing &amp; Formatting (JSONL)"]
B --> C["QLoRA Fine-Tuning (SFTTrainer)"]
C --> D["LoRA Adapter Weights (.safetensors)"]
D --> E["Merge with Base TinyLLaMA 1.1B"]
E --> F["Merged Model"]
F --> G["Deploy via vLLM Server"]
G --> H["API Endpoint / UI (e.g. Chatbot)"]&lt;/div>
&lt;p>vLLMを使ったAPIサーバーの起動は以下の1コマンドで完了します。&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>これで、OpenAI API互換のエンドポイントがオンプレミス環境に構築され、セキュアかつ高速にローカルAIを活用できるようになります。&lt;/p>
&lt;hr>
&lt;h2 id="9-まとめ">9. まとめ
&lt;/h2>&lt;p>本記事では、パラメータ数が1.1Bと軽量でありながら高性能な「TinyLLaMA」を対象に、オンプレミス環境において最速かつメモリ効率良くファインチューニングを行う手法を解説しました。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LoRA / QLoRA&lt;/strong> により、コンシューマー向けGPUでも本格的なLLMチューニングが可能に。&lt;/li>
&lt;li>&lt;strong>Flash Attention 2&lt;/strong> と &lt;strong>Gradient Checkpointing&lt;/strong> を駆使することで、学習時間とVRAM消費を極限まで最適化。&lt;/li>
&lt;li>&lt;strong>vLLM&lt;/strong> を活用したデプロイにより、本番環境でも高いスループットを実現。&lt;/li>
&lt;/ul>
&lt;p>オンプレミスでのローカルLLM運用は、データの機密性を守るだけでなく、特定のドメイン（法務、医療、社内規程など）に特化した専門AIを低コストで構築するための最強の武器となります。ぜひ本ガイドを参考に、自社専用のTinyLLaMAを育成してみてください。&lt;/p></description></item><item><title>C++で始める小規模AIモデル（TinyLLaMAなど）の開発手順</title><link>http://kenji.blog/p/cpp-small-ai-model-tinyllama-dev-guide/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/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 C++で始める小規模AIモデル（TinyLLaMAなど）の開発手順" />&lt;h1 id="cで始める小規模aiモデルtinyllamaなどの開発手順">C++で始める小規模AIモデル（TinyLLaMAなど）の開発手順
&lt;/h1>&lt;p>近年、大規模言語モデル（LLM）のローカル環境での実行に対する関心が急速に高まっています。特に、TinyLLaMA（1.1Bパラメータ）のような小規模モデルは、限られたリソースのエッジデバイスや一般的なノートPC（Windows環境を含む）上でも実用的な速度で推論が可能です。PythonとPyTorchを用いた開発が主流である一方で、究極のパフォーマンスと省メモリ性を追求する場合、C++とC言語ベースのテンソルライブラリである「ggml」の組み合わせがデファクトスタンダードとなっています。&lt;/p>
&lt;p>本記事では、C++を用いてTinyLLaMAをロードし、テキスト生成を行うための推論エンジンをゼロから構築（あるいは既存のllama.cppの内部構造を深く理解）するための非常に詳細な開発手順を解説します。&lt;/p>
&lt;hr>
&lt;h2 id="1-なぜcとggmlなのか">1. なぜC++とggmlなのか？
&lt;/h2>&lt;p>AIの学習段階においては、柔軟性と豊富なエコシステムを持つPythonが圧倒的に有利です。しかし、デプロイや「推論（Inference）」のフェーズにおいては、以下の理由からC++が強力な選択肢となります。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>オーバーヘッドの削減&lt;/strong>: Pythonのグローバルインタプリタロック（GIL）やランタイムのオーバーヘッドを完全に排除できます。&lt;/li>
&lt;li>&lt;strong>メモリ効率とアリーナアロケーション&lt;/strong>: メモリの確保と解放をマニュアルで制御できるため、ガベージコレクションによる予測不能なスパイクを防げます。&lt;/li>
&lt;li>&lt;strong>ハードウェアへの直接アクセス&lt;/strong>: AVX-512、AVX2、ARM NEONなどのSIMD組み込み関数（Intrinsics）を直接呼び出し、CPUの演算能力を極限まで引き出せます。&lt;/li>
&lt;li>&lt;strong>依存関係の排除&lt;/strong>: ggmlは依存関係ゼロ（Zero dependencies）のC/C++ライブラリであり、コンパイラさえあればWindows上のMSVC環境でも容易にビルド可能です。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-アーキテクチャの全体像">2. アーキテクチャの全体像
&lt;/h2>&lt;p>推論パイプライン全体の流れを以下のMermaidダイアグラムに示します。ユーザーの入力テキストから始まり、最終的に次のトークンが生成されるまでの一連のプロセスです。&lt;/p>
&lt;div class="mermaid">graph TD
A["User Input Text"] --> 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 Module"]
I --> J["Next Token ID"]
J --> K["Detokenizer"]
K --> L["Output Text Chunk"]
J -.-> |"Append to Context"| C&lt;/div>
&lt;p>自己回帰モデルであるため、出力されたトークンは再びコンテキストに追加され、次のトークン予測のための入力として循環します（図の点線部分）。&lt;/p>
&lt;hr>
&lt;h2 id="3-モデルフォーマットとメモリマッピング-mmap">3. モデルフォーマットとメモリマッピング (mmap)
&lt;/h2>&lt;p>巨大なニューラルネットワークの重みを扱う上で最大の障壁となるのが、ディスクI/Oとメモリ消費です。C++実装ではこれを**メモリマッピング（mmap）**で解決します。&lt;/p>
&lt;h3 id="31-メモリマッピングの仕組みとwindowsでの実装">3.1 メモリマッピングの仕組みとWindowsでの実装
&lt;/h3>&lt;p>mmapを使用すると、ファイルの内容をプロセスの仮想メモリ空間に直接マッピングできます。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>ゼロコピー（Zero-copy）&lt;/strong>: データはディスクから直接カーネルのページキャッシュに読み込まれ、ユーザー空間への余分なコピーが発生しません。&lt;/li>
&lt;li>&lt;strong>オンデマンド・ロード（Page Fault）&lt;/strong>: 実際にCPUがそのメモリアドレスにアクセスした瞬間に、ページフォールトが発生し、必要なチャンク（通常4KB）だけが物理メモリにロードされます。&lt;/li>
&lt;/ul>
&lt;p>Windows環境では、POSIXの &lt;code>mmap&lt;/code> の代わりにWin32 APIの &lt;code>CreateFileMapping&lt;/code> と &lt;code>MapViewOfFile&lt;/code> を使用します。&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant OS["Windows OS"]
participant RAM["Physical Memory"]
participant App["C++ Application"]
App->>OS: "CreateFileMapping / MapViewOfFile"
OS-->>App: "Virtual Memory Address Pointer"
App->>App: "Read Tensor Data at Pointer"
OS->>RAM: "Page Fault / Load page from Disk"
RAM-->>App: "Data ready for SIMD Compute"&lt;/div>
&lt;h3 id="32-ggufフォーマットのバイナリ構造">3.2 GGUFフォーマットのバイナリ構造
&lt;/h3>&lt;p>Hugging Face等の&lt;code>.safetensors&lt;/code>フォーマットから変換された**GGUF (GPT-Generated Unified Format)**は、推論のための究極のフォーマットです。以下のような厳密なバイナリレイアウトを持っています。&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>: フォーマットのバージョン番号。&lt;/li>
&lt;li>&lt;strong>Tensor Count &amp;amp; Metadata Count&lt;/strong>: テンソル数とメタデータのキーバリューペア数。&lt;/li>
&lt;li>&lt;strong>Metadata (Key-Value Pairs)&lt;/strong>: 文字列長プレフィックス付きのキーと、型付けされた値。&lt;/li>
&lt;li>&lt;strong>Tensor Info&lt;/strong>: 各テンソルの名前、次元数、データ型（FP16, Q4_Kなど）、ファイル内のオフセット位置。&lt;/li>
&lt;li>&lt;strong>Padding&lt;/strong>: テンソルデータが特定の境界（通常は32バイトまたは64バイト）にアライメントされるように挿入されるパディング。SIMD命令（特にAVX）での高速なメモリアクセスに不可欠です。&lt;/li>
&lt;li>&lt;strong>Tensor Data&lt;/strong>: アライメントされた実際の重みデータ配列。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-tinyllamaの数学的基盤とcアルゴリズム">4. TinyLLaMAの数学的基盤とC++アルゴリズム
&lt;/h2>&lt;p>TinyLLaMAは、効率化のためにいくつかの高度なアーキテクチャ上の工夫を取り入れています。これらをC++で正しく実装するための数式表現を解説します。&lt;/p>
&lt;h3 id="41-rmsnorm-root-mean-square-normalization">4.1 RMSNorm (Root Mean Square Normalization)
&lt;/h3>&lt;p>LayerNormから平均のセンタリングを省略し、分散のスケーリングのみを行うことで計算コストを削減します。&lt;/p>
$$ \text{RMSNorm}(x) = \frac{x}{\sqrt{\frac{1}{d}\sum_{i=1}^{d} x_i^2 + \epsilon}} \odot \gamma $$
&lt;p>$d$は次元数、$\gamma$は学習済みのスケーリングテンソルです。
C++で実装する場合、まず配列の二乗和をAVX2の &lt;code>_mm256_fmadd_ps&lt;/code> 等で高速に計算し、逆平方根（&lt;code>_mm256_rsqrt_ps&lt;/code> 命令など）を掛けることで最適化します。&lt;/p>
&lt;h3 id="42-rope-rotary-position-embedding">4.2 RoPE (Rotary Position Embedding)
&lt;/h3>&lt;p>トークンの位置情報をテンソル空間における回転（Rotate）として適用する技術です。複素数平面上での回転とみなすことができ、ベクトル $x$ の隣り合う次元ペア $(x_1, x_2)$ に対して以下のような回転を適用します。&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>ここで、$m$はトークンの絶対的な位置インデックス、$\theta$は事前に計算された基本周波数です。ggmlでは、推論グラフの構築中に &lt;code>ggml_rope&lt;/code> オペレータを追加するだけで並列実行されます。&lt;/p>
&lt;h3 id="43-grouped-query-attention-gqa">4.3 Grouped-Query Attention (GQA)
&lt;/h3>&lt;p>通常のMulti-Head Attention (MHA) では、Query、Key、Valueのそれぞれに対して同じ数のヘッドを持ちます。しかし、TinyLLaMAはメモリ帯域とKVキャッシュの消費量を激減させるために &lt;strong>Grouped-Query Attention (GQA)&lt;/strong> を採用しています。&lt;/p>
$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>GQAでは、複数のQueryヘッドが1つのKey/Valueヘッドを共有します。C++実装では行列積 &lt;code>ggml_mul_mat&lt;/code> を実行する前に、KVテンソルをQueryの数に合わせてブロードキャストする操作が必要になります。&lt;/p>
&lt;h3 id="44-swiglu-活性化関数">4.4 SwiGLU 活性化関数
&lt;/h3>&lt;p>Feed-Forward Network (FFN) 層では、GELUの代わりにSwiGLUが用いられます。&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>計算グラフでは &lt;code>ggml_silu&lt;/code> オペレータと &lt;code>ggml_mul&lt;/code> を組み合わせて表現します。&lt;/p>
&lt;hr>
&lt;h2 id="5-ggmlによる計算グラフの構築とメモリ管理">5. ggmlによる計算グラフの構築とメモリ管理
&lt;/h2>&lt;p>ggmlは、推論のための静的な計算グラフを構築し、それを後から評価（evaluate）する「Define-and-Run」のアプローチを取ります。&lt;/p>
&lt;h3 id="51-ggml_context-とアリーナアロケータ">5.1 ggml_context とアリーナアロケータ
&lt;/h3>&lt;p>ggmlの最もユニークな点は、推論ループ内で動的なメモリ確保（&lt;code>malloc&lt;/code> や &lt;code>new&lt;/code>）を一切行わない「アリーナアロケーション」です。
初期化時に巨大な連続したメモリ領域（アリーナ）を確保し、&lt;code>ggml_new_tensor&lt;/code> などを呼び出すたびに、この領域のポインタがインクリメントされます。推論の1ステップが完了したら、アロケーションポインタを初期位置にリセットするだけで、次の推論ステップのメモリ確保が即座に完了します。&lt;/p>
&lt;h3 id="52-グラフ構築の具体例">5.2 グラフ構築の具体例
&lt;/h3>&lt;p>推論ステップごとに、以下のような計算グラフをメモリ上に組み立てます。&lt;/p>
&lt;div class="mermaid">graph TD
A["Tokens Input ID"] --> B["Embed Lookup"]
B --> C["ggml_rms_norm"]
C --> D["Q / K / V Projections"]
D --> E["ggml_rope Positional"]
E --> F["KV Cache Store"]
E --> G["KV Cache Load"]
G --> H["Self Attention"]
H --> I["Scale &amp; Softmax"]
I --> J["Attention Output"]
J --> K["Out Projection"]
K --> L["Add Residual"]&lt;/div>
&lt;hr>
&lt;h2 id="6-量子化-quantization-と-windows--simd-最適化">6. 量子化 (Quantization) と Windows / SIMD 最適化
&lt;/h2>&lt;p>TinyLLaMA (1.1B) をFP16で扱うと約2.2GBのメモリが必要ですが、4ビット量子化（Q4_Kなど）により約600MB程度まで劇的に圧縮できます。&lt;/p>
&lt;h3 id="61-ブロック量子化アーキテクチャ">6.1 ブロック量子化アーキテクチャ
&lt;/h3>&lt;p>ggmlはテンソル全体を一律に量子化するのではなく、「ブロック」単位で行います。
&lt;code>Q4_0&lt;/code> フォーマットでは、32個のFP16値を1つのブロックにまとめます。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>スケールファクタ&lt;/strong>: 1つのFP16値（2バイト）&lt;/li>
&lt;li>&lt;strong>量子化データ&lt;/strong>: 32個の4ビット値（16バイト）
これにより、局所的な外れ値の影響を最小限に抑えています。&lt;/li>
&lt;/ul>
&lt;h3 id="62-avx2によるドット積の高速化">6.2 AVX2によるドット積の高速化
&lt;/h3>&lt;p>Windows環境の最新のx86 CPU向けにビルドする場合、&lt;code>/arch:AVX2&lt;/code> などのコンパイラフラグを活用し、以下のようなフローでSIMD処理が行われます。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>ロード&lt;/strong>: 256ビットのAVXレジスタに、メモリから4ビット量子化データをロード。&lt;/li>
&lt;li>&lt;strong>展開とアンパック&lt;/strong>: ビットマスクとシフト演算で、4ビット値をInt8またはInt16に展開。&lt;/li>
&lt;li>&lt;strong>逆量子化&lt;/strong>: スケールファクタを乗算して浮動小数点に変換。&lt;/li>
&lt;li>&lt;strong>FMA演算&lt;/strong>: アクティベーション値と &lt;code>_mm256_fmadd_ps&lt;/code>（Fused Multiply-Add）で積和演算を並列実行。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="7-kvキャッシュの実装詳細">7. KVキャッシュの実装詳細
&lt;/h2>&lt;p>自己回帰的生成において、過去のトークンのKeyとValueの計算を省略するための「KVキャッシュ」は必須機能です。&lt;/p>
&lt;p>C++で実装する場合のポイントは以下の通りです。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>テンソルの事前確保&lt;/strong>: 最大コンテキスト長（例: 2048トークン）分の巨大なテンソルをKVキャッシュ用に初期化します（FP16を推奨）。&lt;/li>
&lt;li>&lt;strong>オフセットコピー&lt;/strong>: トークン位置 $N$ に対する計算が行われると、そのステップで得られたKとVのベクトルをKVキャッシュテンソルの $N$ 行目に &lt;code>ggml_cpy&lt;/code> 等を用いてストアします。&lt;/li>
&lt;li>&lt;strong>アテンション時のビュー作成&lt;/strong>: アテンションを計算する際は、0から $N$ 番目までのトークン部分だけを指し示す「ビュー」を作成して行列積に渡します。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-bpe-トークナイザーとデコーディング">8. BPE トークナイザーとデコーディング
&lt;/h2>&lt;p>入力文字列をUTF-8のバイト列として扱い、事前に定義されたボキャブラリーと照らし合わせます。C++では、ボキャブラリーの検索を高速化するために &lt;strong>Trie木（プレフィックスツリー）&lt;/strong> や、優先度付きキューを用いたアルゴリズムを実装します。&lt;/p>
&lt;p>LM Headから出力されるロジットからは、Temperatureパラメータを用いて確率をスケーリングし、Top-K抽出やTop-P（Nucleus Sampling）手法によって候補を絞り込み、乱数を用いて最終的な次のトークンを決定します。&lt;/p>
&lt;hr>
&lt;h2 id="9-cプロジェクトの立ち上げwindows--powershell-環境">9. C++プロジェクトの立ち上げ（Windows / PowerShell 環境）
&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"># Windows (MSVC) 向けの最適化とAVX2フラグの設定
&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>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-まとめ">10. まとめ
&lt;/h2>&lt;p>C++とggmlを用いてTinyLLaMAのような小規模AIモデルの推論エンジンをゼロから実装することは、深層学習のブラックボックスを暴き、低レベルのハードウェア制御の美しさを学ぶ絶好の機会です。メモリマッピングを利用したゼロコピー・ロード、SIMD最適化、KVキャッシュの構築など、システムプログラミングのエッセンスを存分に味わいながら、エッジAIの未来を切り拓いていきましょう。&lt;/p></description></item><item><title>【RAG実装入門】ローカルAIに自分のドキュメントを読み込ませる方法</title><link>http://kenji.blog/p/rag-local-ai-implementation-guide/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/p/rag-local-ai-implementation-guide/</guid><description>&lt;img src="http://kenji.blog/p/rag-local-ai-implementation-guide/img/eyecatch.jpg" alt="Featured image of post 【RAG実装入門】ローカルAIに自分のドキュメントを読み込ませる方法" />&lt;h1 id="はじめに">はじめに
&lt;/h1>&lt;p>近年、大規模言語モデル（LLM）の進化は目覚ましく、ChatGPTやClaudeなどを筆頭に多くのAIが私たちの生活や業務に浸透しています。しかし、一般的なLLMには明確な弱点が存在します。それは「学習時点での公開情報」しか知らないという点です。社内規程、個人的なメモ、未公開のプロジェクト資料といった「プライベートなドキュメント」に関する質問には、当然ながら答えることができません。無理に答えさせようとすると、事実とは異なるもっともらしい嘘（ハルシネーション）を生成してしまうリスクが高まります。&lt;/p>
&lt;p>そこで現在、世界中で爆発的に普及しているのが &lt;strong>RAG (Retrieval-Augmented Generation: 検索拡張生成)&lt;/strong> という技術アーキテクチャです。RAGを用いることで、LLMに独自の知識を外部データベースから動的に与え、それに基づいた正確で根拠のある回答を生成させることが可能になります。&lt;/p>
&lt;p>さらに、エンタープライズ領域や個人の機密情報を扱う場合、OpenAIなどのクラウドベースのAPIにデータを送信することは、セキュリティポリシー上許容されないことが多々あります。そこで求められるのが、&lt;strong>ローカルAI&lt;/strong>（自分のPCやオンプレミスサーバーで完結して動作するLLM）と組み合わせた「ローカルRAG」の構築です。&lt;/p>
&lt;p>本記事では、RAGの基礎理論から、Pythonを用いたローカルRAGの具体的な実装方法、数学的な背景（ベクトル検索の仕組み）、そしてシステムを本番稼働させるための高度なテクニックまでを、徹底的に解説します。&lt;/p>
&lt;hr>
&lt;h1 id="1-ragの全体アーキテクチャ">1. RAGの全体アーキテクチャ
&lt;/h1>&lt;p>RAGは単一のAIモデルではなく、複数のコンポーネントが連携するシステムアーキテクチャです。大きく分けて「インジェスト（データ取り込み）フェーズ」と「リトリーバル＆ジェネレーション（検索と生成）フェーズ」の2つから構成されます。&lt;/p>
&lt;p>以下のMermaid図は、RAGシステムの全体像を示しています。&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "インジェストフェーズ (事前の準備)"
Doc["独自ドキュメント (PDF, TXT, etc.)"] --> Loader["ドキュメントローダー"]
Loader --> Splitter["テキスト分割 (チャンキング)"]
Splitter --> EmbedModel1["埋め込みモデル (Embedding)"]
EmbedModel1 --> VectorDB["ベクトルデータベース"]
end
subgraph "推論フェーズ (ユーザーの問い合わせ時)"
User["ユーザーからの質問 (クエリ)"] --> EmbedModel2["埋め込みモデル (Embedding)"]
EmbedModel2 --> QueryVector["クエリベクトル"]
QueryVector --> Search["類似度検索 (ベクトル検索)"]
VectorDB --> Search
Search --> Context["関連チャンク抽出 (コンテキスト)"]
User --> PromptBuilder["プロンプト構築"]
Context --> PromptBuilder
PromptBuilder --> LocalLLM["ローカルLLM"]
LocalLLM --> Answer["最終的な回答生成"]
end&lt;/div>
&lt;h2 id="インジェストフェーズ事前準備">インジェストフェーズ（事前準備）
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>ドキュメントの読み込み&lt;/strong>: PDF、Word、テキストファイルなどの非構造化データを読み込みます。&lt;/li>
&lt;li>&lt;strong>チャンキング（テキスト分割）&lt;/strong>: LLMの入力制限（コンテキストウィンドウ）に収めるため、そして検索精度を上げるために、長い文章を意味のある塊（チャンク）に分割します。&lt;/li>
&lt;li>&lt;strong>エンベディング（ベクトル化）&lt;/strong>: 分割されたチャンクを、埋め込みモデル（Embedding Model）に入力し、数百〜数千次元の数値の配列（ベクトル）に変換します。&lt;/li>
&lt;li>&lt;strong>データベースへの保存&lt;/strong>: 変換されたベクトルと、元のテキストデータを紐付けてベクトルデータベース（Vector DB）に保存します。&lt;/li>
&lt;/ol>
&lt;h2 id="推論フェーズ実行時">推論フェーズ（実行時）
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>クエリのベクトル化&lt;/strong>: ユーザーからの質問文を、事前準備と同じ埋め込みモデルを使ってベクトル化します。&lt;/li>
&lt;li>&lt;strong>類似度検索&lt;/strong>: クエリベクトルと、データベース内のドキュメントベクトルの間で類似度計算を行い、意味的に近い（関連性の高い）テキストチャンクを上位数件取得します。&lt;/li>
&lt;li>&lt;strong>プロンプトの構築&lt;/strong>: 取得した関連テキストを「コンテキスト（背景知識）」としてユーザーの質問文と結合し、LLMへの入力プロンプトを作成します。&lt;/li>
&lt;li>&lt;strong>回答の生成&lt;/strong>: 拡張されたプロンプトを受け取ったLLMが、付与されたコンテキスト情報を基にして回答を生成します。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-ベクトル検索と埋め込みembeddingsの深い理解">2. ベクトル検索と埋め込み（Embeddings）の深い理解
&lt;/h1>&lt;p>RAGの中核をなすのが「ベクトル検索（セマンティック検索）」です。従来のキーワード検索（BM25など）が単語の完全一致や頻度に基づくのに対し、ベクトル検索は「意味の類似性」に基づきます。例えば「犬」と「子犬」、「PC」と「パソコン」のように、異なる単語でも意味が近ければ検索にヒットします。&lt;/p>
&lt;h2 id="埋め込みモデルembedding-modelとは何か">埋め込みモデル（Embedding Model）とは何か？
&lt;/h2>&lt;p>埋め込みモデルは、自然言語のテキストを入力として受け取り、固定長の密なベクトル（Dense Vector）を出力するニューラルネットワークです。一般的なモデル（例えば &lt;code>text-embedding-3-small&lt;/code> やオープンソースの &lt;code>multilingual-e5-large&lt;/code>）は、テキストを384次元や1024次元の実数ベクトルにマッピングします。&lt;/p>
&lt;p>この多次元空間（潜在空間）においては、意味が似ている文章ほど、座標空間上の距離が近くなるように学習されています。&lt;/p>
&lt;h2 id="類似度計算の数学的背景コサイン類似度">類似度計算の数学的背景：コサイン類似度
&lt;/h2>&lt;p>ベクトルデータベースが関連ドキュメントを検索する際、最も一般的に用いられる距離指標が**コサイン類似度（Cosine Similarity）**です。ユークリッド距離（空間的な絶対距離）とは異なり、コサイン類似度は「2つのベクトルのなす角」に注目します。文章の長さ（ベクトルのノルム）に影響されにくいため、テキストの類似度計算に非常に適しています。&lt;/p>
&lt;p>数式で表すと、ベクトル $\mathbf{A}$ と $\mathbf{B}$ のコサイン類似度は以下のようになります。&lt;/p>
$$ \text{Cosine Similarity}(\mathbf{A}, \mathbf{B}) = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \sqrt{\sum_{i=1}^{n} B_i^2}} $$
&lt;ul>
&lt;li>$\mathbf{A} \cdot \mathbf{B}$ は内積（Dot Product）を表します。&lt;/li>
&lt;li>$\|\mathbf{A}\|$ はベクトル $\mathbf{A}$ のL2ノルム（長さ）を表します。&lt;/li>
&lt;li>$n$ はベクトルの次元数です。&lt;/li>
&lt;/ul>
&lt;p>コサイン類似度は -1 から 1 の値を取ります。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>1 に近い&lt;/strong>: 2つのベクトルの向きがほぼ同じ（意味が非常に似ている）&lt;/li>
&lt;li>&lt;strong>0 に近い&lt;/strong>: 2つのベクトルが直交している（無関係）&lt;/li>
&lt;li>&lt;strong>-1 に近い&lt;/strong>: 2つのベクトルが正反対の向き（意味が逆）&lt;/li>
&lt;/ul>
&lt;p>最近のベクトルDB（Chroma, FAISS, Qdrantなど）は、HNSW（Hierarchical Navigable Small World）と呼ばれる近似最近傍探索（ANN）アルゴリズムを採用しており、数百万件のベクトルデータからでもミリ秒単位でコサイン類似度が高いドキュメントを検索できるよう最適化されています。&lt;/p>
&lt;hr>
&lt;h1 id="3-ローカルragを構築するための技術スタック">3. ローカルRAGを構築するための技術スタック
&lt;/h1>&lt;p>クラウドに依存しない完全なローカルRAGを構築するには、オープンソースのエコシステムを活用します。以下に推奨される技術スタックを紹介します。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>言語モデル (LLM)&lt;/strong>
&lt;ul>
&lt;li>ツール: &lt;code>Ollama&lt;/code> または &lt;code>Llama.cpp&lt;/code>&lt;/li>
&lt;li>モデル: &lt;code>Llama-3-8B-Instruct&lt;/code>, &lt;code>Gemma-2-9B-It&lt;/code>, &lt;code>Qwen2-7B-Instruct&lt;/code> などの軽量・高性能なオープンモデル。日本語タスクには日本語チューンされた &lt;code>Llama-3-ELYZA-JP-8B&lt;/code> などが適しています。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>埋め込みモデル (Embedding)&lt;/strong>
&lt;ul>
&lt;li>モデル: &lt;code>intfloat/multilingual-e5-large&lt;/code> または &lt;code>BAAI/bge-m3&lt;/code>。ローカルで動かす場合、Hugging FaceからダウンロードしてSentence-Transformersで実行するのが一般的です。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>ベクトルデータベース (Vector DB)&lt;/strong>
&lt;ul>
&lt;li>&lt;code>ChromaDB&lt;/code>: Pythonベースでセットアップが極めて簡単。ローカル開発に最適。&lt;/li>
&lt;li>&lt;code>FAISS&lt;/code>: Metaが開発した高速なベクトル検索ライブラリ。&lt;/li>
&lt;li>&lt;code>Qdrant&lt;/code> / &lt;code>Milvus&lt;/code>: より大規模で本番環境向け。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>オーケストレーションフレームワーク&lt;/strong>
&lt;ul>
&lt;li>&lt;code>LangChain&lt;/code>: コンポーネントを繋ぎ合わせる（Chain）ためのデファクトスタンダード。&lt;/li>
&lt;li>&lt;code>LlamaIndex&lt;/code>: 特にRAGに特化したデータ接続フレームワーク。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>今回は、最も導入が簡単な &lt;strong>LangChain + ChromaDB + Ollama + HuggingFaceEmbeddings&lt;/strong> の組み合わせで実装します。&lt;/p>
&lt;hr>
&lt;h1 id="4-実装チュートリアルpythonによる完全なローカルrag構築">4. 実装チュートリアル：Pythonによる完全なローカルRAG構築
&lt;/h1>&lt;p>ここからは、実際にPythonコードを書きながらローカルRAGを構築していきます。あらかじめ、PCにOllamaをインストールし、バックグラウンドで起動しておいてください。また、Ollama上でモデルをプルしておきます（例：&lt;code>ollama run llama3&lt;/code>）。&lt;/p>
&lt;h2 id="step-1-必要なライブラリのインストール">Step 1: 必要なライブラリのインストール
&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;/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">pip install langchain langchain-community langchain-huggingface
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install chromadb sentence-transformers pypdf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="step-2-実装コード全体像">Step 2: 実装コード全体像
&lt;/h2>&lt;p>以下は、PDFファイルを読み込み、ベクトル化してローカルのLLMに質問応答させるための完全なPythonスクリプトです。&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;/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">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">langchain_community.document_loaders&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PyPDFLoader&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">langchain_text_splitters&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&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">langchain_huggingface&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&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">langchain_community.vectorstores&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Chroma&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">langchain_community.llms&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Ollama&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">langchain_core.prompts&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PromptTemplate&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">langchain.chains&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RetrievalQA&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">main&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. ドキュメントの読み込み&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;ドキュメントを読み込んでいます...&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="c1"># 読み込ませたいPDFのパスを指定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;sample_company_policy.pdf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">loader&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">loader&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&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. チャンク分割（Text Splitting）&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">text_splitter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_size&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"># 1チャンクあたりの最大文字数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_overlap&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 前後のチャンクでの重複文字数（文脈の断絶を防ぐ）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">separators&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&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 class="s2">&amp;#34;。&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="s2">&amp;#34; &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>&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">chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">text_splitter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split_documents&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&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="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">)&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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 埋め込みモデルの初期化 (Local HuggingFace Model)&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="nb">print&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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embeddings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&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_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;intfloat/multilingual-e5-large&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_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;device&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;cpu&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># GPUがある場合は &amp;#39;cuda&amp;#39; または &amp;#39;mps&amp;#39;&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. ベクトルデータベースの構築 (Chroma)&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;ベクトルデータベースを構築しています...&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">persist_directory&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./chroma_db&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectorstore&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Chroma&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_documents&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">persist_directory&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"># 検索器（Retriever）の作成。上位3件の関連ドキュメントを取得するように設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vectorstore&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">as_retriever&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;k&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&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. ローカルLLMの初期化 (Ollama)&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;ローカルLLMに接続しています...&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="c1"># 事前に &amp;#39;ollama pull llama3&amp;#39; などでモデルを取得しておくこと&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ollama&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;llama3&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"># 6. プロンプトテンプレートの定義&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt_template&lt;/span> &lt;span class="o">=&lt;/span> &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">以下のコンテキスト（背景情報）のみを使用して、ユーザーの質問に日本語で詳細に答えてください。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">コンテキストから答えが見つからない場合は、勝手に推測せず「提供された情報からは分かりません」と正直に答えてください。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【コンテキスト】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{context}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【質問】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{question}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【回答】:
&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="n">PromptTemplate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">prompt_template&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">input_variables&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;context&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;question&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"># 7. RAGチェーンの構築&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qa_chain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_chain_type&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;stuff&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">retriever&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">retriever&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">return_source_documents&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"># 情報源を返すか設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;prompt&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="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"># 8. 質問の実行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">query&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;リモートワークに関する交通費の支給条件について教えてください。&amp;#34;&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="se">\n&lt;/span>&lt;span class="s2">質問: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="si">}&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="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">qa_chain&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">invoke&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;query&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">query&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="nb">print&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>&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="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;result&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="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&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 class="nb">print&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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">doc&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;source_documents&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="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">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;不明&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">page_content&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">]&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>&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">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;h2 id="コードのポイント解説">コードのポイント解説
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>RecursiveCharacterTextSplitter&lt;/strong>:
自然言語の分割において最も推奨されるスプリッターです。段落(&lt;code>\n\n&lt;/code>)、行(&lt;code>\n&lt;/code>)、句点(&lt;code>。&lt;/code>)の順で分割を試み、意味のまとまりを可能な限り維持したまま指定の &lt;code>chunk_size&lt;/code> に収まるように分割します。&lt;code>chunk_overlap&lt;/code> を設定することで、文脈の境目が切れて情報が失われるのを防ぎます。&lt;/li>
&lt;li>&lt;strong>HuggingFaceEmbeddings&lt;/strong>:
&lt;code>intfloat/multilingual-e5-large&lt;/code> は多言語に対応した非常に強力なオープンソースの埋め込みモデルです。クラウドAPI（OpenAIの &lt;code>text-embedding-ada-002&lt;/code> など）を使わずに、オフラインでローカルメモリ上でテキストをベクトル化できます。&lt;/li>
&lt;li>&lt;strong>ChromaDB&lt;/strong>:
インメモリまたはローカルストレージ（SQLiteベース）で動作するため、複雑なデータベースサーバーの立ち上げが不要です。&lt;code>persist_directory&lt;/code> を指定することで、再実行時にベクトル化のプロセスをスキップし、ディスクからDBを読み込むことができます。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="5-発展的なrag手法advanced-rag-techniques">5. 発展的なRAG手法（Advanced RAG Techniques）
&lt;/h1>&lt;p>上記のチュートリアルで構築した基本のRAGシステム（Naive RAG）でも動作しますが、本番環境で高い回答精度を要求される場合、以下のような高度なテクニックの導入が必要になります。&lt;/p>
&lt;h2 id="51-ハイブリッド検索-hybrid-search">5.1 ハイブリッド検索 (Hybrid Search)
&lt;/h2>&lt;p>ベクトル検索は「意味」を捉えるのが得意ですが、「特定の固有名詞」「製品型番」「従業員ID」などの厳密なキーワード検索を苦手とすることがあります。
そこで、ベクトル検索による&lt;strong>セマンティック検索&lt;/strong>と、BM25アルゴリズムなどを用いた&lt;strong>キーワード検索&lt;/strong>を並行して行い、両者の結果をスコアリングして統合する（Reciprocal Rank Fusion; RRFなどの手法を用いる）ことで、検索漏れを劇的に減らすことができます。&lt;/p>
&lt;h2 id="52-リランキング-re-ranking">5.2 リランキング (Re-ranking)
&lt;/h2>&lt;p>ベクトル検索は高速ですが、必ずしもコンテキストの正確な文脈適合性を評価しているわけではありません。検索精度を向上させるための一般的なパイプラインは以下のようになります。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>初期検索 (First-stage Retrieval)&lt;/strong>: ベクトルDBから、広く浅く関連チャンクを20件〜30件程度取得します。&lt;/li>
&lt;li>&lt;strong>再評価 (Re-ranking)&lt;/strong>: Cross-Encoderと呼ばれる別のより重い機械学習モデル（例: &lt;code>bge-reranker&lt;/code> など）を使用して、ユーザーのクエリと取得したチャンクのペアを入力し、意味的適合度のスコアを再計算します。&lt;/li>
&lt;li>&lt;strong>選別&lt;/strong>: スコアの高い上位3〜5件のみを最終的なコンテキストとしてLLMのプロンプトに渡します。&lt;/li>
&lt;/ol>
&lt;p>この手法により、無関係なノイズ情報がLLMに渡るのを防ぎ、回答の精度（Precision）を大幅に高めることができます。&lt;/p>
&lt;div class="mermaid">graph LR
Query["クエリ"] --> VSearch["ベクトル検索 (上位20件)"]
VSearch --> Reranker["リランカーモデル (Cross-Encoder)"]
Query --> Reranker
Reranker --> TopK["高精度な上位3件"]
TopK --> LLM["LLM生成"]&lt;/div>
&lt;h2 id="53-セマンティックチャンキングと親ドキュメント検索">5.3 セマンティックチャンキングと親ドキュメント検索
&lt;/h2>&lt;p>固定文字数で機械的にテキストを分割するのではなく、文章の意味の変わり目をAIで検知して分割する「Semantic Chunking」という手法があります。
また、「Parent Document Retriever（親ドキュメント検索）」という手法では、検索用に非常に小さな単位（センテンス等）でベクトル化を行って精度の高い検索を実現しつつ、LLMに渡す際にはそのセンテンスが含まれる「元の大きな段落（親ドキュメント）」を渡すことで、LLMに十分な文脈（コンテキスト）を提供します。&lt;/p>
&lt;hr>
&lt;h1 id="6-ローカルrag運用時の課題と対策">6. ローカルRAG運用時の課題と対策
&lt;/h1>&lt;p>ローカル環境でRAGを構築・運用する際には、特有のハードルが存在します。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>VRAM（ビデオメモリ）の枯渇&lt;/strong>:
ローカルLLMを実用的な速度（1秒間に数十トークン）で動かすには、GPUのVRAMにモデルを載せる必要があります。8Bクラスのモデルをfp16（16ビット浮動小数点）で動かすには約16GBのVRAMが必要ですが、**量子化（Quantization）**技術（GGUFやAWQ形式など、4bitや8bitに圧縮する技術）を使うことで、8GBのVRAM（一般的なゲーミングPC等）でも十分に高速動作させることが可能です。Llama.cppやOllamaは標準でこれらの量子化フォーマットに対応しています。&lt;/li>
&lt;li>&lt;strong>コンテキストウィンドウの制限&lt;/strong>:
検索して取得したコンテキストの量が多すぎると、LLMの入力上限（トークンリミット）を超えてしまったり、モデルが情報の中間部分を忘れてしまう（Lost in the middle現象）ことがあります。抽出するチャンク数の調整や、前述のリランキング技術による厳選が不可欠です。&lt;/li>
&lt;li>&lt;strong>データの鮮度管理&lt;/strong>:
ソースドキュメントが更新された場合、ベクトルデータベース内の該当するドキュメントのベクトルも更新・削除（CRUD操作）する必要があります。ChromaDBではドキュメントIDベースでの更新をサポートしているため、ファイルのハッシュ値を管理し、差分だけを同期するバッチ処理を組むのが実践的です。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="まとめ">まとめ
&lt;/h1>&lt;p>RAG（検索拡張生成）は、AIを一般的な汎用アシスタントから「あなた専属の専門家」や「社内業務に特化したエキスパート」へと進化させる強力なパラダイムです。&lt;/p>
&lt;p>クラウドサービスを利用できない機密性の高い要件であっても、Ollama、LangChain、ChromaDBなどのオープンソースエコシステムを組み合わせることで、完全な「ローカルRAG」環境を比較的容易に構築できることが分かりました。&lt;/p>
&lt;p>本記事で解説したベクトル空間の数学的理解や、テキスト分割、リランキングといった発展的アプローチをベースに、ぜひご自身の保有するデータを使ってオリジナルなAIシステムを開発してみてください。ローカルAIの進化のスピードは驚異的であり、今日構築したシステムは、明日登場するさらに賢い軽量モデルに差し替えるだけで、一瞬にして性能をアップデートすることが可能なのです。&lt;/p>
&lt;hr>
&lt;p>&lt;em>本ブログでは今後もAI技術やRAGに関する深掘り記事を掲載していきます。ご質問やフィードバックがありましたら、ぜひコメント欄にお寄せください。&lt;/em>&lt;/p></description></item><item><title>【2026年最新】ローカルLLMをWindows環境で動かす完全ガイド</title><link>http://kenji.blog/p/local-llm-windows-2026/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/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年最新】ローカルLLMをWindows環境で動かす完全ガイド" />&lt;h1 id="1-はじめになぜ今windowsでローカルllmなのか">1. はじめに：なぜ今、WindowsでローカルLLMなのか？
&lt;/h1>&lt;p>2026年現在、生成AIと大規模言語モデル（LLM）の進化は、クラウド上の巨大なAPIサービスから、個人のPCやオンプレミス環境で動作する「ローカルLLM」へと大きなパラダイムシフトを見せています。OpenAIのGPT-5やAnthropicのClaude 3.5といったクラウドAIは非常に強力ですが、企業や個人がすべてのデータをクラウドに送信できるわけではありません。プライバシー、セキュリティ、レイテンシ、そして長期的・持続的なコストの観点から、ローカルLLMの需要はかつてなく爆発的に高まっています。&lt;/p>
&lt;p>特にWindows環境におけるローカルLLMのエコシステムの進化は目覚ましいものがあります。数年前までは「AI開発・実行といえばLinux」が常識でしたが、2026年現在ではWindowsが非常に強力かつ手軽なAIプラットフォームへと変貌を遂げました。&lt;/p>
&lt;p>本記事では、2026年最新の技術動向を踏まえ、Windows環境でローカルLLMを構築・運用・最適化するための完全なガイドを提供します。初心者向けのOllamaを用いた簡単な構築から、上級者向けのllama.cppを活用した極限の最適化、さらにはVRAM計算の数学的アプローチやアーキテクチャの深い理解、そしてローカルでのファインチューニングまで、圧倒的なボリュームで徹底解説します。&lt;/p>
&lt;h2 id="11-2026年のローカルllmを取り巻く技術トレンド">1.1 2026年のローカルLLMを取り巻く技術トレンド
&lt;/h2>&lt;p>現在のローカルLLMエコシステムを形作る主要なトレンドは以下の通りです。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>GGUFフォーマットの完全普及&lt;/strong>: メタデータとテンソルを単一のファイルに統合したGGUF（GPT-Generated Unified Format）が完全にデファクトスタンダード化しました。これにより、Hugging Faceから一つのファイルをダウンロードするだけで、どのような環境でも実行可能になっています。&lt;/li>
&lt;li>&lt;strong>MoE（Mixture of Experts）アーキテクチャの民主化&lt;/strong>: 小規模ながら高性能なMoEモデルが多数リリースされ、推論時に一部のエキスパートのみをアクティブにすることで、コンシューマーPCの計算負荷を抑えながら巨大モデルに匹敵する性能を叩き出しています。&lt;/li>
&lt;li>&lt;strong>推論エンジンの高度な抽象化と最適化&lt;/strong>: Ollama、LM Studio、AnythingLLMなどのツールが洗練され、CUDAドライバのインストールなどの複雑な依存関係をユーザーが意識する必要がなくなりました。また、FlashAttention 3のWindowsネイティブ対応により、推論速度が劇的に向上しています。&lt;/li>
&lt;li>&lt;strong>NPUの活用とWindows Copilot+ PCの台頭&lt;/strong>: GPUを持たないノートPCでも、搭載されているNPU（Neural Processing Unit）を利用して小規模なLLM（SLM: Small Language Models）を低消費電力で動かす技術が実用段階に入りました。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-ハードウェア要件とosの準備">2. ハードウェア要件とOSの準備
&lt;/h1>&lt;p>ローカルLLMを実用的な速度（1秒間に15〜30トークン以上）で動作させるためには、ハードウェアの選定が最も重要です。&lt;/p>
&lt;h2 id="21-推奨ハードウェア構成">2.1 推奨ハードウェア構成
&lt;/h2>&lt;p>AI PCの進化に伴い、要求スペックも変化しています。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OS&lt;/strong>: Windows 11 Pro (24H2以降)。WSL2の完全な機能と高度なメモリ管理、さらにはDirectMLの最新APIを利用するために必須です。&lt;/li>
&lt;li>&lt;strong>CPU&lt;/strong>: Intel Core Ultra 200シリーズ以上、またはAMD Ryzen 9000シリーズ以上。CPU推論を併用する場合、広帯域メモリ通信が不可欠です。&lt;/li>
&lt;li>&lt;strong>RAM&lt;/strong>: 最低32GB、推奨64GB以上。メインメモリの帯域幅（MB/s）がCPU推論時やオフロード時の決定的なボトルネックになります。DDR5-6000以上の高速メモリが理想的です。&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong>: NVIDIA RTX 4000/5000シリーズ。ローカルLLMにおいて最も重要なのは演算性能ではなく「VRAM容量」です。
&lt;ul>
&lt;li>&lt;strong>エントリー&lt;/strong>: RTX 4060 Ti (16GB版) - コスパ最強。8B〜14Bクラスのモデルに最適。&lt;/li>
&lt;li>&lt;strong>ミドルレンジ&lt;/strong>: RTX 4070 Ti SUPER (16GB) / RTX 4080 SUPER (16GB)&lt;/li>
&lt;li>&lt;strong>ハイエンド&lt;/strong>: RTX 4090 (24GB) / RTX 5090 (32GB) - 30B〜70Bクラスの量子化モデルを動かすために必要です。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>ストレージ&lt;/strong>: PCIe Gen4またはGen5のNVMe SSD。数十GBのモデルロード時間を劇的に短縮します。&lt;/li>
&lt;/ul>
&lt;h2 id="22-wsl2-windows-subsystem-for-linux-2-のセットアップ">2.2 WSL2 (Windows Subsystem for Linux 2) のセットアップ
&lt;/h2>&lt;p>多くのGUIツールはWindowsネイティブで動作しますが、Pythonを用いた開発、最新ツールのコンパイル、後述するLoRAファインチューニングにはWSL2が非常に便利です。Windows 11の最新環境では、ホスト側にNVIDIAドライバを入れるだけで、WSL2から透過的にGPU（CUDA）が利用できます。&lt;/p>
&lt;p>管理者権限で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;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"># WSL2と最新の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"># カーネルのアップデート&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>インストール後、WSL2ターミナル内で &lt;code>nvidia-smi&lt;/code> を実行し、GPUが正常に認識されていれば成功です。&lt;/p>
&lt;hr>
&lt;h1 id="3-ローカルllmのアーキテクチャと推論メカニズム">3. ローカルLLMのアーキテクチャと推論メカニズム
&lt;/h1>&lt;p>ローカル環境でモデルがどのようにテキストを生成するのか、その内部構造を理解することは、トラブルシューティングや最適化において非常に有用です。&lt;/p>
&lt;p>以下のMermaid図は、典型的なローカルLLMの推論パイプラインを示しています。&lt;/p>
&lt;div class="mermaid">graph TD
User["ユーザー入力 (プロンプト)"] --> Tokenizer["トークナイザー (Tokenizer)"]
Tokenizer --> Embedding["埋め込み層 (Embedding)"]
subgraph "Transformer Block (x Layers)"
Embedding --> Attn["自己アテンション (Self-Attention)"]
Attn --> KVCache["KV キャッシュ (Key/Value保持)"]
Attn --> FFN["フィードフォワードネットワーク (FFN)"]
end
FFN --> Logits["ロジット計算 (Logits)"]
Logits --> Sampler["サンプラー (Temperature, Top-K, Top-P)"]
Sampler --> OutputToken["出力トークン"]
OutputToken --> |"オートレグレッシブ生成"| Tokenizer
OutputToken --> Decoder["デトークナイザー (Detokenizer)"]
Decoder --> FinalOutput["最終出力テキスト"]&lt;/div>
&lt;h2 id="31-2つのフェーズprefill-と-decode">3.1 2つのフェーズ：Prefill と Decode
&lt;/h2>&lt;p>LLMのテキスト生成は、計算特性の異なる2つのフェーズに分かれます。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Prefill（プロンプト処理）フェーズ&lt;/strong>: 入力されたプロンプト全体を一度に処理し、理解するフェーズです。並列計算が可能であるため、GPUの計算能力（FLOPS）が速度に直結します。プロンプトが長い場合、このフェーズに数秒かかることがあります。&lt;/li>
&lt;li>&lt;strong>Decode（トークン生成）フェーズ&lt;/strong>: 1トークンずつ予測し、次の入力に回す（オートレグレッシブ）フェーズです。このフェーズでは並列計算が制限されるため、GPUのVRAM帯域幅（Memory Bandwidth）が決定的なボトルネックになります。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="4-vram消費量の計算とモデルサイズの数学的理解">4. VRAM消費量の計算とモデルサイズの数学的理解
&lt;/h1>&lt;p>「自分のPCでどのモデルが動くのか？」を正しく判断するには、VRAMの計算式を理解する必要があります。VRAM不足によるシステムメモリ（RAM）へのフォールバックが発生すると、推論速度は10倍〜100倍遅くなります。&lt;/p>
&lt;h2 id="41-パラメータサイズに基づくベースvram">4.1 パラメータサイズに基づくベースVRAM
&lt;/h2>&lt;p>モデルのウェイト（重み）をVRAMに読み込むためのメモリ量です。
モデルサイズ $P$ （パラメータ数、単位: 10億 = 1B）と、1パラメータあたりのバイト数 $B$ を用いて計算します。&lt;/p>
$$
V_{base} = P \times B \quad \text{(GB)}
$$
&lt;p>例えば、8B（80億）パラメータのモデルをFP16（半精度浮動小数点、16ビット=2バイト）でロードする場合：&lt;/p>
$$
V_{base} = 8 \times 2 = 16 \text{ GB}
$$
&lt;p>つまり、16GBのVRAMを持つGPUであっても、モデルをロードするだけでほぼ限界に達してしまいます。&lt;/p>
&lt;h2 id="42-量子化quantizationの魔法">4.2 量子化（Quantization）の魔法
&lt;/h2>&lt;p>そこで「量子化」が登場します。パラメータの精度を落とすことでモデルサイズを劇的に縮小します。最も一般的な4bit量子化（例: Q4_K_M）の場合、1パラメータあたり平均して約0.55バイトとなります。&lt;/p>
$$
V_{base\_4bit} = 8 \times 0.55 = 4.4 \text{ GB}
$$
&lt;p>これにより、16GBのVRAMがあれば、十分に余裕を持って8Bモデルを動かすことができます。&lt;/p>
&lt;h2 id="43-kvキャッシュの計算gqa対応版">4.3 KVキャッシュの計算（GQA対応版）
&lt;/h2>&lt;p>推論時には、過去の文脈を保持するための「KVキャッシュ」がVRAMを消費します。Llama 3等の最新モデルでは、メモリ節約のためにGQA（Grouped Query Attention）が採用されています。&lt;/p>
&lt;p>KVキャッシュの消費量 $V_{kv}$ （ギガバイト）は以下の数式で表されます。&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>整理すると、キーとバリューのヘッド数 $h_{kv}$ を用いてシンプルに計算できます。&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times h_{kv} \times d \times B_{kv} \div 10^9
$$
&lt;p>ここで：&lt;/p>
&lt;ul>
&lt;li>$b$: バッチサイズ（個人のローカル利用なら通常1）&lt;/li>
&lt;li>$s$: シーケンス長（コンテキスト長、例: 8192）&lt;/li>
&lt;li>$l$: レイヤー数（例: 32）&lt;/li>
&lt;li>$h_{kv}$: KVヘッド数（例: 8）&lt;/li>
&lt;li>$d$: ヘッドあたりの次元数（例: 128）&lt;/li>
&lt;li>$B_{kv}$: KVキャッシュのバイト数（FP16なら2）&lt;/li>
&lt;/ul>
&lt;p>計算例（Llama 3 8B, コンテキスト8192, FP16キャッシュ）：
$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>コンテキスト長 $s$ を長くすればするほど、必要なVRAMは線形に増加することに注意してください。&lt;/p>
&lt;hr>
&lt;h1 id="5-実践1ollamaを用いた最速最短セットアップ">5. 実践1：Ollamaを用いた最速・最短セットアップ
&lt;/h1>&lt;p>理論を理解したところで、実際にWindows環境でLLMを動かしてみましょう。
2026年現在、最もユーザーフレンドリーなツールが「Ollama」です。Dockerライクな直感的なCLIを提供します。&lt;/p>
&lt;h2 id="51-インストールと実行">5.1 インストールと実行
&lt;/h2>&lt;ol>
&lt;li>&lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"
>Ollama公式サイト&lt;/a> からWindows版インストーラーをダウンロードして実行します。&lt;/li>
&lt;li>PowerShellを開き、以下のコマンドを入力します。ここでは、日本語対応の &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>初回実行時はモデルのダウンロードが行われます。完了すると、そのままターミナル上で対話が可能です。&lt;/p>
&lt;h2 id="52-modelfileによるカスタムaiの作成">5.2 ModelfileによるカスタムAIの作成
&lt;/h2>&lt;p>特定のペルソナを持つAIを簡単に作成できます。任意の場所に &lt;code>Modelfile&lt;/code> を作成します。&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">あなたは非常に優秀なシニアソフトウェアエンジニアです。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ユーザーの質問に対して、必ずコード例を交えて、論理的かつ簡潔に答えてください。
&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>以下のコマンドで独自のモデルをビルドし、実行します。&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-外部アプリaiエディタからの利用">5.3 外部アプリ（AIエディタ）からの利用
&lt;/h2>&lt;p>Ollamaは &lt;code>http://localhost:11434&lt;/code> にOpenAI互換のAPIエンドポイントを公開します。
CursorやContinue.devといったVS Code拡張機能のバックエンド設定で、URLを上記に指定し、モデル名に &lt;code>SeniorDev&lt;/code> 等を指定するだけで、無料で強力なローカルコーディングアシスタントが実現します。&lt;/p>
&lt;hr>
&lt;h1 id="6-実践2llamacppによる極限のパフォーマンスチューニング">6. 実践2：llama.cppによる極限のパフォーマンスチューニング
&lt;/h1>&lt;p>細かなメモリ管理や、最新フォーマット（EXL2やIQ量子化など）をいち早く試したい場合は、コアエンジンである &lt;code>llama.cpp&lt;/code> を直接操作します。&lt;/p>
&lt;h2 id="61-llamacpp-のビルド手順">6.1 llama.cpp のビルド手順
&lt;/h2>&lt;p>Windows環境では、CUDA ToolkitとCMakeを用いてソースからビルドするのがベストです。&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"># CUDA対応として構成しコンパイル&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-サーバーモードでの高度な起動">6.2 サーバーモードでの高度な起動
&lt;/h2>&lt;p>ビルドされた &lt;code>llama-server.exe&lt;/code> を使用して、モデルをホストします。&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>: 可能限りすべてのレイヤーをGPU VRAMにオフロードします。&lt;/li>
&lt;li>&lt;code>--flash-attn&lt;/code>: FlashAttention 3を有効にし、推論速度の向上とKVキャッシュのVRAM消費削減を達成します。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="7-guiフロントエンドlm-studio-とローカルragの構築">7. GUIフロントエンド：LM Studio とローカルRAGの構築
&lt;/h1>&lt;p>コマンドラインに抵抗がある場合や、RAG（検索拡張生成）を直感的に行いたい場合はGUIを利用します。&lt;/p>
&lt;h2 id="71-lm-studio">7.1 LM Studio
&lt;/h2>&lt;p>LM Studioは、モデルの検索、ダウンロード、システム要件の事前チェック、そしてチャットUIまでを一つにまとめた素晴らしいアプリケーションです。アプリ内の「Local Server」ボタンを押すだけでOpenAI互換APIが立ち上がります。&lt;/p>
&lt;h2 id="72-anythingllm-を用いたragアーキテクチャ">7.2 AnythingLLM を用いたRAGアーキテクチャ
&lt;/h2>&lt;p>社内文書や個人メモを読み込ませるRAG環境のアーキテクチャ図です。&lt;/p>
&lt;div class="mermaid">graph LR
Document["ドキュメント (PDF, MD)"] --> Chunking["チャンク分割"]
Chunking --> EmbedModel["埋め込みモデル"]
EmbedModel --> VectorDB["ベクトルデータベース"]
UserQuery["ユーザー質問"] --> EmbedQuery["質問の埋め込み"]
EmbedQuery --> VectorDB
VectorDB --> |"類似度検索"| RetrievedDocs["関連ドキュメント抽出"]
UserQuery --> PromptBuilder["プロンプト生成"]
RetrievedDocs --> PromptBuilder
PromptBuilder --> LocalLLM["ローカルLLM"]
LocalLLM --> Answer["最終的な回答"]&lt;/div>
&lt;p>AnythingLLMデスクトップ版（Windows）を使えば、設定画面からOllama（LLMとEmbedding）を指定し、ローカルのVectorDB（LanceDB）を利用するよう設定するだけで、数分でこのアーキテクチャが完成します。データを外部に一切送信しないプライベートAIの誕生です。&lt;/p>
&lt;hr>
&lt;h1 id="8-windows-wsl2上でのファインチューニング-lora">8. Windows WSL2上でのファインチューニング (LoRA)
&lt;/h1>&lt;p>ローカルで動かすだけでなく、自分のデータでモデルを賢くしたい場合、LoRA（Low-Rank Adaptation）を用いたファインチューニングが可能です。2026年現在、「Unsloth」というライブラリを使えば、WindowsのWSL2環境において、16GBのVRAMでも8Bモデルの学習が数時間で完了します。&lt;/p>
&lt;p>WSL2のUbuntu内で以下を実行して環境を構築します。&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はCUDAカーネルを極限まで最適化しており、標準のHugging Faceライブラリと比較して学習速度が約2倍、VRAM消費量が約半分になります。Jupyter Notebookを立ち上げ、データセット（JSONL形式）を読み込ませるだけで、数エポックの学習がVRAM 12GB〜16GBのRTX 4060 Ti等でも可能です。&lt;/p>
&lt;hr>
&lt;h1 id="9-パフォーマンストラブルシューティング">9. パフォーマンス・トラブルシューティング
&lt;/h1>&lt;p>よく直面する問題とその解決策です。&lt;/p>
&lt;h3 id="1-推論速度が極端に遅い12-tokenss">1. 推論速度が極端に遅い（1〜2 tokens/s）
&lt;/h3>&lt;p>&lt;strong>原因&lt;/strong>: モデルがVRAMに収まりきらず、システムメモリ（RAM）へオフロードされています。
&lt;strong>対策&lt;/strong>: タスクマネージャーで「専用GPUメモリ」を確認してください。限界に達している場合は、コンテキストサイズ（&lt;code>-c&lt;/code>）を小さくするか、より低いビット数の量子化モデル（Q4_K_Mなど）を使用してください。&lt;/p>
&lt;h3 id="2-cuda-out-of-memoryエラー">2. 「CUDA out of memory」エラー
&lt;/h3>&lt;p>&lt;strong>原因&lt;/strong>: VRAMが完全に枯渇しました。特に対話が長引いてKVキャッシュが肥大化した際に発生します。
&lt;strong>対策&lt;/strong>: Ollamaの場合は &lt;code>num_ctx&lt;/code>、llama.cppの場合は &lt;code>-c&lt;/code> の値を意図的に小さく制限します。&lt;/p>
&lt;h3 id="3-日本語の生成がおかしい">3. 日本語の生成がおかしい
&lt;/h3>&lt;p>&lt;strong>原因&lt;/strong>: プロンプトテンプレートの不一致、または非対応モデルです。
&lt;strong>対策&lt;/strong>: モデル名に &lt;code>Instruct&lt;/code> が含まれるものを使用し、ChatMLやLlama3フォーマットなど、モデル作者が指定した正しいテンプレートがツール側で選択されているか確認してください。&lt;/p>
&lt;hr>
&lt;h1 id="10-まとめと今後の展望">10. まとめと今後の展望
&lt;/h1>&lt;p>2026年、Windows環境におけるローカルLLMの構築は、限られた一部のエンジニアだけの特権ではなくなりました。GGUFフォーマットのデファクト化、OllamaやLM Studioといった洗練されたエコシステムの登場、そしてFlashAttentionをはじめとするハードウェア最適化により、誰でも簡単にエンタープライズ級のAI環境を手に入れることができます。&lt;/p>
&lt;p>本記事で解説した以下のポイントを是非活用してください。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>VRAMの数学的計算&lt;/strong>を用いて、自分のPCスペックに最適なモデルサイズと量子化レベルを論理的に選択する。&lt;/li>
&lt;li>&lt;strong>Ollama&lt;/strong>を使って最速で環境を構築し、AIエディタと連携させて生産性を劇的に向上させる。&lt;/li>
&lt;li>&lt;strong>llama.cpp&lt;/strong>の高度なパラメータ制御で、ハードウェアの限界性能を引き出す。&lt;/li>
&lt;li>&lt;strong>AnythingLLM&lt;/strong>で機密データを扱うセキュアなローカルRAGシステムを構築する。&lt;/li>
&lt;li>**Unsloth (WSL2)**を活用し、自分だけの専門知識を持ったカスタムAIを育成する。&lt;/li>
&lt;/ol>
&lt;p>AIの「民主化」は、もはやバズワードではなく、あなたのWindowsデスクトップ上で稼働する現実のシステムです。クラウドAPIの利用コストや情報漏洩リスクから解放され、自由で強力なプライベートAIの世界へ、今すぐ足を踏み入れてみてください。&lt;/p></description></item></channel></rss>