transformersでGGUFを読み込んでみよう!

こんにちは!クロガネです。
transformersでGGUFが読み込めるようになったのでメモがてらに読み込んでみます。

基本的には公式ドキュメントの通りです。
GGUF and interaction with Transformers (huggingface.co)

ちなみに、書いてある通り、ロード時にfp32にde-quantizeされるので特に軽くなりません。ただし、通常通り、torch_dtype=torch.float16は効きます。
32bit固定ではないですが、有効数字が切り捨てられているので優位性は今(2024/06/16時点)のところないかもしれません。

前準備

transformersでGGUFを読み込むにはtransformersの更新が必須なので最新版(4.41.0以降)にします。

python -m pip install transformers -U

ちなみにgguf-pyのインストールも必須です。
llama.cpp/gguf-py at master · ggerganov/llama.cpp (github.com)

python -m pip install gguf

ドキュメントには書いてないですが、ロード時にエラーを吐きます。
実際のところ、GGUFはllama.cppのところの独自実装らしいので言われてみればその通りであるって感じではあります。

GGUFをロードしてみよう

まずは公式ドキュメントの通り、TheBloke氏のTinyLlama-1.1B-Chat-v1.0-GGUFを読み込んでみましょう。

ロードはレポジトリ名+GGUFファイル名があれば読み込めるようです。
自分はキャッシュをCドラ以外に保存しているのでcache_dirを追記してます。

import json
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer


model_id = "TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF"
filename = "tinyllama-1.1b-chat-v1.0.Q6_K.gguf"

model = AutoModelForCausalLM.from_pretrained(
    model_id, 
    gguf_file=filename,
    cache_dir=r"I:\llm\cache",
    torch_dtype=torch.float16,
    )
tokenizer = AutoTokenizer.from_pretrained(
    model_id,     
    gguf_file=filename,
    cache_dir=r"I:\llm\cache",
    )

自環境でtorch_dtype=torch.float16の設定でVRAMを2.4GB使用、無設定だと4.3GB使用していました。

ただし、AutoModelForCausalLM側にdevice_map="cuda:0"の追加が必要です。
また、以下のような注意書きが返ってきたのでAutoTokenizer側にlegacy=Falseも追加しました。

You are using the default legacy behaviour of the <class 'transformers.models.llama.tokenization_llama_fast.LlamaTokenizerFast'>. This is expected, and simply means that the `legacy` (previous) behavior will be used so nothing changes for you. If you want to use the new behaviour, set `legacy=False`. This should only be set if you understand what it means, and thoroughly read the reason why this was added as explained in https://github.com/huggingface/transformers/pull/24565

推論

読み込み時点でde-quantizedされているので、推論時はいつも通りです。

input_text = "Hello, how are you?"
input_ids = tokenizer(input_text, return_tensors="pt").to("cuda")

outputs = model.generate(**input_ids, max_new_tokens=32)
print(tokenizer.decode(outputs[0]))

参考までに結果はこんな感じです。

<s> Hello, how are you?
I am fine, thank you.
How are you? I am fine, thank you.
Can you repeat that again?
Can you repeat that

ダウンロード済みのGGUFを読み込んでみよう

これは単純です。
上のコードのモデルIDフォルダパスに、gguf_fileモデル名を渡してあげればよいだけです。

model_id = r"I:\llm\text-generation-webui-snapshot-2024-04-28\models"
filename = "Mistral-7B-Instruct-v0.3-Q3_K_L.gguf"

これで普通に読み込めました。


ただ、別の一部モデルによってはtokenizerの読み込みがうまくいかないこともあるみたいですね。何かしらの解決策があるんでしょうかね?

AttributeError: 'GGUFTokenizerSkeleton' object has no attribute 'unk_token_id'


以上でございます。

GGUF資産の活用や、ネット回線がどうしてもキツい人には便利そうではあります。実際、transformersで直接HuggingFaceからダウンロードするとブチブチ切れることがあるので、無しではないかもですね。
8_0や4_0モデルをDLしておいて、8bitや4bitで読み込んで使用する用途としてはありだとは思います。中身もいろいろ触れるし。

いつかGGUFの量子化のままtransformersで動くようになることを期待してメモに残します。

それでは!クロガネでした!


この記事が気に入ったらサポートをしてみませんか?