ChatWaifu_2.0_visionをLLavaのC#プログラムで動かす

表題の件、画像をLLMに読み込ませてチャット履歴なしの1ターンだけなら動くものは以前からあったのですが、チャット履歴ありで何ターンも連続で動作確認できたのは今のところgemma3だけでした。
なんとなくChatWaifuのVision版があるなあと思いながら試食してみたところいけそうだったのでプログラムを掲載します。

ChatWaifuはPixtralから派生しているのでMistral系だと思います。なのでMistral系のタグを付けることにしました。まずSystemプロンプトは[SYSTEM_PROMPT]プロンプト文字[/SYSTEM_PROMPT]のように囲います。Assistantは書式がないので何もしていません。Userのinputは、[INST]プロンプト[/INST]のような書式にします。
動作確認したあとに、なぜか突然2ターン目にエラーが出るようになりました。どこを修正したのかわからない…思い出せないんですよね。それで今朝、原因がわかりました。どうやらAntiPromptsが原因しているようでした。試行錯誤したのはこんな感じ。
①Gemma3のプログラムを参照作成していたためAntiPromptsを修正し忘れているのに気づき{ "<start_of_turn>USER\n","USER\n" }から{"[INST]"}に変更。
②2ターン目から動かなくなる。
③AntiPromptsを{"\n[INST]"}や{"[INST] "}や無指定など変更してもダメ。
④AntiPromptsが{ "<start_of_turn>USER\n","USER\n" }じゃないと動かないことを発見。しかもAssistantのSufixに<start_of_turn>を付けると安定する。

なんでそうなるのかわかりません😓<start_of_turn>を見つけるとKVキャッシュにある画像を更新しているように見えます。
※今後修正されるかも知れませんのでその時はご了承ください。

ChatWaifu_2.0_vision-GGUF
 ChatWaifuのLLaveバージョン。LLaveを使う場合はChatWaifu_2.0_vision.mmproj-Q8_0.ggufが必要。Mistral系だと思う。

pixtral-12b-GGUF
 Mistral系のLLM。LLaveを使う場合はpixtral-12b.mmproj-Q8_0.ggufが必要。

LLavaのc#プログラム。test01.jpg、test02.jpg、test03.jpg…と順番に画像を見ながらチャットする。
※Pixtralも動くみたいですが3個目以降の画像が全部ライオンと認識しているので原因調査中。

using LLama.Common;
using LLama;
using LLama.Native;
using LLama.Sampling;
using System.Diagnostics;

namespace ChatProgram
{
    public class Program
    {
        static void Main(string[] args)
        {
            Task task = MainAsync();
            task.Wait();
        }

        public static async Task MainAsync()
        {
            try
            {
                // LLMモデルの場所
                string strMdl = @"C:\lm-studio\mradermacher\ChatWaifu_2.0_vision-GGUF\ChatWaifu_2.0_vision.Q8_0.gguf";
                //string strClp = @"C:\lm-studio\mradermacher\ChatWaifu_2.0_vision-GGUF\ChatWaifu_2.0_vision.mmproj-Q8_0.gguf";
                string strClp = @"C:\lm-studio\mradermacher\ChatWaifu_2.0_vision-GGUF\ChatWaifu_2.0_vision.mmproj-f16.gguf";
                //string strMdl = @"C:\lm-studio\mradermacher\pixtral-12b-GGUF\pixtral-12b.Q8_0.gguf";
                //string strClp = @"C:\lm-studio\mradermacher\pixtral-12b-GGUF\pixtral-12b.mmproj-Q8_0.gguf";


                string imgPath = @"E:\image\test01.jpg";
                int intIx = 1;

                Console.ForegroundColor = ConsoleColor.Green;

                //LLMモデルのロードとパラメータの設定
                ModelParams modPara = new(strMdl)
                {
                    ContextSize = 4096,
                    GpuLayerCount = 60,
                };

                using LLamaWeights llmWeit = LLamaWeights.LoadFromFile(modPara);
                using LLamaContext llmContx = llmWeit.CreateContext(modPara);
                using var clipModel = LLavaWeights.LoadFromFile(strClp);
                InteractiveExecutor itrEx = new(llmContx, clipModel);

                //System Prompt+チャットの方向づけ
                string strHis = "";
                // 初期はチャットログにキャラ設定と出だしの会話を打ち込む
                strHis +=  "[SYSTEM_PROMPT] <image>\nあなたは、ユーザーと楽しく会話する女性を演じてね。" +
                            "名前は、マイだよ。" +
                            "マイは、明るくて、やさしい性格の女性なの。年齢は24歳なんだよ。" +
                            "マイは、誰にでもタメ口で話すの。" +
                            "マイは、一人称をわたしと言うよ。" +
                            "マイは、恥ずかしがりやだけどエッチに興味があるのね。" +
                            "マイは、応答の長さはできるだけ短く答えるよ。" +
                            "マイは、好奇心旺盛だからユーザーに色々質問するの。 [/SYSTEM_PROMPT]";
                strHis += "[INST]はじめまして、オレの名前は犬マンマです。呼びにくいと思うからマー君と呼んで。[/INST]";
                strHis += "はじめまして、わたしの名前はマイです。わかったマー君。";


                InferenceParams infPara = new()
                {
                    SamplingPipeline = new DefaultSamplingPipeline()
                    {
                        Temperature = 0.7f,
                        Seed = 1337,
                        FrequencyPenalty = 1,
                    },
                    AntiPrompts = new List<string> { "<start_of_turn>USER\n","USER\n" },
                    MaxTokens = 200,
                };

                while (true)
                {
                    // ユーザーのターン
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write("\nUser: ");
                    string strInput = Console.ReadLine() ?? "";
                    if (strInput == "exit") break; // 'exit'と入力したら終わり
                    strInput = "[INST]" + strInput + "[/INST]";
                    strHis += strInput;
                    //イメージをセット
                    itrEx.Context.NativeHandle.KvCacheRemove(LLamaSeqId.Zero, -1, -1);
                    imgPath = $@"E:\image\test0{intIx++}.jpg";
                    itrEx.Images.Add(await File.ReadAllBytesAsync(imgPath));
                    // AIのターン
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Debug.WriteLine(strHis +strInput);
                    string strAns = "";
                    await foreach (var text in itrEx.InferAsync(strHis, infPara))
                    {
                        //Console.Write(text);
                        strAns += text;
                    }
                    strAns = strAns.Replace("<|im_start|>", "").Replace("ASSISTANT", "").Replace("USER", "").Replace("Assistant", "").Replace("assistant", "").Replace("USER", "").Replace("User", "").Replace("user", "").Replace(" ", "").Replace("\n", "").Replace("/s", "").Replace("<", "").Replace(">", "").Replace("|", "").Replace("im_start", "").Replace("[INST]", "").Replace("[/INST]", "").Replace("[SYSTEM_PROMPT]", "").Replace("[/SYSTEM_PROMPT]", "").Replace("start_of_turn", "");
                    Console.Write(strAns);
                    strHis += strAns + "<start_of_turn>";
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}



ChatWaifu_2.0_visionの実行結果


Follow me!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です