コンテンツにスキップ

量子化

言語モデルのデコードはトークンごとに全重みを 1 回ストリームするので、デコード速度はメモリ帯域そのものです。weight-only 量子化は同じ matmul をより少ないバイト数で済ませます: int8 は float32 の 1/4、int4 は 1/8。tensai は Matrix の量子化された双子を作ります — float32 の元はそのまま、量子化コピーが float32 の入出力で MatVec/MatMul に答えます。

int8: quant.Quantize

q := quant.Quantize(w)     // *QMatrix、列ごとのスケール
q.MatVec(x, out)                  // デコード: ベクトル 1 本
q.MatMul(x, out)                  // プレフィル: バッチ行

int8 パスは完全な整数パイプラインです。重みはインターリーブされた 4 行組で格納され、活性値は呼び出しごとに 7 ビットへ動的量子化され、内積全体が 256 ビットの u8 x s8 ペア積和 + 拡張ペア加算で回ります — 列あたり 2 命令、4 行同時。これでメモリ帯域 (16 コアで重み約 31GB/s) に到達します。デコード matvec の実質的な上限です。

int4: quant.Quantize4

q4, err := quant.Quantize4(w)  // *Q4Matrix、グループ単位のスケール

int4 はグループ単位 (列内の行グループごとにスケール、またはスケール/最小値ペア) に量子化し、グループ境界で float32 に累積します。int8 からさらに重みを半分にします — 7B モデルが RAM に収まるかどうかの分かれ目です。

MXFP4

mxfp4.go は gpt-oss がエキスパートの重みに使う MXFP4 ブロック形式を実装しています: 2 のべき乗スケールを共有する 32 要素の 4 ビット float ブロックです。ブロックは 1 シャッフルのテーブルルックアップカーネルで展開されるので、gpt-oss-20b のエキスパートはネイティブ形式のまま最後まで動きます。

量子化が使われる場所

  • _example/gpt2 -q8 はデコードパスの重みを量子化して生成を 2 倍にします (23 → 46 tok/s)。デコードはトークンごとにチェックポイント全体をストリームするからです
  • tensai コマンドは -q8-q4 を受け付けます。各重みはロード時に量子化され float32 コピーは即座に破棄されるので、フル精度のモデルがメモリに収まる必要はありません
  • 量子化済み GGUF チェックポイント (Q8_0, Q4_0, Q5_0, Q4_K/Q5_K/Q6_K 系, MXFP4) はメモリマップしたファイルからこれらのレイアウトへ直接リパックされ、float32 を経由しません — llama.cpp 自身の量子化がそのまま保たれます
  • GPU では UploadQ8/UploadQ4 が重みを量子化したままデバイスに置き、レジスタ内で逆量子化します — GPU (WebGPU) 参照

Note

量子化デコードの出力は一貫していますが、greedy でも float32 リファレンスのトークン列を正確には再現しなくなります。ビット一致のリファレンスチェックには float32 パスを使ってください。