タイトルで期待した方には最初にごめんなさいなのですが、0.11.1ではできません。
しかしできるようにする変更はマージされており、GitHubからインストールすればできます(0.11.2.dev0)
はじめに
チケットご用意されてほし〜 、nikkieです。
最近のToday I Learnedの一本です。
目次
PEFTモデルを読み込みたい
nikkieはLoRAでファインチューンを完全に理解しました!(馬鹿の山ナウ)
Hugging Faceにアップロードしたモデルはこちら
こちらを読み込んでいきます。
ColabのT4 GPUを使いました
peft 0.11.1で読み込む
revisionを指定しない場合、うまくいきます。
PEFTモデルもそのベースモデルも、mainの最新コミットが指定されたことになると理解しています。
https://huggingface.co/docs/peft/quicktour#inference を見つつも、ファインチューンに使ったnotebookのコードを再利用しています1
import torch from peft import AutoPeftModelForCausalLM from transformers import AutoTokenizer, BitsAndBytesConfig bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16, ) tokenizer = AutoTokenizer.from_pretrained(model_id) tokenizer.pad_token = tokenizer.eos_token peft_model = AutoPeftModelForCausalLM.from_pretrained( "ftnext/gemma-2b-peft-tutorial-english-quotes", quantization_config=bnb_config, device_map={"": 0}, ) inputs = tokenizer("Quote: Imagination is more", return_tensors="pt").to("cuda:0") with torch.no_grad(): outputs = peft_model.generate(**inputs, max_new_tokens=20) print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Quote: Imagination is more important than knowledge. Knowledge is limited. Imagination encircles the world. Author: Albert Einstein
この出力形式、ファインチューンしたモデル(=PEFTモデル)です!
では、revisionを指定すると?
peft_model2 = AutoPeftModelForCausalLM.from_pretrained(
"ftnext/gemma-2b-peft-tutorial-english-quotes",
revision="012f11616218df1b57a87eff262c6fa5d035a703",
quantization_config=bnb_config,
device_map={"": 0},
)
HTTPError: 404 Client Error: Not Found for url: https://huggingface.co/google/gemma-2b/resolve/012f11616218df1b57a87eff262c6fa5d035a703/config.json
今回の例では、revisionが指すのはLoRAでできたモデルの最新のコミットIDです。
すなわち、revisionを指定しない場合と比べて、PEFTモデルのファイルに違いはありません。
ところが、revisionを指定したときは動きません。
ベースのモデル(gemma-2b)にも同じrevisionを指定したとして扱われており、PEFTモデルとベースモデルとはコミットIDが異なるのでベースモデルがロードできずに落ちます
- PEFTモデル (ftnext/gemma-2b-peft-tutorial-english-quotes)
- mainの最新コミット 012f11616218df1b57a87eff262c6fa5d035a703
- ベースのgoogle/gemma-2b
- main(そこに 012f11616218df1b57a87eff262c6fa5d035a703 というコミットはない)
peft 0.11.2.dev0にアップデートすればrevisionを指定できる
% pip uninstall -y peft % pip install git+https://github.com/huggingface/peft % pip list | grep peft peft 0.11.2.dev0
(Colabのセッションを再起動して、必要なセルを実行)
peft_model2 = AutoPeftModelForCausalLM.from_pretrained(
"ftnext/gemma-2b-peft-tutorial-english-quotes",
revision="012f11616218df1b57a87eff262c6fa5d035a703",
quantization_config=bnb_config,
device_map={"": 0},
)
inputs = tokenizer("Quote: Imagination is more", return_tensors="pt").to("cuda:0")
with torch.no_grad():
outputs = peft_model2.generate(**inputs, max_new_tokens=20)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
読み込めています🙌
対応の過程を追いかける
issue
対応するpull request
changed name of parameter from revision to base_model_revision for clarity
テストコードを見ました。
https://github.com/huggingface/peft/blob/e02b938e0246e94aa9b4ead39087e2171b94b355/tests/test_hub_features.py#L98-L110
class TestBaseModelRevision: def test_load_different_peft_and_base_model_revision(self, tmp_path): base_model_id = "hf-internal-testing/tiny-random-BertModel" base_model_revision = None peft_model_id = "peft-internal-testing/tiny-random-BertModel-lora" peft_model_revision = "v1.2.3" peft_model = AutoPeftModelForCausalLM.from_pretrained(peft_model_id, revision=peft_model_revision).eval() assert peft_model.peft_config["default"].base_model_name_or_path == base_model_id assert peft_model.peft_config["default"].revision == base_model_revision
読み込むPEFTモデルはこちらです。
v1.2.3を指定しています https://huggingface.co/peft-internal-testing/tiny-random-BertModel-lora/tree/v1.2.3
ベースにしたモデルはこちら
pull requestの範囲のコードにbreakpointを入れて、以下を理解しました。
https://github.com/huggingface/peft/blob/e02b938e0246e94aa9b4ead39087e2171b94b355/src/peft/auto.py#L58-L137
class _BaseAutoPeftModel: @classmethod def from_pretrained( cls, pretrained_model_name_or_path, # テストコードでは tiny-random-BertModel-lora adapter_name: str = "default", is_trainable: bool = False, config: Optional[PeftConfig] = None, revision: Optional[str] = None, # テストコードでは v1.2.3 **kwargs, ): peft_config = PeftConfig.from_pretrained(pretrained_model_name_or_path, revision=revision, **kwargs) base_model_path = peft_config.base_model_name_or_path base_model_revision = peft_config.revision # 略
動きとしては
- PEFTモデルの adapter_config.json (など)を取得する(tiny-random-BertModel-lora の v1.2.3 という指定で)
- adapter_config.jsonから、ベースモデルやそのrevisionを参照する
- tiny-random-BertModel
- revisionはNone
- 2を元にベースモデルを読み込む
と理解しました
終わりに
PEFTしたモデルをpeft.AutoPeftModelForCausalLMで読み込むとき、peft 0.11.1までは、revisionを指定するとベースモデルも同じrevisionを指定した扱いとなります(これがエラーの原因)。
次期バージョンのpeftではこれは修正されており、指定したPEFTモデルのadapter_config.jsonを見てベースモデルのrevisionを取得します(PEFTモデルとはもちろん別の値になるので動きます)
今回見た範囲から、0.11.1までは、adapter_config.jsonにベースモデルのrevisionを書いても無視されていたのではないかと思われます。
これも0.11.2.devでは直っていると思います(未検証事項)
- ロードしたPEFTモデルにtokenizerもあるようなので、ブラッシュアップの余地がありそうです(宿題事項)↩