ローカル LLM 量子化 入門ガイド|2026-08 版
第 10 章

手を動かす — 選ぶ・落とす・自分で量子化する

llama.cpp / Ollama / LM Studio / MLX で最短経路をたどる

この章で分かること

最短経路は 4 段のはしごになっている

量子化の実務は一本道ではなく、目的の深さに応じた 4 段のはしごです。大半の人は 1 段目で用が足ります。上に登るのは、下の段で具体的な不満が出たときだけです。

そう言い切れるのは、主要ツールの既定値が独立に一致しているからです。llama.cpp の -hf は量子化を省略すると Q4_K_M を取りに行き、Ollama を Hugging Face 経由で使ったときも公式が「By default, the Q4_K_M quantization scheme is used」と明記し、LM Studio 公式の選び方ガイダンスは「Choose a 4-bit option or higher if your machine is capable enough for running it.」の 1 行です。3 つのツールが同じ場所を指しているので、1 段目は「Q4_K_M を落として動かす」で終わって構いません。

① 既製の量子化モデルを使う Ollama / LM Studio ② 設定を詰めて自分で回す llama cli / llama serve ③ 自分で GGUF に変換する convert_hf_to_gguf.py ④ 自分で量子化する llama-quantize + imatrix 遅い・GPU に載らない 欲しい量子化が配布されていない 1〜3bit を試す・品質を追い込む タグを選ぶだけ。既定は Q4_K_M 量子化・コンテキスト長・GPU 配分を指定できる HF のどんなモデルでも GGUF にできる 混合ビット・層単位の型指定まで届く
図 10-1 左の矢印に書いてあるのが「次の段に登る条件」です。条件が出ていないのに上へ行くと、手間と RAM を払って同じ結果を得ることになります。

段①: 既製の量子化モデルを落として動かす

経路 A — Ollama

モデル指定は <モデル名>:<タグ> で、タグの中身はパラメータ数・チューニング種別・量子化タイプをハイフンでつないだものです。llama3.2:3b-instruct-q4_K_M なら「Llama 3.2 の 3B 版/指示追従チューニング済み/GGUF の Q4_K_M」。text はチューニング前の素のモデルです。

llama3.2 : 3b - instruct - q4_K_M モデル名 パラメータ数 チューニング種別 量子化タイプ ollama run llama3.2 :3b-instruct-q4_K_M digest a80c4f17acd5 で一致 実体は同じ 2.0GB のファイル
図 10-2 digest(= ファイル内容のハッシュ。同じ digest なら同じファイル)を突き合わせると、タグを省略したときに何が落ちてくるかが確定します。ライブラリページで実測した値(2026-08 時点)です。

ここで情報の質を区別します。「Ollama の既定量子化は Q4_K_M」と明文で書いた公式ページは存在しません。言えるのは「latest / 3b / 3b-instruct-q4_K_M の digest が一致している」という実測までです。Hugging Face 経由の既定 Q4_K_M だけは公式に明記されています。

いま何が動いているかは ollama show で見ます。出力の Model テーブルに architecture / parameters / context length と並んで quantization の行が出ます(API なら details.quantization_level)。

ollama pull llama3.2:3b-instruct-q4_K_M
ollama show llama3.2
ollama run  hf.co/bartowski/Llama-3.2-3B-Instruct-GGUF:Q8_0   # HF から直接、大文字小文字は不問

効き目はサイズに出ます。llama3.2 の 3B instruct は fp16 の 6.4GB が q4_K_M で 2.0GB、約 3 分の 1(q8_0 は 3.4GB、q2_K は 1.4GB。いずれもライブラリページ実測)。旧方式の q4_1 は 2.1GB で q4_K_M より大きいという逆転もあります(命名の中身は第 6 章)。なお選択肢の数はモデル依存で、llama3.2 は 15 種のタグを持つ一方、qwen3 は 3 種、gpt-oss は量子化タグを持ちません。新しいモデルでは実質「Q4_K_M か Q8_0 か fp16」の 3 択です。

