【ローカルLLM】Gradioとllama-cpp-pythonで日本語チャットボットを作る
先日の記事に続き、ウェブUI用のPythonライブラリ「gradio」を使って、簡単なチャットボットを作ってみた記録。
今回はLlama系の言語モデルを使いたいので、モデルとgradioUIをつなぐPythonバインディングに「llama-cpp-python」を使用。これにより軽量な量子化モデル(GGUF)を扱える。
ひな形を探す
Hugging Face Spaces用のウェブUIサンプルを公開しているRepoがあり、ここにgradio+llama-cpp-pythonの例もあると教えてもらった。
ここでは、モデルに「Llama-2-7B-Chat-GGML」を使っている。
このサンプルを少し加工して使えばいいな、と思ったが、日本語で使おうとするとちょっと問題あり。
llama-cpp-pythonで漢字が欠落
どうやら、llama-cpp-pythonでは出力時に漢字が部分的に欠ける問題があるらしい。例えば以下のテキストでは、私、音声、意味、多数といった語彙に欠落が起きている。
この事象はStreamオプション(ウェブのChatGPTのように、テキストを1トークンずつ流れるように出力させる)を指定したときだけ起きる模様。Stream無効に修正すると、漢字は欠けなかった。
ちょっと調べてみると、こちらのツイートなどで既に同じことが指摘されていた。llama.cpp本体の問題ではなさそう。
OpenBuddy-Llama2を使う
「Llama-2-Chat」以外のLlama系モデルを使った場合も、llama-cpp-python経由で出力すると軒並みこの現象が起きる。
ただ自分が試した範囲だと、昨日紹介した「OpenBuddy-Llama2-13B」では漢字が欠けずに出力できる様子。
このモデルはCJK文字のサポートをうたっているので、トークナイザー?とかが漢字用に調整されてるのかもしれない。
とりあえず今回はこのモデルをllama.cppでGGUFフォーマット(.gguf)に変換して使用することに。
コード
あとは、先ほどのサンプルをローカルで使うようにエイヤーで修正。
ついでに、プロンプトフォーマットもシンプルなVicunaスタイルに変更。system_messageも英語から日本語に変更した。
Google Colabで試す用のコードは下記。ランタイムをGPUに変更のこと。
# ライブラリのインストール
!CMAKE_ARGS="-DLLAMA_CUBLAS=on" FORCE_CMAKE=1 pip install llama-cpp-python
#(CPUで実行する場合)!pip install llama-cpp-python
!pip install gradio
# モデルのダウンロード
!wget https://huggingface.co/TFMC/openbuddy-llama2-13b-v11.1-bf16-GGUF/resolve/main/ggml-model-q4_m.gguf
# ウェブUIの起動
import os
import gradio as gr
import copy
import time
from llama_cpp import Llama
llm = Llama(
model_path="ggml-model-q4_m.gguf",
n_ctx=2048,
n_gpu_layers=100, #CPUで実行する場合は削除
)
history = []
system_message = """
あなたはAIアシスタントです。
"""
def generate_text(message, history):
temp = ""
input_prompt = f"{system_message}"
for interaction in history:
input_prompt = input_prompt + "\nUSER: " + str(interaction[0]) + "\nASSISTANT: " + str(interaction[1])
input_prompt = input_prompt + "\nUSER: " + str(message) + "\nASSISTANT: "
output = llm.create_completion(
input_prompt,
temperature=0.7,
top_p=0.3,
top_k=40,
repeat_penalty=1.1,
max_tokens=1024,
stop=[
"ASSISTANT:",
"USER:",
"SYSTEM:",
],
stream=True,
)
for out in output:
stream = copy.deepcopy(out)
temp += stream["choices"][0]["text"]
yield temp
history = ["init", input_prompt]
demo = gr.ChatInterface(
generate_text,
title="Japanese chatbot using llama-cpp-python",
description="",
examples=["日本の四国にある県名を挙げてください。"],
cache_examples=True,
retry_btn=None,
undo_btn="Remove last",
clear_btn="Clear all",
)
demo.queue(concurrency_count=1, max_size=5)
demo.launch(debug=True, share=True)
参考
「llama-cpp-python」の基本的な使い方は以下の記事が分かりやすかった。※ ちょうど数日前に、llama.cppのファイルフォーマットがGGML(.bin)からGGUF(.gguf)に切り替わったので留意。
なお「Rinna」などGPT-NeoX系の日本語LLMは、現時点では「llama-cpp-python」だと使えない(llama.cpp本体はGPT-NeoX対応済み)。ただ「CTranslate2」という別のPythonバインディングが利用できる。