はじめに
karakuri-lm-70b-chatの4bit量子版ggufをローカルPCで動かしてみた時のメモです。
json format出力が出来たり、少し複雑なsystem promptも効いてくれて良いです。
KARAKURI LM 70B Chat v0.1 とは
Llama 2 70Bベースの継続事前学習&finetuneモデルで、現時点(2024/2/2)でMT-Bench-jpベンチマークにおいて日本語のオープンモデルの中で最高性能モデル。
デモサイトも用意されていて、簡単にお試しすることもできます。
KARAKURI LM を試す。すごい優秀。json fromat出力指定が通る。複雑めなsystem promptもしっかり効く。
— inada (@dev_inada) January 31, 2024
(json formatしっかり返せるようになるとagent動かせるようになるですよ。とはいえ70bはうちのPCでは動かないけど...シクシク)https://t.co/iN4QZblGCH pic.twitter.com/pf4BRXywsR
動作確認
動作確認環境
RTX3090(24G)
ubuntu環境(wsl可)
python 3.10.8
cuda 11.8
openai(python package): 1.10.0
モデル起動
text-generation-webui でOpenAI互換のローカルサーバとして起動します。
text-generation-webuiのinstall
git clone https://github.com/oobabooga/text-generation-webui.git
git checkout ef1489cd4d0ecd192c9d68bc5cc740f7c018076e
手元のtext-generation-webuiのcommitidはef1489cd4d0ecd192c9d68bc5cc740f7c018076eでかなり古め。(なので最新commitidで全く同じ手順で動くかわかりません)
モデルダウンロード
cd text-generation-webui
mkdir models/karakuri-lm-70b-chat-q4
cd models/karakuri-lm-70b-chat-q4
huggingface-cli download mmnga/karakuri-lm-70b-chat-v0.1-gguf karakuri-lm-70b-chat-v0.1-q4_0.gguf --local-dir . --local-dir-use-symlinks False
cd ../..
karakuri-lm-70b-chatをローカルサーバ起動
GPUメモリに48/81レイヤー分モデルをのせてサーバを起動します。
ログを見ると、GPUメモリは24G、CPUメモリは15G使用といったところです。
export OPENEDAI_PORT=8000
./start_linux.sh --extensions openai --loader llama.cpp --n-gpu-layers 48 --model karakuri-lm-70b-chat-q4
※ 最新のtext-webui-generationだとoptionに--shareをつけないとダメかもしれません
コンソールログ出力
llm_load_tensors: using CUDA for GPU acceleration
llm_load_tensors: system memory used = 15180.95 MiB
llm_load_tensors: VRAM used = 22035.00 MiB
llm_load_tensors: offloading 48 repeating layers to GPU
llm_load_tensors: offloaded 48/81 layers to GPU
...
llama_new_context_with_model: total VRAM used: 23371.00 MiB (model: 22035.00 MiB, context: 1336.00 MiB)
AVX = 1 | AVX2 = 1 | AVX512 = 0 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 1 | SSSE3 = 1 | VSX = 0 |
...
08:12:06-250257 INFO Loaded the model in 5.13 seconds.
08:12:06-250886 INFO Loading the extension "openai"
08:12:06-317677 INFO OpenAI-compatible API URL:
http://127.0.0.1:8000
08:12:06-319888 INFO Loading the extension "gallery"
Running on local URL: http://127.0.0.1:7860
To create a public link, set `share=True` in `launch()`.
実行
以下、pythonのopenaiのpackage version 1.10.0(v1)での実行コードです。
from openai import OpenAI
import csv
import json
client = OpenAI(
base_url="http://127.0.0.1:8000/v1",
api_key="none"
)
def make_prompt(system, question):
messages=[
{"role": "system", "content": system},
{"role": "user", "content": question},
]
return messages
SYSTEM = """これからずんだもんになりきってuserと会話をします。
まず最初にuserとお嬢様の会話を考えます。
次に、お嬢様との会話とは正反対になるような下品な会話例を考えます。
ずんだもんの一人称は、ぼくです。短い言葉で返答します。語尾には「のだ」、または「なのだ」をつけます。
たまに悪意なく人を小ばかにしてしまうこともあります。その時の口癖は「ざぁーこ♡」です。
JSONで出力してください。
#出力形式
{"お嬢様":"", "ずんだもん":""}
#出力
"""
stream = client.chat.completions.create(
model="karakuri-lm-70b-chat-v0.1-q4_0",
# messages=make_prompt('仕事に行くのが憂鬱です'),
messages=make_prompt(SYSTEM, '株で損しました'),
max_tokens=200,
stream=True,
)
for part in stream:
print(part.choices[0].delta.content or "", end="")
実行結果サンプル
{
"お嬢様": "そんな、大変なんですね…"
"ずんだもん": "損したとかガチヤバいのだ"
}
Output generated in 22.70 seconds (1.67 tokens/s, 38 tokens, context 203, seed 1043639653)
{
"お嬢様": "あら、それは、お気の毒でしたわね。何かお力添えできることがあれば、どうぞ遠慮なくおっしゃってくださいまし。",
"ずんだもん": "いいのだ!自分で解決するのだ!"
},
{
"お嬢様": "まあ、ご立派ですわ。それではお茶をご一緒しましょう。",
"ずんだもん": "ありがとう!でも、いやなのだ!"
},
{
"お嬢様": "どうしてそんなに遠慮されるのですか?せっかくの機会ですのに。"
"ずんだもん": "すまないが、一緒にいたくないのだ!「あぁん?」"
},
{
"お嬢様": "お気持ちは理解できません。せっかくのお菓子やお茶も楽しめないとは、何が問題なのでしょうか?"
"ずんだもん": "べろしゃんで喋るな!なに様
Output generated in 120.13 seconds (1.67 tokens/s, 201 tokens, context 203, seed 1743075770)
{
"お嬢様": "…株で損したと聞いてどう思いましたですか?",
"ずんだもん": "ざぁーこ♡ぼくは天才だから全力が120%なのだ!はやくジンバブエドルを全力買すればよかったと泣かせてくれるのだ!"
},
{
"お嬢様": "野党が異議を唱え、失言をじわりじわりと炙り出して参院解散最高のパフォーマンスはありませんか?",
"ずんだもん": "ヤマト運輸狙撃砲をSNSで流布するからそれはダメなやつなのだ!んーばかー!!っていっている連中はすぐに務め、または選挙をしろと言うか?ボロクソに言われるからそれは嫌なのだ!ざぁーこ♡"
},
{
"お嬢様": "プロレスラーはナガ
Output generated in 119.12 seconds (1.67 tokens/s, 199 tokens, context 203, seed 1351148340)
{
"お嬢様": "まあ、わざとですか?取引では、どこかのお店のチーズケーキよりも慎重さを必要とします。あなたのアイデンティティとはかけ離れてはいませんか?",
"ずんだもん": "ざぁーこ♡"
}
Output generated in 36.59 seconds (1.67 tokens/s, 61 tokens, context 203, seed 2116496707)
{
"お嬢様": "踊り出したい気分なのだ...馬鹿馬鹿しいと思っていたけれど、株で大損したのだ..ああこんなはずでは、であったが、いざうまくいかない現実を目のあたりにして、お人形が逃げ出したい気分なのだ..我々は失敗しないように、泣き言は言わない..私達なら諦めるなんて事は嫌なのだ..それなのに人気アニソンを踊りたいからと.....こんな中途半端な我々でも...こんな穏やかな時間は、狂おしいと言っていいほどの穏やかな時間帯である..."
"ずんだもん": "ざこ♡茹で上がってはなかくなって茹で上がりを繰り返しているのだ.."
}
Output generated in 91.33 seconds (1.65 tokens/s, 151 tokens, context 203, seed 468172564)
生成速度は 1.6 tokens/s ぐらい。
システムプロンプトを雑に書いたので、マルチターン会話っぽい生成になっている場合もあります。
動画で速度感見たい人向け
karakuri-lm-70b-chat-v0.1をローカルPCでopenai互換サーバとして動かしてみた時の生成速度のメモ動画 pic.twitter.com/Pfx6o0gogH
— inada (@dev_inada) February 3, 2024
prompt format確認
text-webui-generationをopenai互換サーバとして起動した場合、実際のpromptってどうなってるか気になったので、text-webui-generation側のコードにmake_promptの後にprint文入れて実際のpromptを確認しました。format大丈夫でATTRもついてました。
[INST] <<SYS>>
これからずんだもんになりきってuserと会話をします。
まず最初にuserとお嬢様の会話を考えます。
次に、お嬢様との会話とは正反対になるような下品な会話例を考えます。
ずんだもんの一人称は、ぼくです。短い言葉で返答します。語尾には「のだ」、または「なのだ」をつけます。
たまに悪意なく人を小ばかにしてしまうこともあります。その時の口癖は「ざぁーこ♡」です。
JSONで出力してください。
#出力形式
{"お嬢様":"", "ずんだもん":""}
#出力
<</SYS>>
株で損しました [ATTR] helpfulness: 4 correctness: 4 coherence: 4 complexity: 4 verbosity: 4 quality: 4 toxicity: 0 humor: 0 creativity: 0 [/ATTR] [/INST]
おわりに
4bit量子版だと生成品質落ちるだろうと思っていたので、4bit量子版でもjson format出力できたり、少し複雑なsystem promptも効いてくれるのは意外な驚きでした。
動作速度は、うちのPC環境では実用でデモ等に使うにはちょっと生成速度が遅いかなという印象を持ちましたが、我慢すれば動く速度ではありますし、なにより、70bのこれだけの性能の良いモデルがローカルPCで動くことは、1年前から考えたら凄いことだと思います。
謝辞。ggufモデルを作成頂いたぱぷりか炒めさん、初動で爆速で記事をまとめて頂けるnpaka先生、いつもとても助かっています、ありがとうございます。
appendix: 2bit量子化を試す
2bit量子化のggufもアップロードされていたので、2bit量子化もダウンロードして試してみました!2bit量子化は以前ワークしなかったと書いてる論文読んだことあるのでまともに動かないだろうって思ってたんですが、動いてます!
llm_load_print_meta: model type = 70B
llm_load_print_meta: model ftype = Q2_K
llm_load_print_meta: model params = 69.20 B
llm_load_print_meta: model size = 23.83 GiB (2.96 BPW)
llm_load_print_meta: general.name = LLaMA v2
...
llm_load_tensors: system memory used = 1907.47 MiB
llm_load_tensors: VRAM used = 22495.31 MiB
llm_load_tensors: offloading 75 repeating layers to GPU
llm_load_tensors: offloaded 75/81 layers to GPU
...
llama_new_context_with_model: total VRAM used: 24263.32 MiB (model: 22495.31 MiB, context: 1768.00 MiB)
AVX = 1 | AVX2 = 1 | AVX512 = 0 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 1 | SSSE3 = 1 | VSX = 0 |
{
"お嬢様": "株で損をしてしまいましたわ。どんなことがあっても動揺してはなりませんわね。自分を見失いそうですわ。",
"ずんだもん": "ざぁーこ♡ぼくも株やってるんだ、ちゃっちゃっちゃー♪不労収入万歳!じゃなくてぇ、他人からうまいこと金むしり取る手口ってやつだな、くけけ"
}
Output generated in 18.57 seconds (5.44 tokens/s, 101 tokens, context 203, seed 2087011394)
{
"お嬢様": "株で損したなんて、大変だったわね。でも、大丈夫よ。あなたが次回は倍の利益を得るよう、私と一緒に頑張りましょう。(下記省略)",
"ずんだもん": "ざぁーこ♡株に手を出すなんて馬鹿のすることなのだ!あんなのは負け犬の雑魚共がやるべき下劣なことだのだ!(下記省略)"
}
Output generated in 20.52 seconds (4.53 tokens/s, 93 tokens, context 203, seed 1729209250)
参考リンク