# Modelos de chat multimodais

Modelos de chat multimodais aceitam entradas como imagens, áudio ou vídeo, além de texto. A chave `content` em um histórico de chat multimodal é uma lista contendo vários itens de diferentes tipos. Isso difere dos modelos de chat apenas com texto, cuja chave `content` é uma única string.

Da mesma forma que a classe [Tokenizer](./fast_tokenizers) trata modelos de chat e tokenização para modelos apenas de texto, a classe [Processor](./processors) trata pré-processamento, tokenização e modelos de chat para modelos multimodais. Seus métodos [apply_chat_template()](/docs/transformers/main/pt/main_classes/processors#transformers.ProcessorMixin.apply_chat_template) são quase idênticos.

Este guia mostrará como conversar com modelos multimodais usando o [ImageTextToTextPipeline](/docs/transformers/main/pt/main_classes/pipelines#transformers.ImageTextToTextPipeline) de alto nível e, em um nível mais baixo, utilizando os métodos [apply_chat_template()](/docs/transformers/main/pt/main_classes/processors#transformers.ProcessorMixin.apply_chat_template) e [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate).

## ImageTextToTextPipeline

[ImageTextToTextPipeline](/docs/transformers/main/pt/main_classes/pipelines#transformers.ImageTextToTextPipeline) é uma classe de alto nível para geração de imagem e texto com um “modo de chat”. O modo de chat é ativado quando um modelo conversacional é detectado e o prompt de chat está [corretamente formatado](./llm_tutorial#prompt-format).

Adicione blocos de imagem e texto à chave `content` no histórico do chat.

```py
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?"},
        ],
    },
]
```

Crie um [ImageTextToTextPipeline](/docs/transformers/main/pt/main_classes/pipelines#transformers.ImageTextToTextPipeline) e passe o chat para ele. Para modelos grandes, definir [device_map="auto"](./models#big-model-inference) ajuda a carregar o modelo mais rapidamente e o posiciona automaticamente no dispositivo mais rápido disponível. Definir o tipo de dados como [auto](./models#model-data-type) também ajuda a economizar memória e melhorar a velocidade.

```python
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'])
```

```text
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?
```

Além da transição gradual do jargão de piratas para o inglês americano moderno (é **apenas** um modelo de 3B, afinal), isso está correto!

## Usando `apply_chat_template`

Assim como nos [modelos apenas de texto](./chat_templating), use o método [apply_chat_template()](/docs/transformers/main/pt/main_classes/processors#transformers.ProcessorMixin.apply_chat_template) para preparar as mensagens de chat para modelos multimodais. Este método trata a tokenização e o formatação das mensagens de chat, incluindo imagens e outros tipos de mídia. Os resultantes são passados ao modelo para geração.

```python
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?"},
        ],
    },
]
```

Passe `messages` para [apply_chat_template()](/docs/transformers/main/pt/main_classes/processors#transformers.ProcessorMixin.apply_chat_template) para tokenizar o conteúdo de entrada. Diferentemente dos modelos de texto, a saída de `apply_chat_template` contém uma chave `pixel_values` com os dados de imagem pré-processados, além do texto tokenizado.

```py
processed_chat = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt")
print(list(processed_chat.keys()))
```

```text
['input_ids', 'attention_mask', 'pixel_values', 'image_grid_thw']
```

Passe estas entradas para [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate).

```python
out = model.generate(**processed_chat.to(model.device), max_new_tokens=128)
print(processor.decode(out[0]))
```

A saída decodificada contém a conversa completa até o momento, incluindo a mensagem do usuário e os tokens de espaço reservado que contêm as informações da imagem. Você pode precisar remover a conversa anterior da saída antes de exibi-la para o usuário.

## Entradas de vídeo

Alguns modelos de visão também suportam entradas de vídeo. O formato da mensagem é muito semelhante ao formato para entradas de imagem descrito na seção anterior.

- O conteúdo `"type"` deve ser `"video"` para indicar que o conteúdo é um vídeo.
- Para vídeos, pode ser um link para o vídeo (`"url"`) ou um caminho de arquivo (`"path"`). Os vídeos são decodificados com [torchcodec](https://meta-pytorch.org/torchcodec/stable/index.html). Se o torchcodec não estiver disponível e você estiver usando uma versão mais antiga do torchvision, a decodificação usa o torchvision como alternativa.
- Além de carregar vídeos a partir de uma URL ou caminho de arquivo, você também pode passar diretamente os dados do vídeo decodificados. Isso é útil se você já pré-processou ou decodificou os quadros do vídeo em outro lugar na memória. Não é necessário salvar em arquivos ou armazenar em uma URL.

> [!TIP]
> [PyAV](https://pyav.basswood-io.com/docs/stable/) e [Decord](https://github.com/dmlc/decord) estão disponíveis, mas apenas se você decodificar o vídeo por conta própria e solicitar o backend explicitamente com `load_video(backend=...)`.

```python
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?"},
        ],
    },
]
```

### Exemplo: Passando objetos de vídeo decodificados

```python
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?"}
        ],
    },
]
```

Você também pode usar a função existente (`"load_video()"`) para carregar um vídeo, editá-lo em memória e passá-lo nas mensagens.

```python

# 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?"}
        ],
    },
]
```

Passe `messages` para [apply_chat_template()](/docs/transformers/main/pt/main_classes/processors#transformers.ProcessorMixin.apply_chat_template) para tokenizar o conteúdo de entrada. Há alguns parâmetros extras a incluir em [apply_chat_template()](/docs/transformers/main/pt/main_classes/processors#transformers.ProcessorMixin.apply_chat_template) que controlam o processo de amostragem.

O parâmetro `num_frames` controla quantos quadros devem ser amostrados uniformemente do vídeo. Cada checkpoint possui um número máximo de quadros com o qual foi pré-treinado, e exceder esse limite pode reduzir significativamente a qualidade da geração. É importante escolher um número de quadros que se adeque tanto à capacidade do modelo quanto aos recursos de hardware disponíveis. Se `num_frames` não for especificado, o vídeo inteiro será carregado sem qualquer amostragem de quadros.

```python
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())
```

Essas entradas estão agora prontas para serem usadas em [generate()](/docs/transformers/main/pt/main_classes/text_generation#transformers.GenerationMixin.generate).

Para vídeos mais longos, pode ser melhor amostrar mais quadros para uma melhor representação com o parâmetro `fps`. Isso determina quantos quadros por segundo devem ser extraídos. Como exemplo, se um vídeo tem 10 segundos de duração e `fps=2`, o modelo amostra 20 quadros. Em outras palavras, 2 quadros são amostrados uniformemente a cada 10 segundos.

```py
processed_chat = processor.apply_chat_template(
    messages,
    add_generation_prompt=True,
    tokenize=True,
    return_dict=True,
    fps=16,
)
print(processed_chat.keys())
```

Vídeos também podem existir como um conjunto de quadros amostrados armazenados como imagens, em vez do arquivo de vídeo completo.

Nesse caso, passe uma lista de caminhos de arquivos de imagem e o processador os concatenará automaticamente em um vídeo. Certifique-se de que todas as imagens tenham o mesmo tamanho, pois é assumido que elas provêm do mesmo vídeo.

```py
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())
```

