【ローカルLLM】Hugging FaceによるGPTQ量子化ガイド

  • ローカルLLMの量子化フォーマットとしては、llama.cpp(GGUF/GGML)とGPTQの2種類が広く使われている。

  • 主要なモデルはTheBloke氏によって迅速に量子化されるので、基本的に自分で量子化の作業をする必要はない。

  • が、たまに量子化されていないモデルを使ってみたい時もあるので、自分でもサクっとできたら嬉しい。

  • llama.cppによる量子化は、Readmeに説明されている手順で手軽に行える(CPUのみで処理が完結)。

  • GPTQの量子化は敷居高そうな雰囲気を醸してるが、一応HuggingFace Transformersでできるそうなので、まずガイドを読んでみた。


Transformersモデルを量子化する🤗

AutoGPTQの統合

🤗 Transformers には、言語モデルで GPTQ 量子化を実行するための optimum API が統合されています。モデルを 8、4、3、さらには 2 ビットでロードおよび量子化することで、パフォーマンスを大幅に低下させることなく、推論速度を高速化します!これは、ほとんどの GPU ハードウェアでサポートされています。

量子化モデルの詳細については、以下も確認してください。

GPTQ のペーパー
・GPTQ量子化に関するoptimumガイド
・バックエンドとして用いられるAutoGPTQライブラリ

Requirements

後述のコードを実行するには、次のRequirementsがインストールされている必要があります。

・最新のAutoGPTQライブラリをインストール
 pip install auto-gptq
・ソースから最新のoptimumをインストール
 pip install git+https://github.com/huggingface/optimum.git
・ソースから最新のtransformersをインストール
 pip install git+https://github.com/huggingface/transformers.git
・最新のaccelerateライブラリをインストール
 pip install --upgrade accelerate

GPTQ の統合は現時点ではテキストモデルのみをサポートしており、視覚、音声、またはマルチモーダルモデルでは予期しない動作が発生する可能性があることに注意してください。

モデルをロードして量子化

GPTQ は、量子化モデルを使用する前に重みのキャリブレーションを必要とする量子化手法です。トランスフォーマーモデルを最初から量子化する場合は、量子化モデルを作成するまでに時間がかかる場合があります (facebook/opt-350mの場合、Google colabで約 5 分)。

したがって、GPTQ 量子化モデルを使用するシナリオは 2 つあります。最初の使用例は、ハブで利用可能な他のユーザーによってすでに量子化されたモデルをロードすることです。2 番目の使用例は、モデルを最初から量子化し、保存するかハブにプッシュして、他のユーザーが使用できるようにすることです。

GPTQ Configuration

モデルをロードして量子化するには、GPTQConfigを作成する必要があります。ビット数、量子化をキャリブレーションするためのデータセット、データセットを準備するためのモデルのトークナイザーを渡す必要があります。

model_id = "facebook/opt-125m"
tokenizer = AutoTokenizer.from_pretrained(model_id)
gptq_config = GPTQConfig(bits=4, dataset = "c4", tokenizer=tokenizer)

なお、独自のデータセットを文字列のリストとして渡すこともできます。しかし、GPTQ論文のデータセットを使うことを強く推奨します。

dataset = ["auto-gptq is an easy-to-use model quantization library with user-friendly apis, based on GPTQ algorithm."]
quantization = GPTQConfig(bits=4, dataset = dataset, tokenizer=tokenizer)

量子化

from_pretrainedを使い、quantization_configを設定することで、モデルを量子化することができます。

from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=gptq_config)

モデルを量子化するにはGPUが必要です。モデルをCPUに置き、量子化するためにモジュールをGPUに行ったり来たりさせます。

CPUオフロードを使用しながらGPUの使用量を最大にしたい場合は、device_map = "auto "に設定できます。

from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", quantization_config=gptq_config)

ディスク・オフロードはサポートされていないことに注意してください。さらに、データセットのためにメモリが不足している場合、from_pretainedにmax_memoryを渡す必要があるかもしれません。device_mapとmax_memoryについては、こちらのガイドを参照してください。

※GPTQ量子化は、今のところテキストモデルに対してのみ機能します。さらに、量子化処理にはハードウェアによって多くの時間がかかります(NVIDIA A100を使用した場合、175Bモデルで4GPU時間)。このモデルのGPTQ量子化バージョンがないかどうか、ハブで確認してください。ない場合は、githubで要求を出すこともできます。

量子化モデルを🤗ハブにプッシュ

他の🤗モデルと同様に、量子化されたモデルをpush_to_hubを使用してハブにプッシュできます。量子化構成は保存され、モデルに沿ってプッシュされます。

quantized_model.push_to_hub("opt-125m-gptq")
tokenizer.push_to_hub("opt-125m-gptq")

量子化されたモデルをローカルマシンに保存したい場合は、save_pretrainedを使うこともできます。

quantized_model.save_pretrained("opt-125m-gptq")
tokenizer.save_pretrained("opt-125m-gptq")

