0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

llama.cppってなんだ?〜ローカルLLM推論の心臓部を完全理解〜

0
Posted at

この記事の対象読者

  • LLM(大規模言語モデル)に興味があり、ローカルで動かしてみたい方
  • OllamaやLM Studioの「中身」が気になるエンジニア
  • C/C++でのAI推論に興味がある方
  • GPUがなくてもAIを動かしたいと考えている方

この記事で得られること

  • llama.cppが何者で、なぜ革命的なのかの理解
  • GGUFフォーマットの仕組みと量子化の基礎知識
  • 環境構築から実際の推論までの実践スキル
  • 各種ハードウェア(CPU/GPU/Apple Silicon)での最適化手法

この記事で扱わないこと

  • モデルのファインチューニング(学習)
  • PyTorchやTensorFlowでの推論
  • クラウドAPIの使い方

1. llama.cppとの出会い

「ローカルでLLMを動かしたい」

2023年、Meta社がLLaMAモデルをオープンソース化したとき、世界中の開発者がこの夢を追いかけ始めた。しかし、当時のLLMはPyTorchベースで、GPU必須、メモリ消費は凄まじく、一般のPCでは到底動かせる代物ではなかった。

そこに彗星のごとく現れたのが、Georgi Gerganov氏が開発したllama.cppだ。

llama.cppとは、一言でいうと「C/C++で書かれた、依存関係ゼロのLLM推論エンジン」である。料理でいえば、巨大な業務用厨房(PyTorch + CUDA)がなくても、コンパクトなIHクッキングヒーター(llama.cpp)で同じ料理が作れるようになったイメージだ。

2025年12月時点でGitHubスター数は85,000を超え、ローカルLLM界のデファクトスタンダードとなっている。

ここまでで、llama.cppがどんなものか、なんとなくイメージできたでしょうか。次は、この記事で使う用語を整理しておきましょう。


2. 前提知識の確認

本題に入る前に、この記事で登場する用語を確認します。

2.1 LLM(Large Language Model)とは

大規模言語モデル。ChatGPTやClaude、Geminiの中核をなす技術である。大量のテキストデータで学習し、文章生成や質問応答ができるAIモデルのこと。

2.2 推論(Inference)とは

学習済みモデルに入力を与えて、出力を得るプロセス。学習(Training)とは異なり、モデルのパラメータは変更しない。llama.cppは「推論」に特化したツールである。

2.3 量子化(Quantization)とは

モデルの精度を落として、ファイルサイズとメモリ使用量を削減する技術。例えば、32bit浮動小数点を4bitや8bit整数に変換する。精度は若干落ちるが、必要なメモリが激減する。

2.4 GGUFとは

llama.cppが使用するモデルファイル形式。「GPT-Generated Unified Format」の略。モデルの重み、トークナイザー、設定情報をひとつのファイルにまとめた規格である。

これらの用語が押さえられたら、llama.cppの背景を見ていきましょう。


3. llama.cppが生まれた背景

3.1 きっかけ

2023年3月、Georgi Gerganov氏がMeta社のLLaMAモデルをMacBookで動かすために開発を開始した。当時、LLMの推論にはNVIDIA GPUとCUDAが必須とされていた常識を覆すプロジェクトだった。

3.2 解決しようとした課題

従来の課題 llama.cppの解決策
PyTorch依存(巨大な環境構築) 依存関係ゼロのC/C++実装
NVIDIA GPU必須 CPUで動作、各種GPUにも対応
大量のメモリ消費 量子化による省メモリ化
Linux中心の開発環境 クロスプラットフォーム対応

3.3 主要なマイルストーン

llama.cppは驚異的なペースで進化を続けている。

時期 マイルストーン
2023年3月 プロジェクト開始
2024年4月 FlashAttention導入
2025年4月 libmtmd導入(マルチモーダル対応強化)
2025年9月 Docker Hubからの直接モデル取得対応
2025年12月 Android/ChromeOSでのフルアクセラレーション

背景がわかったところで、基本的な仕組みを見ていきましょう。


4. 基本概念と仕組み

4.1 アーキテクチャ概要

llama.cppは以下の構成で動作する。

