llama.cppの量子化でLLMモデルをGGUF形式に変換する方法

AI tutorial - IT technology blog
AI tutorial - IT technology blog

問題:LLMはローカルで動かすには大きすぎる

Hugging Faceで素晴らしいオープンソースモデルを見つけたとしましょう — Mistral 7B、LLaMA 3、Qwen2あたりかもしれません。ダウンロードして読み込もうとすると、マシンがフリーズするか、メモリ不足エラーが発生します。float16形式の70億パラメータモデルは、約14GBのVRAMを必要とします。130億パラメータモデルなら26GB以上。ほとんどの開発者にはそれだけのリソースがありません。

根本的な原因は精度にあります。モデルの重みはデフォルトで16ビットまたは32ビットの浮動小数点数として保存されます。つまり1パラメータあたり2〜4バイト — 推論が実際に必要とする精度をはるかに超えています。解決策は量子化です。各重みのビット幅を削減することで、精度をそれほど損なわずにモデルを小型化できます。

このパイプラインを習得してから、ローカルAIとの付き合い方が変わりました。適切に量子化されたモデルであれば、Mistral 7Bは最新のノートPCのCPUで毎秒10〜20トークンの速度で動作します — GPUもデータセンターもクラウド料金も不要です。

押さえておくべき基本概念

量子化とは何か

量子化とは、高精度な浮動小数点値を低精度の整数にマッピングすることです。1重みあたり16ビットの代わりに、4ビットや8ビットを使用します。モデルは数値的な細かさを一部失いますが、実際には出力品質はほとんど劣化しません — 特にQ4以上では顕著です。

一般的な量子化レベルの比較は以下の通りです:

  • Q2_K — 約2ビット/重み。最小ファイルサイズですが、品質の劣化が目立ちます。極端なメモリ制約がある場合にのみ有用です。
  • Q4_K_M — 約4ビット/重み。最適なバランス。高速な推論と、フル精度に近い品質を両立します。
  • Q5_K_M — 約5ビット/重み。品質がより高く、ファイルサイズはやや大きめ。RAMに余裕があれば選ぶ価値があります。
  • Q8_0 — 約8ビット/重み。ほぼ無損失。量子化形式の中で最高品質ですが、ファイルサイズが最大で生成も最も遅くなります。

具体的には:Q4_K_Mを使うと、7Bモデルが約4.1GBまで圧縮されます。8GBのシステムRAMに余裕を持って収まり、GPUは不要です。

GGUFとは何か

GGUF(GPT-Generated Unified Format)はllama.cppが使用するファイル形式です。旧来のGGML形式を置き換えたもので、ランタイムが必要とするすべてのもの — 重み、トークナイザー、ハイパーパラメータ — を1つのバイナリにまとめています。ファイル1つで完結。別途設定ファイルを追いかける必要はありません。

GGUFはHugging Face上でmodel-Q4_K_M.ggufのような名前で見かけるものです。多くの人気モデルはすでに変換済みですが、新しいリリースが出てコミュニティがまだパッケージ化していない場合は、自分で変換する必要があります。それがまさにこのガイドの内容です。

llama.cppの役割

llama.cppはGGUFモデルをCPUおよびGPUで実行するために最適化されたC++推論エンジンです。変換パイプラインでは2つのツールを使用します。convert_hf_to_gguf.pyがHugging FaceのモデルディレクトリをGGUF形式に変換し、llama-quantizeが指定したビット幅に圧縮します。この順番で実行します:まず変換、次に量子化です。

実践:モデルの変換と量子化

ステップ1:依存関係のインストール

Python 3.10以上、Git、C++コンパイラが必要です。Ubuntu/Debianの場合:

sudo apt update && sudo apt install -y git build-essential cmake
pip install torch transformers sentencepiece huggingface_hub

ステップ2:llama.cppのクローンとビルド

git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make -j$(nproc)

このコマンドでllama-quantizellama-clillama-serverなどのユーティリティがコンパイルされます。CUDAがあり、推論時にGPUアクセラレーションを使いたい場合は:

make LLAMA_CUDA=1 -j$(nproc)

ステップ3:変換スクリプト用のPython依存関係をインストール

pip install -r requirements.txt

ステップ4:Hugging Faceからソースモデルをダウンロード

huggingface-cliを使ってモデルを取得します。ここではmistralai/Mistral-7B-v0.3を使用します:

huggingface-cli login  # ゲーテッドモデルの場合は必須
huggingface-cli download mistralai/Mistral-7B-v0.3 \
  --local-dir ./models/Mistral-7B-v0.3 \
  --local-dir-use-symlinks False

すべての.safetensorsシャード、トークナイザー、設定ファイルがダウンロードされます。この時点でMistral 7Bは合計約14GBになります。

