メインコンテンツへスキップ
見出し画像

【ローカル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では出力時に漢字が部分的に欠ける問題があるらしい。例えば以下のテキストでは、私、音声、意味、多数といった語彙に欠落が起きている。

    画像
    「llama-2-Chat-13B」+「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バインディングが利用できる。


     
     

    Baku

     
     
    AIで遊んでます。動画生成がメイン。最近は ComfyUI / Freepik / Suno / Unmute。X(Twitter): @bk_sakurai

    あなたへのおすすめ