科学と神々株式会社アドベントカレンダー 2025
LLM量子化 Day 3: 量子化の基本原理
コンピュータは数をどう表現するか
量子化を理解するために、まずコンピュータがどのように数を表現しているかを見てみましょう。
私たちが普段使う「3.14159」のような小数は、コンピュータ内部では「浮動小数点数」という形式で保存されます。FP16(16ビット浮動小数点数)の場合、1つの数値を16個のビット(0と1)で表現します。
FP16の構造(16ビット):
┌─────┬───────────┬──────────────────┐
│符号 │ 指数部 │ 仮数部 │
│ 1bit│ 5bit │ 10bit │
└─────┴───────────┴──────────────────┘
この16ビットで、-65504から+65504までの範囲を、約3〜4桁の精度で表現できます。
量子化の核心:「間引く」こと
量子化の本質は、連続的な値を離散的な値に変換することです。
わかりやすい例で考えてみましょう。
身長を測るとき、「175.3847cm」まで測れる精密な身長計と、「175cm」しか表示できない簡易な身長計があったとします。後者は精度が低いですが、ほとんどの目的には十分ですよね。
量子化も同じです。FP16で表現できる膨大な数(約6万5千種類)を、INT4(4ビット整数)で表現できる16種類に「間引く」のです。
FP16: -65504 〜 +65504 の間の無数の値
↓ 量子化
INT4: -8, -7, -6, ..., 0, ..., +6, +7 の16種類のみ
線形量子化:最もシンプルな方法
最も基本的な量子化方法は「線形量子化」です。値の範囲を均等に分割して、各値を最も近い区間に割り当てます。
例:0〜100の値を4段階に量子化
元の値 → 量子化後
0〜25 → 0
26〜50 → 1
51〜75 → 2
76〜100 → 3
実際の計算では、「スケール」と「ゼロポイント」という2つのパラメータを使います。
量子化: q = round(x / scale + zero_point)
逆量子化: x' = scale × (q - zero_point)
ここで重要なのは、量子化して逆量子化しても、元の値に完全には戻らないということです。この差が「量子化誤差」です。
量子化誤差:避けられない代償
「42.7」という値を4ビット整数に量子化し、再び元に戻す過程を見てみましょう。
元の値: 42.7
↓ 量子化(スケール=10, ゼロポイント=0)
量子化値: round(42.7 / 10) = 4
↓ 逆量子化
復元値: 4 × 10 = 40.0
誤差: 42.7 - 40.0 = 2.7
この誤差は避けられません。しかし、LLMの重みは統計的に特定のパターンを持っているため、うまく量子化すれば誤差の影響を最小限に抑えられます。
対称量子化と非対称量子化
量子化には大きく2つのスタイルがあります。
対称量子化
0を中心に対称的に量子化します。実装がシンプルで計算が速いですが、値の分布が偏っている場合に無駄が生じます。
対称量子化(4ビット、符号付き):
-8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7
└──────────────────┼──────────────────────────┘
0(必ず正確に表現される)
非対称量子化
値の実際の範囲を最大限に活用します。精度は高くなりますが、ゼロポイントの計算が追加で必要です。
非対称量子化:
min ゼロポイント max
│ │ │
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
どちらが良いかは、データの分布やユースケースによります。LLMの重みは比較的0を中心に対称的な分布を持つことが多いため、対称量子化がよく使われます。
グループ量子化:精度向上の秘訣
ここまでの説明では、モデル全体または層全体に対して1つのスケールを使うことを想定していました。しかし、これには問題があります。
外れ値問題
重みの中に極端に大きな値(外れ値)があると、スケールがその値に引っ張られて、他の値の精度が犠牲になります。
例:値の分布が [0.1, 0.2, 0.1, 0.3, 50.0, 0.2] の場合
全体スケール: 50.0 を表現するためにスケールを大きく設定
→ 0.1〜0.3の小さな値は粗く量子化される
グループ量子化の解決策
重みを小さなグループ(例:128個ずつ)に分割し、各グループに個別のスケールを設定します。
グループ1 [0.1, 0.2, ..., 0.3] → スケール=0.05
グループ2 [0.5, 50.0, ..., 0.8] → スケール=8.0
グループ3 [0.2, 0.1, ..., 0.2] → スケール=0.04
これにより、外れ値の影響が局所化され、全体的な精度が向上します。
llm-quantizeでは、デフォルトのグループサイズを128に設定しています。これは精度と効率のバランスが良いとされる値です。
なぜLLMの量子化はうまくいくのか
「こんなに粗く量子化して、本当に大丈夫なの?」という疑問は自然です。LLMの量子化がうまくいく理由を3つ挙げましょう。
1. 冗長性
LLMには多くの冗長性があります。70億個のパラメータすべてが等しく重要なわけではありません。多くのパラメータは似たような値を持っており、多少の誤差は問題になりません。
2. 誤差の相殺
量子化誤差はランダムな方向に発生します。正の誤差と負の誤差が統計的に相殺し合うため、全体としての影響は小さくなります。
3. 重要な重みの保護
現代の量子化手法(k-quant、AWQなど)は、重要な重みを特定し、それらを高い精度で保持します。すべての重みを平等に扱うのではなく、「賢い」量子化を行います。
Tips: 量子化を理解するための実験
理解を深めるために、簡単な実験をしてみましょう。
import numpy as np
# 元のデータ(疑似的な重み)
original = np.random.randn(1000) * 0.1 # 平均0、標準偏差0.1
# 量子化(4ビット相当)
scale = (original.max() - original.min()) / 15
zero_point = -original.min() / scale
quantized = np.round(original / scale + zero_point).astype(int)
quantized = np.clip(quantized, 0, 15)
# 逆量子化
dequantized = scale * (quantized - zero_point)
# 誤差を計算
error = original - dequantized
print(f"平均二乗誤差: {np.mean(error**2):.6f}")
print(f"最大誤差: {np.max(np.abs(error)):.6f}")
この実験で、量子化誤差がどの程度になるか体感できます。
次回予告
Day 4では「量子化手法の分類」について解説します。PTQ(学習後量子化)とQAT(量子化を考慮した学習)の違い、そしてllm-quantizeがなぜPTQを採用しているのかを説明します。
量子化は「情報の圧縮」です。完璧な復元はできませんが、重要な情報を残しながら効率的に圧縮することは可能です。JPEGが画像を圧縮するように、量子化はモデルを圧縮します。