Transformers documentation
Modèles de discussion multimodaux
Modèles de discussion multimodaux
Les modèles de chat multimodaux acceptent des entrées telles que des images, de l'audio ou de la vidéo, en plus du texte. La clé content dans un historique de chat multimodal est une liste contenant plusieurs éléments de types différents. Cela diffère des modèles de chat texte uniquement, dont la clé content est une simple chaîne de caractères.
De la même manière que la classe Tokenizer gère les modèles de chat et la tokenisation pour les modèles textuels, la classe Processor gère la prétraitement, la tokenisation et les modèles de chat pour les modèles multimodaux. Leurs méthodes apply_chat_template() sont presque identiques.
Ce guide vous montre comment discuter avec des modèles multimodaux à l’aide du pipeline de haut niveau ImageTextToTextPipeline et, à un niveau plus bas, en utilisant les méthodes apply_chat_template() et generate().
ImageTextToTextPipeline
ImageTextToTextPipeline est une classe de haut niveau pour la génération d’images et de texte avec un « mode conversation ». Le mode conversation est activé lorsqu’un modèle conversationnel est détecté et que le prompt de conversation est correctement formaté.
Ajoutez des blocs d’image et de texte à la clé content dans l’historique de la conversation.
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?"},
],
},
]Créez un ImageTextToTextPipeline et passez-lui la conversation. Pour les grands modèles, définir device_map=“auto” aide à charger le modèle plus rapidement et le place automatiquement sur le périphérique le plus rapide disponible. Définir le type de données sur auto aide également à économiser de la mémoire et à améliorer la vitesse.
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?
En dehors de la transition progressive du jargon des pirates vers l’anglais américain moderne (c’est un modèle de 3B, après tout), c’est correct !
Utilisation de apply_chat_template
Comme pour les modèles de texte uniquement, utilisez la méthode apply_chat_template() pour préparer les messages de chat destinés aux modèles multimodaux. Cette méthode gère la tokenisation et le formatage des messages de chat, y compris les images et les autres types de médias. Les entrées résultantes sont transmises au modèle pour la génération.
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?"},
],
},
]Passez messages à apply_chat_template() pour tokeniser le contenu d'entrée. Contrairement aux modèles de texte, la sortie de apply_chat_template contient une clé pixel_values avec les données d'image prétraitées, en plus du texte tokenisé.
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']
Passez ces entrées à generate().
out = model.generate(**processed_chat.to(model.device), max_new_tokens=128)
print(processor.decode(out[0]))La sortie décodée contient la conversation complète jusqu’à présent, y compris le message de l’utilisateur et les jetons de substitution qui contiennent les informations de l’image. Il est peut-être nécessaire de retirer la conversation précédente de la sortie avant de l’afficher à l’utilisateur.
Entrées vidéo
Certains modèles de vision prennent également en charge les entrées vidéo. Le format des messages est très similaire au format des entrées d’images décrit dans la section précédente.
- Le contenu
"type"doit être"video"pour indiquer que le contenu est une vidéo. - Pour les vidéos, il peut s’agir d’un lien vers la vidéo (
"url") ou d’un chemin de fichier ("path"). Les vidéos sont décodées avec torchcodec. Si torchcodec n’est pas disponible et que vous utilisez une ancienne version de torchvision, le décodage bascule sur torchvision. - En plus de charger des vidéos à partir d’une URL ou d’un chemin de fichier, vous pouvez également transmettre directement des données vidéo décodées. Cela est utile si vous avez déjà prétraité ou décodé les images vidéo ailleurs en mémoire. Vous n’avez pas besoin de les enregistrer dans des fichiers ni de les stocker dans une URL.
PyAV et Decord sont disponibles, mais uniquement si vous décodez la vidéo vous-même et que vous demandez explicitement le backend avec
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?"},
],
},
]Exemple : Passer des objets vidéo décodés
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?"}
],
},
]Vous pouvez également utiliser la fonction existante ("load_video()") pour charger une vidéo, la modifier en mémoire et la transmettre dans les messages.
# 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?"}
],
},
]Passez messages à apply_chat_template() pour tokeniser le contenu d’entrée. Il y a quelques paramètres supplémentaires à inclure dans apply_chat_template() qui contrôlent le processus d’échantillonnage.
Le paramètre num_frames contrôle le nombre de frames à échantillonner uniformément dans la vidéo. Chaque checkpoint a un nombre maximal de frames avec lequel il a été pré-entraîné, et dépasser ce nombre peut réduire considérablement la qualité de la génération. Il est important de choisir un nombre de frames adapté à la capacité du modèle et à vos ressources matérielles. Si num_frames n’est pas spécifié, la vidéo entière est chargée sans aucun échantillonnage de 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())Ces entrées sont désormais prêtes à être utilisées dans generate().
Pour les vidéos plus longues, il peut être préférable d’échantillonner davantage d’images pour une meilleure représentation à l’aide du paramètre fps. Ce paramètre détermine le nombre d’images à extraire par seconde. À titre d’exemple, si une vidéo dure 10 secondes et que fps=2, le modèle échantillonne 20 images. Autrement dit, 2 images sont échantillonnées uniformément toutes les 10 secondes.
processed_chat = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
fps=16,
)
print(processed_chat.keys())Les vidéos peuvent également exister sous forme d'un ensemble de frames échantillonnées stockées sous forme d'images, plutôt que sous forme de fichier vidéo complet.
Dans ce cas, passez une liste de chemins d’accès aux fichiers d’images et le processeur les concaténera automatiquement en une vidéo. Assurez-vous que toutes les images ont la même taille, car elles sont supposées provenir de la même vidéo.
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())