🎓 レベル:標準 | 重要度:A(必須) 📎 前提:モデル形式(safetensorsとGGUF) | 原理:推論の実務(機械学習)
要点(結論先出し)
- 量子化=重みの数値精度を下げること。16bit浮動小数点(FP16/BF16)を int8・int4 などに丸め、1weightあたりのビット数(bpw)を減らしてファイルとVRAMを縮める。
- 鍵はスケール(倍率)とゼロ点。連続値を「代表点の格子」に丸め、
実値 = スケール x 整数 + ゼロ点(近似)で復元する。 - ブロック単位で別々のスケールを持たせると、外れ値の影響を局所化でき、低ビットでも品質を保ちやすい。
概念 ── 連続値を格子に丸める
重みはおおむね0付近に密集した実数です。FP16は1個16bitで広い範囲を表せますが、ローカルでは贅沢。量子化は値域を等間隔(または工夫した間隔)の格子に区切り、最も近い格子点の整数インデックスだけ保存します。復元時は 値 = スケール x 量子化整数 (+ ゼロ点)。
- 対称量子化:ゼロ点を0に固定(重み向き)。
- 非対称量子化:ゼロ点を別途持つ(活性化など分布が偏る場合)。
仕組み ── ブロックごとにスケールを持つ
1本のテンソル全体に1つのスケールだと、巨大な外れ値に引っ張られて他の値の分解能が潰れます。そこで重みを小さなブロック(例:32個や256個)に区切り、ブロックごとにスケールを持つ。これが低ビット量子化の品質を支える基本アイデアで、第3トピックの k-quants はこれをさらに階層化したものです。
flowchart LR W["FP16の重み列"] --> B["ブロック分割(例256要素)"] B --> S["ブロック毎にスケール算出"] S --> Q["各値を整数へ丸め(int4等)"] Q --> PACK["整数+スケールを格納(小さい)"]
計算例 ── ビット数がサイズを決める
1weightあたりのビット数(bpw)が分かれば、サイズは パラメータ数 x bpw / 8。8Bモデルなら FP16=約15GiB、Q8で約8GiB、Q4_K_M で約4.5GiB。実数値は対応lab vram_sizing.py で確認できます(cp932安全な print のみ使用)。低ビットほど小さいが、丸め誤差は増えます。
運用の勘所
- まず Q4 系から試す:多くの用途で「ほぼ無劣化に感じる」コスパ点(要最新確認)。足りなければ Q5/Q6 へ。
- 極端な低ビット(2bit級)は最後の手段:載せるためだけ。品質低下を許容できるか要評価。
- 活性化ではなく重みの量子化が基本。KVキャッシュの量子化は別の話 → コンテキスト長とKVキャッシュ
なぜそうするか
LLMは重みのほとんどが冗長で、精度を多少落としても出力分布はあまり崩れません。だから「FP16のまま全部持つ」のは過剰。必要な分解能だけ残すことで、家庭用GPUや統合メモリに巨大モデルを載せられるようになります。
⚠️ よくある落とし穴
- ビット数だけ見て方式を無視する:同じ4bitでも方式で品質が違う → 量子化方式(k-quantsとGPTQとAWQ)
- 「量子化=必ず劣化が体感できる」と誤解:Q5/Q6では多くの用途で差が分かりにくい(要最新確認)。
- 全レイヤー一律に低ビット化する前提:重要レイヤーは高ビットで残す方式がある(importance matrix)。
対応lab
local-llm-study/labs/vram_sizing.py… bpw からモデルサイズを計算実証。
関連
- 方式の違い → 量子化方式(k-quantsとGPTQとAWQ)
- サイズと品質の釣り合い → 量子化とVRAM・品質のトレードオフ
- メモリへ収める実務 → オフロードと量子化でメモリに収める