一文要約: Quantizationとは重みの値をより少ないビット数で保存することです。14 GBのfp16 7Bモデルをint4で3.5 GBに圧縮し、ラップトップでも動かせるようにし、多くの場合は高速化もしてくれます。メモリ帯域幅が本当のボトルネックだからです。
27.1 なぜQuantizationが必要か?
27.1.1 メモリの計算
冷たい数字から始めましょう。
LLaMA-7Bの精度別メモリ要件:
| 精度 | 重みあたりのバイト数 | 7Bモデルのサイズ |
|---|---|---|
| FP32 | 4バイト | 28 GB |
| FP16 / BF16 | 2バイト | 14 GB |
| INT8 | 1バイト | 7 GB |
| INT4 | 0.5バイト | 3.5 GB |
28 GBから3.5 GBは8倍の圧縮率です。
より大きなモデルへのスケーリング:
| モデル | FP16サイズ | INT4サイズ | 圧縮率 |
|---|---|---|---|
| LLaMA-7B | 14 GB | 3.5 GB | 4倍 |
| LLaMA-13B | 26 GB | 6.5 GB | 4倍 |
| LLaMA-70B | 140 GB | 35 GB | 4倍 |
| Mixtral-8x7B | ~90 GB | ~22 GB | 4倍 |
RTX 4090のVRAMは24 GBです。fp16では13Bモデルを載せられません。int4ならCPUオフローディングを有効にして70Bモデルを載せられます。
27.1.2 Quantizationは推論も高速化する
メモリサイズの削減はモデルを収めるためだけではありません。LLMの推論はコンピュート律速ではなくメモリ帯域幅律速なので、生成も高速化されます。
フォワードパスのたびに重み行列をVRAMから読み込み、適用し、中間アクティベーションを破棄します。GPUの行列演算ユニットは高速です---ボトルネックはメモリから重みをどれだけ速くストリーミングできるかです。重みが小さければ = ストリーミングが速くなります。
RTX 3090でのLLaMA-7B計測値:
| 精度 | VRAM使用量 | 生成速度 (トークン/秒) |
|---|---|---|
| FP16 | 14 GB | 25 |
| INT8 | 7 GB | 35 |
| INT4 | 4 GB | 45 |
INT4はFP16より80%速く、VRAMは70%少なく使います。どちらの恩恵も同じ根本原因から来ています: 表現がより小さいということです。
27.1.3 コスト: 精度の損失
Quantizationは重みを近似します。この近似が誤差を生みます:
- 元の値:
0.12345678(FP32、有効十進桁数7桁程度) - INT4量子化後:
0.125になることもある (有効桁数2-3桁)
誤差はレイヤーを通じて積み重なります。実際には現代のQuantization手法はほとんどのタスクで劣化を検知不能なほど小さく抑えますが、すべてのタスクで、すべての精度レベルで、というわけではありません。必ず実際のワークロードで評価してください。
27.2 Quantizationの基礎
27.2.1 Quantizationが何をするか
Quantizationは連続した浮動小数点の範囲を離散的な整数値のセットにマッピングします。
元のFP16重み: -0.5, 0.0, 0.25, 0.5, 0.75, 1.0, ...
INT4量子化後: -8, 0, 2, 4, 6, 7, ...
INT4は16通りの値しかありません。FP16は65,536通りあります。サイズと引き換えに表現の解像度を失います。
27.2.2 線形量子化
標準的なアプローチは線形マッピングを使います:
quantized_value = round((original - zero_point) / scale)
dequantized = quantized_value × scale + zero_point
例: [-1.0, 1.0]の範囲をINT8 [-128, 127]にマッピングする:
scale = 2.0 / 255 # (最大値 - 最小値) / (2^8 - 1)
zero_point = 0
original = 0.5
quantized = round(0.5 / 0.00784) = 64
dequantized = 64 * 0.00784 = 0.50176 # 小さいが非ゼロの誤差
27.2.3 対称量子化と非対称量子化
対称量子化: ゼロ点を0に固定します。演算がシンプルです。重みの分布がゼロ付近に中心がある場合に有効。
q = round(x / scale)
非対称量子化: ゼロ点が移動できます。より柔軟で、偏った分布に適合します。
q = round(x / scale) + zero_point
現代のQuantization手法のほとんどはデフォルトで非対称を使います。
27.2.4 量子化グラニュラリティ
1つのスケールとゼロ点を共有するグループのサイズ:
テンソル単位: 重み行列全体が1ペアを共有します。シンプルで速いですが、行列内で値の範囲が変動すると精度が落ちます。
チャンネル単位: 各出力チャンネルが独自のペアを持ちます。精度が上がり、ストレージのオーバーヘッドは小さいです。
グループ単位: たとえば128個の連続した重みがペアを共有します。GPTQとAWQはどちらもグループサイズ128をデフォルトにしています。実際には精度と効率のトレードオフが最も良いです。
27.2.5 一般的なビット幅
| ビット数 | 整数の範囲 | FP16圧縮率 | 品質 | 一般的な用途 |
|---|---|---|---|---|
| INT8 | -128〜127 | 2倍 | 高 | サーバー推論 |
| INT4 | -8〜7 | 4倍 | 中 | コンシューマ推論 |
| INT3 | -4〜3 | 5.3倍 | 低 | 極限圧縮 |
| INT2 | -2〜1 | 8倍 | 非常に低 | 実験的 |
実践的なアドバイス: 品質が重要でVRAMに余裕があるならINT8。典型的な用途での最良のサイズ/品質トレードオフにはINT4。INT3以下はメモリが極めて限られている場合のみ。
27.3 GPTQ: キャリブレーションを使ったPost-Training Quantization
27.3.1 コアアイデア
GPTQ (GPT Quantization) はポスト学習量子化 (PTQ) の手法です。事前学習済みモデルを取り、小さなキャリブレーションデータセットを通し、導入した誤差を補正しながら重みを量子化します。
目的関数:
ここで W は元の重み、W_q は量子化された重み、X はキャリブレーションデータのアクティベーション行列です。量子化後のレイヤーが代表的な入力に対して元のレイヤーと同じ出力を生成することを目指します。
27.3.2 OBQアルゴリズム
GPTQはOBQ (Optimal Brain Quantization) を基盤としており、これは1990年代のOptimal Brain Damage枝刈り研究の子孫です。
主なステップ:
-
ヘッシアンの計算:
H = 2 X Xᵀ。この行列は各重みの変化に対して出力がどれだけ敏感かをエンコードします。ヘッシアンの対角成分が高い = その重みは重要。 -
貪欲な量子化: 量子化誤差の影響が最も少ない重みの列を選択します。量子化し、残りの未量子化列を導入した誤差を補正するように調整します。
-
全列が量子化されるまで繰り返す。
補正付きの貪欲な選択こそが、GPTQが単純にすべての重みを最近傍の量子化レベルに丸めるよりもはるかに精度が高い理由です。
27.3.3 GPTQの高速化トリック
素朴なOBQは1つの重みを1つずつ処理し、各ステップの後にヘッシアンの更新を再計算します。7B以上のモデルでは法外に遅くなります。
GPTQの実際的な貢献:
バッチ列更新: 1つずつではなく128個の重みをまとめて量子化します。1回のヘッシアン更新がバッチ全体をカバーします。
遅延バッチ更新: ヘッシアンの更新を多くの列にわたって累積してから適用し、メモリトラフィックを削減します。
コレスキー分解: 各ステップの後に再計算するのではなく、コレスキー分解を使って一度だけヘッシアンの逆行列を事前計算します。
これらのトリックにより量子化時間が数週間から数時間に短縮されます。175Bモデルでも1台のA100で4時間以内に量子化できます。
27.3.4 量子化パイプライン
入力: FP16の事前学習済みモデル + キャリブレーションデータセット (128-512サンプル)
出力: INT4量子化モデル
処理:
1. GPUにモデルを読み込む
2. レイヤーごとにアクティベーションをキャプチャしながらキャリブレーションデータを通す
3. 各線形レイヤーに対して:
a. ヘッシアンを構築: H = X @ Xᵀ
b. Hをコレスキー分解する
c. 順番通りに重み列を量子化し、残りの列を調整する
4. 量子化された重みと量子化メタデータ (グループごとのscale, zero_point) を保存する
27.3.5 AutoGPTQの使用例
from transformers import AutoTokenizer
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
# 1. キャリブレーションデータ
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
calibration_data = [
tokenizer("The agent opened a pull request.", return_tensors="pt"),
tokenizer("Review the diff before merging.", return_tensors="pt"),
# 通常はターゲットドメインをカバーする128-512サンプル
]
# 2. 量子化設定
quantize_config = BaseQuantizeConfig(
bits=4,
group_size=128,
desc_act=True, # 精度向上のためアクティベーションを降順にソート
sym=False, # 非対称
)
# 3. 読み込みと量子化
model = AutoGPTQForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantize_config=quantize_config,
)
model.quantize(calibration_data)
# 4. 保存
model.save_quantized("./llama-7b-gptq-4bit")
tokenizer.save_pretrained("./llama-7b-gptq-4bit")
読み込みと推論:
from auto_gptq import AutoGPTQForCausalLM
model = AutoGPTQForCausalLM.from_quantized(
"./llama-7b-gptq-4bit",
device="cuda:0",
use_safetensors=True,
)
inputs = tokenizer("The agent reviewed", return_tensors="pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens=50)
print(tokenizer.decode(outputs[0]))
27.3.6 GPTQのトレードオフ
強み:
- FP16に非常に近い精度 (ほとんどのベンチマークで99%以上)
- ExLlama/ExLlamaV2バックエンドで高速推論
- 大きなエコシステム: HuggingFaceに何千ものGPTQ量子化済みモデル
弱み:
- 量子化自体に数時間かかり、GPUが必要
- キャリブレーションデータが必要 (128-512サンプル)
- CPUサポートが弱く、ローカルCPU推論には実用的でない
27.4 AWQ: アクティベーション対応重み量子化
27.4.1 鍵となる洞察
AWQは重みの重要性に関する経験的な観察から始まります:
約1%の重みがモデル出力に不均衡な影響を持っています。 これらは大きな大きさのアクティベーションに接続された重みです。これらを不注意に量子化すると品質が破壊されます。保護することで品質を維持できます。
問いは: どの重みが「重要」か?アクティベーションを見ればわかります。
重みチャンネルが大きなアクティベーションで掛け算される場合、その重みの量子化誤差は同じ大きさで増幅されます。アクティベーションが大きい = 感度が高い = 保護が必要。
27.4.2 保護戦略
重要な重みを高精度に保つのではなく (均一性が崩れるため)、AWQは量子化前に重要なチャンネルをスケーリングします:
元の計算: y = W @ x
AWQ: y = (W × s) @ (x / s)
出力は同一です。しかし W × s の大きさが増すため、その量子化誤差はスケールに対して相対的に小さくなります。入力側の /s は前のレイヤーの重みに吸収できるため、推論コストは増えません。
最適なスケール係数 s はグリッドサーチで求めます:
def find_best_scale(W, X, n_bits):
best_scale, best_loss = 1.0, float('inf')
for alpha in [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]:
# アクティベーションの大きさのalpha乗に比例するスケール
scale = X.abs().mean() ** alpha
# スケール、量子化、逆量子化
W_scaled = W * scale
W_quant = quantize(W_scaled, n_bits)
W_deq = dequantize(W_quant) / scale
# 出力誤差を測定
loss = ((W @ X) - (W_deq @ X)).pow(2).mean()
if loss < best_loss:
best_loss = loss
best_scale = scale
return best_scale
27.4.3 AutoAWQの使用例
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
model_path = "meta-llama/Llama-2-7b-hf"
model = AutoAWQForCausalLM.from_pretrained(model_path)
tokenizer = AutoTokenizer.from_pretrained(model_path)
quant_config = {
"zero_point": True, # 非対称量子化
"q_group_size": 128, # グループサイズ
"w_bit": 4, # 4ビット
"version": "GEMM", # 推論速度のためのGEMMカーネル
}
model.quantize(tokenizer, quant_config=quant_config)
model.save_quantized("./llama-7b-awq-4bit")
tokenizer.save_pretrained("./llama-7b-awq-4bit")
27.4.4 AWQ vs GPTQ
| 特徴 | GPTQ | AWQ |
|---|---|---|
| 量子化速度 | 遅い (数時間) | 速い (数十分) |
| 出力精度 | 非常に高い | 非常に高い (しばしばより良い) |
| 推論速度 | 速い (ExLlama) | 速い (GEMMカーネル) |
| キャリブレーションデータ | 128-512サンプル | より少ないサンプルで可能 |
| CPUサポート | 貧弱 | 貧弱 |
| エコシステムの成熟度 | 大きい | 急速に成長中 |
私の実践的な推奨: まずAWQを試してください。量子化が速く、品質がわずかに良いことが多いです。特定のベンチマークで最高の精度が必要なら、両方を比較してください。
27.5 GGUF: CPU推論の標準
27.5.1 GGUFとは
GGUF (GPT-Generated Unified Format) はllama.cppが使うモデルファイルフォーマットです。量子化アルゴリズムではなく、モデルを実行するのに必要なすべてを1つにまとめたコンテナフォーマットです:
- 量子化された重みテンソル
- トークナイザーの語彙とマージルール
- アーキテクチャのメタデータ (n_layers, n_heads, d_model, rope_thetaなど)
- モデルのハイパーパラメータ
すべてが1つの .gguf ファイルに。別のトークナイザーJSONも、config.jsonも不要。ダウンロードして実行するだけです。
GGUFはllama.cppの元の名前にある「ML」の部分であるGGMLフォーマットから進化しました。
27.5.2 GGUFの量子化タイプ
GGUFはほぼ無損失から極端な圧縮まで、幅広い量子化レベルをサポートします:
| タイプ | 実効ビット数 | 説明 | 推奨用途 |
|---|---|---|---|
| Q2_K | ~2.5 | 極限圧縮、大きな品質低下あり | RAM非常に限られた場合 |
| Q3_K_S | ~3.0 | 小さいKクォント | RAM少ない |
| Q3_K_M | ~3.3 | 中くらいのKクォント | RAM少ない |
| Q4_0 | 4.0 | 基本的な4ビット、旧フォーマット | 一般用途 |
| Q4_K_S | ~4.5 | 小さいKクォント4ビット | 一般用途 |
| Q4_K_M | ~4.8 | 中くらいのKクォント4ビット | 推奨デフォルト |
| Q5_0 | 5.0 | 基本的な5ビット | 高品質 |
| Q5_K_S | ~5.5 | 小さいKクォント5ビット | 高品質 |
| Q5_K_M | ~5.8 | 中くらいのKクォント5ビット | 高品質推奨 |
| Q6_K | 6.0 | 6ビットKクォント | ほぼ無損失 |
| Q8_0 | 8.0 | 8ビット、ほぼ元の精度 | RAMがある場合 |
| F16 | 16.0 | 半精度、圧縮なし | リファレンス |
Kクォント (_K_ バリアント) は混合戦略を使います: 重要なレイヤー (Attention QとKのプロジェクション) は高い精度、重要度が低いレイヤー (FFNの中間層) は低い精度。同じ平均ビット数で、Kクォントは一様量子化より優れています。
27.5.3 Q4_0とQ4_K_Mの内部
Q4_0 (シンプルなケース):
32個の重みごとに1つのFP16スケール係数を共有。
保存量: 32 × 4ビット + 16ビット = 144ビット
重みあたりの平均ビット数: 4.5
Q4_K_M (Kクォント):
レイヤーごとに異なる扱い:
- Attention Q/Kプロジェクション: より高い精度で保存
- FFN中間層: より低い精度で保存
- 全体の平均: 重みあたり~4.8ビット
結果: Q4_0より同じサイズでパープレキシティが顕著に良い
27.5.4 GGUFへの変換
# 1. llama.cppのクローンとビルド
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make -j
# 2. HuggingFaceモデルをGGUFに変換 (fp16の中間ファイル)
python convert.py /path/to/llama-7b-hf \
--outfile llama-7b-f16.gguf \
--outtype f16
# 3. Q4_K_Mに量子化
./quantize llama-7b-f16.gguf llama-7b-q4_k_m.gguf Q4_K_M
27.5.5 llama.cppで実行
# 直接生成
./main -m llama-7b-q4_k_m.gguf \
-p "The agent opened a pull request" \
-n 128 \
--temp 0.7
# OpenAI互換APIサーバー
./server -m llama-7b-q4_k_m.gguf \
--host 0.0.0.0 \
--port 8080
27.5.6 Pythonバインディング
from llama_cpp import Llama
llm = Llama(
model_path="./llama-7b-q4_k_m.gguf",
n_ctx=4096, # コンテキスト長
n_gpu_layers=35, # GPUにオフロードするレイヤー数 (0 = CPUのみ)
n_threads=8, # CPUスレッド数
)
output = llm(
"The agent reviewed the diff and",
max_tokens=128,
temperature=0.7,
stop=["</s>"],
)
print(output["choices"][0]["text"])
n_gpu_layers パラメータにより部分的なGPUオフローディングが可能です。16 GBユニファイドメモリを持つMacBook Pro M2なら7B Q4_K_Mモデルをメモリにフル収納できます。同じファイルがLinuxサーバーでも動き、速度のためGPUレイヤーにオフロードできます。
27.5.7 GGUFのトレードオフ
強み:
- 最高クラスのCPU推論パフォーマンス、特にApple Silicon (Metal) とAVX対応x86で
- シングルポータブルファイルフォーマットで配布が簡単
- GPUは不要、システムRAMだけで実行できる
- アクティブなコミュニティ、新しいモデルサポートが素早く追加される
- CPU/GPU混合セットアップでの部分的なGPUオフローディング
弱み:
- HuggingFaceエコシステムにネイティブではない (変換ステップが必要)
- LoRAアダプタのサポートが限定的でGPUパスほど成熟していない
- 同等のビット深度でGPTQ/AWQより最高精度がわずかに低い
27.6 その他のQuantization手法
27.6.1 bitsandbytes (BNB)
学習と推論向けのHuggingFace統合量子化。INT8とNF4をサポート。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # NormalFloat4
bnb_4bit_compute_dtype="float16",
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=bnb_config,
device_map="auto",
)
BNBの利点はロード時の即時量子化です---別の量子化ステップもキャリブレーションデータも不要です。モデルが4ビットで読み込まれます。これがQLoRAが凍結ベース重みに使っているものです。
27.6.2 SmoothQuant
INT8推論向けに設計されています。鍵となる観察: アクティベーションは重みより量子化しにくいです (より大きな外れ値を持っています)。SmoothQuantは数学的に等価なスケールを通じて量子化の難しさをアクティベーションから重みに移します:
y = (X / s) @ (W × s)
アクティベーションの分散を減らすようにsを選ぶことで、両側がINT8に量子化しやすくなります。
27.6.3 EETQ
EETQ (Efficient and Easy Transformer Quantization) は推論スループット向けに最適化されたINT8重みのみ量子化手法です。重みとアクティベーションの両方を量子化するのではなく、アクティベーションをfp16のまま保ち、重み行列だけをINT8に量子化することで、完全なINT8量子化と比べて精度損失を大幅に削減します。EETQは現代のNVIDIA GPUで効率的なカーネルレベルのINT8 GEMMルーチンを使います。実際の結果として、BNB INT8より同等か少し良い精度で高いスループットを実現し、キャリブレーションのオーバーヘッドはほぼゼロです。キャリブレーションデータセットを用意せずにINT8 GPU推論が必要な場合の良いデフォルト選択です。
from transformers import AutoModelForCausalLM, EetqConfig
eetq_config = EetqConfig("int8")
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=eetq_config,
device_map="auto",
)
27.6.4 HQQ (半二次量子化)
キャリブレーションデータ不要、高速な量子化、低ビット幅でもまずまずの精度。
from transformers import AutoModelForCausalLM, HqqConfig
hqq_config = HqqConfig(nbits=4, group_size=128)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=hqq_config,
device_map="auto",
)
HQQはキャリブレーションセットを用意せずに高速な量子化が必要な場合に便利です。精度はGPTQ/AWQよりわずかに劣りますが、多くの場合許容範囲です。
27.7 比較と選択ガイド
27.7.1 全比較
| 手法 | ビット数 | 量子化速度 | 推論速度 | 精度 | キャリブレーションデータ | CPUサポート |
|---|---|---|---|---|---|---|
| GPTQ | 4/3/2 | 遅い | 速い (ExLlama) | 非常に高い | あり | 貧弱 |
| AWQ | 4 | 中程度 | 速い (GEMM) | 非常に高い | あり (少なくて可) | 貧弱 |
| GGUF | 2-8 | 速い | 中程度 | 中〜高 | なし | 優秀 |
| BNB NF4 | 4 | 即時 | 中程度 | 中程度 | なし | 貧弱 |
| HQQ | 4/3/2 | 速い | 中程度 | 中程度 | なし | 中程度 |
27.7.2 LLaMA-7BのパープレキシティComparison (WikiText-2)
パープレキシティは低いほど良い。FP16がリファレンス:
| 手法 | FP16 | INT8 | INT4 |
|---|---|---|---|
| 元のモデル (FP16) | 5.68 | --- | --- |
| GPTQ | --- | 5.70 | 5.85 |
| AWQ | --- | 5.69 | 5.78 |
| GGUF Q4_K_M | --- | --- | 5.92 |
| BNB NF4 | --- | 5.72 | 6.05 |
INT4でのAWQとGPTQはFP16からパープレキシティ0.25ポイント以内です。ほとんどの実用タスクで差は見えません。
27.7.3 ユースケース別デシジョンツリー
推論ハードウェアは何ですか?
├── NVIDIA GPU
│ ├── 優先: 品質 → AWQまたはGPTQ (両方を比較)
│ ├── 優先: 速いデプロイ → BNB (即時、キャリブレーション不要)
│ └── 優先: スループット → GPTQ + ExLlamaV2
├── CPU (Linux/Windows)
│ └── GGUF (バランスにはQ4_K_M、品質重視にはQ5_K_M)
├── Apple Silicon (Mac)
│ └── GGUF + Metal (llama.cpp Metalビルド)
└── GPU + CPUオフロードの混合
└── GGUF (利用可能なVRAMに合わせてn_gpu_layersを調整)
| シナリオ | 推奨 | 理由 |
|---|---|---|
| GPU推論、品質優先 | AWQ | 量子化が最速、精度が優秀 |
| GPU推論、速いデプロイ | BNB NF4 | オフラインステップなし、ただロードするだけ |
| CPU推論 | GGUF Q4_K_M | 最高のCPUパフォーマンス、ポータブルフォーマット |
| Apple Silicon | GGUF + Metal | Metalバックエンドは小さいモデルでCUDAに匹敵 |
| 極限メモリ制限 | GGUF Q2_KまたはQ3_K | 最深の圧縮 |
| 高スループットサービング | GPTQ + ExLlamaV2 | 1ドルあたり最高のGPUスループット |
27.8 実践的な検証
27.8.1 量子化前チェックリスト
- ターゲットハードウェアを特定する: GPU → GPTQ/AWQ; CPU → GGUF; Mac → GGUF Metal。
- 精度ターゲットを設定する: 品質優先 → Q5_K_M; バランス → Q4_K_M; メモリ優先 → Q3_K。
- キャリブレーションデータを用意する (GPTQ/AWQのみ): ターゲットユースケースを代表する128-512サンプル。
- 評価メトリクスを把握する: パープレキシティはプロキシです。タスク固有のベンチマークで測定してください。
27.8.2 量子化後の検証
def evaluate_quantized_model(original_model, quantized_model, test_prompts):
"""元のモデルと量子化モデルの出力を比較する。"""
results = []
for prompt in test_prompts:
orig_out = original_model.generate(prompt, max_new_tokens=100)
quant_out = quantized_model.generate(prompt, max_new_tokens=100)
results.append({
"prompt": prompt,
"original": orig_out,
"quantized": quant_out,
"match": orig_out == quant_out,
})
return results
# 確認すべき点:
# 1. 出力が一貫している (文字化けしていない)
# 2. 保留中の評価セットでのタスク精度
# 3. エッジケース: 非常に短いプロンプト、長いコンテキスト、珍しい語彙
27.8.3 よくある失敗モード
量子化後に出力が文字化けする:
- 通常は量子化が積極的すぎる (Q4が正解なのにQ2かQ3を使っている)
- キャリブレーションデータが悪い (範囲が狭すぎる、代表的でない)
- 解決策: 精度を上げるかキャリブレーションセットを広げる
推論速度が改善しない:
- ハードウェアが効率的な低精度カーネルをサポートしていない
- 正しいバックエンドを有効化し忘れている (GPTQにはExLlama、AWQにはGEMM、MacのllaamaにはMetal)
- 解決策: バックエンドの設定を明示的に確認する
VRAMの使用量が減らない:
- 期待より高い精度でモデルが読み込まれている (読み込み呼び出しの
dtypeを確認) - 量子化が適用されているが正しく保存/再読み込みされていない
- 解決策:
model.dtypeを表示して期待と一致しているか確認する
27.9 第27章まとめ
27.9.1 キーコンセプト
| コンセプト | 説明 |
|---|---|
| Quantization | 重みをより少ないビットで保存してメモリを削減し、多くの場合速度も改善する |
| GPTQ | キャリブレーションデータを使ってレイヤーごとに誤差を補正するポスト学習量子化 |
| AWQ | スケーリングで感度の高い1%の重みを保護するアクティベーション対応量子化 |
| GGUF | llama.cppのモデルフォーマット; CPUフレンドリー、ポータブル、2ビットから8ビットを1ファイルにカバー |
| Kクォント | レイヤーの重要度に基づいてビットを配分するGGUFの混合精度バリアント |
| BNB NF4 | NormalFloat4を使ったロード時の即時4ビット量子化; QLoRAが使っているもの |
27.9.2 メモリクイックリファレンス
| FP16サイズ | INT8サイズ | INT4サイズ | 圧縮率 |
|---|---|---|---|
| 14 GB (7B) | 7 GB | 3.5 GB | 2倍 / 4倍 |
| 26 GB (13B) | 13 GB | 6.5 GB | 2倍 / 4倍 |
| 140 GB (70B) | 70 GB | 35 GB | 2倍 / 4倍 |
27.9.3 核心的な学び
Quantizationは大規模モデルの推論を広く普及させた技術です。fp16重みをint4に縮小するとメモリが4分の1になり、多くの場合推論が速くなります。帯域幅が本当のボトルネックだからです。GPU品質ではGPTQとAWQが先頭、CPUポータビリティではGGUFが先頭。リーダーボードのランキングではなく、あなたのハードウェアに基づいて選択し、必ず実際のタスクで評価してください。
チャプターチェックリスト
このチャプターを終えたら、以下ができるはずです:
- fp16、int8、int4での任意のモデルのメモリフットプリントを計算できる。
- Quantizationが多くの場合推論を高速化する理由 (帯域幅の議論) を説明できる。
- GPTQのOBQベースの誤差補正メカニズムを説明できる。
- AWQが何を保護し、どのように重要な重みチャンネルをスケーリングするかを説明できる。
- GGUFとは何か (フォーマット vs アルゴリズム)、Q4_K_Mが何を意味するかを説明できる。
- ハードウェアと品質要件に基づいて適切なQuantization手法を選択できる。
パート8 完了
デプロイメントとFine-Tuningのセクションが完成しました:
| 章 | トピック | コア技術 |
|---|---|---|
| 26 | LoRAとQLoRA | 低ランク適応、NF4、効率的なFine-Tuning |
| 27 | モデルのQuantization | GPTQ、AWQ、GGUF、BNB |
この2つの章はLLMをデプロイするすべての人への2つの実践的な問いに答えています:
- データセンターなしでこのモデルを自分のタスクに適応させるにはどうすればいいか? (LoRA / QLoRA)
- 適応させた後、このモデルを安く動かすにはどうすればいいか? (Quantization)
次の章へ
Quantizationは推論のコスト面を処理します。次の問いは品質面です: モデルに実際に何をやってほしいかをどう伝えるか?
第28章ではPrompt Engineeringを扱います---ゼロショットとフューショットの基礎から、Chain-of-Thought、Self-Consistency、Tree-of-Thought、そしてプロンプトがツールを使うエージェントを指揮する現代の世界まで。