Wiki IA
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èleEntrepriseCapacités
GPT-4VOpenAIVision + texte, analyse d'images
GPT-4oOpenAIVision + audio + texte natif
Claude 3AnthropicVision avancée, documents, graphiques
GeminiGoogleNatif multimodal, vidéo
LLaVAOpen sourceVision-langage, fine-tunable
Qwen-VLAlibabaVision multilingue

Audio-Langage

ModèleCapacités
WhisperSpeech-to-text multilingue
GPT-4oConversation audio native
GeminiCompré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 texte

Approches 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 complexe

Utilisation 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.content

Traitement 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 visuelles

Bonnes 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 similaires

Ré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.

On this page