┌─────────────────────────────────────────────────────┐
│                    llama.cpp                        │
├─────────────────────────────────────────────────────┤
│  フロントエンド(モデル固有のコード)                   │
├─────────────────────────────────────────────────────┤
│  GGMLテンソルライブラリ(演算の心臓部)                 │
├─────────────────────────────────────────────────────┤
│  バックエンド                                        │
│  ┌───────┬────────┬───────┬────────┬──────────┐    │
│  │ CPU   │ Metal  │ CUDA  │ Vulkan │ OpenCL   │    │
│  │(AVX2) │(Apple) │(NVIDIA)│(汎用)  │(汎用)    │    │
│  └───────┴────────┴───────┴────────┴──────────┘    │
└─────────────────────────────────────────────────────┘

4.2 GGUFファイルの構造

GGUFファイルは3つのセクションで構成される。

┌──────────────────────────────────────┐
│ ヘッダー                             │
│ - マジックナンバー                    │
│ - バージョン                         │
│ - テンソル数                         │
├──────────────────────────────────────┤
│ メタデータ(Key-Value形式)           │
│ - モデルアーキテクチャ                │
│ - コンテキスト長                      │
│ - トークナイザー情報                  │
├──────────────────────────────────────┤
│ テンソルデータ                        │
│ - 各層の重み(量子化済み)            │
│ - アテンション層                     │
│ - FFN層                             │
└──────────────────────────────────────┘

4.3 量子化タイプの選び方

llama.cppは多様な量子化オプションを提供している。

量子化タイプ ビット数 品質 メモリ効率 推奨用途
Q2_K 2bit メモリ極限環境
Q4_K_M 4bit 最もバランス良好(推奨)
Q5_K_M 5bit 品質重視
Q8_0 8bit 精度最優先
F16 16bit × 検証用

私のおすすめはQ4_K_MQ5_K_M。実用上、ほとんど品質劣化を感じない。

基本概念が理解できたところで、実際にコードを書いて動かしてみましょう。


5. 実践:実際に使ってみよう

5.1 環境構築

まずはllama.cppをビルドする。

# リポジトリのクローン
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp

# ビルド(CPU版)
cmake -B build
cmake --build build --config Release

GPU対応ビルド(オプション)

# NVIDIA CUDA対応
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release

# Apple Metal対応(macOS)
cmake -B build -DGGML_METAL=ON
cmake --build build --config Release

# AMD ROCm対応
cmake -B build -DGGML_HIP=ON
cmake --build build --config Release

# Vulkan対応(汎用GPU)
cmake -B build -DGGML_VULKAN=ON
cmake --build build --config Release

5.2 環境別の設定ファイル

プロジェクトで使用する際の設定例を3パターン用意した。

開発環境用(config.development.json)

{
  "model_path": "./models/llama-3.1-8b-q4_k_m.gguf",
  "context_length": 4096,
  "n_gpu_layers": 0,
  "threads": 4,
  "batch_size": 512,
  "temperature": 0.7,
  "repeat_penalty": 1.1,
  "top_p": 0.9,
  "top_k": 40,
  "verbose": true,
  "seed": 42
}

本番環境用(config.production.json)

{
  "model_path": "${MODEL_PATH}",
  "context_length": 8192,
  "n_gpu_layers": -1,
  "threads": 8,
  "batch_size": 2048,
  "temperature": 0.3,
  "repeat_penalty": 1.0,
  "top_p": 0.95,
  "top_k": 50,
  "verbose": false,
  "seed": -1,
  "flash_attention": true
}

テスト環境用(config.test.json)

{
  "model_path": "./models/test-model-q4_k_m.gguf",
  "context_length": 2048,
  "n_gpu_layers": 0,
  "threads": 2,
  "batch_size": 256,
  "temperature": 0.0,
  "repeat_penalty": 1.0,
  "top_p": 1.0,
  "top_k": 1,
  "verbose": true,
  "seed": 12345
}

5.3 基本的な使い方

CLIでの会話

# Hugging Faceから直接モデルをダウンロードして実行
./build/bin/llama-cli -hf ggml-org/gemma-3-1b-it-GGUF

# ローカルモデルファイルを使用
./build/bin/llama-cli -m ./models/llama-3.1-8b-q4_k_m.gguf

# パラメータ指定
./build/bin/llama-cli \
  -m ./models/llama-3.1-8b-q4_k_m.gguf \
  -c 4096 \
  -ngl 35 \
  --temp 0.7

APIサーバーの起動

# OpenAI互換APIサーバーを起動
./build/bin/llama-server \
  -m ./models/llama-3.1-8b-q4_k_m.gguf \
  --host 0.0.0.0 \
  --port 8080

# APIを叩く
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "system", "content": "You are a helpful assistant."},
      {"role": "user", "content": "Pythonでフィボナッチ数列を生成する関数を書いて"}
    ]
  }'

