19日に更新してた

アフィリエイトはないよ

NovelAI/genji-jp を CPU でなんとか動かした話

日本語の LLM が使えるといいなぁと思ったものの特にやりたいこともないなぁと思っていたら、小説家になろうのデータから作ったのがあると目にしたので使ってみようとやってみた。

huggingface.co

win11 Home、i7、32G、GTX1060 6Gでございます。とりあえず、

huggingface.co


の how to use にあるのを jupyter-notebook 上で試してみる。モデルデータはダウンロードしてきてくれるがGPU のメモリーが足りない。

OutOfMemoryError: CUDA out of memory. Tried to allocate 32.00 MiB (GPU 0; 6.00 GiB total capacity; 5.37 GiB already allocated; 0 bytes free; 5.38 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation.  See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

memory 絡みをなんとかできなかったので、CPU で動かしたほうがいいのでは? と適当な類推でやってみた。

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

tokenizer = AutoTokenizer.from_pretrained("EleutherAI/gpt-j-6B")
model = AutoModelForCausalLM.from_pretrained("NovelAI/genji-jp", torch_dtype=torch.float16, low_cpu_mem_usage=True).eval().cpu()
text = '''あらすじ:あなたは異世界に転生してしまいました。勇者となって、仲間を作り、異世界を冒険しよう!
***
転生すると、ある能力を手に入れていた。それは、'''

tokens = tokenizer(text, return_tensors="pt").input_ids
generated_tokens = model.generate(tokens.long().cpu(), use_cache=True, do_sample=True, temperature=1, top_p=0.9, repetition_penalty=1.125, min_length=1, max_length=len(tokens[0]) + 400, pad_token_id=tokenizer.eos_token_id)
last_tokens = generated_tokens[0]
generated_text = tokenizer.decode(last_tokens).replace("�", "")
print("Generation:\n" + generated_text)

cuda を cpu に変えただけ。すると

"LayerNormKernelImpl" not implemented for 'Half'

と出るので、調べてみるとどうも cpu では torch.float16 は上手く動かないらしい。

BFloat16: The secret to high performance on Cloud TPUs | Google Cloud Blog あたりで調べた雑な解釈だとtorch.float32とtorch.bfloat16の指数部は同じ桁数だからいけるのでは?と以下のように。

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

tokenizer = AutoTokenizer.from_pretrained("EleutherAI/gpt-j-6B")
model = AutoModelForCausalLM.from_pretrained("NovelAI/genji-jp", torch_dtype=torch.bfloat16, low_cpu_mem_usage=True).eval().cpu()
text = '''あらすじ:あなたは異世界に転生してしまいました。勇者となって、仲間を作り、異世界を冒険しよう!
***
転生すると、ある能力を手に入れていた。それは、'''

tokens = tokenizer(text, return_tensors="pt").input_ids
generated_tokens = model.generate(tokens.long().cpu(), use_cache=True, do_sample=True, temperature=1, top_p=0.9, repetition_penalty=1.125, min_length=1, max_length=len(tokens[0]) + 400, pad_token_id=tokenizer.eos_token_id)
last_tokens = generated_tokens[0]
generated_text = tokenizer.decode(last_tokens).replace("�", "")
print("Generation:\n" + generated_text)

で待つこと約50分、でてきたのは

Generation:
あらすじ:あなたは異世界に転生してしまいました。勇者となって、仲間を作り、異世界を冒険しよう!
***
転生すると、ある能力を手に入れていた。それは、
<|extratoken_1|>[宣告、から笑見てくらんだ?  → ×が三

<|endoftext|>

これは動いたと言っていいのか?エラーが出なかったからいいと言いたいが、2回目は3時間40分くらいかかって

Generation:
あらすじ:あなたは異世界に転生してしまいました。勇者となって、仲間を作り、異世界を冒険しよう!
***
転生すると、ある能力を手に入れていた。それは、も<|extratoken_16|> inからくが・・・いに辿でんと、ハラドーンカ。<|extratoken_139|> of  だそれは彼を離しーから・・・・[’。イに辿アロ・ミヨンテンタフヨンデッドーサレサレソン・ナー・」
<|extratoken_55|>-’  -」 なあう、なかのー
【 - うきい たの字の正素明 だけど■ ご
 ナスモだーブだかこだれマダ ムシのと
 おれさまつきだし すっき とよわれだますまんだんで 
 に』ご みんだがに すっき  お前は おれ  す  ご      
<|extratoken_119|>/

これなので、ネタとしては面白かったかも。なろう系小説を書こうとして異世界語になってしまったのを、日本語表音表示したらこうなった的な。

bfloat16 はこの場合は、あかんやつやったみたいです。

でも、電気代高くなっているとか言われているのに何やってるんだろ、俺。とばかりによく考えてみたら torch.float32 で順当にやればいいだろってことで、

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

tokenizer = AutoTokenizer.from_pretrained("EleutherAI/gpt-j-6B")
model = AutoModelForCausalLM.from_pretrained("NovelAI/genji-jp", torch_dtype=torch.float32, low_cpu_mem_usage=True,).eval().cpu()
text = '''あらすじ:あなたは異世界に転生してしまいました。勇者となって、仲間を作り、異世界を冒険しよう!
***
転生すると、ある能力を手に入れていた。それは、'''

tokens = tokenizer(text, return_tensors="pt").input_ids
generated_tokens = model.generate(tokens.long().cpu(), use_cache=True, do_sample=True, temperature=1, top_p=0.9, repetition_penalty=1.125, min_length=1, max_length=len(tokens[0]) + 400, pad_token_id=tokenizer.eos_token_id)
last_tokens = generated_tokens[0]
generated_text = tokenizer.decode(last_tokens).replace("�", "")
print("Generation:\n" + generated_text)

にしたら、

Generation:
あらすじ:あなたは異世界に転生してしまいました。勇者となって、仲間を作り、異世界を冒険しよう!
***
転生すると、ある能力を手に入れていた。それは、種族変化(ぐんしょう)能力で、自分の体の一部を変えることができるというもの。
俺の windshieldから目、牙、尻尾、魔力、角が伸びて、それぞれの形と量が変わる。
最初は身体能力が上がるだけだったが、これが強くなると影響を受けた人間の魂に衝撃を与えることができるようになってしまうのだ。
「つまり、俺の種族が神々しい巨竜に変わる理由がこれか」
気配を感じさせない黒髪ロングで、メガネの細身イケメン……スキル持ちの誰かの死後、俺に転生したのかな。その謎は、俺が見つけることになる。
現在の俺は二十歳の三枚目。凄まじい幸運に恵まれたことを考えれば、心の中は穏やかではないが。
俺の名前は

やっとまともなのが出てきた。ssd アクセスが100%に張り付いている時もありましたが、なんとか動くようになりました、これだけに30分足らずかかるので出てくる文字数と時間を考えるとちっとも実用的ではないですが。

試しにもう一回やってみたら25分程度かかって

Generation:
あらすじ:あなたは異世界に転生してしまいました。勇者となって、仲間を作り、異世界を冒険しよう!
***
転生すると、ある能力を手に入れていた。それは、文字が読める事だ。本当に知らなかったので驚いた。神様も何気に不便だ。俺の場合、ヒイロに会うのが遅すぎたと思う。これも後悔か? って事はさておき。
「ふん、良い男は少ないのだ」
 宿屋に部屋を借りてリアーナさんと別れて来た。
「そうですか。ありがとうございました」
「…可愛くないのだ」
 えー、明らかにエッチ目的でしょ。リアーナさんの意外な一面を見る事が出来た気がする。
「今日は泊まって行ってください。明日は帰りますので」
 リアーナさんの顔が真っ赤になっているので送って行く事にした。
 ベッドにダイブして寝ていると天啓が。
「魔力回復」
 魔力回復の魔法を使った。すると、パンク中の女の子の精神年齢が

こんな感じです。できてきた文章のストーリーは疑問符がつく内容ですが、日本語にはなっておりますのでご査収ください。*1

*1:いやいや、文を嵩増しするためにこのように16だの32だのと書いたわけではございませんです、時系列です。