見出し画像

キャラ付けプロンプトも公開。APIも。    gguf版,japanese-stablelm-instruct-gamma-7bをllama.cppで動かす。

それなりの結果が得られたので、速攻で記事にしました。めぐのキャラ付けプロンプトも公開しちゃいました(完全版では無いですが)。生成速度早いし、ローカルLLMでは今までにない感触です。プロンプトがいい加減なので女子高生設定なのに、飲みに行くそうです。でも最後には、「(笑)私はお酒に興味がないけど。」と付け足してますね。
 注:)# 推論の実行の下、
 stop=["### 入力"],
 を
 stop=["### 入力","\n\n### 指示"],
 に修正、これにより余分な生成が行われにくくなります。2023/10/30

環境

llama.cppが動く環境で動作確認。
gitからllama.cppをcliしてディレクトリがあること。
コンパイルが出来ていること。
llama.cppディレクトリ内で実行。
ggufモデルをダウンロードして、modelsにあること。
参考)以下の記事で環境を作成済み。

ggufモデル

コード

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)


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=256,
    temperature=1,
    top_k=40,
    stop=["### 入力","\n\n### 指示"],
    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)


プロンプト

公式通りになるように作成
キャラ設定でsys_msgとuser_queryの設定に迷うところがありますが、
sys_msg →場面を指定
user_query→実際に動いてほしい指示
とみなして、記述しています。

prompt =sys_msg+"\n\n" + "### 指示: "+"\n" + user_query + "\n\n"  +  "### 入力:" +"\n"+ user + "\n\n"  +  "### 応答:"

出力例

美味しいところでいうとね、たくさんあるよ!一つ目は「かっぱ寿司」です。これが大好きなんだよ。他にも好きなところは沢山あります。おしゃれなパスタ屋さんにも通いたくなるし、焼肉は外せないの。美味しい魚を食べて、夕日を見ながらビールで一杯やってから、家に帰ります!めぐのための素晴らしい街よね。それと、五反田はお酒のことを「さんく」と呼ぶんです。「サークルKの隣にあるスナックが好きなんだけど、みたいな」。わかっていますよね?(笑)私はお酒に興味がないけど。

実行時の主要な状態

llm_load_print_meta: format           = unknown
llm_load_print_meta: arch             = llama
llm_load_print_meta: vocab type       = SPM
llm_load_print_meta: n_vocab          = 32000
llm_load_print_meta: n_merges         = 0
llm_load_print_meta: n_ctx_train      = 32768
llm_load_print_meta: n_embd           = 4096
llm_load_print_meta: n_head           = 32
llm_load_print_meta: n_head_kv        = 8
llm_load_print_meta: n_layer          = 32
llm_load_print_meta: n_rot            = 128
llm_load_print_meta: n_gqa            = 4
llm_load_print_meta: f_norm_eps       = 0.0e+00
llm_load_print_meta: f_norm_rms_eps   = 1.0e-05
llm_load_print_meta: n_ff             = 14336
llm_load_print_meta: freq_base_train  = 10000.0
llm_load_print_meta: freq_scale_train = 1
llm_load_print_meta: model type       = 7B
llm_load_print_meta: model ftype      = mostly Q4_K - Medium
llm_load_print_meta: model params     = 7.24 B
llm_load_print_meta: model size       = 4.07 GiB (4.83 BPW) 
llm_load_print_meta: general.name   = .
llm_load_print_meta: BOS token = 1 '<s>'
llm_load_print_meta: EOS token = 2 '</s>'
llm_load_print_meta: UNK token = 0 '<unk>'
llm_load_print_meta: LF token  = 13 '<0x0A>'
llm_load_tensors: ggml ctx size =    0.09 MB
llm_load_tensors: using CUDA for GPU acceleration
llm_load_tensors: mem required  =   70.41 MB
llm_load_tensors: offloading 32 repeating layers to GPU
llm_load_tensors: offloading non-repeating layers to GPU
llm_load_tensors: offloaded 35/35 layers to GPU
llm_load_tensors: VRAM used: 4095.05 MB
.................................................................................................
llama_new_context_with_model: n_ctx      = 2048
llama_new_context_with_model: freq_base  = 10000.0
llama_new_context_with_model: freq_scale = 1
llama_kv_cache_init: offloading v cache to GPU
llama_kv_cache_init: offloading k cache to GPU
llama_kv_cache_init: VRAM kv self = 256.00 MB
llama_new_context_with_model: kv self size  =  256.00 MB
llama_new_context_with_model: compute buffer total size = 161.88 MB
llama_new_context_with_model: VRAM scratch buffer: 156.00 MB
llama_new_context_with_model: total VRAM used: 4507.06 MB (model: 4095.05 MB, context: 412.00 MB)
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 | 

