LLM et IA Générative
Multimodalité
Modèles IA combinant vision, langage, audio et plus
La multimodalité désigne la capacité d'un modèle à comprendre et générer plusieurs types de données : texte, images, audio, vidéo. Cette convergence représente une avancée majeure vers une IA plus proche de la perception humaine.
Qu'est-ce que la multimodalité ?
MODÈLE UNIMODAL vs MULTIMODAL :
Unimodal (GPT-3, BERT) :
┌─────────┐ ┌─────────┐
│ Texte │ ──→ │ LLM │ ──→ Texte
└─────────┘ └─────────┘
Multimodal (GPT-4V, Claude 3, Gemini) :
┌─────────┐
│ Texte │ ──┐
└─────────┘ │ ┌─────────────┐
┌─────────┐ ├─→ │ Modèle │ ──→ Texte + Images
│ Image │ ──┤ │ Multimodal │
└─────────┘ │ └─────────────┘
┌─────────┐ │
│ Audio │ ──┘
└─────────┘Les modèles multimodaux peuvent "voir" des images, "entendre" de l'audio et raisonner sur ces entrées combinées, ouvrant des cas d'usage impossibles avec les modèles texte seul.
Modèles multimodaux majeurs
Vision-Langage
| Modèle | Entreprise | Capacités |
|---|---|---|
| GPT-4V | OpenAI | Vision + texte, analyse d'images |
| GPT-4o | OpenAI | Vision + audio + texte natif |
| Claude 3 | Anthropic | Vision avancée, documents, graphiques |
| Gemini | Natif multimodal, vidéo | |
| LLaVA | Open source | Vision-langage, fine-tunable |
| Qwen-VL | Alibaba | Vision multilingue |
Audio-Langage
| Modèle | Capacités |
|---|---|
| Whisper | Speech-to-text multilingue |
| GPT-4o | Conversation audio native |
| Gemini | Compréhension audio |
Architecture des modèles multimodaux
Encodeurs spécialisés
ARCHITECTURE TYPIQUE :
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Encodeur │ │ Encodeur │ │ Encodeur │
│ Vision │ │ Audio │ │ Texte │
│ (ViT) │ │ (Whisper) │ │ (Tokenizer) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
↓ ↓ ↓
┌──────────────────────────────────────────────────────┐
│ Projection / Alignement │
│ (Aligner les espaces d'embedding) │
└──────────────────────────────────────────────────────┘
│
↓
┌──────────────────────────────────────────────────────┐
│ Transformer LLM │
│ (Raisonnement unifié) │
└──────────────────────────────────────────────────────┘
│
↓
Génération texteApproches d'intégration
1. EARLY FUSION (Gemini)
├── Toutes modalités tokenisées ensemble
├── Entraînement from scratch
└── Meilleure intégration, plus coûteux
2. LATE FUSION (LLaVA, GPT-4V)
├── Encodeurs pré-entraînés séparés
├── Projection vers espace LLM
└── Plus modulaire, moins coûteux
3. CROSS-ATTENTION
├── Attention entre modalités
├── Préserve les représentations
└── Flexible mais complexeUtilisation pratique
Vision avec Claude
import anthropic
import base64
import httpx
def encode_image(image_path: str) -> str:
"""Encode une image locale en base64."""
with open(image_path, "rb") as f:
return base64.standard_b64encode(f.read()).decode("utf-8")
def analyze_image(image_source: str, question: str) -> str:
"""Analyse une image avec Claude."""
client = anthropic.Anthropic()
# Déterminer si c'est une URL ou un fichier local
if image_source.startswith("http"):
# Image depuis URL
image_data = base64.standard_b64encode(
httpx.get(image_source).content
).decode("utf-8")
else:
# Image locale
image_data = encode_image(image_source)
# Déterminer le type MIME
if image_source.endswith(".png"):
media_type = "image/png"
elif image_source.endswith(".gif"):
media_type = "image/gif"
elif image_source.endswith(".webp"):
media_type = "image/webp"
else:
media_type = "image/jpeg"
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": media_type,
"data": image_data,
},
},
{
"type": "text",
"text": question
}
],
}
],
)
return message.content[0].text
# Exemples d'utilisation
result = analyze_image(
"photo.jpg",
"Décris cette image en détail. Que vois-tu ?"
)
# Analyse de document
result = analyze_image(
"facture.pdf", # Claude peut lire les PDFs
"Extrais le montant total et la date de cette facture."
)Vision avec OpenAI
from openai import OpenAI
import base64
def analyze_with_gpt4v(image_path: str, question: str) -> str:
client = OpenAI()
# Encoder l'image
with open(image_path, "rb") as f:
image_data = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": question
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{image_data}",
"detail": "high" # ou "low" pour réduire les coûts
}
}
]
}
],
max_tokens=1024
)
return response.choices[0].message.content
# Comparaison d'images
def compare_images(image1: str, image2: str) -> str:
client = OpenAI()
with open(image1, "rb") as f:
img1_data = base64.b64encode(f.read()).decode()
with open(image2, "rb") as f:
img2_data = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Compare ces deux images. Quelles sont les différences ?"},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{img1_data}"}},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{img2_data}"}}
]
}
]
)
return response.choices[0].message.contentTraitement de documents
import anthropic
import base64
from pathlib import Path
def analyze_document(pdf_path: str, questions: list[str]) -> dict:
"""Analyse un document PDF avec plusieurs questions."""
client = anthropic.Anthropic()
# Encoder le PDF
pdf_data = base64.standard_b64encode(
Path(pdf_path).read_bytes()
).decode("utf-8")
results = {}
for question in questions:
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": pdf_data,
},
},
{"type": "text", "text": question}
],
}
],
)
results[question] = message.content[0].text
return results
# Exemple : analyser un contrat
questions = [
"Quelles sont les parties contractantes ?",
"Quelle est la durée du contrat ?",
"Quelles sont les principales obligations ?",
"Y a-t-il des clauses de résiliation ?"
]
analysis = analyze_document("contrat.pdf", questions)Cas d'usage multimodaux
1. Analyse de documents visuels
def extract_chart_data(image_path: str) -> dict:
"""Extraire les données d'un graphique."""
client = anthropic.Anthropic()
with open(image_path, "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode()
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=2048,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": image_data,
},
},
{
"type": "text",
"text": """Analyse ce graphique et extrais les données au format JSON.
Inclus :
- Type de graphique
- Titre et légendes
- Données (valeurs, labels, séries)
- Tendances observées
Réponds uniquement en JSON."""
}
],
}
],
)
import json
return json.loads(message.content[0].text)2. Accessibilité (description d'images)
def generate_alt_text(image_path: str, context: str = "") -> str:
"""Générer un texte alternatif accessible pour une image."""
client = anthropic.Anthropic()
with open(image_path, "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode()
prompt = f"""Génère un texte alternatif (alt text) pour cette image,
destiné aux personnes utilisant des lecteurs d'écran.
Contexte : {context if context else "Page web générale"}
Règles :
- Sois concis mais descriptif (max 150 caractères)
- Décris le contenu et la fonction de l'image
- Ne commence pas par "Image de..."
- Inclus le texte visible si pertinent
Alt text :"""
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=100,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": image_data,
},
},
{"type": "text", "text": prompt}
],
}
],
)
return message.content[0].text.strip()3. Assistance visuelle en temps réel
def visual_assistant(image_path: str, user_query: str) -> str:
"""Assistant visuel pour répondre aux questions sur une image."""
client = anthropic.Anthropic()
with open(image_path, "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode()
system = """Tu es un assistant visuel aidant les utilisateurs à comprendre
ce qu'ils voient. Sois précis, utile et adapte ton niveau de détail à la question."""
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system=system,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": image_data,
},
},
{"type": "text", "text": user_query}
],
}
],
)
return message.content[0].text
# Exemples d'utilisation
# - "Quel est ce panneau de signalisation ?"
# - "Cette plante est-elle comestible ?"
# - "Comment brancher ces câbles ?"
# - "Quel est le prix affiché ?"4. Modération de contenu
def moderate_image(image_path: str) -> dict:
"""Modérer une image pour détecter du contenu inapproprié."""
client = anthropic.Anthropic()
with open(image_path, "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode()
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=500,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": image_data,
},
},
{
"type": "text",
"text": """Analyse cette image pour la modération de contenu.
Évalue chaque catégorie (safe/warning/unsafe) :
- Violence
- Contenu adulte
- Discours haineux
- Contenu illégal
- Spam/Publicité
Réponds en JSON avec une explication brève pour chaque catégorie."""
}
],
}
],
)
import json
return json.loads(message.content[0].text)Modèles open source multimodaux
LLaVA (Large Language and Vision Assistant)
from transformers import LlavaNextProcessor, LlavaNextForConditionalGeneration
from PIL import Image
import torch
# Charger le modèle
processor = LlavaNextProcessor.from_pretrained("llava-hf/llava-v1.6-mistral-7b-hf")
model = LlavaNextForConditionalGeneration.from_pretrained(
"llava-hf/llava-v1.6-mistral-7b-hf",
torch_dtype=torch.float16,
device_map="auto"
)
def analyze_with_llava(image_path: str, question: str) -> str:
image = Image.open(image_path)
prompt = f"[INST] <image>\n{question} [/INST]"
inputs = processor(prompt, image, return_tensors="pt").to(model.device)
output = model.generate(**inputs, max_new_tokens=512)
return processor.decode(output[0], skip_special_tokens=True)BLIP-2
from transformers import Blip2Processor, Blip2ForConditionalGeneration
from PIL import Image
import torch
processor = Blip2Processor.from_pretrained("Salesforce/blip2-opt-2.7b")
model = Blip2ForConditionalGeneration.from_pretrained(
"Salesforce/blip2-opt-2.7b",
torch_dtype=torch.float16,
device_map="auto"
)
def caption_image(image_path: str) -> str:
"""Générer une légende pour une image."""
image = Image.open(image_path)
inputs = processor(image, return_tensors="pt").to(model.device, torch.float16)
generated_ids = model.generate(**inputs, max_new_tokens=50)
return processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
def vqa(image_path: str, question: str) -> str:
"""Visual Question Answering."""
image = Image.open(image_path)
prompt = f"Question: {question} Answer:"
inputs = processor(image, prompt, return_tensors="pt").to(model.device, torch.float16)
generated_ids = model.generate(**inputs, max_new_tokens=50)
return processor.batch_decode(generated_ids, skip_special_tokens=True)[0]Limites et considérations
Limites actuelles
LIMITES DES MODÈLES MULTIMODAUX :
1. HALLUCINATIONS VISUELLES
├── Peuvent "voir" des objets inexistants
├── Erreurs sur les détails fins (texte, chiffres)
└── Mauvaise interprétation spatiale
2. COMPRÉHENSION LIMITÉE
├── Difficultés avec les graphiques complexes
├── Raisonnement spatial approximatif
└── Comptage d'objets imprécis
3. COÛTS ET LATENCE
├── Tokens images plus coûteux
├── Temps de traitement plus long
└── Besoin de GPU puissants (local)
4. DONNÉES SENSIBLES
├── Risque de mémorisation d'images
├── Extraction de données personnelles
└── Biais dans les représentations visuellesBonnes pratiques
# 1. Toujours valider les extractions critiques
extracted_amount = extract_from_invoice(image)
# Demander confirmation humaine pour les montants importants
# 2. Utiliser des prompts spécifiques
# MAUVAIS : "Que vois-tu ?"
# BON : "Liste les produits visibles avec leurs prix"
# 3. Gérer les cas d'échec
def safe_analyze(image_path: str, question: str) -> dict:
try:
result = analyze_image(image_path, question)
return {"success": True, "result": result}
except Exception as e:
return {"success": False, "error": str(e)}
# 4. Optimiser les coûts
# - Réduire la résolution si détail non nécessaire
# - Utiliser "detail: low" pour les aperçus
# - Batch les images similairesRésumé
MULTIMODALITÉ EN PRATIQUE :
MODÈLES PROPRIÉTAIRES
├── Claude 3 : Documents, graphiques, raisonnement
├── GPT-4o : Vision + audio natif, temps réel
└── Gemini : Vidéo, contexte long
MODÈLES OPEN SOURCE
├── LLaVA : Vision-langage fine-tunable
├── BLIP-2 : Captioning, VQA
└── Qwen-VL : Multilingue
CAS D'USAGE
├── Analyse de documents (PDF, factures, contrats)
├── Accessibilité (alt text, description)
├── Modération de contenu
├── Assistance visuelle
└── Extraction de données (graphiques, tableaux)
BONNES PRATIQUES
├── Prompts spécifiques et structurés
├── Validation humaine pour données critiques
├── Gestion des erreurs et hallucinations
└── Optimisation des coûts (résolution, batch)La multimodalité est en évolution rapide. Les modèles deviennent plus précis et moins coûteux, ouvrant de nouveaux cas d'usage comme l'analyse vidéo en temps réel et les interfaces conversationnelles visuelles.