ステップ5:GGUF形式に変換(Float16)

変換スクリプトは中間ステップとして、フル精度のGGUFファイルを生成します:

python convert_hf_to_gguf.py ./models/Mistral-7B-v0.3 \
  --outfile ./models/Mistral-7B-v0.3-F16.gguf \
  --outtype f16

ディスク速度によっては2〜5分かかります。出力ファイルは約14GB — オリジナルと同じ精度でGGUF形式に再パッケージされたものです。

ステップ6:目的の形式に量子化

次にllama-quantizeを実行します。ほぼ常にQ4_K_Mから始めるのが正解です:

./llama-quantize \
  ./models/Mistral-7B-v0.3-F16.gguf \
  ./models/Mistral-7B-Q4_K_M.gguf \
  Q4_K_M

2〜4分で4.1GBのファイルが出力されます。その後、中間のF16ファイルを削除して約10GBのディスク領域を回収しましょう。

複数の量子化レベルを比較のために生成したい場合は:

for QTYPE in Q2_K Q4_K_M Q5_K_M Q8_0; do
  ./llama-quantize \
    ./models/Mistral-7B-v0.3-F16.gguf \
    ./models/Mistral-7B-${QTYPE}.gguf \
    $QTYPE
done

ステップ7:推論を実行して動作確認

llama.cpp組み込みのCLIで量子化モデルをテストします:

./llama-cli \
  -m ./models/Mistral-7B-Q4_K_M.gguf \
  -p "Dockerボリュームとは何か、わかりやすく説明してください。" \
  -n 300 \
  --temp 0.7

意味のある出力が得られれば変換成功です。文字化けしたトークンが出る場合は、トークナイザーが正しくパッケージされていない可能性があります — 変換ステップを再実行し、トークナイザーファイルの欠落に関する警告を確認してください。

パープレキシティ評価(任意だが推奨)

パープレキシティはモデルがテキストをどれだけうまく予測できるかを測る指標です。値が低いほど優秀です。ファイルサイズと引き換えにどれだけ品質を失ったかを正確に計測できます:

# テストデータセットのダウンロード
wget https://huggingface.co/datasets/ggml-org/ci/resolve/main/wikitext-2-raw-v1.zip
unzip wikitext-2-raw-v1.zip

# パープレキシティ評価の実行
./llama-perplexity \
  -m ./models/Mistral-7B-Q4_K_M.gguf \
  -f wikitext-2-raw/wiki.test.raw

ほとんどの7Bモデルでは、Q4_K_MはF16に比べてパープレキシティが0.5ポイント未満しか増加しません。ファイルサイズが70%削減されるのに対して、これは無視できる程度の精度低下です。

OllamaまたはOpen WebUIへの読み込み

生のCLIよりチャットインターフェースを好む場合は、GGUFを直接Ollamaに読み込めます:

# Modelfileの作成
cat > Modelfile <<EOF
FROM ./models/Mistral-7B-Q4_K_M.gguf
PARAMETER temperature 0.7
PARAMETER num_ctx 4096
EOF

ollama create mistral-local -f Modelfile
ollama run mistral-local

適切な量子化レベルの選び方

最適な形式はお使いのハードウェアによって異なります。実用的な判断基準は以下の通りです:

  • 利用可能なRAMが4〜6GB:Q2_KまたはQ3_K_M。複雑な推論では品質の低下が目立ちます。
  • 8GB RAM:7BモデルにはQ4_K_M。ほとんどの環境でのデフォルト選択です。
  • 16GB RAM:7BモデルにはQ5_K_M、または13BモデルにQ4_K_M。
  • 32GB以上のRAM:7B/13BモデルにはQ8_0、または30B以上のモデルをQ4で実行。

次のステップ

量子化モデルが手に入ったら、さまざまな方向に発展できます。llama-serverを起動するとOpenAI互換のREST APIが立ち上がります — OpenAIと通信できるツール(LangChain、Open WebUI、LlamaIndex)であれば、コード変更なしにすぐ使えます。あるいはローカルモデルの上にRAGパイプラインを構築したり、ベースモデルをファインチューニングしてからその重みを変換したりすることもできます。

llama.cppプロジェクトはほぼ毎日アップデートされ、新しいモデルがリリースされると数日以内にサポートが追加されます。LLaMA、Mistral、Qwen、Phi、Gemma — オープンウェイトのモデルであれば、ほぼ確実にGGUFサポートが存在します。

まずはQ4_K_Mから始めましょう。手軽にパープレキシティを確認して、品質を優先してQ5に上げるか、メモリ使用量を抑えてQ3に下げるかを判断してください。量子化ステップは数分で完了します — 試行錯誤のコストは低く、自分の環境に合った最適な形式を見つける価値は十分にあります。

Share: