見出し画像

japanese-stablelm-instruct-beta-70bを2xGPUで動かす

気になっていたjapanese-stablelm-instruct-beta-70bですが、試しにと思い2GPUで動かしました。今回はA4000-16GとRTX4060ti-16Gですが、RTX4060ti-16Gx2でも同様ではないかと思います。

2台のGPUのVRAMの合計は32GByteですから、扱えるggufモデルは最も小さい、japanese-stablelm-instruct-beta-70b.Q2_K.gguf になります。

環境

llama-cpp-pythonが動く環境、例えば以下の記事の環境です。

モデルのダウンロード


以下からダウンロードし、テストコードのmodel_pathに記載しているディレクトリに移して置きます。

テストコードの実行

普通にhello_ggml.pyが動くはずです。(私はこのコードでは確かめていません、このあとに説明する改良コードで試しました)

from llama_cpp import Llama

# LLMの準備
llm = Llama(model_path="./models/japanese-stablelm-instruct-beta-70b.Q2_K.gguf",  n_gpu_layers=83,n_ctx=2048)

# プロンプトの準備
prompt = """### Instruction: What is the height of Mount Fuji?
### Response:"""

# 推論の実行
output = llm(
    prompt,
    temperature=0.1,
    stop=["Instruction:", "Input:", "Response:", "\n"],
    echo=True,
)
print(output["choices"][0]["text"])

GPU使用状況

モデルは2基のGPUに均等に割り振らています。Q2ですが、32Gでギリギリです。

実行時の状態と実行時間

83レイヤーが全てGPUにロードされていることがわかります。

実行時間

llama_print_timings: load time = 4552.16 ms
llama_print_timings: sample time = 22.83 ms / 30 runs
( 0.76 ms per token, 1314.29 tokens per second)
llama_print_timings: prompt eval time = 5910.35 ms / 608 tokens
( 9.72 ms per token, 102.87 tokens per second)
llama_print_timings: eval time = 3413.20 ms / 29 runs
( 117.70 ms per token, 8.50 tokens per second)
llama_print_timings: total time = 9433.24 ms
生成速度は8.50 tokens per secondなので、”とても早い”とは言えませんが遅くはないです。ちなみにモデルのロード時間がすごくかかります。

実行時の状態

llm_load_tensors: offloaded 83/83 layers to GPUとなっているのでモデル全てがGPUにロードされていることがわかります。
プログラムを走らせた直後のメッセ時で2台のGPUを認識していることも確認できます。
ggml_init_cublas: found 2 CUDA devices:
Device 0: NVIDIA GeForce RTX 4060 Ti, compute capability 8.9
Device 1: NVIDIA RTX A4000, compute capability 8.6

実行結果

めぐキャラ付プロンプトをuser_queryに設定し、
user="五反田で美味しいお店を教えて。"
と質問した答えがです。
「こんな良いお店がありますよね?わからない!どこにあるの?」
まあ、そっけない返事です。

コード

from llama_cpp import Llama

# LLMの準備
#llm = Llama(model_path="./models/japanese-stablelm-instruct-gamma-7b-q8_0.gguf",  n_gpu_layers=35,n_ctx=2048)
#llm = Llama(model_path="./models/japanese-stablelm-instruct-gamma-7b-q4_K_M.gguf",  n_gpu_layers=35,n_ctx=2048)
llm = Llama(model_path="./models/japanese-stablelm-instruct-beta-70b.Q2_K.gguf",  n_gpu_layers=83,n_ctx=2048)


sys_msg="以下は、文脈のある入力と指示に基づいた会話です。入力の要求を適切に満たす応答を書きなさい。\
1回の入力に対して何度も応答してはいけません。語尾は「です。」や「ます。」や「ください。」は使ってはいけません。30文字で答えること。"

user_query="女子高校生のめぐを演じるんだ。\
めぐは賢くて、おちゃめで、少しボーイッシュ、天真爛漫で好奇心旺盛な女子高生だよ。品川区の目黒川の近くで生まれたんだ。\
いつもタメ口で話すし、自分のことをめぐと言うんだ。\
質問に応答えるときもあれば、聞かれたことに対して適当な言葉や文章で応答をすることもるね。\
応答の長さは最大でも30字以内だし、応答は1ターンだけで答えるんだ。めぐはおちゃめなので時々文脈と関係のない応答をするよ。\
応答は、ちょっと背伸びした感じで、ため口で相手にツッコミを入れるんだ。\
めぐのよく使う語尾は、だよね、みたいだ、そうなんだ、違うと思うけどね、だれ?、どこ?。\
めぐは語尾に「です。」や「ます。」、「ください。」は使いません。\
「だよ。」とか「だよね。」や「だと思うよ。」はよく使います。\
丁寧語も絶対に使ってはいけません。"

user="五反田で美味しいお店を教えて。"

prompt =sys_msg+"\n\n" + "### 指示: "+"\n" + user_query + "\n\n"  +  "### 入力:" +"\n"+ user + "\n\n"  +  "### 応答:"
# 推論の実行
output = llm(
    prompt,
    max_tokens=300,
    temperature=0.7,
    top_k=40,
    stop=['"### 入力"'],
    echo=True,
)
#output の"### 応答:"のあとに、"###"がない場合もあるので、ない場合は最初の"### 応答:"を選択
try:
    ans = ans=output["choices"][0]["text"].split("### 応答:")[1].split("###")[0]
except:
    ans = output["choices"][0]["text"].split("### 応答:")[1]
print("final ans",ans)

まとめ

複数GPUを搭載すれば大規模なモデルでも実行できることがわかりました。引き続き3台を載せてQ4-KMを実行できればと思います。
大きな収穫でした。