Skip to content

Tech Notes

llama.cpp によるモデルの自作量子化(Quantization)

Hugging Faceからオリジナル精度(FP16/BF16)の生の重み(Safetensors)を入手し、llama.cpp の変換スクリプトで無圧縮のGGUF(FP16)を作成。そこからC++ネイティブの llama-quantize で4bit(Q4_K_M)へ量子化し、自作した量子化モデルがV100で高速かつ論理破綻なく動くことを確認した記録。

前提

  • 作業ディレクトリ: ~/llama.cpp
  • 対象モデル: Qwen2.5-7B-Instruct
  • 変換の流れ: Safetensors(生データ)→ FP16 GGUF(無圧縮)→ Q4_K_M(4bit量子化)

1. 生の重みデータ(Safetensors)を入手

誰かが量子化済みのファイルではなく、公式配布のオリジナル精度の重みを取得する(約15GB)。

cd ~/llama.cpp
hf download Qwen/Qwen2.5-7B-Instruct --local-dir models/Qwen2.5-7B-Instruct-Raw

2. 変換用のPython仮想環境(venv)

現代のLinux(PEP 668)ではシステムのpipへ直接入れられないため、venvで隔離する。

sudo apt install python3-venv -y
python3 -m venv llama-env
source llama-env/bin/activate

依存ライブラリは requirements.txt でコケることがある。その場合はコアだけ直接入れる。

pip install torch transformers gguf sentencepiece protobuf numpy

3. 無圧縮GGUF(FP16)へ変換

複数の .safetensors を、llama.cpp が扱える1つのGGUF(FP16, 無劣化)に結合する。

cd ~/llama.cpp
python convert_hf_to_gguf.py ../models/Qwen2.5-7B-Instruct-Raw \
  --outfile ../models/qwen2.5-7b-f16.gguf --outtype f16

完了すると約15GBの qwen2.5-7b-f16.gguf ができる。

4. C++ツールで4bit量子化

llama-quantize で下位ビットを削り、Q4_K_Mへ再マッピングする。容量は約1/4になる。

./build/bin/llama-quantize \
  ../models/qwen2.5-7b-f16.gguf \
  ../models/qwen2.5-7b-q4_k_m.gguf Q4_K_M

5. 推論確認(V100フル稼働)

全レイヤーをV100へオフロードして実行。情報量を大きく削っても知能が保たれているかを確認する。

./build/bin/llama-cli -m ../models/qwen2.5-7b-q4_k_m.gguf \
  -p "AIのエッジコンピューティングにおける量子化の重要性について教えてください。" \
  -n 400 -c 4096 -ngl 99

実測(V100 32GB):

  • プロンプト処理: 約 628.9 t/s
  • 生成速度: 108.3 t/s
  • 4bitまで圧縮しても、エッジのメモリフットプリントや計算負荷削減について論理破綻のない出力を確認

つまずきポイント

  • 大容量バイナリ(.safetensors / .gguf)を誤って cat するとターミナルが文字化けして入力が壊れる。Ctrl+C の後、画面が見えなくても reset と打てば復帰できる。
  • convert_hf_to_gguf.py が見つからないエラーは、カレントディレクトリのズレが原因。スクリプトは ~/llama.cpp 直下にあるので、cd ~/llama.cpp してから相対パス(../models/...)で指定する。

量子化は一律ではない

今回選んだのは「バランスの良い王道設定」に過ぎない。実際はハードの制約(メモリ)と必要な知能(精度)の妥協点を探る、奥の深い調整領域がある。

ビット数を変える

  • Q2 / Q3(2〜3bit): 極限まで圧縮。メモリが絶望的にない環境向けだが、知能(Perplexity)が明確に低下し、幻覚が増える。
  • Q6 / Q8(6〜8bit): ほぼ劣化なし。FP16と区別がつかない知能を保つが、ファイルは大きい。

層ごとに削り分ける(K-Quants)

Q4_K_M_M(Medium)がこれ。多少削っても影響の小さい層と、少しでも削ると破綻する重要な層を、層ごとにビット数を変えて扱う。

  • _S(Small): 重要な層も容赦なく削り、サイズ最小
  • _L(Large): 重要な層のビット数を多めに残し、賢さを担保

Imatrix(Importance Matrix)

現在の llama.cpp で最高峰の量子化アプローチ。量子化前にAIへ実データ(Wikipediaやコード等)を読ませて「テスト走行」し、どの重みが頻繁に発火するかを記録する(=重要度行列)。その記録を llama-quantize に渡すと、「よく使う回路は高精度、使わない回路は大胆に削る」というオーダーメイド圧縮ができる。エッジデバイスのRAM残量に合わせてどこをどう削るかを設計するのが、組み込みAIの腕の見せ所になる。