量子化形式とそのコスト
FP32からINT4、NF4、GGUFのk-quant、AWQ、GPTQまでを1ページにまとめ、パラメータあたりのバイト数、7 Bと70 Bモデルのメモリ量、報告されている精度への影響、ハードウェア対応を示します。
このページは、手持ちのハードウェアにモデルをどう収めるかを決める人のためのものです。各行には、保存コスト、7 Bと70 Bの密モデルの重みに必要なメモリ、その形式の論文や保守者が精度について報告している内容、そしてカーネルが存在する場所を示します。重みは予算の一部にすぎません。KVキャッシュ、活性、オプティマイザの状態がその上に乗り、長いコンテキストではKVキャッシュが支配的になります。背景は /topics/efficient-ml/ と /topics/hardware-and-acceleration/ を参照してください。
数値形式
メモリの数値は重みのみで、パラメータ数にパラメータあたりのバイト数を掛けて丸めたものです。「ビット」には、ブロック形式が重みと一緒に持つスケールとゼロ点を含めています。
| 形式 | 重みあたりのビット数 | パラメータあたりのバイト数 | 7 Bの重み | 70 Bの重み | 報告されている精度への影響 | ハードウェア対応 |
|---|---|---|---|---|---|---|
| FP32 | 32(符号1、指数8、仮数23) | 4.0 | 28 GB | 280 GB | 基準 | すべて |
| TF32 | 19を使用(指数8、仮数10)、FP32として格納 | 4.0 | 28 GB | 280 GB | 演算用の形式であり、保存用ではない。NVIDIAはテストしたモデルでFP32と同等の学習精度を報告している | Ampere(2020年)以降のNVIDIA tensorコア。PyTorchでは畳み込みには既定で有効、行列積はtorch.backends.cuda.matmul.allow_tf32 = Trueを設定しない限り無効 |
| BF16 | 16(指数8、仮数7) | 2.0 | 14 GB | 140 GB | Kalamkar et al.(2019)は、損失スケーリングなしでCNN、RNN、Transformerの学習がFP32と同等だったと報告 | NVIDIA Ampere以降、AMD MI200以降、TPU(ネイティブ形式)、Apple M2以降、AVX-512 BF16またはAMX対応のx86 CPU |
| FP16 | 16(指数5、仮数10) | 2.0 | 14 GB | 140 GB | Micikevicius et al.(2017)は、マスターコピーと損失スケーリングによりFP32と同等だったと報告。65,504を超えるとオーバーフローするため、活性が発散しうる | 2017年以降のほぼすべてのGPU(NVIDIA Volta tensorコア、Pascalはスループット低下あり)、Apple Silicon、FP16拡張を持つARM CPU |
| FP8 E4M3 | 8(指数4、仮数3) | 1.0 | 7 GB | 70 GB | Micikevicius et al.(2022)は、テンソル単位のスケーリングと重み・活性へのE4M3の使用により、GPT-3規模のモデルで学習と推論の結果が16ビットと同等だったと報告 | NVIDIA HopperとAda(2022年)以降、AMD MI300。Transformer Engineまたはtorch.float8_e4m3fn経由 |
| FP8 E5M2 | 8(指数5、仮数2) | 1.0 | 7 GB | 70 GB | 同じ論文: レンジの広い変種で、逆伝播の勾配に使われる | 同じハードウェア |
| INT8(重みと活性) | 8 | 1.0 | 7 GB | 70 GB | Dettmers et al.(2022、LLM.int8)は、外れ値の特徴を16ビットで保持すれば175 Bまでパープレキシティの劣化がないと報告。Xiao et al.(2022、SmoothQuant)は、活性の外れ値を重みに移すことでOPTとBLOOMのW8A8がFP16と同等の精度だったと報告 | NVIDIA Turing以降のtensorコア、VNNIまたはAMX対応のIntel CPU、ほとんどのモバイルNPU、AMD MI200以降 |
| INT4(重みのみ、素朴な方式) | 4とグループごとのスケール | 0.5〜0.56 | 3.5〜3.9 GB | 35〜39 GB | 丸めの方法に完全に依存する。キャリブレーションなしの4ビット最近傍丸めはGPTQとAWQの出発点であり、どちらも小さいモデルでは顕著に劣化すると報告している | HopperにはネイティブのINT4 tensorコアがない(Ampere以降で削除)。重みはカーネル内で16ビットに逆量子化される。BlackwellはFP4を追加 |
| NF4(bitsandbytes) | 4とブロックスケール(二重量子化) | 約0.53 | 3.7 GB | 37 GB | Dettmers et al.(2023、QLoRA)は、LoRAを使った4ビットNF4のファインチューニングが同論文のベンチマークで16ビットのフルファインチューニングと同等であり、同じサイズでNF4が素朴なFP4とINT4に勝ると報告 | ソフトウェアのみ: bitsandbytesのCUDAカーネル。ROCmとCPUバックエンドは新しく、遅い。行列積のたびにBF16に逆量子化されるため16ビットより遅い |
モデルファイル形式
これらは独自の量子化を含むパッケージ方式で、学習ではなく推論に使われます。
| 形式 | 重みあたりのビット数 | パラメータあたりのバイト数 | 7 Bのファイル | 70 Bのファイル | 報告されている精度への影響 | ハードウェア対応 |
|---|---|---|---|---|---|---|
| GGUF Q8_0 | 8と32重みごとのFP16スケール1つ、計8.5 | 1.06 | 7.4 GB | 74 GB | llama.cpp保守者のパープレキシティ表では、LlamaモデルでFP16とノイズの範囲内 | CPU(AVX2、AVX-512、NEON)、Metal、CUDA、Vulkan、ROCm、SYCL。llama.cppとOllama経由 |
| GGUF Q6_K | 約6.6 | 0.82 | 5.7 GB | 57 GB | 保守者の表: パープレキシティの増加はごくわずか | 同じ |
| GGUF Q5_K_M | 約5.7 | 0.71 | 5.0 GB | 50 GB | 保守者の表: 小さな増加。収まるなら通常は品質面での選択肢 | 同じ |
| GGUF Q4_K_M | 約4.85(4ビットの重み、6ビットのブロックスケール、一部のテンソルはより高精度) | 0.61 | 4.2 GB | 42 GB | 保守者の表: 目に見えるが小さなパープレキシティの増加。ほとんどのツールが選ぶ既定値 | 同じ |
| GGUF Q4_0 | 4.5 | 0.56 | 3.9 GB | 39 GB | 旧来の4ビット方式で、ほぼ同じサイズのQ4_K_Mより劣る。ARM向けに最適化した再パック版が存在する | 同じ。一部のARM CPUでは最速 |
| GGUF Q3_K_MとQ2_K | 約3.9と3.4 | 0.49と0.42 | 3.4と2.9 GB | 34と29 GB | 保守者の表: 明確な劣化があり、小さいモデルで最悪。重要度行列(imatrix)量子化で一部回復する | 同じ |
| GPTQ(4ビット、グループ128) | 4と128ごとのFP16スケールとゼロ点、約4.25 | 0.53 | 3.7 GB | 37 GB | Frantar et al.(2022)は、二次の誤差補正によりOPT-175BとBLOOM-176Bで4ビットの精度損失が無視できる程度であり、3ビットも実用的だったと報告 | vLLM、GPTQModel、TransformersのCUDAとROCmカーネル(Marlin、ExLlama)。重みのみで、カーネル内で逆量子化 |
| AWQ(4ビット、グループ128) | 約4.25 | 0.53 | 3.7 GB | 37 GB | Lin et al.(2023)は、活性が重要だと示す1%のチャネルをスケーリングすることで、同じビット幅のGPTQと最近傍丸めよりLlamaとOPTで低いパープレキシティを得たと報告。逆伝播は不要 | vLLM、AutoAWQ、TensorRT-LLMのCUDAカーネル。重みのみ |
3つの4ビット系は、パラメータあたりのバイト数で互いに0.1以内に収まります。実行環境で選びます。llama.cppとOllamaならGGUF、NVIDIA上のvLLMならAWQかGPTQ、QLoRAでのファインチューニングならNF4です。形式間の変換は、互いからではなく16ビットの元モデルから再量子化することを意味します。
数値が隠しているもの
- 重みは予算のすべてではありません。4ビットの7 Bモデルの重みは4 GBですが、32層・8 KVヘッドのモデルで32 kコンテキストにすると、FP16ではシーケンスあたり約1 GBのKVキャッシュが加わります。サービングエンジンはキャッシュも量子化します(vLLMとTensorRT-LLMのFP8 KVキャッシュ、llama.cppのQ8)。
- パープレキシティはどの論文も報告する指標ですが、コードや数学のように正解が1つのタスクでの損傷を過小評価します。自分のタスクの下流ベンチマークを信頼区間付きで確認してください(/reference/evaluation-metrics/ を参照)。
- 小さいモデルほど失うものが大きいです。論文の見出しの数値は65 B〜175 Bのモデルのものです。1 Bや3 Bのモデルを4ビットにすると、推論ベンチマークで数ポイント落ちることがあります。
- 重みのみの形式はメモリと、メモリ律速のデコードフェーズを助けます。計算律速で逆量子化後に16ビットで動くプリフィルは速くなりません。W8A8とFP8は両方を速くします。
- 量子化ファインチューニング(QLoRA)は、凍結した4ビットの重みの上で16ビットのアダプタを学習します。ベースモデルの丸め誤差は焼き込まれたままです。
- 速度は形式よりカーネルに依存します。同じAWQチェックポイントでも、バッチサイズとGPU世代によってFP16より速くも遅くもなります。計測してください。
int8量子化の具体例
対称int8は、範囲[-max|w|, max|w|]を1つのスケールで[-127, 127]に写像します。テンソル単位のスケーリングでは、たった1つの外れ値がレベルの大半を無駄にします。行単位(チャネル単位)のスケーリングは、出力行ごとに1つのスケールを持つ代わりにこれを解決し、表のすべてのINT8方式がそうしています。
import numpy as np
rng = np.random.default_rng(0)
w = rng.normal(0.0, 0.02, size=(256, 1024)).astype(np.float32) # a weight matrix like a small linear layer
w[3, 17] = 0.5 # one outlier, as real weights have
def quantise_int8_symmetric(x: np.ndarray, axis=None):
"""Symmetric int8: q = round(x / s), s = max|x| / 127. axis=None is per-tensor, axis=1 per output row."""
amax = np.abs(x).max() if axis is None else np.abs(x).max(axis=axis, keepdims=True)
scale = np.maximum(amax, 1e-12) / 127.0
q = np.clip(np.rint(x / scale), -128, 127).astype(np.int8)
return q, scale.astype(np.float32)
def dequantise(q, scale):
return q.astype(np.float32) * scale
for name, axis in [("per-tensor", None), ("per-row", 1)]:
q, s = quantise_int8_symmetric(w, axis)
w_hat = dequantise(q, s)
err = w_hat - w
rel = np.linalg.norm(err) / np.linalg.norm(w)
zeros = (q == 0).mean()
print(f"{name:11} bytes/param 1.0 relative error {rel:.4f} max abs error {np.abs(err).max():.5f} weights rounded to zero {zeros:.1%}")
print("fp32 bytes:", w.nbytes, " int8 bytes:", w.size, " ratio:", w.nbytes / w.size)
per-tensor bytes/param 1.0 relative error 0.0568 max abs error 0.00197 weights rounded to zero 7.8%
per-row bytes/param 1.0 relative error 0.0087 max abs error 0.00197 weights rounded to zero 1.1%
fp32 bytes: 1048576 int8 bytes: 262144 ratio: 4.0
0.02前後の重みの行列に0.5の外れ値が1つあるだけで、テンソル単位のスケールは各行に必要な粗さの25倍になり、重みの7.8%がゼロに丸められ、誤差は6倍になります。行単位のスケーリングなら、悪い行は1つで残り255行は良好です。グループ単位のスケーリング(GGUF、GPTQ、AWQのように32または128重みごと)は同じ考え方をさらに進めたもので、これらの形式がスケールを持ち、重みあたりのビット数が切りのよい数にならないのはそのためです。
出典
- Kalamkar et al., A Study of BFLOAT16 for Deep Learning Training, 2019
- Micikevicius et al., Mixed Precision Training, 2017
- Micikevicius et al., FP8 Formats for Deep Learning, 2022
- Dettmers et al., LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale, 2022
- Xiao et al., SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models, 2022
- Dettmers et al., QLoRA: Efficient Finetuning of Quantized LLMs, 2023
- 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, 2023
- GGUF仕様とllama.cppの量子化ツール
- NVIDIA A100のTensorFloat-32(TF32)
- PyTorchの数値精度とTF32に関するノート
- bitsandbytesドキュメントとvLLMの量子化サポート