Pythonからの呼び出し

"""
llama.cppをPythonから利用するサンプル
実行方法: pip install llama-cpp-python && python llama_example.py
"""
from llama_cpp import Llama

def main():
    """メイン処理"""
    # モデルのロード
    llm = Llama(
        model_path="./models/llama-3.1-8b-q4_k_m.gguf",
        n_ctx=4096,        # コンテキスト長
        n_gpu_layers=-1,   # 全レイヤーをGPUにオフロード(-1 = 全部)
        verbose=False
    )
    
    # 推論実行
    response = llm.create_chat_completion(
        messages=[
            {"role": "system", "content": "あなたは親切なアシスタントです。"},
            {"role": "user", "content": "日本の首都はどこですか?"}
        ],
        temperature=0.7,
        max_tokens=512
    )
    
    print(response["choices"][0]["message"]["content"])

if __name__ == "__main__":
    main()

5.4 実行結果

上記のPythonコードを実行すると、以下のような出力が得られる。

$ python llama_example.py
日本の首都は東京です。東京は日本の政治、経済、文化の中心地であり、
世界有数の大都市として知られています。人口は約1,400万人で、
首都圏全体では約3,700万人が暮らしています。

5.5 よくあるエラーと対処法

エラー 原因 対処法
failed to load model モデルファイルが見つからない パスを確認、ファイルの存在を確認
CUDA out of memory GPUメモリ不足 n_gpu_layersを減らす、または量子化レベルを下げる
AVX2 not supported 古いCPU llama.cppの古いバージョンを使う、またはCPU対応版をビルド
mmap failed メモリ不足 --no-mmapオプションを追加、またはスワップを増やす
context size exceeded コンテキスト長オーバー -cオプションで適切なサイズを指定

5.6 環境診断スクリプト

問題が発生した場合は、以下のスクリプトで環境を診断できる。

#!/usr/bin/env python3
"""
llama.cpp環境診断スクリプト
実行方法: python check_llama_env.py
"""
import subprocess
import sys
import os

def check_environment():
    """環境をチェックして問題を報告"""
    issues = []
    info = []
    
    # Python バージョン確認
    if sys.version_info < (3, 9):
        issues.append(f"Python 3.9以上が必要です(現在: {sys.version}")
    else:
        info.append(f"Python: {sys.version}")
    
    # llama-cpp-python確認
    try:
        import llama_cpp
        info.append(f"llama-cpp-python: {llama_cpp.__version__}")
    except ImportError:
        issues.append("llama-cpp-pythonがインストールされていません")
        issues.append("  → pip install llama-cpp-python")
    
    # CUDA確認
    try:
        result = subprocess.run(
            ["nvidia-smi", "--query-gpu=name,memory.total", "--format=csv,noheader"],
            capture_output=True, text=True
        )
        if result.returncode == 0:
            info.append(f"GPU: {result.stdout.strip()}")
        else:
            info.append("GPU: 検出されませんでした(CPU推論を使用)")
    except FileNotFoundError:
        info.append("GPU: nvidia-smiが見つかりません(CPU推論を使用)")
    
    # AVX2サポート確認(Linux/Mac)
    if sys.platform != "win32":
        try:
            result = subprocess.run(
                ["grep", "-o", "avx2", "/proc/cpuinfo"],
                capture_output=True, text=True
            )
            if "avx2" in result.stdout:
                info.append("AVX2: サポートされています")
            else:
                issues.append("AVX2がサポートされていない可能性があります")
        except:
            pass
    
    # 結果出力
    print("=" * 50)
    print("llama.cpp 環境診断結果")
    print("=" * 50)
    
    print("\n📋 環境情報:")
    for i in info:
        print(f"{i}")
    
    if issues:
        print("\n❌ 問題が見つかりました:")
        for issue in issues:
            print(f"  - {issue}")
    else:
        print("\n✅ 環境は正常です")

if __name__ == "__main__":
    check_environment()

実装方法がわかったので、次は具体的なユースケースを見ていきます。


6. ユースケース別ガイド

6.1 ユースケース1: ローカルチャットボット構築

想定読者: 社内用チャットボットを作りたいエンジニア

推奨構成: llama-server + Webフロントエンド

サンプルコード:

"""
FastAPIでラップしたチャットボットAPI
実行方法: pip install fastapi uvicorn && uvicorn chatbot:app --reload
"""
from fastapi import FastAPI
from pydantic import BaseModel
import httpx

