Transformers 文档

图像到文本

Hugging Face's logo
加入Hugging Face社区

并获得增强的文档体验

开始使用

图像文本到文本

图像文本到文本模型,也称为视觉语言模型 (VLM),是接受图像输入的语言模型。这些模型可以处理各种任务,从视觉问答到图像分割。此任务与图像到文本有很多相似之处,但有一些重叠的用例,例如图像字幕。图像到文本模型仅接受图像输入,并且通常完成特定任务,而 VLM 接受开放式文本和图像输入,并且是更通用的模型。

在本指南中,我们简要概述了 VLM,并展示了如何使用 Transformers 进行推理。

首先,有多种类型的 VLM

  • 用于微调的基础模型
  • 用于对话的聊天微调模型
  • 指令微调模型

本指南重点介绍使用指令微调模型进行推理。

让我们开始安装依赖项。

pip install -q transformers accelerate flash_attn 

让我们初始化模型和处理器。

from transformers import AutoProcessor, Idefics2ForConditionalGeneration
import torch

device = torch.device("cuda")
model = Idefics2ForConditionalGeneration.from_pretrained(
    "HuggingFaceM4/idefics2-8b",
    torch_dtype=torch.bfloat16,
    attn_implementation="flash_attention_2",
).to(device)

processor = AutoProcessor.from_pretrained("HuggingFaceM4/idefics2-8b")

此模型具有一个聊天模板,可帮助用户解析聊天输出。此外,模型还可以接受单个对话或消息中的多个图像作为输入。我们现在将准备输入。

图像输入如下所示。

Two cats sitting on a net
A bee on a pink flower
from PIL import Image
import requests

img_urls =["https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png",
           "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"]
images = [Image.open(requests.get(img_urls[0], stream=True).raw),
          Image.open(requests.get(img_urls[1], stream=True).raw)]

以下是聊天模板的示例。我们可以通过将对话轮次和最后一条消息附加到模板末尾来将其作为输入提供。

messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": "What do we see in this image?"},
        ]
    },
    {
        "role": "assistant",
        "content": [
            {"type": "text", "text": "In this image we can see two cats on the nets."},
        ]
    },
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": "And how about this image?"},
        ]
    },       
]

我们现在将调用处理器的apply_chat_template()方法来预处理其输出以及图像输入。

prompt = processor.apply_chat_template(messages, add_generation_prompt=True)
inputs = processor(text=prompt, images=[images[0], images[1]], return_tensors="pt").to(device)

现在我们可以将预处理的输入传递给模型。

with torch.no_grad():
    generated_ids = model.generate(**inputs, max_new_tokens=500)
generated_texts = processor.batch_decode(generated_ids, skip_special_tokens=True)

print(generated_texts)
## ['User: What do we see in this image? \nAssistant: In this image we can see two cats on the nets. \nUser: And how about this image? \nAssistant: In this image we can see flowers, plants and insect.']

流式传输

我们可以使用文本流式传输来获得更好的生成体验。Transformers 支持使用TextStreamerTextIteratorStreamer类进行流式传输。我们将与 IDEFICS-8B 一起使用TextIteratorStreamer

假设我们有一个应用程序,它保留聊天历史记录并接收新的用户输入。我们将像往常一样预处理输入并初始化TextIteratorStreamer来处理单独线程中的生成。这允许您实时地流式传输生成的文本标记。任何生成参数都可以传递给TextIteratorStreamer

import time
from transformers import TextIteratorStreamer
from threading import Thread

def model_inference(
    user_prompt,
    chat_history,
    max_new_tokens,
    images
):
    user_prompt = {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": user_prompt},
        ]
    }
    chat_history.append(user_prompt)
    streamer = TextIteratorStreamer(
        processor.tokenizer,
        skip_prompt=True,
        timeout=5.0,
    )

    generation_args = {
        "max_new_tokens": max_new_tokens,
        "streamer": streamer,
        "do_sample": False
    }

    # add_generation_prompt=True makes model generate bot response
    prompt = processor.apply_chat_template(chat_history, add_generation_prompt=True)
    inputs = processor(
        text=prompt,
        images=images,
        return_tensors="pt",
    ).to(device)
    generation_args.update(inputs)

    thread = Thread(
        target=model.generate,
        kwargs=generation_args,
    )
    thread.start()

    acc_text = ""
    for text_token in streamer:
        time.sleep(0.04)
        acc_text += text_token
        if acc_text.endswith("<end_of_utterance>"):
            acc_text = acc_text[:-18]
        yield acc_text
    
    thread.join()

现在让我们调用我们创建的model_inference函数并流式传输值。

generator = model_inference(
    user_prompt="And what is in this image?",
    chat_history=messages,
    max_new_tokens=100,
    images=images
)

for value in generator:
  print(value)

# In
# In this
# In this image ...

在较小的硬件上适配模型

VLM 通常很大,需要进行优化才能适应较小的硬件。Transformers 支持许多模型量化库,这里我们只展示使用Quanto进行 int8 量化。int8 量化最多可将内存提高 75%(如果所有权重都被量化)。但是,这不是免费的午餐,因为 8 位不是 CUDA 原生精度,权重会在运行时来回量化,这会增加延迟。

首先,安装依赖项。

pip install -U quanto bitsandbytes

要在加载期间量化模型,我们需要首先创建QuantoConfig。然后像往常一样加载模型,但在模型初始化期间传递quantization_config

from transformers import Idefics2ForConditionalGeneration, AutoTokenizer, QuantoConfig

model_id = "HuggingFaceM4/idefics2-8b"
quantization_config = QuantoConfig(weights="int8")
quantized_model = Idefics2ForConditionalGeneration.from_pretrained(model_id, device_map="cuda", quantization_config=quantization_config)

就是这样,我们可以像往常一样使用该模型,无需任何更改。

进一步阅读

以下是有关图像文本到文本任务的一些更多资源。

< > 在 GitHub 上更新