環境構築
- まず、フォルダを作りましょう。
mkdir rinna-gpt
これで、"rinna-gpt"という名前のディレクトリが作成されます。
これから作成するファイルはすべてこのディレクトリの中に置いてください。
また、実行する場合もこのディレクトリの中で行ってください。
- 続いて、環境構築はDockerを使います。
Dockerを使うためには、Docker Engine か Docker Desktop が必要です。
入れていない方は、調べてみて自分の環境に導入してください。
今後、私のほうでもDocker Engine等のインストール記事を書くかもしれないので、投稿次第リンクを貼ります。
また、Dockerというものについては、過去記事で簡単に解説しているので、Dockerが分からない方は目を通しておくと理解が早まるかもしれません。
以下、Dockerfileのコードです。
FROM pytorch/pytorch:latest
WORKDIR /app
COPY requirements.txt .
RUN apt-get update && \
apt-get install -y python3-pip
RUN pip3 install --no-cache-dir -r requirements.txt
COPY . . 上記Dockerfileでは、pytorchベースのコンテナを作成しています。
- 次に、requirements.txtを作成しましょう。
以下のような内容のrequirements.txtを作成してください。
transformers sentencepiece
本来であればバージョン指定すべきなのでしょうが、推奨が分からないので、とりあえず指定しないで最新版にしておきます。
環境はこれで大丈夫でしょう。
実行ファイル作成
次に実行するPythonファイルを作成しましょう。
以下、huggingfaceの公式ページ(
rinna/japanese-gpt-neox-3.6b-instruction-sft · Hugging Face
)よりサンプルコードを使いましょう。
本ブログでは、以下のスクリプトを、"talk.py"と命名します。(なんでもいいです)
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("rinna/japanese-gpt-neox-3.6b-instruction-sft", use_fast=False)
model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt-neox-3.6b-instruction-sft")
prompt = [
{
"speaker": "ユーザー",
"text": "日本のおすすめの観光地を教えてください。"
},
{
"speaker": "システム",
"text": "どの地域の観光地が知りたいですか?"
},
{
"speaker": "ユーザー",
"text": "渋谷の観光地を教えてください。"
}
]
prompt = [
f"{uttr['speaker']}: {uttr['text']}"
for uttr in prompt
]
prompt = "<NL>".join(prompt)
prompt = (
prompt
+ "<NL>"
+ "システム: "
)
print(prompt)
# "ユーザー: 日本のおすすめの観光地を教えてください。<NL>システム: どの地域の観光地が知りたいですか?<NL>ユーザー: 渋谷の観光地を教えてください。<NL>システム: "
if torch.cuda.is_available():
model = model.to("cuda")
token_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
with torch.no_grad():
output_ids = model.generate(
token_ids.to(model.device),
do_sample=True,
max_new_tokens=128,
temperature=0.7,
pad_token_id=tokenizer.pad_token_id,
bos_token_id=tokenizer.bos_token_id,
eos_token_id=tokenizer.eos_token_id
)
output = tokenizer.decode(output_ids.tolist()[0][token_ids.size(1):])
output = output.replace("<NL>", "\n")
print(output)
"""分かりました。いくつかのおすすめを紹介します。
1. ハチ公像です。ハチ公像は、日本の観光スポットの1つとして人気があります。
2. スクランブル交差点です。多くの人々が行き交う大きな交差点で、観光客に人気のスポットです。
3. 109です。109は、ショッピングやエンターテイメント施設です。
4. 道玄坂です。道玄坂は、日本の商業地区である坂道です。</s>"""
サンプルコードを実行してみる
まず、ビルドしましょう。
以下のコマンドでDockerイメージを作成しましょう。
docker build -t rinna-gpt .
終わったらrunしてみましょう。
docker run --rm -it --gpus all rinna-gpt:latest
いろいろオプションがついてますが、GPUが使えない環境の方は、"-gpus all"を消してください。
うまく動いて、コンテナに入れば環境はOKです。
次に以下のコマンドをコンテナ内で実行してください。
python talk.py
すると、以下のようにtokenizer等のダウンロードが始まります。
Downloading (…)okenizer_config.json: 100%|█████████████████████████████████████████████| 284/284 [00:00<00:00, 2.23MB/s] Downloading spiece.model: 100%|██████████████████████████████████████████████████████| 786k/786k [00:00<00:00, 12.9MB/s]
次に、configとモデルのダウンロードが始まると思います。
Downloading (…)lve/main/config.json: 100%|█████████████████████████████████████████████| 534/534 [00:00<00:00, 5.52MB/s] Downloading model.safetensors: 100%|███████████████████████████████████████████████| 7.37G/7.37G [02:58<00:00, 41.3MB/s]
これが終われば、ようやくGPTに質問を自動で投げかけます。
ユーザー: 日本のおすすめの観光地を教えてください。<NL>システム: どの地域の観光地が知りたいですか?<NL>ユーザー: 渋谷の観光地を教えてください。<NL>システム:
これは、以下のように、
ユーザー:日本のおすすめの観光地を教えてください。
AI:どの地域の観光地が知りたいですか?
ユーザー:渋谷の観光地を教えてください。
と、一連の会話の流れを与えたうえで、次に返されるAIの返答を待っています。
しばらく待つと返答が返ってきてプログラムが終了します。
私の場合は、「どのような種類の観光地に興味がありますか?」と返ってきました。
完全な対話形式に改造する。
今のサンプルコードでは、自分で質問を連続して送れないので、サンプルコードを改造して好きに対話できるようにします。
以下に改造後のコードを載せます。
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("rinna/japanese-gpt-neox-3.6b-instruction-sft", use_fast=False)
model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt-neox-3.6b-instruction-sft")
if torch.cuda.is_available():
model = model.to("cuda")
output = ""
request = ""
prompt = [
{
"speaker": "ユーザー",
"text": "こんにちは。"
},
{
"speaker": "システム",
"text": "こんにちは!何かお聞きしたいことはありますか?"
}
]
prompt = [
f"{uttr['speaker']}: {uttr['text']}"
for uttr in prompt
]
prompt = "<NL>".join(prompt)
while True:
text = input("\n話しかけてください。終わる場合は「end」と入力して下さい:")
if (text == "end"):
break
request = prompt + "<NL>ユーザー: " + text + "<NL>システム: "
request = request.replace("\n", "<NL>")
token_ids = tokenizer.encode(request, add_special_tokens=False, return_tensors="pt")
with torch.no_grad():
output_ids = model.generate(
token_ids.to(model.device),
do_sample=True,
max_new_tokens=128,
temperature=0.7,
pad_token_id=tokenizer.pad_token_id,
bos_token_id=tokenizer.bos_token_id,
eos_token_id=tokenizer.eos_token_id
)
output = tokenizer.decode(output_ids.tolist()[0][token_ids.size(1):])
output = output.replace("<NL>", "\n")
prompt = request + output
print(output)
print("\n\nデバッグ情報#")
print("会話履歴:" + prompt)
print("入力テキスト:" + text)
print("リクエストテキスト:" + request)
print("レスポンス:" + output)これで、cmd上でGPTと会話を続けることができます。
急ぎで作ったので、コードが汚い・無駄が多い・例外処理が無いのは目を瞑ってください...。
では、もう一度ビルドと実行をしましょう。
docker build -t rinna-gpt .
docker run --rm -it --gpus all rinna-gpt:latest python talk.py
モデルのダウンロードが終わったら
話しかけてください。終わる場合は「end」と入力して下さい:
と表示されるので、好きに入力して実行しましょう。
しばらく待つと返答が返ってきて、また自分のターンが来ますので、そのまま好きなだけ会話を続けてください。
今回の改造後のコードには、デバッグ用に
- 会話履歴
- 入力テキスト
- リクエストテキスト
- レスポンス
が表示されるようにしてあります。
必要ない場合は、最後辺りのprint文のコードを消すか、以下のようにコメントアウトしてください。
#print("\n\nデバッグ情報#")
#print("会話履歴:" + prompt)
#print("入力テキスト:" + text)
#print("リクエストテキスト:" + request)
#print("レスポンス:" + output)
まとめ
今回、rinna株式会社様が公開されたGPTモデルを使う方法を解説しました。
レスポンスは、やはり遅めでOpenAIのAPIと比べると劣るのですが、無料で使えるので状況に応じて使用するのがいいですね。
回答内容としては、簡潔な内容が返ってくるなぁといった印象です。
OpenAIのGPTだと、何十行も返ってくる文章が、20文字、30文字ほどで、さっぱりと生成されています。
ちょっと機械的というか、冷たい感じがしますね...。
皆様の研究や勉強に役立てることができたのなら幸いです。
各種リンク
- rinna、日本語に特化した36億パラメータのGPT言語モデルを公開
rinna、日本語に特化した36億パラメータのGPT言語モデルを公開|rinna株式会社のプレスリリース
- Hugging Face