Bitsandbytes
bitsandbytes ライブラリは、ハードウェアアクセラレータの関数に対する軽量な Python ラッパーを通じて、LLM 用の量子化ツールを提供します。メモリフットプリントを削減することで、限られた計算リソースを用いて大規模モデルを扱うことを可能にします。
bitsandbytes のコア機能として、以下を提供します:
- 量子化されたLinearレイヤー: 標準的なPyTorchのlinearレイヤーを、メモリ効率に優れた量子化された代替レイヤーに置き換える
Linear8bitLtおよびLinear4bitレイヤー - 最適化されたオプティマイザー:
optimモジュールを通じて、一般的なオプティマイザーの8ビット版を提供し、メモリ要件を削減しながら大規模モデルの学習を可能にします - 行列積: 量子化形式を活用した最適化された行列積演算
bitsandbytesには、主に2つの量子化機能があります。
LLM.int8() - 推論をより利用しやすくする8ビット量子化手法であり、性能の大幅な低下を伴いません。単純な量子化とは異なり、LLM.int8()は重要な計算に対して動的に高い精度を維持し、モデルの感度の高い部分における情報損失を防ぎます。
QLoRA - 学習可能な低ランク適応(LoRA)重みの小さなセットを挿入することで、学習可能性を維持しながらモデルをさらに圧縮する4ビット量子化技術。
注: ユーザーフレンドリーな量子化体験を得るには、
bitsandbytesの コミュニティスペース を利用できます。
bitsandbytes をインストールするには、以下のコマンドを実行してください。
pip install --upgrade transformers accelerate bitsandbytes
ソースからコンパイルするには、bitsandbytes インストールガイドの手順に従ってください。
ハードウェアの互換性
bitsandbytes は、CUDA バージョン 11.8 - 13.0 対応の NVIDIA GPU、Intel XPU、Intel Gaudi (HPU)、および CPU でサポートされています。追加のプラットフォームへの対応に向けた取り組みが進行中です。フィードバックの提供やテストにご興味がある場合は、詳細については bitsandbytes リポジトリ をご確認ください。
NVIDIA GPU (CUDA)
このバックエンドは、Linux x86-64、Linux aarch64、および Windows プラットフォームでサポートされています。
| 機能 | 最低限のハードウェア要件 |
|---|---|
| 8ビットオプティマイザー | NVIDIA Pascal (GTX 10X0 シリーズ、P100) 以降の GPU * |
| LLM.int8() | NVIDIA Turing(RTX 20X0 シリーズ、T4)以降の GPU |
| NF4/FP4量子化 | NVIDIA Pascal (GTX 10X0 シリーズ、P100) 以降の GPU * |
Intel GPU(XPU)
このバックエンドは、Linux x86-64 および Windows x86-64 プラットフォームでサポートされています。
Intel Gaudi (HPU)
このバックエンドは、Gaudi2 および Gaudi3 において Linux x86-64 でサポートされています。
CPU
このバックエンドは、Linux x86-64、Linux aarch64、および Windows x86-64 プラットフォームでサポートされています。
量子化の例
BitsAndBytesConfig を from_pretrained() に渡すことでモデルを量子化できます。これは、Accelerate をサポートし、torch.nn.Linear レイヤーを含むモデルであれば、モダリティを問わず適用できます。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model_8bit = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-1b7",
device_map="auto",
quantization_config=quantization_config
)デフォルトでは、torch.nn.LayerNorm などの他のすべてのモジュールは、デフォルトの torch dtype に設定されます。これらのモジュールのデータ型は、dtype パラメータで変更できます。dtype="auto" を設定すると、モデルの config.json ファイルで定義されたデータ型でモデルが読み込まれます。
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model_8bit = AutoModelForCausalLM.from_pretrained(
"facebook/opt-350m",
device_map="auto",
quantization_config=quantization_config,
dtype="auto"
)
model_8bit.model.decoder.layers[-1].final_layer_norm.weight.dtypeモデルが8ビットに量子化されると、push_to_hub()を使用して量子化済みモデルをHubにプッシュできますが、そのためにはTransformersとbitsandbytesの最新バージョンを使用している必要があります。最新バージョンを使用している場合、まず量子化設定のconfig.jsonファイルがプッシュされ、その後、量子化済みモデルの重みがプッシュされます。
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-560m",
device_map="auto",
quantization_config=quantization_config
)
model.push_to_hub("bloom-560m-8bit")from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_4bit=True)
model_4bit = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-1b7",
device_map="auto",
quantization_config=quantization_config
)デフォルトでは、torch.nn.LayerNorm などの他のすべてのモジュールは torch.float16 に変換されます。これらのモジュールのデータ型は、dtype パラメータで変更できます。dtype="auto" を設定すると、モデルの config.json ファイルで定義されたデータ型でモデルが読み込まれます。
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_4bit=True)
model_4bit = AutoModelForCausalLM.from_pretrained(
"facebook/opt-350m",
device_map="auto",
quantization_config=quantization_config,
dtype="auto"
)
model_4bit.model.decoder.layers[-1].final_layer_norm.weight.dtype4ビットモデルをシリアライズしてpush_to_hub()でHubにプッシュできるように、bitsandbytesの最新バージョンがインストールされていることを確認してください。4ビットモデルをローカルに保存するには、save_pretrained()を使用します。
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_4bit=True)
model = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-560m",
device_map="auto",
quantization_config=quantization_config
)
model.push_to_hub("bloom-560m-4bit")8ビットおよび4ビットの学習は、追加パラメータの学習のみサポートされています。
get_memory_footprint を使用して、メモリフットプリントを確認してください。
print(model.get_memory_footprint())quantization_configなしで、from_pretrained()を使用して量子化モデルを読み込みます。
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("{your_username}/bloom-560m-8bit", device_map="auto")LLM.int8
このセクションでは、オフロード、外れ値のしきい値、モジュール変換のスキップ、ファインチューニングなど、8ビット量子化の特定の機能について詳しく見ていきます。
オフローディング
8-bitモデルでは、CPUとGPU間で重みをオフロードすることで、非常に大きなモデルをメモリに収めることができます。CPUにディスパッチされた重みはfloat32で保存され、8-bitに変換されることはありません。例えば、BitsAndBytesConfigを通じてbigscience/bloom-1b7のオフロードを有効にできます。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(llm_int8_enable_fp32_cpu_offload=True)lm_head 以外のすべてを GPU に収めるよう、カスタムのデバイスマップを設計し、lm_head は CPU にディスパッチします。
device_map = {
"transformer.word_embeddings": 0,
"transformer.word_embeddings_layernorm": 0,
"lm_head": "cpu",
"transformer.h": 0,
"transformer.ln_f": 0,
}次に、カスタムのdevice_mapとquantization_configを指定してモデルを読み込みます。
model_8bit = AutoModelForCausalLM.from_pretrained(
"bigscience/bloom-1b7",
dtype="auto",
device_map=device_map,
quantization_config=quantization_config,
)外れ値の閾値
「アウトライア」とは、特定の閾値を超える隠れ状態の値を指し、これらの値は fp16 で計算されます。通常、これらの値は正規分布([-3.5, 3.5])に従いますが、大規模モデルでは分布が大幅に異なる場合があります([-60, 6] や [6, 60] など)。8-bit 量子化は値が約 5 程度の場合に良好に機能しますが、それを超えるとパフォーマンスに大きなペナルティが発生します。適切なデフォルトの閾値は 6 ですが、より不安定なモデル(小規模モデルやファインチューニング中)では、より低い閾値が必要になる場合があります。
モデルに最適な閾値を見つけるには、BitsAndBytesConfigのllm_int8_thresholdパラメータを調整してみてください。例えば、閾値を0.0に設定すると、精度がわずかに低下する可能性があるものの、推論が大幅に高速化されます。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
model_id = "bigscience/bloom-1b7"
quantization_config = BitsAndBytesConfig(
llm_int8_threshold=0.0,
llm_int8_enable_fp32_cpu_offload=True
)
model_8bit = AutoModelForCausalLM.from_pretrained(
model_id,
dtype="auto",
device_map=device_map,
quantization_config=quantization_config,
)モジュール変換をスキップ
Jukebox などの一部のモデルでは、すべてのモジュールを 8 ビットに量子化すると不安定になる可能性があるため、量子化を省略する必要があります。Jukebox の場合、BitsAndBytesConfig の llm_int8_skip_modules パラメータを使用して、lm_head モジュールをスキップする必要があります。
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
model_id = "bigscience/bloom-1b7"
quantization_config = BitsAndBytesConfig(
llm_int8_skip_modules=["lm_head"],
)
model_8bit = AutoModelForCausalLM.from_pretrained(
model_id,
dtype="auto",
device_map="auto",
quantization_config=quantization_config,
)ファインチューニング
PEFT ライブラリは、flan-t5-large や facebook/opt-6.7b のような大規模モデルのファインチューニングを、8ビット量子化と組み合わせてサポートしています。モデルは自動的に GPU にロードされるため、トレーニング時に device_map パラメータを渡す必要はありません。ただし、device_map パラメータ(device_map="auto" は推論時のみ使用してください)でデバイスマップをカスタマイズすることも可能です。
QLoRA
このセクションでは、4ビット量子化の特定の機能、例えば計算データ型の変更、Normal Float 4 (NF4) データ型、およびネスト量子化について解説します。
計算データ型
BitsAndBytesConfig でデータ型を float32(デフォルト値)から bf16 に変更して、計算を高速化します。
import torch
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)通常の Float 4 (NF4)
NF4 は QLoRA の論文で提案された 4 ビットデータ型で、正規分布から初期化された重みに適応されています。4 ビットのベースモデルの学習には NF4 を使用してください。
from transformers import BitsAndBytesConfig
nf4_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
)
model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, dtype="auto", quantization_config=nf4_config)推論において、bnb_4bit_quant_typeはパフォーマンスに大きな影響を与えません。ただし、モデルの重みと整合性を保つため、bnb_4bit_compute_dtypeとdtypeの値を使用する必要があります。
ネストされた量子化
ネスト量子化により、追加の性能コストなしにさらなるメモリを節約できます。この機能は、すでに量子化された重みに対して2回目の量子化を実行し、パラメータあたり追加で0.4ビットを節約します。例えば、ネスト量子化を使用すると、シーケンス長1024、バッチサイズ1、4ステップの勾配蓄積を有効にした設定で、16GBのNVIDIA T4 GPU上でLlama-13bモデルのファインチューニングを行うことができます。
from transformers import BitsAndBytesConfig
double_quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
)
model_double_quant = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-13b-chat-hf", dtype="auto", quantization_config=double_quant_config)bitsandbytesモデルのデクアンタイズ
量子化されたモデルは、dequantize() を使用して元の精度に復元できますが、これにより品質が低下する可能性があります。デクォンタイズされたモデルを収容するのに十分な GPU メモリがあることを確認してください。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("facebook/opt-125m", BitsAndBytesConfig(load_in_4bit=True))
model.dequantize()リソース
8-bit量子化の詳細については、Hugging Face Transformers、Accelerate、bitsandbytesを用いた大規模transformers向け8-bit行列積のやさしい入門を参照してください。
Try 4-bit quantization in this notebook and learn more about its details in Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA.
Update on GitHub