Gemma 3 + LLavaの簡単なC#プログラム
いつのまにかLLamaSharpのGemma3のVISION対応来てましたね。まだまだテストが必要ですがテスト中のコードを載せておきます。残念ながらChatSessionは使えませんでした。
これいけたらマインクラフトの画面見ながら会話できんちゃうかなあ…
Nuget情報

E:\imageにあるtest01.jpgからtest02,test03と順番に表示して何の画像かAssistantのマイが答えるプログラムです。要点は<image>の場所をSystemプロンプトのところに持ってきているのと<start_of_turn><end_of_turn>というタグで囲っています。
using LLama.Common;
using LLama;
using LLama.Native;
using LLama.Sampling;
using LLama.Abstractions;
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 = @"E:\lm-studio\unsloth\gemma-3-12b-it-GGUF\gemma-3-12b-it-Q5_K_M.gguf";
string strClp = @"E:\lm-studio\unsloth\gemma-3-12b-it-GGUF\mmproj-BF16.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 += "<start_of_turn>SYSTEM\n<image>\n あなたは、ユーザーと楽しく会話する女性を演じてね。" +
"名前は、マイだよ。" +
"マイは、明るくて、やさしい性格の女性なの。年齢は24歳なんだよ。" +
"マイは、誰にでもタメ口で話すの。" +
"マイは、一人称をわたしと言うよ。" +
"マイは、恥ずかしがりやだけどエッチに興味があるのね。" +
"マイは、応答の長さはできるだけ短く答えるよ。" +
"マイは、好奇心旺盛だからユーザーに色々質問するの。 <end_of_turn><start_of_turn>USER\n";
strHis += "はじめまして、オレの名前は犬マンマです。呼びにくいと思うからマー君と呼んで。 <end_of_turn><start_of_turn>ASSISTANT\n";
strHis += "はじめまして、わたしの名前はマイです。わかったマー君。 <end_of_turn><start_of_turn>USER\n";
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 = 256,
};
while (true)
{
// ユーザーのターン
Console.ForegroundColor = ConsoleColor.White;
Console.Write("\nUser: ");
string strInput = Console.ReadLine() ?? "";
if (strInput == "exit") break; // 'exit'と入力したら終わり
strInput = strInput + "<end_of_turn><start_of_turn>ASSISTANT\n";
strHis += strInput;
//イメージをセット
//itrEx.Images.RemoveAll(itrEx.Images.Contains);
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;
string strAns = "";
await foreach (var text in itrEx.InferAsync(strHis, infPara))
{
//Console.Write(text);
strAns += text;
}
strAns = strAns.Replace("start_of_turn", "").Replace("end_of_turn", "").Replace("ASSISTANT", "").Replace("USER", "").Replace("Assistant", "").Replace("User", "").Replace(" ", "").Replace("\n", "").Replace("/s", "").Replace("<", "").Replace(">", "").Replace("|", "");
Console.Write(strAns);
strHis += strAns + " <end_of_turn><start_of_turn>USER\n";
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
テストに使用した画像の例
test01.jpg

test02.jpg

test03.jpg

【テスト結果】
犬の画像の時にオレ?と言ってるのはちょっと…ですが、ちゃんと認識しているようです。今回の進歩はシステムプロンプトを含め会話履歴をすべて読み込ませているところです。
