Skip to content
Published on

LLM量子化技法完全比較:GPTQ、AWQ、GGUF 実践適用ガイド

Authors
  • Name
    Twitter
LLM量子化技法比較

はじめに

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モデルメモリ
FP3232bit約±3.4×10^38~280GB
FP1616bit約±6.5×10^4~140GB
INT88bit-128 ~ 127~70GB
INT44bit-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)アルゴリズムを基盤としている。核心的なアイデアは以下の通りである。

  1. レイヤー単位の量子化:モデル全体を一度に量子化するのではなく、レイヤー単位で順次処理する
  2. ヘッセ行列ベースの補正:量子化による出力誤差をヘッセ逆行列を活用して残りの重みで補償する
  3. 列順序の最適化:量子化順序を最適化して誤差伝搬を最小化する

数学的には、各重み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らが提案した手法で、核心的な観察はすべての重みが同等に重要ではないという点である。

  1. Salient Weight(重要な重み)の識別:活性化(Activation)の大きさを基準に、重要な重みチャネル(約1%)を識別する
  2. 選択的保護:重要な重みにスケーリングファクターを適用して量子化誤差を低減する
  3. 残りの量子化:残りの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_K2.6bit~2.8GB+2.5~3.0極限メモリ制限
Q3_K_M3.3bit~3.5GB+1.0~1.5メモリ制限環境
Q4_K_M4.5bit~4.9GB+0.3~0.5汎用推奨
Q5_K_M5.3bit~5.7GB+0.1~0.2品質重視
Q6_K6.6bit~6.6GB+0.05ほぼ無損失
Q8_08.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

核心特性比較表

項目GPTQAWQGGUFBitsAndBytes
量子化方式PTQ(ヘッセ基盤)PTQ(Activation-aware)PTQ(多様な方式)動的量子化
基本ビット4bit4bit2~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.4Q4_K_M: +0.3~0.5基準+0.2~0.4

推論性能ベンチマーク(Llama-3.1-8B、A100 80GB)

手法スループット(tok/s)VRAM使用量HumanEval Pass@1レイテンシ(TTFT)
FP16(基準)~35016GB53.2%45ms
GPTQ 4bit~5205.5GB50.6%32ms
GPTQ + Marlin~7125.5GB50.6%25ms
AWQ 4bit~5505.2GB51.8%30ms
AWQ + Marlin~7415.2GB51.8%23ms
GGUF Q4_K_M~2804.9GB51.8%55ms
BitsAndBytes NF4~3005.8GB51.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~8BGPTQ/AWQ 4bitFP16推奨GGUF Q4_K_M
13BGPTQ/AWQ 4bitFP16またはAWQ 4bitGGUF Q4_K_M
34BGGUF Q4_K_MAWQ 4bit + MarlinGGUF Q3_K_M
70BGGUF Q3_K_M(部分)AWQ 4bit + MarlinGGUF 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.0torch>=2.1.0の組み合わせを推奨する。CUDAバージョンも12.1以上が安定的だ。

量子化品質検証チェックリスト

  1. Perplexity測定:オリジナル対比でperplexityの増加が0.5以内かを確認
  2. タスク別ベンチマーク:実際の使用タスク(コード生成、要約など)で品質を確認
  3. エッジケーステスト:長い入力、多言語、数学問題などの境界ケースを検証
  4. レイテンシプロファイリング:TTFT(Time to First Token)とTPS(Tokens per Second)を測定
  5. メモリモニタリング:実際のサービング環境でのVRAM使用量を追跡

おわりに

LLMの量子化は単にモデルサイズを縮小することではなく、デプロイの可能性を決定する核心技術である。2026年現在の推奨事項をまとめると以下の通りだ。

  • プロダクションGPUサービング:AWQ + Marlinカーネル(最高スループット + 高品質)
  • 開発/実験:BitsAndBytes NF4(量子化プロセス不要、QLoRA統合)
  • エッジ/CPUデプロイ:GGUF Q4_K_M(汎用性、単一ファイル配布)
  • レガシー互換:GPTQ(最も広いエコシステムサポート)

量子化技法は進化を続けている。2025年以降に登場したMarlinカーネルのように、アルゴリズム自体よりもカーネル実装の最適化が実際の性能により大きな影響を与えるトレンドだ。新しい量子化手法を評価する際には、理論的な利点だけでなく実際のサービング環境でのベンチマークを必ず確認しよう。

参考資料

  1. Frantar et al., "GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers" (2022)
  2. Lin et al., "AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration" (2024)
  3. Hugging Face Transformers Quantization Guide
  4. vLLM Quantization Documentation
  5. llama.cpp GitHub Repository - GGUF Format
  6. The Complete Guide to LLM Quantization with vLLM: Benchmarks
  7. AutoGPTQ GitHub Repository
  8. AutoAWQ - Applying AWQ Quantization
  9. BitsAndBytes Foundation GitHub
  10. Dettmers et al., "QLoRA: Efficient Finetuning of Quantized LLMs" (2023)