Questions d'entretien pour Ingénieur en Apprentissage Automatique Multimodal
15 questions d'entretien sélectionnées en apprentissage automatique multimodal, regroupées par niveau de séniorité. Utilisez-les pour réviser les fondamentaux, les compromis pratiques et le raisonnement de production de niveau senior.
1Expliquez l'idée fondamentale de l'apprentissage contrastif pour aligner les représentations d'images et de texte, et pourquoi un espace d'intégration partagé est utile.
L’apprentissage contrastif projette les images et les textes dans un même espace vectoriel. L’objectif donne aux paires correspondantes une similarité élevée et aux autres une similarité plus faible. Les deux encodeurs apprennent ainsi à produire des représentations comparables, par exemple par similarité cosinus. On peut chercher des images à partir d’un texte ou inversement. On peut aussi classer une image sans entraînement propre à la tâche, en comparant son vecteur à ceux de descriptions comme « une photo d’un chien ».
import torch
import torch.nn.functional as F
# image_features: [B, D], text_features: [B, D]
image_norm = F.normalize(image_features, dim=-1)
text_norm = F.normalize(text_features, dim=-1)
# Pairwise cosine similarity matrix: [B, B]
sim_matrix = image_norm @ text_norm.T
# Positive pairs lie on the diagonal; off-diagonals are negatives
2Expliquez l'architecture à double encodeur de type CLIP et les hypothèses qu'elle fait concernant l'interaction image-texte.
Un double encodeur de type CLIP transforme indépendamment l’image et le texte en vecteurs d’un même espace. La comparaison se fait ensuite par produit scalaire ou similarité cosinus. Le calcul suppose qu’un résumé vectoriel par modalité suffit à mesurer leur compatibilité. Il n’y a pas d’attention croisée entre régions et unités de texte pendant l’encodage. On peut donc précalculer les vecteurs d’images et les indexer à grande échelle, au prix d’une interaction moins fine pour les relations spatiales ou l’ancrage précis.
3Quelle est l’intuition d’une projection des caractéristiques image et texte dans un espace commun normalisé avec optimisation de similarité cosinus ?
La normalisation L2 sur une hypersphère unité sépare direction sémantique et norme. Sans elle, le produit scalaire peut réduire la perte simplement en gonflant la norme des exemples faciles ou fréquents plutôt qu’en alignant leur sens. Les vecteurs unitaires bornent le score à [−1,1] et le lient uniquement à l’angle. Cela retire l’échelle des normes, sans empêcher seul l’effondrement des représentations ni égaliser les gradients par exemple. Les paires négatives et l’objectif apportent une pression supplémentaire contre cet effondrement. Une température apprise règle la concentration de la distribution pour équilibrer alignement des vraies paires et dispersion des négatives.
import torch
import torch.nn.functional as F
# Unnormalized embeddings with extreme norm differences
v = torch.tensor([[10.0, 0.0], [0.1, 0.0]])
t = torch.tensor([[5.0, 0.0], [0.1, 0.0]])
# Raw dot products: heavily distorted by magnitude (50.0 vs 0.01)
raw_dot = v @ t.T
# L2 Normalized:
v_norm = F.normalize(v, p=2, dim=-1)
t_norm = F.normalize(t, p=2, dim=-1)
cosine_sim = v_norm @ t_norm.T
print('Cosine similarity matrix:\n', cosine_sim)
4Expliquez l'ancrage visuel (visual grounding) et la compréhension d'expression référentielle (referring expression comprehension) en tant que localisation conditionnée par le langage, et comment ils diffèrent de la similarité au niveau de l'image.
L’ancrage visuel relie une expression à une région, un cadre ou un masque de l’image. Par exemple, pour « la personne en veste bleue à côté de la lampe », le modèle doit utiliser la couleur et la relation spatiale pour distinguer des personnes semblables. La compréhension d’expressions référentielles est une tâche de ce type. Un score de similarité entre le texte et l’image entière mesure leur compatibilité globale, sans fournir de coordonnées ni distinguer nécessairement deux objets dans la même scène.
# Image-level similarity:
# Input: Image I, Text T ("black dog sitting on the left")
# Output: scalar score s in [0, 1] or dot product
similarity_score = image_text_model(image, text)
# Referring Expression Comprehension (Visual Grounding):
# Input: Image I, Text T ("black dog sitting on the left")
# Output: Bounding box coordinates [x_min, y_min, x_max, y_max]
bbox = grounding_model.predict_box(image, text)
5Expliquez l'attention croisée (cross-attention) comme mécanisme de fusion entre les jetons visuels et les jetons textuels dans les transformeurs multimodaux.
Dans l’attention croisée, les requêtes viennent d’une modalité et les clés et valeurs d’une autre. Pour une image qui interroge le texte, les projections donnent Qᵥ à partir de l’image, Kₜ et Vₜ à partir du texte. L’opération `softmax(Qv × Ktᵀ / √dk) × Vt` fournit à chaque élément visuel une combinaison pondérée des valeurs textuelles. Les séquences peuvent avoir des longueurs différentes. Inversez les rôles pour conditionner le texte sur l’image ou combinez les deux directions dans des blocs distincts.
6Expliquez comment les augmentations d'images telles que le recadrage, le jitter de couleur et la compression peuvent aider ou nuire à l'alignement contrastif image-texte.
Des transformations modérées peuvent réduire la dépendance au fond ou à la position et apprendre une certaine invariance d’échelle. Conservez toutefois ce que la légende décrit. Un recadrage qui supprime l’oiseau, une variation qui change la couleur du taxi ou une compression qui efface un panneau créent une paire visuel-texte trompeuse. Choisissez les transformations et leur intensité selon les attributs décrits et mesurez leur effet sur la recherche, notamment pour les couleurs, le texte et les petits objets.
7Expliquez la récupération image-texte en tant que tâche et la différence entre l'appariement en ensemble fermé (closed-set matching) et la récupération en monde ouvert (open-world retrieval) sur de vastes corpus.
La recherche image-texte retrouve des images à partir d’une requête textuelle, ou des textes à partir d’une image. Un ensemble fermé propose des candidats fixes et des correspondances annotées, ce qui permet souvent un calcul exhaustif. En monde ouvert, le corpus peut être vaste, évolutif et peu annoté, avec des éléments proches qui ne sont pas des correspondances et des réponses pertinentes non étiquetées. On utilise souvent un index de recherche approchée des plus proches voisins, puis éventuellement un reclassement plus précis sur les premiers résultats.
import torch
import torch.nn.functional as F
# Closed-set matching: full pairwise similarity matrix over fixed evaluation set
image_embeds = F.normalize(torch.randn(1000, 512), dim=-1)
text_embeds = F.normalize(torch.randn(1000, 512), dim=-1)
sim_matrix = torch.matmul(text_embeds, image_embeds.T) # (1000, 1000)
# Open-world retrieval: query vector queried against an indexed corpus using ANN
# index = faiss.IndexHNSWFlat(512, 32)
# distances, indices = index.search(query_embed, k=10)
8Comparez pertes contrastives softmax de type InfoNCE et pertes sigmoïdes par paires pour apprendre des plongements image-texte.
InfoNCE, comme CLIP, traite l’alignement en classification multiclasse : pour chaque exemple, un softmax normalise la similarité de la paire positive et des négatives du lot. SigLIP traite chaque entrée de la matrice image-texte comme une décision binaire indépendante, avec sigmoïde et entropie croisée, cibles 1 et 0, ou labels signés +1 et −1 dans une perte logistique équivalente. InfoNCE couple les négatives par le dénominateur global, les plus difficiles pesant fortement sur les gradients ; SigLIP découple les paires. CLIP distribué rassemble couramment les plongements pour utiliser des négatives interappareils et la normalisation couple leurs scores. SigLIP évite ce softmax global et permet des calculs par blocs, mais les paires entre appareils demandent encore des échanges de vecteurs. Efficacité et qualité dépendent des lots et du dispositif d’entraînement.
import torch
import torch.nn.functional as F
def siglip_loss(sim_matrix, temperature, bias):
# sim_matrix: [B, B] dot product of normalized embeddings
# targets: 1 on diagonal (positive), -1 on off-diagonals (negative)
B = sim_matrix.size(0)
targets = 2 * torch.eye(B, device=sim_matrix.device) - 1.0
logits = sim_matrix * temperature + bias
# Pairwise binary cross entropy with log-sigmoid
return -torch.mean(F.logsigmoid(targets * logits))
9Expliquez comment les négatifs difficiles et les faux négatifs affectent l'apprentissage contrastif image-texte.
Un négatif difficile est une paire incorrecte mais proche, par exemple un husky associé à une légende de malamute. Il pousse le modèle à apprendre des distinctions fines. Un faux négatif est une correspondance valable traitée comme incorrecte, par exemple une autre photo à laquelle la légende s’applique aussi. L’objectif éloigne alors des représentations qui devraient rester proches. Réduisez ce bruit avec la déduplication, plusieurs positifs par exemple, un traitement des étiquettes incertaines ou un objectif contrastif corrigé.
import torch
import torch.nn.functional as F
# Image 0 and Image 1 both depict 'a red sports car'
# Text 0: 'a red sports car', Text 1: 'a fast red car'
# In standard InfoNCE, Text 1 is treated as a negative for Image 0.
sim = torch.tensor([[0.95, 0.90], # Image 0 similarities
[0.88, 0.94]]) # Image 1 similarities
loss_img0 = -F.log_softmax(sim / 0.07, dim=-1)[0, 0]
print(f'InfoNCE loss for Image 0: {loss_img0.item():.4f}')
# High similarity to false negative Text 1 (0.90) heavily penalizes the model
10Comparez l'alignement global image-texte avec les objectifs d'alignement au niveau de la région ou du jeton.
L’alignement global représente chaque image et chaque texte par un vecteur. Il facilite l’indexation et la recherche, mais compresse les détails spatiaux et les liens entre objets et attributs. Un alignement fin compare des régions ou des blocs d’image à des mots ou sous-mots, par exemple par similarité maximale ou attention croisée. Cela aide à localiser des objets et à résoudre des relations, au prix de calcul et de mémoire supplémentaires et d’une supervision parfois plus bruitée.
import torch
import torch.nn.functional as F
# visual_tokens: [B, N_v, D], text_tokens: [B, N_t, D]
def token_level_maxsim_similarity(visual_tokens, text_tokens):
v_norm = F.normalize(visual_tokens, dim=-1)
t_norm = F.normalize(text_tokens, dim=-1)
# Compute similarity matrix between all visual and text tokens: [B, N_t, N_v]
sim_matrix = torch.bmm(t_norm, v_norm.transpose(1, 2))
# Text-to-image: For each word token, find maximum visual token similarity and average
t2i_sim = sim_matrix.max(dim=-1).values.mean(dim=-1) # [B]
return t2i_sim
11Comparez la fusion précoce, la fusion tardive, la fusion intermédiaire, la fusion par attention croisée, la fusion à portes et la concaténation pour les modèles multimodaux.
La fusion précoce combine les entrées dans un réseau commun dès le départ. Elle permet des interactions riches, mais augmente souvent le calcul. La fusion tardive combine des résultats indépendants et facilite l’indexation. La fusion intermédiaire conserve des couches propres à chaque modalité avant de les relier. L’attention croisée utilise les requêtes de l’une et les clés et valeurs de l’autre. Un mécanisme de porte apprend à pondérer les contributions selon le contexte. La concaténation assemble les caractéristiques ou les séquences si les autres dimensions sont compatibles. Dans un transformeur à attention dense, le coût croît avec le carré de la longueur totale de séquence.
12Comparez les modèles de récupération à double encodeur (dual-encoder retrieval models) avec les re-rankers à encodeur croisé (cross-encoder rerankers) pour la correspondance image-texte en termes de capacité d'interaction, de précision et de latence.
Le double encodeur calcule indépendamment les représentations de l’image et du texte, puis les compare. On peut précalculer les vecteurs des candidats et les interroger avec un index approché. Un encodeur croisé évalue ensemble les unités visuelles et textuelles. Cette interaction peut améliorer les réponses sur les relations spatiales ou les attributs, mais exige un calcul pour chaque paire. En pratique, récupérez d’abord un petit ensemble de candidats avec le double encodeur, puis reclassez-le avec l’encodeur croisé et mesurez le compromis qualité-latence.
13Concevez un système de génération multimodale augmentée par recherche documentaire (RAG) sur PDF ou manuels contenant texte, tableaux, graphiques, captures, diagrammes et images.
Analysez d’abord la mise en page par des modèles comme LayoutLM, DocTR ou une chaîne visuelle pour extraire blocs et positions : textes, tableaux structurés, graphiques et séries, diagrammes et captures. HTML ou un autre format doit préserver les cellules fusionnées que les tableaux Markdown simples ne représentent pas. Stockez les ressources visuelles comme recadrages avec plongements SigLIP, CLIP ou tokens visuels ColPali, plus synthèses et texte issu de reconnaissance optique de caractères (OCR), produits par un modèle vision-langage (VLM) dans l’index texte. Indexez tableaux structurés et passages découpés par sections en vecteurs et BM25. Recherchez en parallèle dans BM25, vecteurs texte et index visuel de recherche approximative des plus proches voisins (ANN), fusionnez par fusion des rangs réciproques (RRF) puis reclassez les meilleurs avec encodeur croisé multimodal ou interaction visuelle tardive sur images haute résolution et texte. Assemblez top-k d’images, schémas de tables et passages avec document et page pour un VLM à instructions, comme GPT-4o, Claude 3.5 Sonnet ou Qwen2-VL. Le prompt demande des citations, mais le code vérifie existence, autorisation et soutien des affirmations par les identifiants cités. Préservez la provenance, appliquez les permissions avant assemblage et traitez les instructions récupérées comme données non fiables.
from dataclasses import dataclass
from typing import Optional, List
@dataclass
class MultimodalChunk:
chunk_id: str
document_id: str
page_number: int
modality_type: str # 'text', 'table', 'chart', 'diagram'
text_payload: str # Raw text or structured Markdown/HTML
vlm_caption: Optional[str] = None # Synthetic summary of visual content
bbox: Optional[List[float]] = None # [x0, y0, x1, y1]
image_crop_path: Optional[str] = None
dense_embedding: Optional[List[float]] = None
# Indexing strategy: Text search covers text_payload + vlm_caption;
# Multimodal search matches dense_embedding or visual tokens.
14Expliquez comment l'évaluation RAG multimodal (Retrieval Augmented Generation) devrait mesurer séparément la qualité de la récupération, l'utilisation des preuves, la provenance et la fidélité de la réponse finale.
Mesurez quatre aspects. Pour la recherche, vérifiez le rappel des passages et régions nécessaires, avec Recall@K et un score de localisation si pertinent. Pour l’usage des preuves, retirez ou remplacez un élément décisif et observez si la réponse change de façon cohérente. Les poids d’attention seuls ne prouvent pas son utilisation. Pour la provenance, vérifiez que la page, la figure ou la région citée contient la preuve. Pour la réponse, évaluez séparément le soutien de chaque affirmation par les sources et son exactitude. Incluez des cas où les preuves manquent ou se contredisent et où le système doit signaler son incertitude.
# Evaluation record schema for a single Multimodal RAG query:
eval_record = {
'retrieval_quality': {
'hit_at_k': True, # Top-3 chunks contain target diagram
'visual_bbox_iou': 0.85 # Retrieved crop overlap with true figure region
},
'evidence_utilization': {
'necessity_ablation_passed': True # Removing chart causes answer to fail
},
'provenance': {
'page_match': True, # Cited Page 12 (Ground Truth Page 12)
'figure_id_match': True # Cited 'Figure 4'
},
'faithfulness': {
'claim_entailment_score': 1.0, # All claims entailed by context
'hallucination_detected': False
}
}
all_passed = all(all(metrics.values()) for metrics in eval_record.values())
print(f'System passes all decoupled checks: {all_passed}')
15Réfléchissez à la mise à jour des modèles de récupération multimodaux en production lorsque les embeddings et les index de la galerie doivent être rafraîchis à grande échelle.
Construisez un nouvel index à partir des vecteurs calculés par la nouvelle version pendant que l’ancien sert les requêtes. Rattrapez ajouts, modifications et suppressions par journal de changements ou double écriture. Comparez rappel, latence et qualité sur des requêtes représentatives, puis basculez ensemble l’encodeur de requêtes et son index compatible. Conservez l’ancien ensemble pour le retour arrière tant qu’il reste à jour. Un encodeur rétrocompatible peut permettre une transition progressive, à condition de démontrer la compatibilité sur les données réelles.
class MultimodalRetrievalRouter:
def __init__(self, v1_service, v2_service, dual_write=True):
self.v1 = v1_service # Model v1 + Index v1
self.v2 = v2_service # Model v2 + Index v2
self.active_version = "v1"
self.dual_write = dual_write
def search(self, query_multimodal):
# Route query strictly to the encoder matching the active index
if self.active_version == "v1":
return self.v1.search(query_multimodal)
return self.v2.search(query_multimodal)
def ingest_new_item(self, item):
# Dual-write during migration window so the new index is up-to-date at cutover
self.v1.index_item(item)
if self.dual_write and self.v2.is_ready_for_ingest:
self.v2.index_item(item)