中古GPU（RTX 3060/12GB）でローカルLLM検証-2 ～ llama.cpp で TinyLlama 1.1B を試す

前回は、Docker コンテナでGPUが使えるところまで設定出来ましたので、今回は、コンテナでローカルLLMを試していきます。
[[前回記事] 中古GPU（RTX 3060/12GB）でローカルLLM検証-1 ～ 初期設定とGPUコンテナ](https://qiita.com/nabe2030/items/5c9d86b1996f1334e9ae)
# 1. ローカルLLMをコンテナで試す
ChatGPT o3 に、どのLLMを試すか相談したら、次の３ルートをおススメされました。

（１）llama.cpp ルート
（２）Ollama ルート
（３）vLLM ルート

違いを表にするとこんな感じ
| 用途        | 手軽さ         | REST/UI            | バッチ性能    | 迷ったら      |
| --------- | ----------- | ------------------ | -------- | --------- |
| **llama.cpp** | ◎ 軽い        | あり (8080)          | ○        | **まず試す**  |
| **Ollama**    | ◎ （pull 自動） | あり (11434) + WebUI | △        | GUI で遊ぶ   |
| **vLLM**      | ○ 要 HF モデル  | あり (8000)          | **◎ 高速** | API 負荷テスト |

ちなみにRTX 3060 のVRAM 12 GB で動くモデルとしては、
| モデル                      | サイズ (4-bit) | 備考               |
| ------------------------ | ----------- | ---------------- |
| **TinyLlama-1.1B-Chat**  | ≈0.5 GB     | 英語中心。実装確認に最適     |
| **Phi-2 2.7B**           | ≈1.2 GB     | 英語・数学強め          |
| **CALM2-3B-Instruct-ja** | ≈1.6 GB     | 日本語◎（ELYZA系より軽量） |
| **open-calm-3b**         | ≈2.4 GB     | 日本語汎用・Apache 2.0 |

こんな感じにおススメされました。もっと他にも試したいモデルはあるのですが、まずは、英語の応答でいいので、ダウンロードに認証とか要らないものをお手軽に試してみます。

# 2. llama.cpp で TinyLlama 1.1B を試す
## 2-1. モデルを取ってくる
（認証不要：公開モデルなので wget だけで取得できる）
```
mkdir -p ~/llm/models && cd ~/llm/models
wget -O tiny.gguf https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf
```
## 2-2. Docker で llama.cpp サーバーを起動
```
docker run --rm --gpus all \
  -v ~/llm/models:/models \
  -p 8080:8080 \
  ghcr.io/ggml-org/llama.cpp:server-cuda \
  --model /models/tiny.gguf \
  --port 8080 \
  --n-gpu-layers 35
  
# 次のような行が出れば起動成功
llama.cpp server listening at http://0.0.0.0:8080
```
- -v ~/llm/models:/models … 先ほど落とした tiny.gguf をコンテナへマウント
- --n-gpu-layers 35 … 量子化 Q4 なので 35 層を VRAM に載せてもまだ余裕がある
- 終了は Ctrl-C で可。自動でコンテナも消えるので注意。
## 2-3. curl で推論を試す
別ターミナルを開き、curl で TinyLlama に「Which planet is known as the Red Planet?」（赤い星はどの惑星？）と聞いてみました。
```
curl -s http://localhost:8080/completion \
  -d '{"prompt":"

 Which planet is known as the Red Planet? 
","n_predict":32}'
```
JSON の `content` に `"The Red Planet, Mars, …"` というテキストが返ってきていますので モデルが正しく推論できています。

ここまでで「モデルをダウンロードして動かす」目的は達成できました。

# 3. llama.cpp について
## 3-1. llama.cppとは何か（概要）
llama.cpp は、Meta（旧Facebook）社が開発した大規模言語モデル「LLaMA」を、C++によって高速かつ軽量に動かすことを目的としたオープンソースの推論エンジン です。

特にGPUがない環境でも、高速で推論できることが特徴です。

GitHubリポジトリ：
https://github.com/ggerganov/llama.cpp
## 3-2. llama.cppの特徴
主な特徴は次の通りです。
- 軽量・高速
    - 純粋なC++実装で、依存関係が少なくシンプル
    - CPU（特にApple SiliconのM1/M2）でも非常に効率よく動作
- GGUFフォーマット対応
    - GGUF形式で量子化（Quantization）されたモデルを利用
    - モデルサイズを大幅に圧縮し、小さいメモリ環境でも動作可能
- GPU対応（CUDA・Metal・Vulkan）
    - CPU推論が基本だが、GPUがあればCUDA（NVIDIA GPU）やMetal（Apple GPU）を用いて高速化も可能
- 低消費リソース
    - 推論時に使用するリソースが小さいため、個人PCやモバイル端末、Raspberry Piなどのエッジデバイスでも動作可能
- オープンソース
    - 誰でも自由に改変や再利用が可能
## 3-3. llama.cppの仕組み（動作のポイント）
llama.cppの仕組みのポイントは以下の通りです。
### (1) GGUF量子化（Quantization）
- 従来の問題
    - オリジナルの大規模モデル（数十GB以上）はメモリ消費が大きすぎる
- llama.cppのアプローチ
    - FP32（32bit浮動小数点数）で表現されているモデルのパラメータを、4bitや8bitの量子化形式に変換
    - 精度をわずかに犠牲にしながら、大幅にサイズを圧縮
    - GGUFフォーマットに変換されたモデルを使って推論を行う
- メリット
    - 数十GBのモデルを数GB程度に抑え、CPUでも扱いやすくする
    - メモリ効率が劇的に改善され、メモリが少ない環境でも動作可能に
### (2) C++によるシンプルで最適化された実装
- 従来の問題
    - Pythonベースのフレームワーク（Hugging Face Transformersなど）は、CPU推論だとオーバーヘッドが大きく、速度が遅い
- llama.cppのアプローチ
    - シンプルなC++コードで、推論に特化した軽量な実装を実現
    - SIMD命令（AVX2/AVX512/NEON）を利用し、CPUの計算能力をフル活用
- メリット
    - CPUでも非常に高速な推論を可能に
    - Apple Silicon（M1/M2）のCPU最適化が特に強力
### (3) 推論時のAttentionの効率化（KV Cache方式）
- 従来の問題
    - Attention計算を毎回すべて再計算すると遅い
- llama.cppのアプローチ
    - すでに計算済みのAttention値をキー・バリュー（KV Cache）としてキャッシュに保存
    - トークンを生成するたびに、必要な部分だけを計算し、キャッシュを再利用
- メリット
    - 推論速度が大幅に向上
    - CPUの負荷が軽減され、低消費電力で動作可能
### (4) GPUサポート（CUDA、Metal、Vulkan）
- GPUアクセラレーションのオプション
    - NVIDIA GPU (CUDA)、Apple GPU (Metal)、AMD GPU (Vulkan) に対応
    - GPUがある環境ではさらに推論速度を高速化
## 3-4. llama.cppの推論の流れ（イメージ）
推論リクエスト
　　↓
GGUF量子化モデルをロード
　　↓
入力トークンをエンコード
　　↓
Attention処理（KVキャッシュ再利用）
　　↓
SIMD最適化により高速推論（CPU/GPU）
　　↓
生成トークンのデコード
　　↓
結果を返却

## 3-5. llama.cppの使い方（CLIの例）
基本的なCLIの使い方：
```
./main -m model.gguf -p "日本の首都は" -n 50
```
- -m でモデル指定、-p はプロンプト、-n は生成するトークン数
- Pythonバインディングも利用可能で、APIからの呼び出しにも対応

## 3-6. llama.cppの活用例（ユースケース）
- 個人のローカル環境でのLLM推論
- Raspberry PiなどエッジデバイスでのAI推論
- CPU環境でのチャットボット開発・検証
- GPUがないクラウドやオンプレ環境での運用

## 3-7. llama.cppと他推論エンジンとの比較

| 項目      | Hugging Face Transformers | vLLM                       | llama.cpp    |
| ------- | ------------------------- | -------------------------- | ------------ |
| CPU推論速度 | △遅い                       | △遅い                        | ◎非常に速い       |
| GPU推論速度 | △普通                       | ◎非常に速い                     | 〇速い（GPU使用時）  |
| メモリ効率   | △低い                       | ◎高い                        | ◎非常に高い       |
| 量子化対応   | 〇対応                       | 〇対応                        | ◎高度対応 (GGUF) |
| 実装言語    | Python                    | Python/C++                 | C++          |
| 対応モデル   | Transformers系全般           | Hugging Face Transformers系 | LLaMA系中心     |

## 3-8. まとめ
llama.cppは以下の特徴を持ちます。
- C++による高速かつ軽量な推論エンジン
- GGUF量子化によるメモリ効率の向上
- SIMDによるCPU最適化で高速化
- GPU（CUDA、Metal、Vulkan）対応で柔軟性
これらにより、特にGPUがない環境や、小型のデバイスでも効率よくLLaMAモデルを動作させることができる点が大きな強みです。