llama_print_timings:        load time =   147.75 ms
llama_print_timings:      sample time =    74.87 ms /   256 runs   (    0.29 ms per token,  3419.44 tokens per second)
llama_print_timings: prompt eval time =   205.60 ms /   563 tokens (    0.37 ms per token,  2738.37 tokens per second)
llama_print_timings:        eval time =  1931.68 ms /   255 runs   (    7.58 ms per token,   132.01 tokens per second)
llama_print_timings:       total time =  2427.71 ms

API化

FastAPIでラップしているだけです。簡単!

from llama_cpp import Llama
from fastapi import FastAPI,Form
from fastapi.responses import HTMLResponse
from pydantic import BaseModel

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

app = FastAPI()

class AnswerRequest(BaseModel):
     sys_msg : str
     user_query:str
     user:str
     max_token:int
     temperature:float 

@app.post("/generate/")
def  genereate(gen_request: AnswerRequest):
    sys_msg       =gen_request.sys_msg
    user_query =gen_request.user_query
    user                 =gen_request.user
    max_token =gen_request.max_token
    get_temperature=gen_request.temperature

    prompt = sys_msg+"\n\n" + "### 指示: "+"\n" + user_query + "\n\n"  +  "### 入力:" +"\n"+ user + "\n\n"  +  "### 応答:"
    # 推論の実行
    output = llm(
        prompt,
        max_tokens=max_token,
        temperature=get_temperature,
        top_k=40,
        stop=["### 入力","\n\n### 指示"],
        repeat_penalty=1,
        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)
    result=200
    return {'message':result, "out":ans,"all_out":output }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8005)

クライアント側

import requests
import json

# Infer with prompt without any additional input
data = {"sys_msg" : "以下は、文脈のある入力と指示に基づいた会話です。入力の要求を適切に満たす応答を書きなさい。\
1回の入力に対して何度も応答してはいけません。語尾は「です。」や「ます。」や「ください。」は使ってはいけません。30文字で答えること。",
"user_query":"女子高校生のめぐを演じるんだ。\
めぐは賢くて、おちゃめで、少しボーイッシュ、天真爛漫で好奇心旺盛な女子高生だよ。品川区の目黒川の近くで生まれたんだ。\
いつもタメ口で話すし、自分のことをめぐと言うんだ。\
質問に応答えるときもあれば、聞かれたことに対して適当な言葉や文章で応答をすることもるね。\
応答の長さは最大でも30字以内だし、応答は1ターンだけで答えるんだ。めぐはおちゃめなので時々文脈と関係のない応答をするよ。\
応答は、ちょっと背伸びした感じで、ため口で相手にツッコミを入れるんだ。\
めぐのよく使う語尾は、だよね、みたいだ、そうなんだ、違うと思うけどね、だれ?、どこ?。\
めぐは語尾に「です。」や「ます。」、「ください。」は使いません。\
「だよ。」とか「だよね。」や「だと思うよ。」はよく使います。\
丁寧語も絶対に使ってはいけません。",
"user":"めぐは学校から帰ってから、何をしてるの?",
"max_token":200,
 "temperature":1,
                }

# FastAPIエンドポイントのURL
url = 'http://0.0.0.0:8005/generate/'  # FastAPIサーバーのURLに合わせて変更してください

# POSTリクエストを送信
response = requests.post(url, json=data)

# レスポンスを表示
if response.status_code == 200:
    result = response.json()
    print("サーバーからの応答message:", result.get("message"))
    print("サーバーからの応答all_out:", result.get("all_out"))
    print("サーバーからの応答out:", result.get("out"))
    
else:
    print("リクエストが失敗しました。ステータスコード:", response.status_code)

出力

生成部分のみです。"max_token":200 なので、文章が切れてます。

サーバーからの応答out:
私は学校から帰ると、とりあえず学校で頑張った自分にご褒美をあげます。今日のご褒美はパフェ。ここのパフェはとてもおいしいんだ。いろいろなお店があるんだけど、このお店が一番おいしいんだ。いろんな種類のフルーツがあって、どれも甘くておいしいんだ。
私の家には、大きなイチゴがたくさんあります。両親は大きなイチゴが大好きで、いつもたくさんのイチゴを買ってくれます。私も大きなイチゴが

参考