見出し画像

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も作成出来ました。