ローカルでLLMを動かすとき、モデルの量子化形式をどれにするかで迷います。Q4_K_Mは軽そうですが精度が気になりますし、Q8_0やF16は高精度でもメモリに余裕が必要です。
この記事では、Ollamaで同じベースモデルの量子化違いを用意し、生成速度・メモリ使用量・回答品質を同じ条件で比較する手順を紹介します。
先に結論を書くと、普段使いではQ4_K_Mが速度とメモリのバランスに優れ、回答品質を重視する場合はQ8_0、十分なVRAMがあり精度劣化を避けたい場合はF16が候補になります。ただし、実際の差はモデル、GPU、コンテキスト長によって変わるため、手元の環境で測ることが重要です。
比較する量子化モデルを用意する
今回は、同じベースモデルから作成したGGUFファイルを使います。モデルファイルはあらかじめ用意し、次のような構成にしました。
models/
├── model-q4_K_M.gguf
├── model-q8_0.gguf
└── model-f16.gguf
量子化形式の違いは、概ね次のように考えられます。
-
Q4_K_M: 4bit量子化。メモリ使用量が小さい -
Q8_0: 8bit量子化。F16に近い品質を狙いやすい -
F16: 16bit浮動小数点。最も大きくなりやすい
Ollamaでは、各GGUFからモデルを作成します。
# Modelfile.q4
FROM ./model-q4_K_M.gguf
PARAMETER temperature 0
PARAMETER num_ctx 4096
# Modelfile.q8
FROM ./model-q8_0.gguf
PARAMETER temperature 0
PARAMETER num_ctx 4096
# Modelfile.f16
FROM ./model-f16.gguf
PARAMETER temperature 0
PARAMETER num_ctx 4096
同じディレクトリで、次のコマンドを実行します。
ollama create lab-q4 -f Modelfile.q4
ollama create lab-q8 -f Modelfile.q8
ollama create lab-f16 -f Modelfile.f16
作成できたモデルは、以下で確認できます。
ollama list
モデル名以外の条件をそろえるため、temperature、コンテキスト長、入力プロンプトはすべて同じにしました。
生成速度を測定する
まず、CLIで同じプロンプトを実行します。
ollama run lab-q4 --verbose \
"量子化モデルのメリットと注意点を、技術者向けに300文字で説明してください。"
--verboseを付けると、生成トークン数や生成時間などの情報を確認できます。比較では初回ロード時間と、モデルがメモリに載った後の生成時間を分けて見るのがポイントです。
APIを使うと、測定値を扱いやすくなります。
curl http://localhost:11434/api/generate \
-H "Content-Type: application/json" \
-d '{
"model": "lab-q4",
"prompt": "量子化モデルのメリットと注意点を、技術者向けに300文字で説明してください。",
"stream": false,
"options": {
"temperature": 0,
"num_ctx": 4096
}
}' | jq '{
eval_count,
eval_duration,
load_duration,
total_duration
}'
生成速度は、次の式で計算できます。
生成速度(tokens/s) =
eval_count / (eval_duration / 1,000,000,000)
同じモデルを続けて実行すると、初回だけload_durationが大きくなる場合があります。そのため、各モデルについて1回目をウォームアップとして捨て、2回目以降を複数回測定しました。
for i in 1 2 3 4; do
curl -s http://localhost:11434/api/generate \
-H "Content-Type: application/json" \
-d '{"model":"lab-q4","prompt":"日本語で100文字の説明を書いてください。","stream":false}' \
| jq '{eval_count, eval_duration, total_duration}'
done
測定時は、他のアプリケーションをなるべく終了し、プロンプトと出力上限を固定します。出力が長くなるほど、単純な平均速度だけでは比較しにくくなるためです。
メモリ使用量を確認する
Ollamaのプロセスが使用するメモリは、モデルサイズだけでは決まりません。コンテキスト長、バッチサイズ、GPUへのオフロード量によっても変化します。
まず、Ollamaがモデルをどのように配置しているかを確認します。
ollama ps
ここで、CPUのみで動いているのか、GPUを使っているのかを確認できます。
NVIDIA GPUを使う場合は、生成中に別のターミナルから次を実行します。
watch -n 1 nvidia-smi
Windowsの場合はタスクマネージャーの「パフォーマンス」から、GPUメモリと専用GPUメモリの使用量を確認しました。測定前のアイドル時メモリを記録し、生成中の最大値との差分を比較します。
私の環境では、量子化ビット数を下げるほどモデル本体のメモリ使用量は小さくなりました。一方で、num_ctxを4096から8192に変更すると、量子化形式に関係なく追加メモリが必要になります。
つまり、VRAMが足りない場合は、量子化形式を変更するだけでなく、コンテキスト長も見直す必要があります。
精度を同じ問題で比較する
「精度」は、速度のように一つの数値で測りにくい項目です。そこで、用途に合わせた固定問題を作り、全モデルに同じ入力を与えました。
問題1:
次のPythonコードのバグを指摘し、修正版を書いてください。
問題2:
次のログから原因と確認手順を箇条書きで説明してください。
問題3:
以下の仕様からJSONを生成してください。JSON以外は出力しないでください。
問題4:
この文章を120文字以内で要約してください。
評価では、次の観点を記録しました。
- 事実関係を誤っていないか
- 指定した形式を守っているか
- コードが実行可能か
- 指示されていない内容を追加していないか
- 日本語として自然か
特にJSON生成やコード修正では、人手確認だけでなく、機械的な検証も有効です。
ollama run lab-q4 \
'次の入力からJSONだけを返してください。入力: name=Alice, age=30'
import json
import sys
answer = sys.stdin.read()
try:
json.loads(answer)
print("valid JSON")
except json.JSONDecodeError as error:
print(f"invalid JSON: {error}")
比較してみると、一般的な説明や要約ではQ4とQ8の差が目立たない場合があります。一方で、複雑なコード、長い文脈、厳密な形式指定では、量子化が強いモデルほど誤りや指示違反が増えることがあります。
一度の回答だけで判断せず、問題を複数用意して、正解数と失敗パターンを記録するのがおすすめです。
結果を表にまとめる
比較全体の流れを図にすると次の通りです。
測定結果は、次のような表にまとめました。
| モデル | 生成速度 | メモリ使用量 | 回答品質 |
|---|---|---|---|
| Q4_K_M | 速い | 小さい | 通常用途では十分 |
| Q8_0 | 中程度 | 中程度 | 複雑な指示に強い傾向 |
| F16 | 環境依存 | 大きい | 劣化を避けやすい |
この表は特定の環境での絶対値ではなく、選定時の傾向を整理したものです。GPUによってはF16の方が効率よく動くこともあり、CPU実行では別の結果になる可能性があります。
実運用では、まずQ4_K_Mでプロトタイプを作り、品質不足が見つかった処理だけQ8_0へ切り替える方法が扱いやすいと感じました。
まとめ
Ollamaで量子化モデルを比較する場合は、次の条件をそろえることが重要です。
- 同じベースモデルを使う
- プロンプト、温度、コンテキスト長を固定する
- 初回ロード時間と生成速度を分けて測る
- GPUとシステムメモリの両方を確認する
- 固定した問題セットで回答品質を評価する
軽さを優先するならQ4_K_M、品質とのバランスならQ8_0、メモリに余裕があり品質劣化を避けたいならF16が候補になります。
量子化形式の優劣は環境と用途で変わるため、モデルのサイズだけで決めず、自分が実際に使うプロンプトで測定するのが一番確実です。