Transformers documentation
マルチモーダルチャットテンプレート
マルチモーダルチャットテンプレート
マルチモーダルチャットモデルは、テキストに加えて、画像、音声、動画などの入力を受け付けます。マルチモーダルチャット履歴のcontentキーは、異なるタイプの複数のアイテムを含むリストです。これに対し、テキスト専用のチャットモデルのcontentキーは単一の文字列です。
テキスト専用モデルのチャットテンプレートとトークナイズ処理をTokenizerクラスが処理するのと同様に、マルチモーダルモデルの前処理、トークナイズ、チャットテンプレートをProcessorクラスが処理します。それぞれのapply_chat_template()メソッドはほぼ同一です。
このガイドでは、高レベルのImageTextToTextPipelineと、低レベルのapply_chat_template()およびgenerate()メソッドを使用して、マルチモーダルモデルとチャットする方法を示します。
ImageTextToTextPipeline
ImageTextToTextPipeline は、チャットモードを備えた高レベルな画像・テキスト生成クラスです。対話型モデルが検出され、チャットプロンプトが適切にフォーマットされている場合、チャットモードが有効になります。
チャット履歴のcontentキーに、画像ブロックとテキストブロックを追加します。
messages = [
{
"role": "system",
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
},
{
"role": "user",
"content": [
{"type": "image", "url": "http://images.cocodataset.org/val2017/000000039769.jpg"},
{"type": "text", "text": "What are these?"},
],
},
]ImageTextToTextPipeline を作成し、チャットを渡します。大規模モデルの場合、device_map=“auto” を設定すると、モデルの読み込みが速くなり、利用可能な最速のデバイスに自動的に配置されます。データ型を auto に設定することも、メモリを節約し速度を向上させるのに役立ちます。
import torch
from transformers import pipeline
pipe = pipeline("image-text-to-text", model="Qwen/Qwen2.5-VL-3B-Instruct", device_map="auto", dtype="auto")
out = pipe(text=messages, max_new_tokens=128)
print(out[0]['generated_text'][-1]['content'])Ahoy, me hearty! These be two feline friends, likely some tabby cats, taking a siesta on a cozy pink blanket. They're resting near remote controls, perhaps after watching some TV or just enjoying some quiet time together. Cats sure know how to find comfort and relaxation, don't they?
海賊言葉から現代のアメリカ英語への段階的な移行(毕竟、3Bモデルに過ぎないため)を除けば、これは正しいです!
apply_chat_templateの使用
テキスト専用モデルと同様に、マルチモーダルモデルのチャットメッセージを準備するには、apply_chat_template()メソッドを使用します。 このメソッドは、画像やその他のメディアタイプを含むチャットメッセージのトークン化とフォーマットを処理します。生成された入力は、モデルに渡されて生成が行われます。
from transformers import AutoProcessor, AutoModelForImageTextToText
model = AutoModelForImageTextToText.from_pretrained("Qwen/Qwen2.5-VL-3B-Instruct", device_map="auto", torch_dtype="auto")
processor = AutoProcessor.from_pretrained("Qwen/Qwen2.5-VL-3B-Instruct")
messages = [
{
"role": "system",
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
},
{
"role": "user",
"content": [
{"type": "image", "url": "http://images.cocodataset.org/val2017/000000039769.jpg"},
{"type": "text", "text": "What are these?"},
],
},
]messages を apply_chat_template() に渡して、入力内容をトークン化します。テキストモデルとは異なり、apply_chat_template の出力には、トークン化されたテキストに加えて、前処理済みの画像データを含む pixel_values キーが含まれます。
processed_chat = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt")
print(list(processed_chat.keys()))['input_ids', 'attention_mask', 'pixel_values', 'image_grid_thw']
これらの入力をgenerate()に渡します。
out = model.generate(**processed_chat.to(model.device), max_new_tokens=128)
print(processor.decode(out[0]))デコードされた出力には、ユーザーメッセージや画像情報を含むプレースホルダートークンなど、これまでの会話全体が含まれています。ユーザーに表示する前に、出力から以前の会話を切り捨てる必要がある場合があります。
動画入力
一部のビジョンモデルは、動画入力にも対応しています。メッセージの形式は、前述のセクションで説明した画像入力の形式と非常に似ています。
- コンテンツの
"type"は、コンテンツが動画であることを示すために"video"である必要があります。 - 動画の場合、リンク (
"url") またはファイルパス ("path") を指定できます。動画は torchcodec でデコードされます。torchcodec が利用できず、古いバージョンの torchvision を使用している場合、デコードは torchvision にフォールバックします。 - URLやファイルパスから動画を読み込むことに加えて、デコード済みの動画データを直接渡すこともできます。これは、メモリ内の他の場所で動画フレームを事前処理またはデコード済みの場合に便利です。ファイルに保存したり、URLに格納したりする必要はありません。
PyAV と Decord は利用可能ですが、
load_video(backend=...)でバックエンドを明示的に指定して、自分で動画をデコードする場合に限ります。
from transformers import AutoProcessor, LlavaOnevisionForConditionalGeneration
model_id = "llava-hf/llava-onevision-qwen2-0.5b-ov-hf"
model = LlavaOnevisionForConditionalGeneration.from_pretrained(model_id)
processor = AutoProcessor.from_pretrained(model_id)
messages = [
{
"role": "system",
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
},
{
"role": "user",
"content": [
{"type": "video", "url": "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_10MB.mp4"},
{"type": "text", "text": "What do you see in this video?"},
],
},
]例:デコード済み動画オブジェクトの渡し方
import numpy as np
video_object1 = np.random.randint(0, 255, size=(16, 224, 224, 3), dtype=np.uint8),
messages = [
{
"role": "system",
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
},
{
"role": "user",
"content": [
{"type": "video", "video": video_object1},
{"type": "text", "text": "What do you see in this video?"}
],
},
]既存の"load_video()"関数を使用して動画を読み込み、メモリ上で動画を編集してから、メッセージに渡すこともできます。
# Make sure a video backend library (torchcodec, pyav, or decord) is available.
from transformers.video_utils import load_video
# load a video file in memory for testing
video_object2, _ = load_video(
"https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_10MB.mp4"
)
messages = [
{
"role": "system",
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
},
{
"role": "user",
"content": [
{"type": "video", "video": video_object2},
{"type": "text", "text": "What do you see in this video?"}
],
},
]messages を apply_chat_template() に渡して、入力内容をトークン化します。apply_chat_template() には、サンプリングプロセスを制御するいくつかの追加パラメータを含める必要があります。
num_frames パラメータは、動画から均等にサンプリングするフレーム数を制御します。各チェックポイントには、事前学習で使用された最大フレーム数が存在し、この数を超えると生成品質が大幅に低下する可能性があります。モデルの容量とハードウェアのリソースの両方に適したフレーム数を選択することが重要です。num_frames が指定されていない場合、フレームサンプリングなしで動画全体が読み込まれます。
processed_chat = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
return_tensors="pt",
num_frames=32,
)
print(processed_chat.keys())これらの入力値は、generate()で使用できるようになりました。
長い動画の場合、fps パラメータを使用してより多くのフレームをサンプリングすることで、より良い表現が得られる場合があります。このパラメータは、1秒あたり何フレーム抽出するかを決定します。例えば、動画の長さが10秒でfps=2の場合、モデルは20フレームをサンプリングします。言い換えれば、10秒間隔で2フレームが均等にサンプリングされるということです。
processed_chat = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
fps=16,
)
print(processed_chat.keys())動画は、完全な動画ファイルではなく、画像として保存されたサンプリングされたフレームのセットとして存在する場合もあります。
この場合、画像ファイルのパスのリストを渡すと、プロセッサが自動的にそれらを連結して動画に変換します。同じ動画からのフレームであると想定されるため、すべての画像が同じサイズであることを確認してください。
frames_paths = ["/path/to/frame0.png", "/path/to/frame5.png", "/path/to/frame10.png"]
messages = [
{
"role": "system",
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
},
{
"role": "user",
"content": [
{"type": "video", "path": frames_paths},
{"type": "text", "text": "What do you see in this video?"},
],
},
]
processed_chat = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
)
print(processed_chat.keys())