科学と神々株式会社アドベントカレンダー 2025
LLM量子化 Day 17: フォーマット変換
「あちらを立てればこちらが立たず」問題
量子化形式にはそれぞれの特徴があります:
- GGUF: llama.cppエコシステム、CPU/GPU両対応
- AWQ: vLLMに最適、高品質な4ビット
- GPTQ: ExLlama v2に最適、複数ビット幅
「ローカルPCでGGUFを使っていたけど、サーバーではvLLMを使いたい」
「GPTQモデルを入手したけど、llama.cppで動かしたい」
このような場面で、フォーマット変換が必要になります。
変換の全体像
llm-quantizeは、すべての形式間の変換をサポートしています:
変換先
↓
変換元 → GGUF AWQ GPTQ
GGUF - ✓ ✓
AWQ ✓ - ✓
GPTQ ✓ ✓ -
合計6つの変換パスがあります。どの形式からでも、他の2形式に変換可能です。
変換の実際
基本的な使い方
# GGUFからAWQへ
llm-quantize convert ./model.gguf awq -o ./output
# AWQからGGUFへ
llm-quantize convert ./model-awq gguf -o ./output
# GPTQからAWQへ
llm-quantize convert ./model-gptq awq -o ./output
シンプルなコマンドで、形式間の変換ができます。
フォーマットの自動検出
変換を行う前に、ソースの形式を正しく識別する必要があります。llm-quantizeは複数の方法で形式を検出します:
GGUFの検出
1. ファイルであること(ディレクトリではない)
2. 拡張子が .gguf
3. マジックバイトが "GGUF"
GGUFは単一ファイルなので、検出は比較的簡単です。
AWQ/GPTQの検出
1. ディレクトリであること
2. config.jsonが存在
3. quantization_configを確認:
├── quant_method == "awq" → AWQ
└── quant_method == "gptq" → GPTQ
4. quantize_config.jsonが存在 → GPTQ
AWQとGPTQは似たディレクトリ構造を持つため、設定ファイルの内容で区別します。
なぜ変換が難しいのか
形式間の変換は、単なるファイル形式の変換ではありません。量子化アルゴリズム自体が異なるため、変換には「再量子化」が必要です。
変換の実際のプロセス
ソース形式(例: GGUF Q4_K_M)
│
▼ 逆量子化(デクオンタイズ)
中間表現(近似的なFP16)
│
▼ 再量子化
ターゲット形式(例: AWQ 4bit)
問題は、逆量子化で元の値を完全に復元できないことです。量子化で失われた情報は、永久に失われます。
変換結果の表現
変換結果は、ConversionResultとして返されます:
ConversionResult:
├── output_path: 変換後のパス
├── source_format: 元の形式
├── target_format: 変換後の形式
├── file_size: ファイルサイズ
├── is_lossy: 品質劣化の有無
└── warning_message: 警告メッセージ
特に重要なのはis_lossyとwarning_messageです。すべての形式間変換は品質劣化を伴うため、常に警告が出力されます。
変換パスごとの特性
すべての変換が同じではありません。変換パスによって、難易度と品質への影響が異なります:
比較的影響が小さい変換
| 変換パス | 理由 |
|---|---|
| AWQ → GPTQ | 同じGPU向け形式、アルゴリズムも類似 |
| GPTQ → AWQ | 同上 |
AWQとGPTQは、どちらもGPU推論向けの形式で、内部表現が似ています。そのため、相互変換の品質劣化は比較的小さいです。
影響が大きい変換
| 変換パス | 理由 |
|---|---|
| GGUF → AWQ | k-quant情報の損失、再キャリブレーション必要 |
| GGUF → GPTQ | 同上、ヘシアン情報なし |
| AWQ → GGUF | k-quant最適化の恩恵なし |
| GPTQ → GGUF | 同上 |
GGUFとAWQ/GPTQの間の変換は、量子化アルゴリズムが根本的に異なるため、品質への影響が大きくなります。
変換が必要なユースケース
ユースケース1: デプロイ環境の変更
開発時: ローカルPCでGGUFを使用
↓
本番時: vLLMサーバーにデプロイしたい
↓
選択肢:
├── 変換: GGUF → AWQ(品質劣化あり)
└── 推奨: 元モデルからAWQを直接生成
ユースケース2: 既存モデルの活用
状況: GPTQモデルを入手したが、llama.cppで使いたい
↓
選択肢:
├── 変換: GPTQ → GGUF(品質劣化あり)
└── 推奨: 元モデルが入手可能ならGGUFを直接生成
ユースケース3: 実験・比較
目的: 同じモデルで各形式の推論速度を比較したい
↓
変換を使用: 厳密な品質比較には不向きだが、速度比較には十分
実装の工夫
変換関数のルーティング
6つの変換パスに対応するため、マッピングを使用しています:
変換関数マップ:
("gguf", "awq") → _convert_gguf_to_awq()
("gguf", "gptq") → _convert_gguf_to_gptq()
("awq", "gguf") → _convert_awq_to_gguf()
("awq", "gptq") → _convert_awq_to_gptq()
("gptq", "gguf") → _convert_gptq_to_gguf()
("gptq", "awq") → _convert_gptq_to_awq()
新しい形式が追加されても、マッピングを更新するだけで対応できます。
既存ファイルの保護
# デフォルトでは既存ファイルを上書きしない
llm-quantize convert ./model.gguf awq -o ./output
# エラー: Output already exists
# 明示的に上書きを指定
llm-quantize convert ./model.gguf awq -o ./output --force
誤って重要なファイルを上書きしないよう、安全側に倒した設計です。
Tips: フォーマット変換のコツ
1. 元モデルが利用可能なら直接量子化
# 変換よりも直接量子化を優先
llm-quantize quantize meta-llama/Llama-2-7b-hf awq -q 4bit
品質を最大化するには、常に元のFP16/BF16モデルから量子化してください。
2. 変換後は必ず検証
# 変換
llm-quantize convert ./model.gguf awq -o ./output
# 推論テストで品質確認
python -c "
from vllm import LLM
llm = LLM('./output/model-awq', quantization='awq')
print(llm.generate(['Hello, world!']))
"
3. 複数形式が必要なら並行して量子化
# 元モデルから各形式を直接生成
llm-quantize quantize model gguf -q Q4_K_M -o ./gguf &
llm-quantize quantize model awq -q 4bit -o ./awq &
llm-quantize quantize model gptq -q 4bit -o ./gptq &
wait
4. 変換は最後の手段
判断フロー:
├── 元モデルが入手可能?
│ ├── Yes → 直接量子化(推奨)
│ └── No → 変換を検討
│ └── 品質劣化を許容できるか?
│ ├── Yes → 変換を実行
│ └── No → 元モデルの入手を検討
次回予告
Day 18では「Lossy変換の警告」として、品質劣化の詳細と、それを最小化するための戦略について解説します。
「変換できる」ことと「変換すべき」ことは別です。技術的には可能でも、品質を考慮すると別の選択肢が適切な場合があります。ツールの機能を理解した上で、最適な方法を選びましょう。