Transformers documentation

多模态聊天模板

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

多模态聊天模板

多模态聊天模型除了文本之外,还可以接受图像、音频或视频等输入。多模态聊天历史中的 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]))

解码后的输出包含迄今为止的完整对话,包括用户消息以及包含图像信息的占位符 token。在将输出显示给用户之前,您可能需要从中裁剪掉之前的对话内容。

视频输入

一些视觉模型还支持视频输入。其消息格式与前面章节中描述的图像输入格式非常相似。

  • "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() 以将输入内容转换为 token。在 apply_chat_template() 中还有几个额外的参数,用于控制采样过程。

固定数量的帧
fps
图像帧列表

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()。

Update on GitHub