app = FastAPI()

class ChatRequest(BaseModel):
    message: str
    history: list = []

@app.post("/chat")
async def chat(request: ChatRequest):
    """llama-serverにリクエストを転送"""
    messages = request.history + [
        {"role": "user", "content": request.message}
    ]
    
    async with httpx.AsyncClient() as client:
        response = await client.post(
            "http://localhost:8080/v1/chat/completions",
            json={"messages": messages, "temperature": 0.7}
        )
        result = response.json()
    
    return {
        "response": result["choices"][0]["message"]["content"],
        "usage": result.get("usage", {})
    }

6.2 ユースケース2: RAG(検索拡張生成)システム

想定読者: 社内ドキュメント検索システムを構築したい方

推奨構成: llama.cpp + 埋め込みモデル + ベクトルDB

サンプルコード:

"""
シンプルなRAGシステム
実行方法: pip install chromadb sentence-transformers llama-cpp-python
"""
import chromadb
from sentence_transformers import SentenceTransformer
from llama_cpp import Llama

class SimpleRAG:
    def __init__(self, model_path: str):
        # 埋め込みモデル
        self.embedder = SentenceTransformer('intfloat/multilingual-e5-small')
        # LLM
        self.llm = Llama(model_path=model_path, n_ctx=4096)
        # ベクトルDB
        self.chroma = chromadb.Client()
        self.collection = self.chroma.create_collection("documents")
    
    def add_documents(self, documents: list[str]):
        """ドキュメントを追加"""
        embeddings = self.embedder.encode(documents).tolist()
        self.collection.add(
            embeddings=embeddings,
            documents=documents,
            ids=[f"doc_{i}" for i in range(len(documents))]
        )
    
    def query(self, question: str, n_results: int = 3) -> str:
        """質問に回答"""
        # 関連ドキュメントを検索
        query_embedding = self.embedder.encode([question]).tolist()
        results = self.collection.query(
            query_embeddings=query_embedding,
            n_results=n_results
        )
        
        context = "\n".join(results["documents"][0])
        
        # LLMで回答生成
        prompt = f"""以下の情報を参考に質問に答えてください。

情報:
{context}

質問: {question}

回答:"""
        
        response = self.llm(prompt, max_tokens=512)
        return response["choices"][0]["text"]

6.3 ユースケース3: コード補完ツール

想定読者: VSCodeなどでローカルコード補完を使いたい開発者

推奨構成: llama-server + Continue.dev拡張機能

サンプルコード:

// .continue/config.json
{
  "models": [
    {
      "title": "Local Llama",
      "provider": "openai",
      "model": "local-model",
      "apiBase": "http://localhost:8080/v1"
    }
  ],
  "tabAutocompleteModel": {
    "title": "Local Autocomplete",
    "provider": "openai",
    "model": "local-model",
    "apiBase": "http://localhost:8080/v1"
  }
}

ユースケースを把握できたところで、この先の学習パスを確認しましょう。


7. 学習ロードマップ

この記事を読んだ後、次のステップとして以下をおすすめする。

初級者向け(まずはここから)

  1. 公式READMEを読む
  2. Hugging Faceでモデルを探す
  3. 小さなモデル(1B〜3B)で実験する

中級者向け(実践に進む)

  1. 自作モデルをGGUFに変換する
  2. 量子化オプションをベンチマークで比較
  3. APIサーバーをDockerで本番運用

上級者向け(さらに深く)

  1. GGMLライブラリのソースを読む
  2. カスタムバックエンドの実装
  3. llama.cppにコントリビュート

8. まとめ

この記事では、llama.cppについて以下を解説した。

  1. llama.cppの正体: 依存関係ゼロのC/C++ LLM推論エンジン
  2. GGUFフォーマット: 量子化されたモデルの統一規格
  3. 実践方法: CLI、APIサーバー、Pythonバインディング
  4. ユースケース: チャットボット、RAG、コード補完

私の所感

llama.cppを初めて動かしたとき、「こんなに軽く動くのか」と衝撃を受けた。PyTorchで同じモデルを動かすのに四苦八苦していた日々が嘘のようだ。

正直、2025年現在、ローカルLLMをやるならllama.cppを避けて通ることはできない。OllamaもLM Studioも、内部ではllama.cppを使っている。「心臓部」という表現は大げさではない。

ぜひ一度、自分の手でビルドして動かしてみてほしい。きっと「AIが手元で動く」感動を味わえるはずだ。


参考文献


関連記事

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?