Introduction aux Avancées de Qwen2-VL
L'équipe Qwen a mis à jour significativement le modèle Qwen-VL avec la sortie de Qwen2-VL, apportant des améliorations majeures dans plusieurs domaines clés.
- Compréhension Image Améliorée : Qwen2-VL offre une meilleure capacité à interpréter les informations visuelles, établissant de nouvelles références de performance.
- Capacités Vidéo Avancées : Le modèle excelle dans l'analyse de contenus vidéo en temps réel avec une haute précision.
- Fonctions d'Agent Visuel Intégrées : Qwen2-VL s'intègre dans des systèmes complexes pour un raisonnement et une prise de décision avancés en tant qu'agent visuel.
- Support Multilingue Étendu : Les capacités linguistiques ont été élargies pour mieux servir une base d'utilisateurs mondiale et diversifiée.
Architecture du Modèle
Une amélioration architecturale clé de Qwen2-VL est le support de la résolution dynamique native (Naive Dynamic Resolution support). Contrairement à la génération précédente, Qwen2-VL peut traiter des images de toute résolution sans les diviser en blocs, assuratn une cohérence entre l'entrée du modèle et l'information intrinsèque de l'image. Cette approche se rapproche de la perception visuelle humaine.
Une autre innovation est l'intégration du Multimodal Rotary Position Embedding (M-ROPE). En décomposant l'embedding rotary original en trois parties représentant le temps et l'espace (hauteur et largeur), M-ROPE permet au LLM de capturer simultanément les informations de position 1D (texte), 2D (visuel) et 3D (vidéo).
Performance du Modèle
À l'échelle de 7B, Qwen2-VL-7B conserve le support pour les entrées image, multi-images et vidéo, offrant des performances compétitives avec une taille de modèle rentable. Il excelle dans les tâches de compréhension de documents (par exemple, DocVQA) et la compréhension multilingue d'images via MTVQA.
Qwen2-VL propose également un modèle plus petit de 2B, optimisé pour le déploiement mobile. Malgré ses 2B paramètres, il surpasse les modèles de taille similaire dans les tâches vidéo, la compréhension de documents et les questions-réponses générales.
Téléchargement du Modèle
Qwen2-VL est open-source avec deux tailles : Qwen2-VL-2B-Instruct et Qwen2-VL-7B-Instruct, ainsi que des versions quantifiées GPTQ et AWQ.
Pour télécharger, utilisez ModelScope CLI :
modelscope download --model=qwen/Qwen2-VL-7B-Instruct --local_dir ./Qwen2-VL-7B-Instruct
Expérience du Modèle
Exemples de capacités :
- Compréhension de vidéos de jeux.
- Résolution de problèmes de géométrie mathématique.
- Reconnaissance OCR.
Inférence avec Transformers
Installez les dépendances :
pip install git+https://github.com/huggingface/transformers
pip install qwen-vl-utils
Inférence sur une seule image
from PIL import Image
import torch
from transformers import Qwen2VLForConditionalGeneration, AutoTokenizer, AutoProcessor
from qwen_vl_utils import process_vision_info
from modelscope import snapshot_download
# Chemin vers le modèle téléchargé
chemin_modele = "/mnt/workspace/Qwen2-VL-2B-Instruct"
# Charger le modèle en demi-précision sur le(s) périphérique(s) disponible(s)
modele = Qwen2VLForConditionalGeneration.from_pretrained(chemin_modele, device_map="auto", torch_dtype=torch.float16)
pixels_min = 256 * 28 * 28
pixels_max = 1280 * 28 * 28
processeur = AutoProcessor.from_pretrained(chemin_modele, min_pixels=pixels_min, max_pixels=pixels_max)
# Définir les messages pour l'inférence
messages = [{"role": "user", "content": [{"type": "image", "image": "https://example.com/image_demo.jpeg"}, {"type": "text", "text": "Décrivez cette image."}]}]
# Préparation pour l'inférence
texte = processeur.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
entrees_image, entrees_video = process_vision_info(messages)
entrees = processeur(text=[texte], images=entrees_image, videos=entrees_video, padding=True, return_tensors="pt")
entrees = entrees.to('cuda')
# Générer la sortie
ids_generes = modele.generate(**entrees, max_new_tokens=128)
ids_generes_ajustes = [out_ids[len(in_ids):] for in_ids, out_ids in zip(entrees.input_ids, ids_generes)]
texte_sortie = processeur.batch_decode(ids_generes_ajustes, skip_special_tokens=True, clean_up_tokenization_spaces=False)
print(texte_sortie)
Inférence sur plusieurs images
# Messages contenant plusieurs images et une requête texte
messages = [{"role": "user", "content": [{"type": "image", "image": "file:///chemin/vers/image1.jpg"}, {"type": "image", "image": "file:///chemin/vers/image2.jpg"}, {"type": "text", "text": "Identifiez les similarités entre ces images."}]}]
# Préparation pour l'inférence
texte = processeur.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
entrees_image, entrees_video = process_vision_info(messages)
entrees = processeur(text=[texte], images=entrees_image, videos=entrees_video, padding=True, return_tensors="pt")
entrees = entrees.to('cuda')
# Inférence
ids_generes = modele.generate(**entrees, max_new_tokens=128)
ids_generes_ajustes = [out_ids[len(in_ids):] for in_ids, out_ids in zip(entrees.input_ids, ids_generes)]
texte_sortie = processeur.batch_decode(ids_generes_ajustes, skip_special_tokens=True, clean_up_tokenization_spaces=False)
print(texte_sortie)
Inférence sur vidéo
# Messages contenant une vidéo et une requête texte
messages = [{"role": "user", "content": [{"type": "video", "video": "file:///chemin/vers/video1.mp4", 'max_pixels': 360 * 420, 'fps': 1.0}, {"type": "text", "text": "Décrivez cette vidéo."}]}]
# Préparation pour l'inférence
texte = processeur.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
entrees_image, entrees_video = process_vision_info(messages)
entrees = processeur(text=[texte], images=entrees_image, videos=entrees_video, padding=True, return_tensors="pt")
entrees = entrees.to('cuda')
# Inférence
ids_generes = modele.generate(**entrees, max_new_tokens=128)
ids_generes_ajustes = [out_ids[len(in_ids):] for in_ids, out_ids in zip(entrees.input_ids, ids_generes)]
texte_sortie = processeur.batch_decode(ids_generes_ajustes, skip_special_tokens=True, clean_up_tokenization_spaces=False)
print(texte_sortie)
Inférence avec vLLM
Installez la dépendance :
pip install git+https://github.com/fyabc/vllm.git@add_qwen2_vl_new
Lancer le service OpenAI :
python -m vllm.entrypoints.openai.api_server --served-model-name Qwen2-VL-7B-Instruct --model chemin_modele
Appel via HTTP :
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen2-VL-7B-Instruct",
"messages": [
{"role": "system", "content": "Vous êtes un assistant utile."},
{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": "https://example.com/image.png"}},
{"type": "text", "text": "Quel texte est illustré ?"}
]}
]
}'
Appel via SDK :
from openai import OpenAI
# Configurer la clé API et la base pour utiliser le serveur API vLLM
cle_api = "EMPTY"
base_url = "http://localhost:8000/v1"
client = OpenAI(
api_key=cle_api,
base_url=base_url,
)
reponse_chat = client.chat.completions.create(
model="Qwen2-VL-7B-Instruct",
messages=[
{"role": "system", "content": "Vous êtes un assistant utile."},
{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": "https://example.com/image.png"}},
{"type": "text", "text": "Quel texte est illustré ?"},
]},
]
)
print("Réponse du chat :", reponse_chat)
Affinement du Modèle avec Swift
Swift est un framework pour l'inférence et l'affinement de modèles multimodaux, disponible sur GitHub : Swift.
Préparez l'environnement :
git clone https://github.com/modelscope/swift.git
cd swift
pip install -e .[llm]
pip install pyav qwen_vl_utils
Affinement pour la description d'images
Utilisez le dataset coco-en-mini pour la description d'images : Dataset COCO.
# Lancer l'affinement avec LoRA
CUDA_VISIBLE_DEVICES=0,1,2,3 NPROC_PER_NODE=4 swift sft \
--model_type qwen2-vl-7b-instruct \
--model_id_or_path qwen/Qwen2-VL-7B-Instruct \
--sft_type lora \
--dataset coco-en-mini#20000 \
--deepspeed default-zero2
Pour un dataset personnalisé, spécifiez :
--dataset train.jsonl \
--val_dataset val.jsonl
Exemple de format de dataset :
{"query": "<image>55555", "response": "66666", "images": ["chemin_image"]}
{"query": "eeeee<image>eeeee<image>eeeee", "response": "fffff", "history": [], "images": ["chemin_image1", "chemin_image2"]}
{"query": "EEEEE", "response": "FFFFF", "history": [["requete1", "reponse1"], ["requete2", "reponse2"]], "images": []}
Script d'inférence après afifnement :
CUDA_VISIBLE_DEVICES=0 swift infer \
--ckpt_dir sortie/qwen2-vl-7b-instruct/vx-xxx/checkpoint-xxx \
--load_dataset_config true --merge_lora true
Affinement pour le grounding d'images
Utilisez le dataset refcoco-unofficial-grounding : Dataset RefCOCO.
# Affinement avec DeepSpeed Zero3
CUDA_VISIBLE_DEVICES=0,1,2,3 NPROC_PER_NODE=4 swift sft \
--model_type qwen2-vl-7b-instruct \
--model_id_or_path qwen/Qwen2-VL-7B-Instruct \
--sft_type lora \
--dataset refcoco-unofficial-grounding#20000 \
--deepspeed default-zero3
Formats de dataset personnalisés :
# Format Swift générique
{"query": "Trouver <bbox>", "response": "<ref-object>", "images": ["/chemin/image.jpg"], "objects": "[{\"caption\": \"personne en rouge\", \"bbox\": [138, 136, 235, 359], \"bbox_type\": \"real\", \"image\": 0}]"}
# Format spécifique Qwen2-VL
{"query": "Trouver the man", "response": "(123,235),(324,546)", "images": ["/chemin/image.jpg"]}
Affinement pour les vidéos
Utilisez le dataset video-chatgpt : Dataset VideoChatGPT.
NFRAMES=24 MAX_PIXELS=100352 CUDA_VISIBLE_DEVICES=0,1,2,3 NPROC_PER_NODE=4 swift sft \
--model_type qwen2-vl-7b-instruct \
--model_id_or_path qwen/Qwen2-VL-7B-Instruct \
--sft_type lora \
--dataset video-chatgpt \
--deepspeed default-zero2
Exemple de format de dataset vidéo :
{"query": "<video>55555", "response": "66666", "videos": ["chemin_video"]}
{"query": "eeeee<video>eeeee<video>eeeee", "response": "fffff", "history": [], "videos": ["chemin_video1", "chemin_video2"]}
{"query": "EEEEE", "response": "FFFFF", "history": [["requete1", "reponse1"], ["requete2", "reponse2"]], "videos": []}
Script d'inférence après affinement vidéo :
NFRAMES=24 MAX_PIXELS=100352 CUDA_VISIBLE_DEVICES=0 swift infer \
--ckpt_dir sortie/qwen2-vl-7b-instruct/vx-xxx/checkpoint-xxx \
--load_dataset_config true --merge_lora true