| name | multi-modal-architectures |
| description | Guide complet des architectures multimodales — CLIP, LLaVA, Flamingo, BLIP, Qwen-VL, image+texte, vidéo+langage, audio+texte. En français. |
Architectures Multimodales — Guide Complet
Fusionner vision, langage, audio : CLIP, LLaVA, Flamingo, BLIP-2, Qwen-VL, architectures 2024-2025.
1. Pourquoi Multimodal ?
Taxonomie
Multimodal
/ | \
/ | \
Vision- Audio- Vidéo-
Langage Langage Langage
| | |
CLIP Whisper VTimeLLM
LLaVA Qwen-Audio Sora
Flamingo Video-LLaVA
BLIP-2
Qwen-VL
2. CLIP (OpenAI, 2021)
Architecture
class CLIP(nn.Module):
"""Contrastive Language-Image Pre-training."""
def __init__(self, image_encoder='ViT-L/14', text_encoder='transformer'):
super().__init__()
self.visual = image_encoder
self.text = text_encoder
self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1/0.07))
def encode_image(self, image):
return F.normalize(self.visual(image))
def encode_text(self, text):
return F.normalize(self.text(text))
def forward(self, image, text):
I = self.encode_image(image)
T = self.encode_text(text)
logits = self.logit_scale.exp() * I @ T.T
labels = torch.arange(len(I), device=I.device)
loss_i = F.cross_entropy(logits, labels)
loss_t = F.cross_entropy(logits.T, labels)
return (loss_i + loss_t) / 2
Utilisation CLIP
def classify_zero_shot(model, image, class_names, templates):
"""CLIP zero-shot."""
text_features = []
for cls in class_names:
texts = [t.format(cls) for t in templates]
text_emb = torch.stack([model.encode_text(t) for t in texts])
text_features.append(text_emb.mean(dim=0))
text_features = torch.stack(text_features)
image_features = model.encode_image(image)
similarities = image_features @ text_features.T
return similarities.argmax(dim=-1)
3. BLIP-2 (Salesforce, 2023)
Architecture : Q-Former
class QFormer(nn.Module):
"""Query Transformer : pont vision-langage.
Composants :
1. Vision encoder (ViT-g, gelé) : extrait features image
2. Queries apprises (32 tokens) : interroge l'image
3. Cross-attention entre queries et features image
4. Self-attention entre queries et texte (optionnel)
"""
def __init__(self, num_queries=32, d_model=768, n_heads=12):
super().__init__()
self.query_tokens = nn.Parameter(torch.randn(1, num_queries, d_model))
self.self_attn = nn.MultiheadAttention(d_model, n_heads, batch_first=True)
self.cross_attn = nn.MultiheadAttention(d_model, n_heads, batch_first=True)
self.ffn = FeedForward(d_model)
self.norm = nn.LayerNorm(d_model)
def forward(self, image_features, text_embeds=None):
B = image_features.size(0)
queries = self.query_tokens.expand(B, -1, -1)
queries = self.self_attn(queries, queries, queries)[0]
queries = self.cross_attn(queries, image_features, image_features)[0]
text_embeds :
queries = torch.cat([queries, text_embeds], dim=)
queries = .self_attn(queries, queries, queries)[]
.ffn(.norm(queries))
4. Flamingo (DeepMind, 2022)
Architecture
class PerceiverResampler(nn.Module):
"""Compresse les features image en tokens fixes.
Une vidéo fait 32 images × 256 tokens = 8192 tokens
Le Perceiver les résume en 64 tokens (×100 compression)
"""
def __init__(self, d_image=768, d_model=1024, n_latents=64):
super().__init__()
self.latents = nn.Parameter(torch.randn(1, n_latents, d_model))
self.cross_attn = nn.MultiheadAttention(d_model, 8, batch_first=True,
kdim=d_image, vdim=d_image)
def forward(self, visual_features):
latents = self.latents.expand(visual_features.size(0), -1, -1)
visual = visual_features.flatten(1, 2)
return self.cross_attn(latents, visual, visual)[0]
class GatedCrossAttention(nn.Module):
"""Cross-attention avec gate (Flamingo).
La gate apprend à quel point la vision influence le texte :
- Au début : gate≈0 (pas d'influence, le LLM est seul)
- Progressivement : gate augmente
- Stabilité d'entraînement
"""
():
().__init__()
.attn = nn.MultiheadAttention(d_model, , batch_first=)
.gate = nn.Parameter(torch.zeros(d_model))
():
attn_out = .attn(text_hidden, vision_hidden, vision_hidden)[]
text_hidden + torch.tanh(.gate.unsqueeze()) * attn_out
5. LLaVA (Large Language and Vision Assistant, 2023-2024)
Architecture (LLaVA 1.5)
class LLaVA(nn.Module):
"""LLaVA : Vision-Language avec un simple MLP projecteur."""
def __init__(self, vision_encoder, llm, proj_hidden=4096):
super().__init__()
self.vision_encoder = vision_encoder
self.mlp_projector = nn.Sequential(
nn.Linear(vision_encoder.hidden_size, proj_hidden),
nn.GELU(),
nn.Linear(proj_hidden, llm.hidden_size),
)
self.llm = llm
def forward(self, images, input_ids, attention_mask):
image_features = self.vision_encoder(images)
image_tokens = self.mlp_projector(image_features)
inputs_embeds = self.interleave(image_tokens, input_ids)
outputs = self.llm(inputs_embeds=inputs_embeds)
return outputs.logits
LLaVA-NeXT (2024)
6. Multi-Modal LLMs Modernes (2024-2025)
Qwen2.5-VL
class DynamicResolutionViT(nn.Module):
"""ViT à résolution dynamique (Qwen-VL).
L'image n'est pas redimensionnée à une taille fixe.
Elle est découpée en patches de taille fixe,
mais le nombre de patches varie selon l'image.
"""
def __init__(self, patch_size=14):
super().__init__()
self.patch_size = patch_size
def forward(self, image):
patches = image.unfold(2, self.patch_size, self.patch_size) \
.unfold(3, self.patch_size, self.patch_size)
return patches.flatten(1, 2)
LLaMA 3.2 Vision
GPT-4o / Gemini 2 / Claude 3.5
7. Vision-Language Training Pipeline
class VisionLanguageTraining:
"""Pipeline d'entraînement VLM en 3 étapes."""
@staticmethod
def stage_1_vision_language_alignment(model, data):
"""Étape 1 : aligner les embeddings vision-langage.
Objectif : le projecteur apprend à mapper les features CLIP
vers l'espace d'embedding du LLM.
Données : paires (image, caption)
Loss : cross-entropy (next token prediction) sur le caption
LLM et vision encoder gelés, seulement projecteur entraîné
"""
pass
@staticmethod
def stage_2_instruction_tuning(model, data):
"""Étape 2 : fine-tuning sur instructions visuelles.
Objectif : comprendre des questions sur l'image
Données : (image, question, réponse)
Format : conversation multi-tour
LLM entraîné, projecteur entraîné, vision gelé
"""
pass
@staticmethod
def stage_3_rlhf(model, data):
"""Étape 3 : alignment avec préférences visuelles.
RLHF sur données visuelles
Reward model évalue la qualité des réponses visuelles
"""
pass
8. Vidéo-Langage
Video-LLaVA
class VideoLLaVA(nn.Module):
"""Extension vidéo de LLaVA."""
def __init__(self, n_frames=8):
super().__init__()
self.n_frames = n_frames
def encode_video(self, frames):
"""frames: (B, T, C, H, W)"""
frame_tokens = []
for t in range(self.n_frames):
tokens = self.vision_encoder(frames[:, t])
frame_tokens.append(tokens)
video_tokens = torch.cat(frame_tokens, dim=1)
return video_tokens
Sora (OpenAI, 2024)
9. Audio-Langage
Whisper (OpenAI, 2022-2023)
Qwen-Audio
10. Tableau Comparatif VLM
| Modèle | Vision Enc. | LLM | Liens | Taille | Année |
|---|
| CLIP | ViT-L | Transformer | Contrastif | 428M | 2021 |
| BLIP-2 | ViT-g | OPT/FlanT5 | Q-Former | 188M+12B | 2023 |
| Flamingo | NFNet | Chinchilla | Perceiver | 80B | 2022 |
| LLaVA 1.5 | ViT-L | Vicuna | MLP | 13B | 2023 |
| LLaVA-NeXT | ViT-L (AnyRes) | Vicuna | MLP | 13B | 2024 |
| Qwen2.5-VL | Dyn-ViT | Qwen2.5 | MLP | 72B | 2025 |
| LLaMA 3.2-V | ViT | LLaMA 3.2 | Cross-Attn | 11B | 2024 |
| GPT-4o | Custom | Custom | Native | ? | 2024 |
11. Applications
def vqa(model, image, question):
"""Répondre à une question sur une image."""
pass
def caption(model, image):
"""Générer une description de l'image."""
pass
def doc_qa(model, document_image, question):
"""Comprendre des documents, tableaux, graphiques."""
pass
def ocr_free(model, image):
"""Lire du texte dans une image sans OCR séparé."""
pass
Références