llama.cpp:再量子化(requantize)による劣化を調べる

  • llama.cpp の量子化では、safetensorsなどの元モデルを一度FP16フォーマットのggufに変換した後で(convert.py)、このFP16モデルをもとに./quantizeによって8bitや4bitなどのggufに圧縮します。
  • ただquantize.cppに目を通すと [--allow-requantize](再量子化を有効にする)というオプションがあり、例えば8bitのggufから4bitのggufに再度圧縮することも可能なことがわかります。

github.com

--allow-requantize: Allows requantizing tensors that have already been quantized. Warning: This can severely reduce quality compared to quantizing from 16bit or 32bit.

すでに量子化されたテンソルを再量子化できるようにする。警告: 16bitや32bitから量子化するのに比べて、品質が著しく低下する可能性があります。

  • このように「再量子化もできるけど、劣化しやすいのでやめたほうがいいよ」という注意書きが書かれています。
  • とはいえ中型以上のモデルだとFP16のファイルサイズはとても大きいので、場合によっては既にある8bitの量子化モデルをもとに4bitや2bitの量子化を行いたい時があります。
  • とりあえず、簡単に再量子化の手順を確認し、通常の量子化とPerplexity(PPL)ベースでどの程度の誤差が出るのかを見てみます。

簡単な検証

  • Mistral 7B instruct v0.2のggufモデルを使い、1)FP16モデルから直接量子化されたQ4K_Medium量子化モデルと、2)一度Q8量子化を行い、さらにQ4K_Mediumに再量子化したモデル でそれぞれPPLを測定します。
  • まず、FP16からの質的劣化はほぼ無いと言われるQ8量子化モデルのPPLは以下の通りでした。

Mistral-7B-Instruct-v0.2: Q8_0 GGUF (7.5GB)

Final estimate: PPL = 6.7117 +/- 0.04375

  • 次に、FP16から直接量子化されたQ4K_MediumのPPLです。PPLが高いほどモデルの量子化誤差が大きいことを意味します。Q8より僅かに変化しているのがわかります。

Mistral-7B-Instruct-v0.2: Q4K_Medium GGUF (4.3GB)

Final estimate: PPL = 6.7742 +/- 0.04414

  • さらに、いったんQ8に量子化した後に--allow-requantizeを有効にしてQ4K_Mediumに再量子化したモデルのPPLを測定します。スコアは以下の通り。

Mistral-7B-Instruct-v0.2: *REQUANT* Q4K_Medium GGUF (4.3GB)

Final estimate: PPL = 6.7611 +/- 0.04393

  • ということで、通常のQ4K_Medium量子化モデルと、再量子化モデルとの間に誤差はありませんでした。

雑感

  • 基本的には「再量子化」は避けたほうがいいようですが、実質的な劣化がほとんどない8bitなど大きめの量子化モデルを使えば、目立った悪影響は出ない可能性が高そうです。
  • 話は反れますが、2bitなど極端な量子化を行うと以下のように大きなPPLの上昇がみられます。

Mistral-7B-Instruct-v0.2: Q2K GGUF (3.0GB)

Final estimate: PPL = 7.0617 +/- 0.04535

  • しかし最近のllama.cppでは、Importance Matrix(重要度行列?)を計算したうえで量子化する手法が熱心に追及されているようで、従来は避けるべきとされていた3bit以下の量子化でもかなり誤差が抑えられるようになっているみたいです。
  • 面白そうなので、この辺りについて引き続き調べてみます。