device_mapでモデルを量子化した場合は、保存する前に、必ずモデル全体をGPUかCPUの1つに移動してください。

quantized_model.to("cpu")
quantized_model.save_pretrained("opt-125m-gptq")

🤗ハブから量子化モデルをロード

from_pretrainedを使用して、量子化されたモデルをハブからロードできます。モデル構成オブジェクトにquantization_config属性が存在することを確認して、プッシュされた重みが量子化されていることを確認します。

from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("{your_username}/opt-125m-gptq")

必要以上のメモリを割り当てずに、より速くモデルをロードしたい場合、device_map引数は量子化モデルでも動作します。accelerateライブラリがインストールされていることを確認してください。

from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("{your_username}/opt-125m-gptq", device_map="auto")

高速推論のためのExllamaカーネル

4ビットモデルでは、より高速な推論を行うためにexllamaカーネルを使用することができます。これはデフォルトで有効になっています。GPTQConfigにdisable_exllamaを渡すことでこの動作を変更できます。これはconfigに保存されている量子化設定を上書きします。上書きできるのはカーネルに関連する属性だけであることに注意してください。さらに、exllamaカーネルを使いたい場合は、モデル全体をgpus上に置く必要があります。

import torch
gptq_config = GPTQConfig(bits=4, disable_exllama=False)
model = AutoModelForCausalLM.from_pretrained("{your_username}/opt-125m-gptq", device_map="auto", quantization_config = gptq_config)

今のところexllamaカーネルは4ビットモデルしかサポートされていないことに注意してください。さらに、peftで量子化モデルを微調整する場合は、exllamaカーネルを無効にすることをお勧めします。

量子化モデルのファインチューン

Hugging Faceエコシステムのアダプターの公式サポートにより、GPTQで量子化されたモデルを微調整することができます。詳しくはpeftライブラリをご覧ください。

デモ

GPTQ を使ってモデルを量子化する方法と、peft を使って量子化されたモデルを微調整する方法については、Google Colab のノートブックをご覧ください。

参考:GPTQConfig

パラメータ:

  • bits (int) - 量子化するビット数。 サポートされる数字は(2、3、4、8)。

  • tokenizer (str or PreTrainedTokenizerBase, optional) - データセットの処理に利用されるトークナイザ。以下のいずれかを渡すことができます:

    • カスタムトークナイザーオブジェクト

    • 文字列。huggingface.co のモデルレポジトリにホストされている、定義済みのトークナイザーのモデル ID。有効なモデル ID は、bert-base-uncased のようにルートレベルにあるか、dbmdz/bert-base-german-cased のようにユーザー名や組織名の下に名前空間があります。

    • 例えば./my_model_directory/.のようにsave_pretrained() メソッドを使用して保存された、トークナイザが必要とする語彙ファイルを含むディレクトリへのパス。

  • dataset (Union[List[str]], optional) - 量子化に使用するデータセット。独自のデータセットを文字列のリストで提供することも、GPTQ論文で使用されたオリジナルのデータセット['wikitext2','c4','c4-new','ptb','ptb-new']を使用することもできます。

  • group_size (int, optional, defaults to 128) - 量子化に使用するグループサイズ。推奨値は 128 で、-1 を指定すると列ごとの量子化が行われます。

  • damp_percent (float, optional, defaults to 0.1) - 平均的なヘシアンの対角に対する減衰の割合.推奨値は0.1。

  • desc_act (bool, optional, defaults to False) - 活性化サイズの小さい順に列を量子化するかどうか。Falseに設定すると、推論が大幅に高速化されますが、perplexityが若干悪化する可能性があります。act-orderとしても知られる。

  • sym (bool, optional, defaults to True) - シンメトリック量子化を使用するかどうか。

  • true_sequential (bool, optional, defaults to True) - 1つのTransformerブロック内でも逐次量子化を行うかどうか。ブロック全体を一度に量子化するのではなく、レイヤーごとに量子化を行います。その結果、各レイヤは、以前に量子化されたレイヤを通過した入力を使用して量子化を受けます。

  • use_cuda_fp16 (bool, optional, defaults to False) - fp16モデルに最適化されたcudaカーネルを使用するかどうか。fp16のモデルが必要。

  • model_seqlen (int, optional) - モデルが取ることのできる最大シーケンス長。

  • block_name_to_quantize (str, optional) - 量子化するトランスフォームブロック名.

  • module_name_preceding_first_block (List[str], optional) - 最初のトランスフォーマーブロックに先行するレイヤー.

  • batch_size (int, optional, defaults to 1) - データセットの処理時に使用するバッチサイズ。

  • pad_token_id (int, optional) - パッドトークンID。batch_size > 1 のときにデータセットを準備するために必要。

  • disable_exllama (bool, optional, defaults to False) - exllamaバックエンドを使うかどうか。bits = 4の場合のみ動作。