- Authors
- Name
- はじめに
- 量子化の基本原理
- GPTQ:Generative Pre-trained Transformer Quantization
- AWQ:Activation-aware Weight Quantization
- GGUF:GPU-poor向け汎用フォーマット
- BitsAndBytesとQLoRAの統合
- 総合比較:GPTQ vs AWQ vs GGUF vs BitsAndBytes
- モデル別量子化品質ガイド
- 運用時の注意事項とトラブルシューティング
- おわりに
- 参考資料

はじめに
70Bパラメータ LLMをFP16でロードすると、約140GBのVRAMが必要になる。A100 80GB 2枚でもぎりぎりのレベルだ。しかし**量子化(Quantization)**を適用すれば、同じモデルを単一のGPUで運用できる。INT4量子化を適用すれば、70Bモデルが約35GBに縮小し、A100 1枚に載せられるようになる。
2024年から2026年の間に、量子化技法は急速に発展した。GPTQ、AWQ、GGUF、BitsAndBytesなどさまざまな手法が登場し、それぞれ精度-速度-メモリのトレードオフが異なる。この記事では各技法の原理を深く分析し、実践コードとベンチマークを通じて最適な選択肢を案内する。
量子化の基本原理
FP16からINT4への道のり
量子化とは、高精度の浮動小数点(FP16/FP32)重みを低ビットの整数(INT8/INT4)に変換するプロセスである。
| データ型 | ビット数 | 表現範囲 | 70Bモデルメモリ |
|---|---|---|---|
| FP32 | 32bit | 約±3.4×10^38 | ~280GB |
| FP16 | 16bit | 約±6.5×10^4 | ~140GB |
| INT8 | 8bit | -128 ~ 127 | ~70GB |
| INT4 | 4bit | -8 ~ 7 | ~35GB |
Absmax 量子化
最も単純な量子化方法で、テンソルの絶対最大値を基準にスケーリングする。
import torch
def absmax_quantize(tensor: torch.Tensor, bits: int = 8) -> tuple:
"""Absmax量子化:絶対最大値基準スケーリング"""
qmax = 2 ** (bits - 1) - 1 # INT8なら127
scale = tensor.abs().max() / qmax
quantized = torch.round(tensor / scale).clamp(-qmax, qmax).to(torch.int8)
return quantized, scale
def absmax_dequantize(quantized: torch.Tensor, scale: float) -> torch.Tensor:
"""逆量子化:元のスケールに復元"""
return quantized.float() * scale
# 例:FP16重みの量子化
weight = torch.randn(4096, 4096, dtype=torch.float16)
q_weight, scale = absmax_quantize(weight.float())
restored = absmax_dequantize(q_weight, scale)
error = (weight.float() - restored).abs().mean()
print(f"平均量子化誤差: {error:.6f}")
Zero-Point 量子化
Absmaxは分布が対称でない場合に非効率的である。Zero-Point量子化は非対称分布を処理する。
import torch
def zeropoint_quantize(tensor: torch.Tensor, bits: int = 8) -> tuple:
"""Zero-Point量子化:非対称分布対応"""
qmin = -(2 ** (bits - 1))
qmax = 2 ** (bits - 1) - 1
rmin, rmax = tensor.min(), tensor.max()
scale = (rmax - rmin) / (qmax - qmin)
zero_point = torch.round(qmin - rmin / scale).clamp(qmin, qmax)
quantized = torch.round(tensor / scale + zero_point).clamp(qmin, qmax).to(torch.int8)
return quantized, scale, zero_point
def zeropoint_dequantize(quantized: torch.Tensor, scale: float, zero_point: float) -> torch.Tensor:
"""Zero-Point逆量子化"""
return (quantized.float() - zero_point) * scale
# 非対称分布テスト(ReLU出力のように正数偏重)
weight = torch.randn(4096, 4096).abs() # 正数のみ
q_weight, scale, zp = zeropoint_quantize(weight)
restored = zeropoint_dequantize(q_weight, scale, zp)
error = (weight - restored).abs().mean()
print(f"Zero-Point量子化平均誤差: {error:.6f}")
Group-wise 量子化
テンソル全体ではなく小さなグループ(通常128個の要素)単位で量子化すると、精度が大幅に向上する。GPTQ、AWQともにgroup_size=128をデフォルト設定として使用する。
GPTQ:Generative Pre-trained Transformer Quantization
アルゴリズムの詳細
GPTQは2022年にFrantarらが提案したPost-Training Quantization(PTQ)手法で、OBQ(Optimal Brain Quantization)アルゴリズムを基盤としている。核心的なアイデアは以下の通りである。
- レイヤー単位の量子化:モデル全体を一度に量子化するのではなく、レイヤー単位で順次処理する
- ヘッセ行列ベースの補正:量子化による出力誤差をヘッセ逆行列を活用して残りの重みで補償する
- 列順序の最適化:量子化順序を最適化して誤差伝搬を最小化する
数学的には、各重みw_qを量子化する際、残りの重みを以下のように更新する:
delta_w = -(w - quant(w)) / H_inv[q,q] * H_inv[:, q]
ここでH_invはヘッセ逆行列である。これにより量子化誤差が他の重みに再分配される。
AutoGPTQによる量子化の実行
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
from transformers import AutoTokenizer
import torch
# 1. 量子化設定
model_name = "meta-llama/Llama-3.1-8B-Instruct"
quantize_config = BaseQuantizeConfig(
bits=4, # 4ビット量子化
group_size=128, # 128個の要素単位グループ
desc_act=True, # Activation order使用
damp_percent=0.01, # ヘッセ damping比率
sym=True, # 対称量子化
)
# 2. モデルおよびトークナイザーのロード
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoGPTQForCausalLM.from_pretrained(
model_name,
quantize_config=quantize_config,
torch_dtype=torch.float16,
)
# 3. キャリブレーションデータの準備
calibration_data = [
tokenizer("The meaning of life is", return_tensors="pt"),
tokenizer("Artificial intelligence has", return_tensors="pt"),
tokenizer("In the context of machine learning", return_tensors="pt"),
# 実際には128~256個の多様なサンプル使用を推奨
]
# 4. 量子化実行(Llama-3.1-8B基準で約15~30分)
model.quantize(calibration_data)
# 5. 量子化モデルの保存
output_dir = "./llama-3.1-8b-gptq-4bit"
model.save_quantized(output_dir)
tokenizer.save_pretrained(output_dir)
print(f"量子化完了。保存先: {output_dir}")
GPTQの長所と短所
長所:
- 4ビットまで量子化してもオリジナル対比で高い精度を維持
- Marlinカーネル使用時に推論速度が大幅向上(2.6倍の高速化)
- Hugging Face Transformersのネイティブサポート
短所:
- キャリブレーションデータが必要(通常128~256サンプル)
- 量子化時間が比較的長い(8Bモデル基準で15~30分)
- GPU専用(CPU推論非対応)
AWQ:Activation-aware Weight Quantization
原理と差別化ポイント
AWQは2024年にMITのLinらが提案した手法で、核心的な観察はすべての重みが同等に重要ではないという点である。
- Salient Weight(重要な重み)の識別:活性化(Activation)の大きさを基準に、重要な重みチャネル(約1%)を識別する
- 選択的保護:重要な重みにスケーリングファクターを適用して量子化誤差を低減する
- 残りの量子化:残りの99%の重みには通常の量子化を適用する
GPTQとの核心的な違いは、ヘッセ逆行列の計算が不要という点だ。AWQは単純な統計ベースのアプローチで、より高速に量子化しながらも同等またはそれ以上の品質を達成する。
AutoAWQによる量子化の実行
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
# 1. モデルのロード
model_path = "meta-llama/Llama-3.1-8B-Instruct"
model = AutoAWQForCausalLM.from_pretrained(
model_path,
low_cpu_mem_usage=True,
use_cache=False,
)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
# 2. 量子化設定
quant_config = {
"zero_point": True, # Zero-Point量子化を使用
"q_group_size": 128, # グループサイズ
"w_bit": 4, # 4ビット量子化
"version": "GEMM", # GEMMカーネル(汎用)vs GEMV(バッチ=1最適化)
}
# 3. 量子化実行(GPTQより高速、約10分)
model.quantize(tokenizer, quant_config=quant_config)
# 4. 保存
output_dir = "./llama-3.1-8b-awq-4bit"
model.save_quantized(output_dir)
tokenizer.save_pretrained(output_dir)
print(f"AWQ量子化完了: {output_dir}")
AWQの長所と短所
長所:
- GPTQより高速な量子化速度
- Activation-awareアプローチにより高い品質を維持(HumanEval Pass@1: 51.8%)
- Marlin-AWQカーネル適用時に741 tok/sの高いスループット
- vLLMのネイティブサポート
短所:
- GPU専用(CPU推論非対応)
- GGUFに比べてエコシステムが小さい
- 一部のモデルアーキテクチャで互換性の問題
GGUF:GPU-poor向け汎用フォーマット
GGUFフォーマットとllama.cppエコシステム
GGUF(GPT-Generated Unified Format)は量子化アルゴリズムではなくファイルフォーマットである。llama.cppプロジェクトが作成したこのフォーマットは、CPUとGPUのハイブリッド推論をサポートする。
GGUFの核心的な特徴:
- 単一ファイル:モデルの重み、トークナイザー、メタデータが一つのファイルに含まれる
- CPU推論サポート:GPUなしでも推論が可能
- ハイブリッドオフローディング:一部のレイヤーはGPU、残りはCPUで処理
- 多様な量子化レベル:Q2_KからQ8_0まで細かい品質-サイズの調整が可能
GGUF量子化タイプ別比較
| 量子化タイプ | ビット数 | Llama-3.1-8Bサイズ | Perplexity増加 | 推奨用途 |
|---|---|---|---|---|
| Q2_K | 2.6bit | ~2.8GB | +2.5~3.0 | 極限メモリ制限 |
| Q3_K_M | 3.3bit | ~3.5GB | +1.0~1.5 | メモリ制限環境 |
| Q4_K_M | 4.5bit | ~4.9GB | +0.3~0.5 | 汎用推奨 |
| Q5_K_M | 5.3bit | ~5.7GB | +0.1~0.2 | 品質重視 |
| Q6_K | 6.6bit | ~6.6GB | +0.05 | ほぼ無損失 |
| Q8_0 | 8.0bit | ~8.5GB | ~0 | 無損失に近い |
llama.cppによるGGUF量子化
# 1. llama.cppのビルド
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp && mkdir build && cd build
cmake .. -DGGML_CUDA=ON # GPUアクセラレーション使用時
cmake --build . --config Release
# 2. HFモデルをGGUF FP16に変換
python convert_hf_to_gguf.py \
/path/to/Llama-3.1-8B-Instruct \
--outtype f16 \
--outfile llama-3.1-8b-f16.gguf
# 3. Q4_K_Mで量子化
./build/bin/llama-quantize \
llama-3.1-8b-f16.gguf \
llama-3.1-8b-q4_k_m.gguf \
Q4_K_M
# 4. 推論テスト
./build/bin/llama-cli \
-m llama-3.1-8b-q4_k_m.gguf \
-p "Explain quantum computing in simple terms:" \
-n 256 \
--n-gpu-layers 35 # GPUオフローディングレイヤー数
llama-cpp-pythonによるPython連携
from llama_cpp import Llama
# GGUFモデルのロード(GPUレイヤーオフローディング含む)
llm = Llama(
model_path="./llama-3.1-8b-q4_k_m.gguf",
n_gpu_layers=35, # GPUに載せるレイヤー数(-1なら全体)
n_ctx=4096, # コンテキスト長
n_threads=8, # CPUスレッド数
verbose=False,
)
# テキスト生成
output = llm(
"Explain the difference between TCP and UDP:",
max_tokens=512,
temperature=0.7,
top_p=0.9,
stop=["\\n\\n"],
)
print(output["choices"][0]["text"])
# ChatCompletion APIスタイル
response = llm.create_chat_completion(
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is quantization in ML?"},
],
max_tokens=512,
temperature=0.7,
)
print(response["choices"][0]["message"]["content"])
BitsAndBytesとQLoRAの統合
4ビット推論とファインチューニング
BitsAndBytesはHugging Face Transformersと直接統合されており、別途の量子化プロセスなしにロード時に量子化を適用する。QLoRAと組み合わせれば、量子化されたモデルの上にLoRAアダプターを学習できる。
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
)
# 4ビット量子化設定
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # NormalFloat4(QLoRA論文)
bnb_4bit_compute_dtype=torch.bfloat16, # 演算はBF16で
bnb_4bit_use_double_quant=True, # 二重量子化(追加のメモリ節約)
)
# モデルのロード(ロード時に自動量子化)
model_name = "meta-llama/Llama-3.1-8B-Instruct"
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# メモリ使用量の確認
print(f"モデルメモリ: {model.get_memory_footprint() / 1e9:.2f} GB")
# 推論
inputs = tokenizer("Explain gradient descent:", return_tensors="pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens=200)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
BitsAndBytesの特徴
長所:
- 事前量子化プロセスが不要(ロード時に即座に適用)
- QLoRAファインチューニングとの自然な統合
- Hugging Faceエコシステムの完全サポート
- NF4量子化による高い品質維持
短所:
- 推論速度がGPTQ/AWQに比べて遅い(カスタムカーネルの欠如)
- 量子化されたモデルをファイルとして保存/共有しにくい
- CUDA専用(AMD/CPU非対応、ただし2025年からROCmの部分的サポート)
総合比較:GPTQ vs AWQ vs GGUF vs BitsAndBytes
核心特性比較表
| 項目 | GPTQ | AWQ | GGUF | BitsAndBytes |
|---|---|---|---|---|
| 量子化方式 | PTQ(ヘッセ基盤) | PTQ(Activation-aware) | PTQ(多様な方式) | 動的量子化 |
| 基本ビット | 4bit | 4bit | 2~8bit選択可 | 4bit(NF4) |
| キャリブレーション | 必要(128~256サンプル) | 必要(少量) | 不要 | 不要 |
| 量子化時間 | 15~30分(8B) | ~10分(8B) | 数分 | ロード時に即座 |
| GPU推論 | 非常に高速 | 最も高速 | 高速(オフロード時) | 普通 |
| CPU推論 | 非対応 | 非対応 | 対応 | 非対応 |
| vLLMサポート | 対応 | 対応 | 部分対応 | 対応 |
| ファインチューニング | 限定的 | 限定的 | 非対応 | QLoRA最適 |
| モデル共有 | HF Hubアップロード | HF Hubアップロード | 単一ファイル配布 | 困難 |
| Perplexity(4bit) | 基準+0.3~0.5 | 基準+0.2~0.4 | Q4_K_M: +0.3~0.5 | 基準+0.2~0.4 |
推論性能ベンチマーク(Llama-3.1-8B、A100 80GB)
| 手法 | スループット(tok/s) | VRAM使用量 | HumanEval Pass@1 | レイテンシ(TTFT) |
|---|---|---|---|---|
| FP16(基準) | ~350 | 16GB | 53.2% | 45ms |
| GPTQ 4bit | ~520 | 5.5GB | 50.6% | 32ms |
| GPTQ + Marlin | ~712 | 5.5GB | 50.6% | 25ms |
| AWQ 4bit | ~550 | 5.2GB | 51.8% | 30ms |
| AWQ + Marlin | ~741 | 5.2GB | 51.8% | 23ms |
| GGUF Q4_K_M | ~280 | 4.9GB | 51.8% | 55ms |
| BitsAndBytes NF4 | ~300 | 5.8GB | 51.8% | 50ms |
上記ベンチマークで注目すべき点は、カーネル実装がアルゴリズムよりも重要ということである。Marlinカーネルを使用すると、GPTQは2.6倍、AWQは10.9倍の速度向上を得られる。
vLLMでの量子化モデルサービング
from vllm import LLM, SamplingParams
# AWQモデルのサービング(Marlinカーネル自動適用)
llm = LLM(
model="casperhansen/llama-3.1-8b-instruct-awq",
quantization="awq_marlin", # Marlinカーネルを明示
max_model_len=8192,
gpu_memory_utilization=0.85,
dtype="half",
)
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
max_tokens=1024,
)
prompts = [
"Explain the CAP theorem in distributed systems.",
"Write a Python function to implement binary search.",
"What are the SOLID principles in software engineering?",
]
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
prompt = output.prompt
generated = output.outputs[0].text
print(f"Prompt: {prompt[:50]}...")
print(f"Output: {generated[:200]}...")
print("---")
モデル別量子化品質ガイド
モデルサイズ別推奨量子化
| モデルサイズ | 消費者GPU(24GB) | サーバーGPU(80GB) | CPU専用 |
|---|---|---|---|
| 7~8B | GPTQ/AWQ 4bit | FP16推奨 | GGUF Q4_K_M |
| 13B | GPTQ/AWQ 4bit | FP16またはAWQ 4bit | GGUF Q4_K_M |
| 34B | GGUF Q4_K_M | AWQ 4bit + Marlin | GGUF Q3_K_M |
| 70B | GGUF Q3_K_M(部分) | AWQ 4bit + Marlin | GGUF Q2_K |
タスク別推奨量子化レベル
- コード生成:AWQ 4bit推奨(HumanEval基準で最高精度)
- 長文生成/要約:Q5_K_M以上推奨(低い量子化で繰り返しが増加)
- 分類/NER:INT4で十分(精度への影響が軽微)
- 数学的推論:Q6_K以上またはAWQ 4bit推奨(数値に敏感)
運用時の注意事項とトラブルシューティング
よく発生する問題
1. GPTQ量子化中のOOM発生
キャリブレーション時にメモリ不足が発生したら、desc_act=Falseに変更し、damp_percentを上げてみよう。
2. AWQモデルでの異常な出力
量子化バージョン(GEMM vs GEMV)と推論フレームワークが合っていない可能性がある。vLLMではawq_marlinを明示するのが安全だ。
3. GGUFモデルが遅い場合
n_gpu_layersの値を上げて、より多くのレイヤーをGPUにオフローディングしよう。全レイヤー数より高く設定すれば、すべてGPUに載る。
4. BitsAndBytesでのtorchバージョン衝突
bitsandbytes>=0.43.0とtorch>=2.1.0の組み合わせを推奨する。CUDAバージョンも12.1以上が安定的だ。
量子化品質検証チェックリスト
- Perplexity測定:オリジナル対比でperplexityの増加が0.5以内かを確認
- タスク別ベンチマーク:実際の使用タスク(コード生成、要約など)で品質を確認
- エッジケーステスト:長い入力、多言語、数学問題などの境界ケースを検証
- レイテンシプロファイリング:TTFT(Time to First Token)とTPS(Tokens per Second)を測定
- メモリモニタリング:実際のサービング環境でのVRAM使用量を追跡
おわりに
LLMの量子化は単にモデルサイズを縮小することではなく、デプロイの可能性を決定する核心技術である。2026年現在の推奨事項をまとめると以下の通りだ。
- プロダクションGPUサービング:AWQ + Marlinカーネル(最高スループット + 高品質)
- 開発/実験:BitsAndBytes NF4(量子化プロセス不要、QLoRA統合)
- エッジ/CPUデプロイ:GGUF Q4_K_M(汎用性、単一ファイル配布)
- レガシー互換:GPTQ(最も広いエコシステムサポート)
量子化技法は進化を続けている。2025年以降に登場したMarlinカーネルのように、アルゴリズム自体よりもカーネル実装の最適化が実際の性能により大きな影響を与えるトレンドだ。新しい量子化手法を評価する際には、理論的な利点だけでなく実際のサービング環境でのベンチマークを必ず確認しよう。
参考資料
- Frantar et al., "GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers" (2022)
- Lin et al., "AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration" (2024)
- Hugging Face Transformers Quantization Guide
- vLLM Quantization Documentation
- llama.cpp GitHub Repository - GGUF Format
- The Complete Guide to LLM Quantization with vLLM: Benchmarks
- AutoGPTQ GitHub Repository
- AutoAWQ - Applying AWQ Quantization
- BitsAndBytes Foundation GitHub
- Dettmers et al., "QLoRA: Efficient Finetuning of Quantized LLMs" (2023)