Ollama 自身にも量子化機能がありますが、作れるのは q8_0 / q4_K_S / q4_K_M の 3 種だけで、入力は FP16 か FP32 に限られます(中身は llama-quantize にシェルアウトしているだけ)。

# Modelfile に FROM /path/to/my/gemma/f16/model と書いてから
$ ollama create --quantize q4_K_M mymodel
transferring model data
quantizing F16 model to Q4_K_M
writing manifest
success
やってみる 10-1|量子化タイプと GPU 配分を確認する

Ollama を入れて最初にやる確認です。5 分。「なんとなく動いている」を「何が動いているか分かっている」に変えます。

  1. 量子化を明示して取得し、ollama show で quantization 行を読む。
  2. 1 度対話してから、別のターミナルで ollama ps を叩く。
ollama pull llama3.2:3b-instruct-q4_K_M
ollama show  llama3.2:3b-instruct-q4_K_M
ollama run   llama3.2:3b-instruct-q4_K_M
ollama ps    # 別ターミナルで
NAME             ID              SIZE      PROCESSOR    CONTEXT    UNTIL
gemma4:latest    c6eb396dbd59    9.6 GB    100% GPU     131072     2 minutes from now

見るのは PROCESSOR 列です。100% GPU なら全部 GPU。48%/52% CPU/GPU は部分オフロード、100% CPU は全部システムメモリで、この 2 つは大幅に遅くなります。公式の指針も「avoid offloading the model to CPU. Verify the split under PROCESSOR using ollama ps」です。

経路 B — LM Studio

llama.cpp の上に作られた GUI で、Apple Silicon では MLX も動かせます。モデル検索では 1 つのモデルに複数の量子化が並び、公式はそれを「These are all copies of the same model, provided in varying degrees of fidelity」と説明します。Q4_K_M と Q5_K_M の優劣についての公式記述はありません(あるのは「4bit 以上」の 1 行だけ)。

混乱しやすいのは形式で量子化の呼び名が違う点です。REST API のレスポンス例がそれを端的に示します。

{ "id": "qwen2-vl-7b-instruct",       "compatibility_type": "mlx",  "quantization": "4bit"   }
{ "id": "meta-llama-3.1-8b-instruct", "compatibility_type": "gguf", "quantization": "Q4_K_M" }

GGUF は Q4_K_M のような K-quant 名、MLX は 4bit のような素朴なビット数表記です。CLI では形式と量子化を絞れます(lms は本体を 1 度起動しないと使えません)。GPU offload(= モデルの層を GPU 側メモリに載せること)は 0.0〜1.0 の比率で、--gpu 0.5 は llama.cpp の -ngl <層数> を比率で言い換えたものです(換算式は非公開)。

lms get qwen --mlx
lms get llama-3.1-8b@q4_k_m
lms load --estimate-only gpt-oss-120b --context-length 8192

最大の実務メリットは --estimate-only で「収まるか」を事前に見られることです。公式の出力例は Estimated GPU Memory: 65.68 GB を返し、この見積りがコンテキスト長・Flash Attention・vision 対応を勘案していると明記されています。つまり「ファイルサイズ = 必要メモリ」ではありません(内訳は第 8 章)。

段②: llama.cpp を直に叩いて設定を詰める

最初の段差はコマンド名です。2026 年の llama.cpp は llama という単一ディスパッチャを持ち、README は llama cli(スペース区切り)で書かれています。一方で従来の llama-cli / llama-server / llama-quantize も生きていて、Hugging Face 側の公式ドキュメントはそちらの表記です。公式内に両方の書き方が併存しているので、まず llama help で自分の環境を確認してください。

curl -LsSf https://llama.app/install.sh | sh   # 公式ワンライナー
brew install llama.cpp                          # Mac / Linux
winget install llama.cpp                        # Windows

git clone https://github.com/ggml-org/llama.cpp   # ソースから(CPU ビルド)
cmake -B build && cmake --build build --config Release

