Llama-3.2-11B-Vision-InstructをGUIで試す
9月末に発表された、最新のLlama-3.2-11B-Vision-Instructを試しました。続けて質問できるような簡単なGUIにも対応しました。普通に日本語も大丈夫です。なんだか詳しい説明が見当たらないので、生成パラメータはは公式通りMAX_NEW_TOKENだけです。
動かしてみる
モデル
以下のモデルを使います。メタのオリジナルは筆者のミスで今回使えなかったので代替です。
環境
色々やってて何が必要なのかよくわからなくなったのですが、 transformersは最低必要。
pip install torch transformers accelerate
CLIで動かす
CLIのコード
SeanScriptsさんのモデルカードにあるコードのプロンプト部分をわかりやすく変更したのみです。
from transformers import MllamaForConditionalGeneration, AutoProcessor, BitsAndBytesConfig
from PIL import Image
import time
# Load model
model_id = "SeanScripts/Llama-3.2-11B-Vision-Instruct-nf4"
model = MllamaForConditionalGeneration.from_pretrained(
model_id,
use_safetensors=True,
device_map="cuda:0"
)
# Load tokenizer
processor = AutoProcessor.from_pretrained(model_id)
# Caption a local image (could use a more specific prompt)
IMAGE = Image.open("test.png").convert("RGB")
messages = [
{"role": "user", "content": [
{"type": "image"},
{"type": "text", "text": "これについて説明してください。"}
]}
]
input_text = processor.apply_chat_template(messages, add_generation_prompt=True)
inputs = processor(IMAGE, input_text, return_tensors="pt").to(model.device)
prompt_tokens = len(inputs['input_ids'][0])
print(f"Prompt tokens: {prompt_tokens}")
t0 = time.time()
generate_ids = model.generate(**inputs, max_new_tokens=256)
t1 = time.time()
total_time = t1 - t0
generated_tokens = len(generate_ids[0]) - prompt_tokens
time_per_token = generated_tokens/total_time
print(f"Generated {generated_tokens} tokens in {total_time:.3f} s ({time_per_token:.3f} tok/s)")
output = processor.decode(generate_ids[0][prompt_tokens:]).replace('<|eot_id|>', '')
print(output)
入力画像
出力結果
この画像は、バーチャル世界の風景です。バーチャル世界とは、現実世界のものと違い、現実世界のものと異なる、架空の世界のことです。バーチャル世界は、ゲームや映画など、多様な媒体で表現されています。
この風景は、バーチャル世界の風景です。バーチャル世界の風景は、現実世界の風景と同様に、様々な風景を表現することができます。バーチャル世界の風景は、現実世界の風景と同様に、様々な風景を表現することができます。
この風景は、バーチャル世界の風景です。バーチャル世界の風景は、現実世界の風景と同様に、様々な風景を表現することができます。バーチャル世界の風景は、現実世界の風景と同様に、様々な風景を表現することができます。バーチャル世界の風景は、現実世界の風景と同様に、様々な風景
GUIで動かす
先程のコードにGradioインターファースを追加して、繰り返し追加質問をできるようにしました。
GUIのコード
モデルとイメージは一度だけ読み込むようになっています。1度目の推論は長い時間がかかりますが、2回目からは比較的早く回答が出ます。
from transformers import MllamaForConditionalGeneration, AutoProcessor, BitsAndBytesConfig
from PIL import Image
import gradio as gr
import time
# モデルとプロセッサのロード
model_id = "SeanScripts/Llama-3.2-11B-Vision-Instruct-nf4"
model = MllamaForConditionalGeneration.from_pretrained(
model_id,
use_safetensors=True,
device_map="cuda:0"
)
processor = AutoProcessor.from_pretrained(model_id)
# 画像とユーザー入力テキストから出力を生成する関数
def generation(image,user_text):
messages = [
{"role": "user", "content": [
{"type": "image"},
{"type": "text", "text": user_text}
]}
]
input_text = processor.apply_chat_template(messages, add_generation_prompt=True)
inputs = processor(image, input_text, add_special_tokens=False,return_tensors="pt").to(model.device)
prompt_tokens = len(inputs['input_ids'][0])
print(f"Prompt tokens: {prompt_tokens}")
t0 = time.time()
generate_ids = model.generate(**inputs, max_new_tokens=256)
t1 = time.time()
total_time = t1 - t0
generated_tokens = len(generate_ids[0]) - prompt_tokens
time_per_token = generated_tokens / total_time
print(f"Generated {generated_tokens} tokens in {total_time:.3f} s ({time_per_token:.3f} tok/s)")
output = processor.decode(generate_ids[0][prompt_tokens:]).replace('<|eot_id|>', '')
print(output)
return output
# Gradio UIの構築
def create_interface():
# Gradioの入力と出力
image_input = gr.Image(type="pil", label="画像をアップロード")
text_input = gr.Textbox(label="ユーザー入力テキスト", placeholder="ユーザーのプロンプト")
output_text = gr.Textbox(label="OUTPUT", interactive=False)
# Gradioアプリの作成
gr.Interface(
fn=generation,
inputs=[image_input,text_input],
outputs=output_text,
title=model_id,
description="画像とテキストを入力して、生成された応答を確認できます。",
).launch()
# メイン関数
if __name__ == '__main__':
create_interface()
起動後のGUI
使い方
① 画像をドロップ
② ユーザー入力テキストに質問を記述す
③ エンターかsubmitボタンをクリック
④ ユーザー入力テキストに引き続き質問
この絵の説明を求めます。
引き続き質問
うまく回答ができるようです。
まとめ
ローカルのマルチモーダルLLMも性能が上がって居ることがわかります。やや推論速度が遅いことが気になるところですが、十分使える速さです。Llavaのときと比べると随分簡単にGUIも作成出来ました。