Poetry で環境構築して大規模言語モデル Rinna を動かして文章生成させてみた
ようやく安定した Python 環境で GPT が動かせるようになりましたよ~。
以前から格闘していたローカル LLM。
- 過去記事 : 2021-04-11 GPT2 再挑戦して WSL で日本語文章を自動生成できた
- ↑ 試行錯誤して萎えてた
- 過去記事 : 2023-02-24 OpenAI の GPT-3 API を使って ChatGPT を作る (Python Poetry と Node.js コード)
- ↑ API 呼び出しだけの簡単なコードなので Poetry 化できていた
今回は rinna/japanese-gpt-neox-3.6b-instruction-sft-v2
という大規模言語モデルを使って、ローカルで文章生成をさせてみる。
Rinna って何
今回、GPT 関連の用語やモデルを色々調べていたので、素人なりに参考文献をまとめておく。
- rinna/japanese-gpt-neox-3.6b-instruction-sft-v2 · Hugging Face
- 今回使うモデル。Rinna という会社が作っている Rinna というシリーズのモデルの一つ
- 36億のパラメータを学習し、Instruction Tuning を施したモノ
- EleutherAI の GPT-NeoX というモデルがベースになっている
- 日本語特化型の大規模言語モデル、OpenCALMとrinna/japanese-gpt-neox-3.6bの検証 #ChatGPT - Qiita
- Instruction Tuning とは、ChatGPT (チャットボット) のように、指示に基づいてタスクを実行するようファインチューニングすること
- Rinna でいうと rinna/japanese-gpt-neox-3.6b コチラがファインチューニング前の事前学習のみ行ったモデル、ということになる。どちらが「良い」のかは用途次第であろう
- 色々な大規模言語モデルを試してみる
- 環境構築やコーディングで参考にした
- LLMでよく見る関数についての解説 #Python - Qiita
transformers
あたりの関数の詳細
- rinna GPT-2モデルの生成パラメータ
model.generate()
に与えるパラメータの詳細
- 自宅PCで「rinna」の日本語言語モデルを試用、メモリ32GBあればCPUだけでも動くぞ!【イニシャルB】 - INTERNET Watch
- 後でまた詳しく話すが、自分の環境 (GTX1080) だと一文の生成に2分ほどかかった。この所要時間が速い方なのか遅い方なのか知りたくて調べた
- RTX3070 で10秒以下、という感じらしい
- 最近ローカルLLMがアツいらしい – soy-software
- 今時は RTX4060Ti や RTX4090 なんかを使うのが当たり前で、2枚挿ししている人も少なくないようだ
これらの文献でだいぶ理解が深まった。
WSL 上の Poetry で環境構築してみる
以前の記事でも愚痴ったが、Python 界隈はいつまで経っても環境構築の再現性が乏しいというか、その辺の解説を無視してるモノが多いなと思っている。なので今回も Poetry でランタイムのバージョンや必要なライブラリを吐き出しておくことにする。
WSL 上で作業開始する時点で、次のような状態。
$ python3 -V
Python 3.11.2
$ poetry -V
Poetry (version 1.8.3)
まずは Poetry プロジェクトを作る。
$ poetry new practice
$ cd ./practice/
# 以下に処理を書く
$ touch ./practice/__main__.py
次に必要なライブラリのインストール。後述するコード内で明示的に import
しているのは torch
と transformers
の2つだけなのだが、実行時にエラーが出たりして怒られたので、後ろ3つもインストールしている。
$ poetry add torch transformers accelerate sentencepiece protobuf
コーディング
コードは Hugging Face にある Rinna 公式のサンプルコードをベースに、色んな文献を見たり、実行時のワーニングメッセージを見たりして調整した。
import datetime
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = 'rinna/japanese-gpt-neox-3.6b-instruction-sft-v2'
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Start : Model Name [', model_name, ']')
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Tokenizer') # ワーニングが出るから legacy と clean_up_tokenization_spaces を入れた・float16 は高速化のため
tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=False, legacy=False, clean_up_tokenization_spaces=True, torch_dtype=torch.float16)
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Model')
model = AutoModelForCausalLM.from_pretrained(model_name)
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Is Cuda Available?')
if torch.cuda.is_available():
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Use Cuda')
model = model.to('cuda')
input_text = 'こんにちは世界!'
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Prompt : [', input_text, ']')
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Prompt Tokenizer')
inputs = tokenizer(input_text, add_special_tokens=False, return_tensors='pt').to(model.device)
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Model Generate')
with torch.no_grad():
outputs = model.generate(
**inputs,
do_sample=True,
max_new_tokens=256,
temperature=0.7,
repetition_penalty=1.1,
pad_token_id=tokenizer.pad_token_id,
bos_token_id=tokenizer.bos_token_id,
eos_token_id=tokenizer.eos_token_id
)
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), 'Decode')
output_text = tokenizer.decode(outputs[0], clean_up_tokenization_spaces=True, skip_special_tokens=True)
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), '----------')
print(output_text)
print(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9))), '==========')
実行時間を見るために print
文を挟んでいるが、主な流れは次のとおり。
AutoTokenizer.from_pretrained()
で Tokenizer を準備するAutoModelForCausalLM.from_pretrained()
で Model を読み込む- Cuda が使えそうなら
torch.cuda.is_available()
Cuda を使う :model = model.to('cuda')
tokenizer('プロンプト')
で Input を作るmodel.generate()
で文章を生成させるtokenizer.decode()
で Output を整形する
動かしてみる
コーディングしたら以下のコマンドで実行する。
$ poetry run python -m practice
実行例は以下のとおり。初回はモデルのダウンロードが入ってだいぶ時間がかかるが、2回目以降はキャッシュされるので、モデルのロードと計算時間だけになる。
$ poetry run python -m practice
2024-08-10 13:47:15.382350+09:00 Start : Model Name [ rinna/japanese-gpt-neox-3.6b-instruction-sft-v2 ]
2024-08-10 13:47:15.382409+09:00 Tokenizer
2024-08-10 13:47:16.179210+09:00 Model
2024-08-10 13:47:51.498773+09:00 Is Cuda Available?
2024-08-10 13:47:55.486486+09:00 Use Cuda
2024-08-10 13:48:31.154504+09:00 Prompt : [ 私は一風変わった猫を飼っています。その猫はいま ]
2024-08-10 13:48:31.154595+09:00 Prompt Tokenizer
2024-08-10 13:48:31.302476+09:00 Model Generate
2024-08-10 13:49:51.914125+09:00 Decode
2024-08-10 13:49:51.938365+09:00 ----------
私は一風変わった猫を飼っています。その猫はいま、私のお腹の上に寝ています。私のお腹の上というのは、私が彼女の上に座れる唯一の場所です。そして私は彼女の頭や顔に触れて安心します。そうやって寝るのが好きです。
2024-08-10 13:49:51.938428+09:00 ==========
検証に利用したマシンは i7-7700K・GTX1080・RAM 32GB という構成なのだが、実行開始から出力終了までに2分ちょっとかかっている。コレは torch_dtype=torch.float16
の指定を入れても入れなくても同じくらいで、max_new_tokens
を大きくすると時間が長くなる印象だ。
GPU をちゃんと使えているのはパフォーマンスモニタでも確認できていて、GTX1080 だとコレが速度的に限界なのかなーという感じ。ChatGPT のようにキビキビと高速に返事してもらうのは難しそうだ。
プロジェクト全量を GitHub に置きました
いつものように、これら検証用コードを含めた Poetry プロジェクトは以下の GitHub リポジトリに置いてある。
環境再現時は以下のコマンドで依存ライブラリをインストールして上げてから $ poetry run
すれば OK。
$ poetry install
GPT-2 より精度は上がっている
以前の記事 (2021-04-11 GPT2 再挑戦して WSL で日本語文章を自動生成できた) と比べてみると、同じマシンを使っているのでハード的なスペックは同じで、実行時間は一文あたり2分程度でコレもほぼ同じ。
しかしながら、出力される文章の精度が Rinna GPT-NeoX はかなりそれっぽくなっていて、実行速度を無視すれば OpenAI ChatGPT の GPT-3.5 に迫る精度なのではないだろうか。
今回は Poetry でプロジェクト環境を整えることも出来たし、ワケも分からず書いていたコードの意味もだいぶ理解できた。あとは他にも色々な日本語対応の大規模言語モデルがあるので、今回検証した「りんな」と比較して今後も遊んでみようと思う。