Apple Silicon では Metal が既定で有効(「On MacOS, Metal is enabled by default」)、NVIDIA なら -DGGML_CUDA=ON を付けます。実行はファイルを落とさず Hugging Face のリポジトリ名を直接渡すのが最短です。-hf <user>/<model>[:quant] の quant は省略可で、既定が Q4_K_M、無ければリポジトリ内の最初のファイルにフォールバックします。

フラグ既定値何に効くか
-ngl, --n-gpu-layers NautoVRAM に載せる層の数。auto / all / 数値
-c, --ctx-size N0(= モデルの値)コンテキスト長。KV キャッシュはほぼこれに比例する
-ctk / -ctv TYPEf16KV キャッシュ自体の型。q8_0 / q4_0 なども選べる
-fa, --flash-attnautoFlash Attention。量子化 V キャッシュを使うなら必須
-fit, --fit [on|off]on未指定の引数をデバイスメモリに収まるよう自動調整
--list-devices—使えるデバイスとそのメモリ量を表示

ここで古い常識を捨ててください。-ngl の既定はもう 0 ではなく auto で、--fit が既定 on として「デバイスごとに 1024 MiB のマージンを残して収まるよう」引数を調整します。手で大きな値を固定すると自動調整を潰し、VRAM 溢れを招きます。メモリが足りないときに削る順序も公式に書かれています。--ctx-size を下げる → --parallel を下げる → 最後の手段として -ngl を下げる(残りは CPU で走り「much slower」になる)。この痛みは実測されていて、A6000 + 7 物理コアで 30B の 4bit を回すと CPU のみ 1.7 tokens/s、GPU 全載せ 9.1 tokens/s で約 5.4 倍。同じ表の GPU 全載せ同士を比べると -t 7(8.7)は -t 4(9.1)より遅く、CPU スレッドも多いほど速いわけではありません(公式も「It's extremely important that this parameter is not too large.」と書き、まず 1 から倍々に増やして探せと助言しています)。

やってみる 10-2|HF から直接動かし、OpenAI 互換サーバを立てる

ダウンロードもファイル管理もせずに量子化を切り替えて比べます。10 分。

  1. llama help でサブコマンド形式が使えるか確認する。
  2. 既定(Q4_K_M)と :Q8_0 で同じ質問を投げ、応答速度を比べる。
  3. llama serve を立て、OpenAI 互換エンドポイントを叩く。
llama help
llama cli -hf ggml-org/gemma-3-1b-it-GGUF
llama cli -hf bartowski/Llama-3.2-3B-Instruct-GGUF:Q8_0
llama serve -hf ggml-org/gemma-3-1b-it-GGUF
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer no-key" \
-d '{"messages": [{"role": "user", "content": "Write a limerick about Python exceptions"}]}'

ダウンロード先は LLAMA_CACHE 環境変数で決まり、2 度目以降はキャッシュから起動します(-cl で一覧、--offline でネットワークを使わない)。サーバは /v1/chat/completions に JSON を返すので、OpenAI SDK からそのまま叩けます。起動ログに「何層を GPU に載せたか」が出るので、--list-devices の出力と併せて読んでください。

段③④: 自分で変換して、自分で量子化する

ここからは「欲しい量子化が配布されていない」ときの領域です。まず地図として、元の safetensors(= Hugging Face が標準にしている重みファイル形式)から先は、目的の形式ごとに別のツールへ分岐します。形式そのものの選び分けは第 7 章、ここでは「どのコマンドがどれを作るか」だけを押さえます。

元モデル safetensors / FP16 GGUF(Q4_K_M など) llama.cpp / Ollama / LM Studio MLX(4bit / group 64) mlx-lm / LM Studio compressed-tensors(W4A16) vLLM convert_hf_to_gguf.py → llama-quantize mlx_lm.convert -q llmcompressor / oneshot
図 10-3 辺のラベルが実際に叩くコマンドです。GGUF だけが 2 段(変換 → 量子化)で、MLX と vLLM 系は 1 コマンドで量子化まで終わります。

GGUF は必ず 2 段階を通る

公式の言い方は「Quantization is done in two phases: Convert the original model to GGUF format. / Quantize the converted GGUF file.」です。いきなり Q4_K_M は作れません。一度 bf16 や f16 の「量子化前の GGUF」を作り、それを入力にします。

python3 -m pip install -r requirements.txt

python convert_hf_to_gguf.py --outfile gemma-4-E2B-it-bf16.gguf \
  --outtype bf16 --remote google/gemma-4-E2B-it

./build/bin/llama-quantize gemma-4-E2B-it-bf16.gguf \
  gemma-4-E2B-it-Q4_K_M.gguf Q4_K_M

公式は「16-bit で配布されている通常のケースでは --outtype auto(または省略)でもうまく動く」と述べています。すでにローカルにあるならディレクトリを指定して --remote を外します。型名は大文字小文字を区別せず、走らせる前にサイズだけ見たいときは --dry-run が使えます。

ここが最大の落とし穴です。量子化作業には、元モデルが丸ごと入るディスクと RAM が要ります。公式の注記は「you will need adequate disk space to save them and sufficient RAM to load them. At the moment, memory and disk requirements are the same.」です。

モデル元サイズQ4_K_M 後
Llama 3.1 8B32.1 GB4.9 GB
Llama 3.1 70B280.9 GB43.1 GB
Llama 3.1 405B1,625.1 GB249.1 GB

この表の「元サイズ」は1 パラメータ 4 バイト(FP32)換算だと読めます。Llama 3.1 8B は約 80.3 億パラメータで、80.3 億 × 4 バイト = 32.1 GB になるからです(計算例)。bf16 で配布されているモデルならダウンロード自体はその半分(約 16 GB)で、そこから作る中間の bf16 GGUF がもう約 16 GB。合計するとやはり 30 GB 台を触ることになります。

つまり 「4.9 GB を作るために 30 GB 台を用意する」のが 8B の実情で、ノート PC の作業ではありません。だから公式自身が逃げ道を用意しています。llama.cpp の main から 6 時間ごとに同期される Space「GGUF-my-repo」なら、セットアップなしでブラウザから量子化できます。

imatrix — 「どの重みが効くか」を測って渡す

imatrix(importance matrix、重要度行列)は、実際のテキストを流したときにどの重みが出力に大きく効いたかを実測した表です。量子化時にこれを渡すと、効く重みの誤差を優先して小さくできます。

convert_hf_to_gguf.py llama-quantize llama-perplexity 元モデル 32.1 GB(8B) bf16 の GGUF 量子化前の中間物 Q4_K_M 4.9 GB 品質を測る PPL と KLD imatrix(重要度行列) llama-imatrix -m ... -f calib.txt -ngl 99 bf16 GGUF + キャリブレーション文 --imatrix で渡す
図 10-4 imatrix は本流ではなく枝です。作るには量子化前の GGUF とキャリブレーション用テキストが要り、その出力を量子化ステップに --imatrix で合流させます。
./llama-imatrix -m ggml-model-f16.gguf -f calibration-data.txt -ngl 99

./llama-quantize --imatrix imatrix.gguf ggml-model-f16.gguf \
  ./ggml-model-q4_k_m.gguf q4_k_m

重要なのは、imatrix が「あった方がいい」ではなく型によっては必須だという点です。ソース(tensor_requires_imatrix())が対象を 6 種に確定しています。IQ1_S / IQ1_M / IQ2_XXS / IQ2_XS / IQ2_S / IQ3_XXS を imatrix なしで指定すると ERROR: this quantization requires an importance matrix! で処理が中断します。IQ2_M や IQ3_S は「IQ」でも必須ではないので、頭文字ではなく型名そのもので覚えてください。もう 1 つ例外があり、Q2_K_S を指定したときにその中で使われる Q2_K テンソルだけは必須になります(ソースのコメントが「as a general rule, the k-type quantizations don't require imatrix data. the only exception is Q2_K tensors that are part of a Q2_K_S file.」と明言しています)。

Q4_K_M のような k-quant は無くても作れますが、品質は変わります。Llama 3 8B の公式スコアボードでは Q4_K_M の PPL 増分が imatrix あり 0.1513、なし 0.1755(差 0.024)。ところが Q2_K は 2.416 対 3.520 で差が 1.10 に開きます。効き幅はビット数が下がるほど大きいので、4bit なら「あれば少し良い」、2bit なら「無いと話にならない」と読めます(PPL の読み方は第 9 章)。一方、キャリブレーションデータを増やす方向には投資しないでください。公式の観察は「There seems to be no consistent improvement from using more Wikitext tokens」で、Q2_K の PPL は 1 千トークンで 8.683、1 千万トークンで 8.648 と誤差レベルです。

やってみる 10-3|safetensors から Q4_K_M を自分で作る

1B 前後の小さいモデルで 2 段階を通します。ダウンロードした重みファイルの 2 倍強のディスクを空けてから始めてください(重み本体 + 中間の GGUF + 出力)。

  1. Python 依存を入れ、量子化前の GGUF に変換する。
  2. --dry-run でサイズを確認してから本番の量子化を走らせる。
  3. Wikitext-2 を落として perplexity を測り、bf16 版と比べる。
python3 -m pip install -r requirements.txt
python convert_hf_to_gguf.py --outfile model-bf16.gguf --outtype auto ./local-model-dir

./build/bin/llama-quantize --dry-run model-bf16.gguf Q4_K_M
./build/bin/llama-quantize model-bf16.gguf model-Q4_K_M.gguf Q4_K_M

./scripts/get-wikitext-2.sh
./build/bin/llama-perplexity -m model-Q4_K_M.gguf -f wikitext-2-raw/wiki.test.raw

--dry-run は量子化せずに最終サイズだけを表示します。実行するとテンソル 1 本ごとに「連番・テンソル名・形・元の型・サイズの変化」が 1 行ずつ流れ、最後に model size と quant size がそれぞれ BPW(1 重みあたりの実効ビット数)付きで表示されます。この BPW が公称ビット数より大きいのが正常です。llama-perplexity の値は別モデルや他プロジェクトの数値と比較できません(公式が「not directly comparable」と明記)。比べるのは同じモデルの bf16 版と量子化版の間だけです。

別ルート: Apple Silicon の MLX と GPU サーバの vLLM

経路 C — MLX(Apple Silicon)

Apple 製の MLX では変換と量子化が 1 コマンドで終わり、中間ファイルが要りません。--hf-path と --model は同じ引数の別名です(HF 側ドキュメントは前者の表記)。python -m mlx_lm.convert の直呼びは非推奨です。

pip install mlx-lm

mlx_lm.convert --model mistralai/Mistral-7B-Instruct-v0.3 -q
mlx_lm.convert --model Qwen/Qwen3-8B -q --q-bits 4 --q-group-size 64 --mlx-path ./q3-4bit
mlx_lm.generate --model ./q3-4bit --prompt "hello"

指定するのは主に --q-bits(affine で使えるのは 2 / 3 / 4 / 5 / 6 / 8。7 は無い)、--q-group-size(32 / 64 / 128)、--q-mode(affine / mxfp4 / nvfp4 / mxfp8)です。ヘルプに既定値が出ませんが、affine の実際の既定は bits = 4、group_size = 64(実装のテーブルで確定)。--mlx-path の既定は mlx_model で、既存パスを指定すると失敗します。

group size を意識すべき理由は算術で説明できます。affine では group_size 個の重みごとに scale と bias を 1 組持ち、その 2 つは入力と同じ dtype(bf16 = 16bit)で保存されます。つまりグループ 1 個につき 16 + 16 = 32 ビットが重みとは別に必要で、これを group_size 個の重みで割り勘します。したがって 1 重みあたりの実効ビット数は次のようになります。

bpw = bits + 32 ÷ group_size

既定値を入れると bpw = 4 + 32 ÷ 64 = 4.5(計算例)。配布されている mlx-community/Qwen3-8B-4bit の実測は 4.5005 bpw で式と一致します。--q-group-size 32 にするとスケールの数が倍になって 4 + 32 ÷ 32 = 5.0 bpw に増え、group 32 で配布されている別モデルの実測も 5.0007 bpw です。MLX の「4bit」は 1/4 ではなく、bf16 比で約 3.56 分の 1(16 ÷ 4.5)です。llama.cpp の _M に相当する混合ビットは --quant-predicate mixed_3_6 などで選べ、実装コメントも「similar choices to, for example, llama.cpp's Q4_K_M」と明言しています。

やってみる 10-4|Mac で 4bit と 6bit を作り分けて比べる

同じモデルからビット数だけ違う 2 つを作り、サイズと体感速度を比べます。

pip install mlx-lm
mlx_lm.convert --model Qwen/Qwen3-4B-Instruct-2507 -q --mlx-path ./q3-4bit
mlx_lm.convert --model Qwen/Qwen3-4B-Instruct-2507 -q --q-bits 6 --mlx-path ./q3-6bit
du -sh ./q3-4bit ./q3-6bit
mlx_lm.generate --model ./q3-4bit --prompt "3 行で自己紹介して"

4bit 側は 4.5 bpw、6bit 側は 6 + 32 ÷ 64 = 6.5 bpw なので、サイズ比はおよそ 1.44 倍になります(計算例)。各ディレクトリの config.json に "quantization": {"group_size": 64, "bits": 4, "mode": "affine"} が残るので、後から何で作ったか分かります。大きいモデルで [WARNING] Generating with a model that requires ... が出たら、macOS 15.0 以降で sudo sysctl iogpu.wired_limit_mb=N(N はモデルの MB より大きく機械の RAM より小さい値)を試します。

経路 D — vLLM(GPU サーバ)

複数リクエストを同時に捌くサーバ用途で GGUF は使いません(公式が「GGUF support in vLLM is highly experimental and under-optimized」と明記)。使うのは compressed-tensors 形式で、W4A16 は「重みを 4bit、活性化(層を流れる中間の数値)は 16bit のまま」を意味します。まずは既製を引くのが正解で、発行元のモデルカードが削減率と精度回復率を公表しています。RedHatAI/Meta-Llama-3.1-8B-Instruct-quantized.w4a16 は「reducing the disk size and GPU memory requirements by approximately 75%」(128 パラメータごとの per-group、OpenLLM v1 回復率 98.9%)、...-quantized.w8a8 は約 50% 削減に加えて「matrix-multiply compute throughput (by approximately 2x)」です。

選び分けには根拠があります。重みだけを量子化した A16 は GPU メモリからの読み出し量を減らす最適化で、演算そのものは 16bit のままなので減りません。W8A8 は活性化も 8bit なので低精度の演算パスに乗り、計算自体が速くなります。開発チームの論文(arXiv:2411.02355)の結論は「W4A16 is the most cost-efficient for synchronous setups, while W8A8 dominates in asynchronous continuous batching」。1 件ずつ順に処理するなら W4A16、大量同時なら W8A8 です。

自分で作る最小レシピはこうなります。vLLM と llm-compressor は別の環境に入れてください(公式が「Please use separate environments for vLLM and llm-compressor as they might not work together.」と全ページに書いています)。

from llmcompressor import oneshot
from llmcompressor.modifiers.quantization import GPTQModifier

recipe = GPTQModifier(targets="Linear", scheme="W4A16", ignore=["lm_head"])

oneshot(model=model, dataset=ds, recipe=recipe,
        max_seq_length=2048, num_calibration_samples=512)
model.save_pretrained(SAVE_DIR, save_compressed=True)

キャリブレーション(= 実データを流して量子化パラメータを決める工程)の規模は公式の定数どおり 512 サンプル・最大長 2048 で、助言は「It's best to use calibration data that closely matches your deployment data.」。所要時間の目安は「Calibration for 8B model takes ~20 minutes on one A100 gpu」です。キャリブレーションを省きたいなら、チェックポイントを作らずロード時に落とす vllm serve <model> --quantization fp8_per_tensor もあります。

やってはいけないこと と、詰まったときの逆引き

量子化済みモデルをさらに量子化する

--allow-requantize の公式説明文がそのまま警告です。「Warning: This can severely reduce quality compared to quantizing from 16bit or 32bit」。Ollama の --quantize が FP16 / FP32 入力しか受け付けないのも同じ理由です。Q4_K_M から Q3_K_M を作るのではなく、bf16 の GGUF に戻ってやり直します。

imatrix なしで極低ビットを作ろうとする

IQ1_S / IQ1_M / IQ2_XXS / IQ2_XS / IQ2_S / IQ3_XXS は必須で、渡さなければ中断します(IQ2_M や IQ3_S のように、同じ IQ でも必須ではない型もあります)。そもそも 1〜2bit の実用性は厳しく、Llama 3 8B の IQ1_S は、imatrix を渡してさえ PPL 60.69(f16 は 6.23、ΔPPL は +54.46)、正解トークンの確率が平均 32% 下がります(第 9 章のスコアボード)。

量子化 GGUF を「軽い学習用モデル」として使う

GGUF を Transformers で読むと「The GGUF checkpoint is dequantized to fp32」されます。ファイルが 4.9 GB でも読み込んだ瞬間に fp32 相当のメモリを食います。量子化した重みを凍結し、追加した小さなパラメータ(LoRA アダプタ)だけを学習する QLoRA 系の経路を取ってください。その用途で最も確立しているのは bitsandbytes です(公式の言い方は「the most established and straightforward path for QLoRA」)。

手を動かす前に Hub を見ない

キャリブレーションを伴う量子化は長い(175B を A100 1 枚で GPTQ 量子化すると約 4 時間)。公式自身が「Before you quantize a model, it is a good idea to check the Hub if a GPTQ-quantized version of the model already exists.」と書いています。

マルチモーダルの mmproj まで強く量子化する

mmproj(= 画像や音声を LLM が読める形の入力に変換する部品)は bf16 か q8 で残します。公式の判断基準は「multimodal components are usually kept in a high-quality format such as bf16 or q8. The impact on speed and memory from using a smaller quant is negligible, but overall quality could be impacted.」で、理由も「these components are in charge of preparing the inputs for the LLM」と書かれています。小さくしても得るものがほとんど無く、失うものだけがある部品です。

症状 / メッセージ意味対処
unknown model architecture: '...' GGUF の general.architecture に対応する実装が、その llama.cpp ビルドに無い llama update か再ビルドで新しくする。対応状況は convert_hf_to_gguf.py --print-supported-models
this quantization requires an importance matrix! IQ1_S / IQ1_M / IQ2_XXS / IQ2_XS / IQ2_S / IQ3_XXS を imatrix なしで指定した llama-imatrix で作って --imatrix で渡す。--dry-run なら必要かどうかだけ先に分かる
ncols ... not divisible by ... falling back to ... テンソルの形がブロックサイズで割り切れず、その層だけ別の型になった 失敗ではない。ファイルが公称 bpw より大きくなる原因の 1 つなので、想定外のサイズを見たらこれを疑う
拡張子 .bin のモデルが読めない GGUF 以前の GGML / GGMF / GGJT 形式。GGJT の v1 / v2 / v3 は構造は同じだが量子化方式が違い、前方互換もない convert_llama_ggml_to_gguf.py で GGUF へ変換する経路がある
GPU があるのに極端に遅い 層が CPU 側に落ちている(部分オフロード) Ollama は ollama ps の PROCESSOR、llama.cpp は -ngl all を明示。まず -c を下げるのが正しい順序
変換中に落ちる / ディスクが足りない 元モデル分の RAM とディスクが必要 --use-temp-file(公式に「helpful when running out of memory, process killed」)。厳しければ GGUF-my-repo Space へ逃がす

つまずきポイント

「量子化すれば全部速くなる」と思っていた

速くなるのは生成(1 トークンずつ出す段階)だけです。Llama-3.1-8B の公式実測で、text generation は F16 の 29.17 t/s に対し Q4_K_M が 71.93 t/s と約 2.5 倍。ところが prefill(= 入力プロンプトを一気に読む段階)は F16 が 923 t/s で最速、Q4_K_M は 822 t/s とむしろ遅い。生成はメモリ帯域で律速されるので小さいほど速く、prefill は計算量で律速されるので逆になります。長いプロンプトを何度も投げる用途では恩恵が思ったほど出ません(この非対称性の理由と見積り方は第 8 章)。

記事を真似して -ngl 99 を付けた

数年前は必要でしたが、現行は -ngl が既定 auto、--fit が既定 on で、デバイスごとに 1024 MiB のマージンを残して自動調整します。手で大きな値を固定すると自動調整を潰し、VRAM 溢れの原因になります。古い記事から写しがちなフラグとしては --no-mmap / --mmap / --mlock も非推奨になり、-lm, --load-mode(既定 auto)に統合されています。

「小さいモデルを作るのだから作業も軽い」と思っていた

逆です。公式表は 8B の「元サイズ」を 32.1 GB としていて、モデルを丸ごとメモリに載せるので RAM も同じだけ要ります。ディスクはダウンロードした重み + 中間の bf16 GGUF + 出力で、重みファイルの 2 倍強を見ておく必要があります。無理なら既製の量子化モデルか GGUF-my-repo Space が正解です。なお Q4_K は Q4_K_S ではなく Q4_K_M のエイリアス(Q3_K / Q5_K も同様)で、型名の大文字小文字は区別されません。

理解度チェック

Q1. ollama run llama3.2 はどの量子化を落としてきますか。その根拠はどこまで強いですか?

Q4_K_M(3B instruct 版、2.0GB)です。ただし根拠は「latest / 3b / 3b-instruct-q4_K_M の digest が a80c4f17acd5 で一致している」という実測で、「既定は Q4_K_M」と明文で書いた公式ページはありません。Hugging Face 経由の既定だけは公式に明記されています。

Q2. safetensors から Q4_K_M の GGUF を作るとき、必ず経由するものは何ですか?

量子化前の高精度 GGUF(bf16 や f16)です。convert_hf_to_gguf.py は GGUF 形式にするところまでで、k-quant を作るのは llama-quantize の仕事です。この中間物のぶん、作業中のディスク消費はダウンロードした重みファイルの 2 倍強になります。

Q3. IQ2_S を imatrix なしで作ろうとすると何が起きますか。Q4_K_M ではどうですか?

IQ2_S は ERROR: this quantization requires an importance matrix! で中断します(IQ1_S / IQ1_M / IQ2_XXS / IQ2_XS / IQ3_XXS も同じ)。Q4_K_M は作れますが PPL 増分が 0.1513 から 0.1755 に悪化します。Q2_K だと 2.416 対 3.520 で差がはるかに大きく、ビット数が低いほど imatrix が効きます。

Q4. MLX で -q だけを付けたとき、1 重みあたり実際に何ビット使いますか?

4.5 bpw です。既定は bits = 4、group_size = 64 で、64 個ごとに scale と bias を 16bit ずつ持つため 4 + 32 ÷ 64 = 4.5 になります。配布モデルの実測も 4.5005 bpw。--q-group-size 32 にするとスケールの数が倍になり 5.0 bpw に増えます。

Q5. vLLM で 1 件ずつ順に応答するサービスなら、W4A16 と W8A8 のどちらを選びますか?

W4A16 です。逐次処理では重みの読み出しがボトルネックなので重みを小さくするほど効き、大量同時処理では演算がボトルネックになるため活性化も 8bit にして低精度演算パスに乗せる方が効きます。論文の結論も「W4A16 is the most cost-efficient for synchronous setups, while W8A8 dominates in asynchronous continuous batching」です。

まとめ

次章では、ここまでの選択と数値を 1 枚に畳んだ選択フロー・ビット数対応表・用語辞典をまとめます。

参考リンク