👩

rinna/japanese-gpt2-mediumをgguf化してllama.cppで動かす

2024/02/29に公開

Rinna 3.6Bとかではなく、japanese-gpt2-mediumをllama.cppで動かしたメモです。

https://huggingface.co/rinna/japanese-gpt2-medium
https://github.com/ggerganov/llama.cpp

モチベ

  • 馴染みのあるモデルで入門したかった
  • デカいモデルはストレージに悪い
  • llama.cppを経由してSwiftで動かしたい

下準備

llama.cppをクローン。一度makeします。コミットIDは0becb22ac05b6542bd9d5f2235691aa1d3d4d307でした。

git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make

llama.cppの直下にrinnaをクローンします。スクリプトの都合に合わせてモデルをコピーしておきます。

git lfs install
git clone https://huggingface.co/rinna/japanese-gpt2-medium
cp rinna/spiece.model rinna/tokenizer.model

エディタでconvert-hf-to-gguf.pyを開きます。これはHugging FaceのモデルをGGUFに変換するスクリプトです。GPT-2クラス内部にset_vocabを追加します。これは現時点の実装がGPT-2モデルに対してBPEのトークナイザのみを想定している一方でrinnaはUnigramトークナイザが利用されているためです。

class GPT2Model(Model):
    def set_vocab(self):
        self._set_vocab_sentencepiece()

以上でスクリプトが動作するので、以下を実行します。数分もかかりません。

python3 convert-hf-to-gguf.py rinna/japanese-gpt2-medium

次に、エディタでllama.cppを開きます。これは名前通りllama.cppの本体ですが、llama_byte_to_tokenの実装に以下を追加します。

これは次のような理由によります。

  • llama.cppでは改行コードに対応するトークンが存在する前提で処理が行われますが、rinnaはこれを持っていないので、そのままだとエラーが発生します。
  • rinnaのREADME.mdにもtokenizer.do_lower_case = Trueが「some bug of tokenizer config loading」のために必要である旨が書かれていますが、英語の大文字をトークン変換できずにエラーが発生することがあります。そこで小文字化をかけることによってこれを防ぎます。
    switch (llama_vocab_get_type(vocab)) {
        case LLAMA_VOCAB_TYPE_SPM: {
            // ここから
            if (ch == '\n') {
                return vocab.linefeed_id;
            }
            if ('A' <= ch && ch <= 'Z') {
                ch = ch - 'A' + 'a';
            }
            // ここまで
            const char buf[7] = { '<', '0', 'x', hex[ch >> 4], hex[ch & 15], '>', 0 };

この変更を含めてもう一度makeします。

make

以上で完成です。

動かす

llama.cpp % ./main -m rinna/japanese-gpt2-medium/ggml-model-f16.gguf  -p "最高のお味噌汁を作るには" -n 100

 最高のお味噌汁を作るには、お米を炊くのと同じように、お水と麹菌を混ぜるのが重要です。 発酵させた後、3~4日程度でお味噌が仕上がります。1週間~10日ほど熟成させると「しつこい味噌」となり、味のクオリティもグンとアップします。 発酵期間は約6ヶ月。約1年以上の熟成を経て初めて「しつこい味噌」が完成するのです。 [end of text]

いい感じ!かはわからないですが、無事に動きました。

そのほかのメモ

実行時にllm_load_vocab: mismatch in special tokens definition ( 3540/32000 vs 7/32000 )というWarningが出ていました。実装を読む限り「特殊トークンは通常トークン対の合成では得られない」という前提から「特殊トークンらしきトークン」を数え、それ(3540)が実際の特殊トークン数(7)と合わないと述べるものですが、Unigramトークナイザを使用しているモデルなので無視して良さそうです。

Discussion