Préparation à l'entretien en Vision par Ordinateur
Questions d'entretien d'ingénieur en Vision par Ordinateur
15 questions d'entretien sélectionnées sur la vision par ordinateur, regroupées par niveau d'ancienneté. Utilisez-les pour réviser les fondamentaux, les compromis pratiques et le raisonnement de production de niveau senior.
1Qu'est-ce qu'une convolution discrète 2D sur une image, et comment cela se rapporte-t-il aux noyaux, aux filtres et à la corrélation croisée ?
Une convolution discrète 2D sur une image est une opération de filtrage spatial linéaire où une matrice de poids (un noyau) glisse sur l'image d'entrée. À chaque emplacement spatial, elle calcule un produit élément par élément entre les poids du noyau et le patch d'image local superposé (champ récepteur), et additionne les résultats (ajoutant souvent un terme de biais) pour produire une seule valeur de pixel dans la carte de caractéristiques de sortie. En mathématiques classiques et en traitement du signal, la véritable convolution implique de retourner (rotation de 180 degrés) le noyau horizontalement et verticalement avant de calculer le produit scalaire glissant : $(I * K)(i, j) = \sum_m \sum_n I(i - m, j - n) K(m, n)$. En revanche, la corrélation croisée calcule le produit scalaire glissant directement sans retourner le noyau : $(I \star K)(i, j) = \sum_m \sum_n I(i + m, j + n) K(m, n)$. Dans les cadres d'apprentissage profond comme PyTorch et TensorFlow, l'opération implémentée sous le nom de "convolution" est en fait une corrélation croisée. Étant donné que les poids du noyau sont des paramètres apprenables optimisés directement via la rétropropagation, le réseau apprend simplement les poids orientés de manière appropriée, rendant le retournement mathématique du noyau redondant sur le plan calculatoire pendant l'entraînement et l'inférence.
2Quand utiliseriez-vous les représentations RGB, HSV, Lab, YCbCr ou en niveaux de gris dans un pipeline de vision ?
Différents espaces colorimétriques découplent des propriétés physiques, perceptuelles et statistiques spécifiques des données visuelles, ce qui les rend adaptés à des tâches de vision spécifiques :
1. **RGB / BGR** : Format standard pour les capteurs de caméra et le matériel d'affichage représentant les couleurs primaires additives (Rouge, Vert, Bleu). Les canaux de couleur sont fortement corrélés avec la luminance (les changements d'éclairage affectent les trois canaux simultanément). C'est l'entrée standard pour les réseaux de neurones profonds (CNN, Vision Transformers). Un problème majeur en production est l'échange de canaux RGB vs BGR (par exemple, OpenCV charge le BGR, tandis que PIL/PyTorch attendent le RGB), ce qui réduit silencieusement la précision du modèle.
2. **HSV / HSL** : Découple explicitement la chromaticité (Teinte (Hue) = couleur, Saturation (Saturation) = pureté de la couleur) de l'intensité (Valeur (Value)/Luminosité (Lightness)). Il est idéal pour le seuillage classique des couleurs, le suivi d'objets par couleur et la segmentation de couleurs sous des éclairages variés, car la Teinte est relativement insensible aux ombres et aux changements de luminosité.
3. **CIE Lab** : Un espace colorimétrique perceptuellement uniforme où la distance euclidienne entre deux points ($\Delta E$) reflète directement la différence de perception humaine. Il sépare la Luminosité ($L^*$) des axes de couleur opposés ($a^*$ vert-rouge, $b^*$ bleu-jaune). Il est utilisé pour l'inspection des différences de couleur, la correction des couleurs, l'évaluation de la qualité d'image et les tâches de colorisation.
4. **YCbCr** : Sépare la luminance ($Y$) des composantes de chrominance de la différence de bleu ($Cb$) et de la différence de rouge ($Cr$). C'est la base des normes de compression vidéo et d'image (JPEG, MPEG, H.264/H.265) car le système visuel humain est moins sensible aux détails de chrominance, ce qui permet un sous-échantillonnage de la chrominance (par exemple, 4:2:0) pour réduire la bande passante et la charge de calcul.
5. **Niveaux de gris** : Représentation d'intensité à canal unique ($Y \approx 0.299R + 0.587G + 0.114B$). Il est idéal pour les tâches basées sur la géométrie et la texture où la couleur est non pertinente (par exemple, le flux optique, le SLAM (Simultaneous Localization and Mapping), l'extraction de caractéristiques classiques comme SIFT/ORB, la détection de contours) afin d'économiser 66% de mémoire et de calcul. Cependant, il ne doit pas être utilisé lorsque la couleur est un indice discriminatoire clé (par exemple, la classification de l'état des feux de circulation).
import cv2
import numpy as np
# Sample image: saturated red under normal and shaded lighting
img_bgr = np.zeros((100, 100, 3), dtype=np.uint8)
img_bgr[:, :50] = [0, 0, 255] # Bright Red in BGR
img_bgr[:, 50:] = [0, 0, 120] # Shaded/Dark Red in BGR
# Convert to HSV (OpenCV H: 0-179, S: 0-255, V: 0-255)
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
# Red Hue wraps around 0/180; track red with single Hue range [0, 10] & high saturation
lower_red = np.array([0, 100, 50])
upper_red = np.array([10, 255, 255])
mask_hsv = cv2.inRange(img_hsv, lower_red, upper_red)
print("HSV segmented pixels:", np.count_nonzero(mask_hsv), "out of", mask_hsv.size)
3Pourquoi la normalisation d'image par canal, la normalisation par image et la mise à l'échelle cohérente des pixels sont-elles importantes dans les systèmes de vision ?
La normalisation d'image est vitale dans les pipelines de vision pour maintenir la stabilité numérique, accélérer la convergence de la descente de gradient et prévenir le décalage de distribution entre l'entraînement et le service (train-serving distribution shift) : 1. **Mise à l'échelle des pixels ([0, 1] ou [-1, 1])** : Les pixels d'image bruts sont stockés sous forme d'entiers non signés sur 8 bits (`uint8` $\in [0, 255]$). Alimenter des valeurs brutes de $[0, 255]$ dans les réseaux de neurones provoque des activations précoces extrêmement importantes et une explosion ou une saturation du gradient. La mise à l'échelle à $[0.0, 1.0]$ (en divisant par 255.0) ou $[-1.0, 1.0]$ centre les entrées autour de zéro, s'alignant avec les méthodes standard d'initialisation des poids (He, Xavier). 2. **Normalisation par canal au niveau du jeu de données (Standardisation Moyenne-Écart-type)** : Standardise les entrées via $x_{norm} = \frac{x - \mu_c}{\sigma_c}$ en utilisant des statistiques globales précalculées par canal (par exemple, la moyenne ImageNet `[0.485, 0.456, 0.406]` et l'écart-type `[0.229, 0.224, 0.225]`). Cela centre chaque canal autour d'une moyenne nulle avec une variance unitaire sur l'ensemble du jeu de données, assurant un flux de gradient équilibré entre les canaux. Une défaillance opérationnelle critique est le **biais entraînement-service (train-serving skew)** : si l'inférence omet la division par 255, utilise des constantes de moyenne/écart-type non concordantes, ou les applique dans le mauvais ordre des canaux (RGB vs BGR), les performances du modèle chutent sévèrement. 3. **Normalisation par image (Normalisation d'instance / Min-Max / Z-score)** : Calcule la moyenne et l'écart-type par image individuelle : $x_{norm} = \frac{x - \mu_{img}}{\sigma_{img}}$. Cela élimine les variations globales de contraste et d'éclairage dues aux différentes conditions de capture. Bien qu'efficace dans le transfert de style, l'imagerie médicale IRM/CT ou l'imagerie satellitaire, cela peut être préjudiciable lorsque l'intensité absolue des pixels a une signification physique (par exemple, la classification jour/nuit, la réflectance des matériaux ou la détection de défauts sous éclairage calibré).
import torch
import torchvision.transforms as T
from PIL import Image
import numpy as np
# Create a mock uint8 RGB image
raw_img = Image.fromarray(np.random.randint(0, 256, (224, 224, 3), dtype=np.uint8))
# Standard transform pipeline:
# 1. ToTensor scales uint8 [0, 255] -> float32 [0.0, 1.0] and permutes HWC -> CHW
# 2. Normalize standardizes per-channel using dataset mean and std
preprocess = T.Compose([
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
tensor_img = preprocess(raw_img)
print("Tensor shape:", tensor_img.shape)
print("Tensor dtype:", tensor_img.dtype)
print("Channel 0 min/max:", round(tensor_img[0].min().item(), 2), round(tensor_img[0].max().item(), 2))
4Comment les augmentations géométriques et photométriques favorisent-elles l'invariance, et comment décidez-vous si une augmentation préserve les étiquettes (labels) ?
Les augmentations géométriques (telles que la rotation, la translation, la mise à l'échelle et le retournement) modifient le mappage des coordonnées spatiales des pixels, tandis que les augmentations photométriques (telles que la luminosité, le contraste, le décalage de teinte et le flou) modifient l'intensité des pixels et les canaux de couleur sans modifier les coordonnées spatiales. En classification, ces deux catégories exposent le modèle à des variations réalistes, l'encourageant à apprendre des représentations invariantes où les prédictions restent stables malgré les changements de pose, de point de vue ou de conditions d'éclairage. Dans les tâches de prédiction spatiale (détection et segmentation), les transformations géométriques nécessitent des transformations correspondantes aux boîtes ou masques de vérité terrain pour préserver l'équivariance. Décider si une augmentation préserve les étiquettes exige d'évaluer la sémantique du domaine et les a priori physiques. Une transformation préserve l'étiquette si l'image résultante reste une instance plausible de la classe cible d'origine sans altérer son identité sémantique. Par exemple, le retournement horizontal préserve l'identité pour les objets généraux (comme les voitures ou les animaux), mais altère l'identité ou invalide les caractères dans la reconnaissance optique de caractères (ROC) et la classification de chiffres. De même, une rotation complète à 360 degrés est valide en histologie ou en imagerie satellite où aucune orientation canonique n'existe, mais elle est non naturelle dans la conduite autonome où les objets à l'envers violent les contraintes physiques du monde réel.
5Que sont les interpolations par plus proche voisin, bilinéaire, bicubique et par aire, et comment le redimensionnement peut-il introduire l'aliasing ou le flou ?
Les méthodes d'interpolation estiment les intensités de pixels à des coordonnées continues lors du rééchantillonnage sur une nouvelle grille discrète :
- **Plus proche voisin (Nearest-Neighbor)** : Assigné l'intensité du pixel discret le plus proche. Elle est computationnellement en $O(1)$ et préserve les valeurs originales exactes, mais crée des artefacts de bloc lors de l'agrandissement (upsampling) et des bords très dentelés lors de la réduction d'échelle (downsampling).
- **Interpolation Bilinéaire (Bilinear Interpolation)** : Calcule une moyenne pondérée par la distance des $2 \times 2$ (4 plus proches) pixels voisins en utilisant l'interpolation linéaire le long des deux axes, produisant des transitions douces avec un flou modéré.
- **Interpolation Bicubique (Bicubic Interpolation)** : Échantillonne un voisinage de $4 \times 4$ (16 plus proches) pixels en utilisant des noyaux polynomiaux cubiques. Elle capture les gradients d'intensité locaux, produisant des bords plus nets et des courbes plus lisses que la bilinéaire, mais peut introduire des artefacts de dépassement/d'ondulation (overshoot/ringing) autour des transitions abruptes.
- **Interpolation par Aire (Area (Box) Interpolation)** : Calcule le chevauchement fractionnaire de la surface des pixels cibles projetés sur les pixels sources et moyenne les intensités sources sous-jacentes. Elle est particulièrement efficace pour le sous-échantillonnage sans moiré.
**Mécanismes d'Aliasing vs. Flou :**
- L'**aliasing** se produit lors de la réduction d'échelle (downsampling) lorsque le contenu haute fréquence dépasse la fréquence de Nyquist ($f_s / 2$) du nouveau taux d'échantillonnage sans un filtrage passe-bas suffisant. Les hautes fréquences se replient dans des bandes de fréquences plus basses, produisant de faux motifs, du moiré et des bords dentelés.
- Le **flou (blur)** se produit lorsque les noyaux d'interpolation agissent comme des filtres de lissage passe-bas qui atténuent les hautes fréquences légitimes (par exemple, le lissage bilinéaire) ou lorsque les détails haute fréquence sont moyennés lors de la réduction d'échelle.
6Quels modes de défaillance visuels réels un système de vision devrait-il évaluer, et comment déplacent-ils la distribution d'entrée ?
Les modes de défaillance visuels réels se répartissent en plusieurs grandes catégories : conditions environnementales (faible luminosité, éblouissement direct, pluie, neige, brouillard), effets de capteur et optiques (flou de mouvement, flou de défocalisation, bruit de capteur ISO élevé, distorsion par obturateur roulant), dégradation due à la compression et à la transmission (blocage JPEG, limitation du débit vidéo, sous-échantillonnage), et décalages sémantiques/spatiaux (occlusion partielle, troncature, poses d'objets hors distribution). Ces modes de défaillance déplacent la distribution d'entrée des domaines d'entraînement nominaux à plusieurs niveaux. Au niveau pixel, ils altèrent les histogrammes de luminance et de chrominance, détruisent le contraste local, réduisent le rapport signal/bruit (SNR) et introduisent des artefacts artificiels haute fréquence ou des noyaux de flou. Au niveau structurel et sémantique, ils atténuent les gradients de bord, obscurcissent les caractéristiques visuelles clés, déforment les silhouettes et masquent les régions diagnostiques critiques. Lorsque des modèles entraînés sur des données propres rencontrent ces entrées décalées, les extracteurs de caractéristiques convolutifs ou d'attention de bas niveau ne s'activent pas correctement, ce qui produit des détections manquées, des faux positifs hallucinés sur des motifs de bruit et des erreurs sur-confiantes.
7Comment les descripteurs classiques tels que HOG (Histogram of Oriented Gradients) représentent-ils la structure d'une image, et quelles sont leurs limites par rapport aux caractéristiques apprises par les réseaux de neurones convolutifs (CNN) ?
L'Histogramme de Gradients Orientés (HOG) est un descripteur de caractéristiques classique conçu manuellement pour capturer la forme et l'apparence locales d'objets à travers la distribution des orientations de gradients d'intensité. Le pipeline de calcul HOG implique :
(1) le calcul des gradients d'image horizontaux et verticaux (par exemple, avec des filtres de dérivation 1D `[-1, 0, 1]`) pour obtenir la magnitude et l'orientation du gradient ;
(2) la division de l'image en petites régions spatiales appelées 'cellules' (telles que 8x8 pixels) et l'accumulation d'histogrammes 1D d'orientations de gradients pondérés par la magnitude du gradient ;
(3) le regroupement de cellules adjacentes en des 'blocs' plus grands et superposés (tels que 2x2 cellules) et la normalisation des vecteurs de caractéristiques de bloc (en utilisant la norme L2 ou L1-sqrt) pour obtenir une robustesse face aux variations locales d'illumination, de contraste et d'ombres ; et
(4) la concaténation des vecteurs de blocs normalisés en une représentation de caractéristiques 1D finale, historiquement associée aux machines à vecteurs de support linéaires (SVM) pour la détection de piétons et d'objets.
Comparé aux caractéristiques apprises par les réseaux de neurones convolutifs (CNN), HOG présente des limitations majeures : Premièrement, les caractéristiques HOG sont fixes et conçues manuellement, ne capturant que des statistiques d'orientation d'arêtes locales de bas niveau sans la capacité d'apprendre des représentations hiérarchiques spécifiques à la tâche (telles que les textures, les parties d'objets et les concepts sémantiques). Deuxièmement, HOG offre une invariance géométrique très limitée : bien que la normalisation des blocs gère les changements d'illumination monotones et les petits décalages spatiaux à l'intérieur des cellules, HOG est fragile face aux rotations 3D hors plan, aux variations d'échelle significatives, aux articulations de pose non rigides et à un fort désordre d'arrière-plan. En revanche, les CNN apprennent des abstractions non linéaires multicouches optimisées de bout en bout pour l'objectif cible.
8Comment le pas, le remplissage, la dilatation et la taille du noyau déterminent-ils la taille de la sortie de convolution et le champ récepteur ?
Les dimensions spatiales de sortie d'une couche de convolution et son champ récepteur cumulatif sont déterminés par la taille du noyau $k$, le pas $s$, le remplissage $p$ et la dilatation $d$ :
1. **Taille spatiale de sortie** : La dilatation introduit $(d - 1)$ espaces entre les éléments du noyau, donnant une taille effective du noyau de $k' = d(k - 1) + 1$. La dimension de sortie le long d'un axe est donnée par :
$$O = \left\lfloor \frac{I + 2p - k'}{s} \right\rfloor + 1 = \left\lfloor \frac{I + 2p - d(k - 1) - 1}{s} \right\rfloor + 1$$
Ici, le pas sous-échantillonne la résolution en faisant avancer le noyau de $s$ pixels par étape, le remplissage ajoute des pixels de bordure virtuels pour préserver ou ajuster les dimensions spatiales, et la dilatation étend l'empreinte du filtre sans ajouter de paramètres supplémentaires.
2. **Champ Récepteur (RF)** : Le champ récepteur théorique décrit l'étendue spatiale dans l'image d'entrée qui influence une activation particulière. À travers les couches empilées, le champ récepteur $RF_l$ et le pas cumulatif (saut $j_l$) se mettent à jour de manière récursive :
* Saut : $j_l = j_{l-1} \cdot s_l$, avec $j_0 = 1$
* Champ Récepteur : $RF_l = RF_{l-1} + (k'_l - 1) \cdot j_{l-1}$, avec $RF_0 = 1$
Les pas et le pooling étendent le champ récepteur de manière multiplicative à travers la profondeur car les étapes du noyau de la couche suivante correspondent à des sauts de pixels plus grands dans l'espace de coordonnées d'entrée original. La dilatation étend le champ récepteur de manière additive au sein d'une seule couche en augmentant $k'_l$ sans sous-échantillonnage spatial.
9Comment un noyau de convolution correspond-il à un filtre d'image linéaire classique, et quand un filtre 2D peut-il être rendu séparable ?
Dans le traitement classique des signaux et images linéaires, un noyau de convolution représente la réponse impulsionnelle spatiale (fonction d'étalement du point) d'un système linéaire invariant par translation (LSI). Appliquer le noyau est une opération de filtrage linéaire dans le domaine spatial qui façonne la réponse en fréquence de l'image (sa transformée de Fourier 2D). Les noyaux passe-bas (par exemple, gaussien, flou de boîte) atténuent les hautes fréquences spatiales pour supprimer le bruit et lisser les textures, tandis que les noyaux passe-haut ou passe-bande (par exemple, Sobel, Laplacien, Prewitt) amplifient les hautes fréquences pour détecter les contours et les gradients. Un noyau de filtre 2D $K \in \mathbb{R}^{M \times N}$ est spatialement séparable s'il peut être décomposé en le produit extérieur de deux filtres 1D : $K = u \cdot v^T$, où $u \in \mathbb{R}^{M \times 1}$ et $v \in \mathbb{R}^{N \times 1}$. En termes d'algèbre linéaire, une matrice 2D est séparable si et seulement si son rang matriciel est 1. Cela peut être vérifié via la Décomposition en valeurs singulières (SVD), où exactement une valeur singulière est non nulle ($ \sigma_1 > 0, \sigma_2 = \dots = 0$). La séparabilité réduit considérablement la complexité computationnelle. Appliquer un noyau non séparable de taille $K \times K$ à une image de taille $H \times W$ nécessite $O(H \cdot W \cdot K^2)$ multiplications et additions. Lorsqu'il est décomposé en deux passes 1D consécutives (horizontale puis verticale), la complexité tombe à $O(H \cdot W \cdot 2K)$. Pour un noyau de $15 \times 15$, cela offre une accélération d'environ $7,5\times$.
10Comment le redimensionnement, le recadrage central, le recadrage redimensionné aléatoire, l'étirement et le letterboxing modifient-ils la distribution d'entrée ?
Les différentes stratégies de redimensionnement et de recadrage modifient la distribution des données d'entrée en termes de géométrie, d'échelle, de couverture de contenu et de limites spatiales :
1. **Redimensionnement direct (étirement/écrasement) :** Redimensionne l'image de manière non-isotrope à une dimension cible $(H, W)$, déformant les proportions originales. Cela force le modèle à traiter des formes d'objets déformées (par exemple, les objets circulaires deviennent des ellipses allongées).
2. **Recadrage central :** Extrait un recadrage central de taille ou de rapport fixe. Il préserve le rapport d'aspect natif et l'échelle locale, mais introduit un fort biais central (en supposant que les cibles sont centrées) et écarte le contexte périphérique ou coupe les objets positionnés en bordure.
3. **Recadrage redimensionné aléatoire (RRC - Random-Resized Cropping) :** Extrait des sous-régions aléatoires sur différentes échelles de surface et rapports d'aspect, puis les redimensionne à une dimension fixe. Cela élargit la distribution d'échelle d'entraînement et encourage l'apprentissage de caractéristiques basées sur des parties, mais des recadrages extrêmes peuvent exclure entièrement l'objet cible.
4. **Letterboxing (redimensionnement isotrope avec rembourrage) :** Redimensionne l'image uniformément jusqu'à ce que sa plus longue dimension corresponde à la taille cible, puis remplit les bordures restantes avec une valeur constante. Cela maintient les proportions et les rapports d'aspect réels des objets, mais introduit des bordures artificielles à contraste élevé et des pixels rembourrés non informatifs.
11Quels modes de bruit d'annotation apparaissent dans les jeux de données visuelles, et comment les détecter ou les atténuer ?
Les jeux de données de vision par ordinateur présentent couramment quatre modes principaux de bruit d'annotation :
1. **Bruit d'étiquette catégorique** : Une image ou un objet se voit attribuer la mauvaise étiquette de classe (par exemple, classer à tort un chat comme un chien, ou confondre des classes subtiles à grain fin).
2. **Annotations manquantes (bruit d'omission)** : Des objets de premier plan valides sont laissés non annotés. En détection d'objets, les cibles omises sont traitées comme des négatifs d'arrière-plan, pénalisant directement les détections correctes du modèle pendant l'entraînement.
3. **Tremblement de boîte englobante / de point clé (bruit de localisation)** : Coordonnées de boîtes englobantes et emplacements de points de repère imprécis, lâches ou décalés, causés par l'incohérence de l'annotateur humain.
4. **Ambigüité de la frontière de masque** : Contours de segmentation inconsistants ou grossiers le long de frontières complexes ou floues (par exemple, cheveux, surfaces semi-transparentes, flou de mouvement).
**Stratégies de Détection et d'Atténuation :**
* **Suivi des valeurs aberrantes de perte et apprentissage confiant (Confident Learning)** : Le suivi de la perte des échantillons au fil des époques d'entraînement identifie les valeurs aberrantes à perte élevée et persistantes, qui indiquent souvent des instances mal étiquetées ou omises. Des algorithmes comme Confident Learning estiment les distributions de bruit pour élaguer ou corriger les erreurs.
* **Discrepances de prédiction hors-plis (Out-of-Fold - OOF)** : Entraîner des modèles de validation croisée et comparer les prédictions des données de validation avec la vérité terrain met en évidence les images mal étiquetées et les boîtes englobantes manquantes.
* **Accord inter-annotateurs (Inter-Annotator Agreement - IAA) et adjudication** : Mesurer des métriques comme le Kappa de Cohen (classification) ou l'Intersection-sur-Union moyenne (localisation) entre plusieurs annotateurs signale les échantillons à faible accord pour une révision consensuelle.
* **Formulations de perte robustes** : Utiliser le lissage d'étiquettes (label smoothing), des pertes de classification tolérantes au bruit, ou des pertes de régression robustes basées sur l'IoU (Intersection-over-Union) réduit la sensibilité au tremblement et au mauvais étiquetage.
import torch
import torch.nn.functional as F
def find_label_noise_candidates(model, dataloader, device, top_k=50):
model.eval()
sample_losses = []
with torch.no_grad():
for batch_idx, (images, targets, sample_ids) in enumerate(dataloader):
images, targets = images.to(device), targets.to(device)
logits = model(images)
loss_per_sample = F.cross_entropy(logits, targets, reduction='none')
for sid, l, target, pred in zip(sample_ids, loss_per_sample.cpu(), targets.cpu(), logits.argmax(dim=-1).cpu()):
sample_losses.append({'id': sid, 'loss': l.item(), 'target': target.item(), 'pred': pred.item()})
sample_losses.sort(key=lambda x: x['loss'], reverse=True)
return sample_losses[:top_k]
12Comment le déséquilibre des classes affecte-t-il l'entraînement de la classification d'images, de la détection et de la prédiction dense ?
Le déséquilibre des classes affecte la dynamique d'optimisation et les paysages de perte dans toutes les tâches de vision :
1. **Classification d'images :** Lorsque les classes majoritaires sont plus nombreuses que les classes minoritaires, la minimisation du risque empirique fait en sorte que les mises à jour des paramètres sont dominées par les gradients des classes majoritaires. Le modèle apprend la distribution a priori empirique des classes $P(Y)$ et biaise sa frontière de décision contre les classes rares. Cela conduit à une précision top-1 globale élevée tout en souffrant d'un effondrement sévère du rappel (recall) pour les classes minoritaires.
2. **Détection d'objets :**
* **Déséquilibre premier plan-arrière-plan :** Dans les détecteurs denses à une seule étape et basés sur des ancres, des centaines de milliers d'emplacements candidats sont évalués par image, dont plus de 99 % sont de l'arrière-plan. Même si les ancres d'arrière-plan individuelles et faciles génèrent de petites pertes, leur vaste gradient agrégé submerge les signaux de gradient informatifs provenant des objets de premier plan épars.
* **Déséquilibre des classes de premier plan :** Les catégories d'objets courantes apparaissent des ordres de grandeur plus fréquemment que les catégories rares, ce qui réduit la taille effective de l'échantillon et le signal d'apprentissage pour les classes rares.
3. **Prédiction dense (Segmentation) :** Le déséquilibre au niveau des pixels est grave car les grandes classes d'arrière-plan et de « matériel » (par exemple, route, ciel) occupent des millions de pixels, tandis que les petites classes d'« objets » (par exemple, panneaux de signalisation, piétons) peuvent occuper moins de 0,1 % des pixels de l'image. La perte d'entropie croisée standard par pixel est dominée par les classes de grande surface, ce qui entraîne une sous-segmentation ou une disparition complète des petites structures fines.
13Comment débogueriez-vous les valeurs NaNs ou une perte instable lors d'un entraînement distribué à grande échelle en vision par ordinateur ?
Le débogage des valeurs NaNs (Not a Number) ou de l'instabilité de la perte dans un entraînement de vision distribué à grande échelle en `Distributed Data Parallel` (DDP) nécessite d'isoler si la cause première provient de mauvaises données d'entrée, de débordements/sous-débordements numériques en précision mixte (AMP - Automatic Mixed Precision), ou d'instabilités d'optimisation entre les workers.
Premièrement, établissez le déterminisme et des points d'ancrage de sécurité : activez la détection d'anomalies (`torch.autograd.set_detect_anomaly(True)`), enregistrez des hooks de gradient/activation pour capturer la couche exacte où les NaNs apparaissent, et ajoutez une validation stricte des données dans le DataLoader (affirmant des valeurs finies, vérifiant les images corrompues de 0 octet, les boîtes englobantes vides ou les diviseurs de normalisation à variance nulle). La journalisation au niveau du mini-batch devrait suivre la perte par rang, les URI (Uniform Resource Identifiers) d'entrée, la norme du gradient avant écrêtage et les facteurs d'échelle du `GradScaler`.
Deuxièmement, inspectez la Précision Mixte Automatique (AMP) et la mise à l'échelle dynamique de la perte : en FP16, les grands gradients débordent facilement (`> 65504`), ce qui fait que le scaler de perte (loss scaler) saute des étapes et réduit de moitié son facteur d'échelle à plusieurs reprises jusqu'à ce que l'échelle atteigne zéro ; le passage d'opérations instables (par exemple, softmax, LayerNorm, exposants de perte focale, ou dénominateurs IoU (Intersection over Union) de boîtes englobantes) à FP32 ou l'adoption de BF16 (qui correspond à la plage dynamique de FP32) stabilise généralement l'entraînement.
Enfin, vérifiez les pièges spécifiques au DDP comme les opérations `all-reduce` propageant les NaNs d'un seul worker à tous les rangs, la mise à l'échelle du 'warmup' du taux d'apprentissage (par exemple, la règle de mise à l'échelle linéaire avec de grandes tailles de batch globales) et l'écrêtage des gradients.
import torch
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4)
for step, (images, targets, uris) in enumerate(dataloader):
# 1. Input sanitization
if not torch.isfinite(images).all():
print(f"Corrupt input detected from URIs: {uris}")
continue
optimizer.zero_grad(set_to_none=True)
with autocast(dtype=torch.float16):
outputs = model(images)
loss = criterion(outputs, targets)
if not torch.isfinite(loss):
print(f"NaN/Inf loss at step {step} on rank {torch.distributed.get_rank()}; skipping step.")
continue
scaler.scale(loss).backward()
# Unscale before clipping to inspect true gradient norms
scaler.unscale_(optimizer)
grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
if torch.isnan(grad_norm) or torch.isinf(grad_norm):
print(f"Warning: Grad norm is {grad_norm}. Scaler will adjust.")
scaler.step(optimizer)
scaler.update()
14Comment concevriez-vous un composant de stabilisation vidéo numérique en ligne pour une caméra avec gigue d'image?
Concevoir un pipeline de stabilisation vidéo numérique en ligne pour la gigue de caméra en temps réel implique quatre étapes principales : estimation de mouvement, lissage de mouvement, compensation de mouvement (déformation) et gestion des bords.
1. **Estimation de mouvement inter-images** : Extraire des points d'intérêt (keypoints) 2D épars sur des images consécutives en utilisant des détecteurs de caractéristiques rapides (par exemple, ORB, FAST ou coins de Shi-Tomasi) et calculer les correspondances en utilisant le flux optique de Lucas-Kanade ou la mise en correspondance de descripteurs de caractéristiques. Estimer une transformation géométrique inter-images (telle qu'un modèle Affine ou d'Homographie) en utilisant RANSAC pour rejeter les correspondances aberrantes causées par des objets de premier plan se déplaçant indépendamment.
2. **Accumulation de la trajectoire de mouvement et lissage en ligne** : Intégrer les transformations image par image au fil du temps pour maintenir le chemin cumulé de la caméra $P_t = P_{t-1} \cdot H_t$. Appliquer un filtre de lissage en ligne — tel qu'un filtre de Kalman 1D/2D ou une moyenne mobile causale à courte fenêtre — pour séparer la gigue involontaire de haute fréquence du panoramique intentionnel de basse fréquence de la caméra.
3. **Compensation et déformation d'image** : Calculer la transformation de correction $C_t = S_t \cdot P_t^{-1}$ (où $S_t$ est le chemin lissé) et déformer l'image actuelle en utilisant l'interpolation bilinéaire/bicubique.
4. **Gestion des bords et contraintes de latence** : La déformation introduit des pixels de bord manquants / des bordures noires ; résoudre ce problème en appliquant un facteur de recadrage dynamique fixe (par exemple, un zoom avant de 5 à 10 %) avec extrapolation de bord ou une échelle adaptative. Dans un environnement en ligne, maintenir une mise en tampon minimale (1 à 3 images d'anticipation) pour limiter la latence de traitement.
15Comment optimiseriez-vous un pipeline de vision en temps réel lorsque le détecteur est plus lent que la fréquence d'images cible ?
Lorsqu'un détecteur d'objets ne peut pas maintenir la fréquence d'images cible (par exemple, fonctionnant à 15-20 FPS sur un flux vidéo à 60 FPS), une architecture de production robuste découple la détection de la boucle de présentation en temps réel en utilisant un pipeline asynchrone multithreadé combinant la détection lourde avec le suivi léger. Dans cette architecture hybride, un thread d'ingestion capture des images vidéo en continu. Le détecteur lourd s'exécute de manière asynchrone en tant que 'détecteur d'images clés' sur un thread de travail en arrière-plan. Pendant ce temps, un traceur léger (tel que le flux optique Lucas-Kanade, ByteTrack/BoT-SORT, ou un filtre de corrélation rapide/filtre de Kalman) s'exécute de manière synchrone sur chaque image à 60 FPS, maintenant l'état de l'objet, son identité et des trajectoires de boîtes englobantes fluides. Pour gérer le décalage et la contre-pression sans introduire de latence illimitée ou d'images périmées, des tampons circulaires bornés et des politiques de suppression de la dernière image sont utilisés. Lorsque le détecteur termine une image T_0 au temps T_curr, sa sortie est périmée. Le pipeline effectue un réalignement/rétroprojection des coordonnées : il associe les résultats de détection retardés à l'état historique du tracklet à T_0, met à jour les identités et les pistes manquées, et propage les corrections vers T_curr via les vecteurs de mouvement de suivi ou les étapes de prédiction du filtre de Kalman.
import queue
import threading
frame_queue = queue.Queue(maxsize=1) # Drop stale frames, keep latest
det_result_queue = queue.Queue()
def detector_worker():
while True:
frame, frame_id, timestamp = frame_queue.get()
boxes, scores, classes = heavy_detector.infer(frame)
det_result_queue.put({'frame_id': frame_id, 'boxes': boxes, 'timestamp': timestamp})
def realtime_pipeline(video_stream):
tracker = FastTracker() # e.g. Optical flow or Kalman tracker
for frame, frame_id, timestamp in video_stream:
if frame_queue.empty():
frame_queue.put((frame, frame_id, timestamp))
if not det_result_queue.empty():
det_result = det_result_queue.get()
tracker.reconcile_and_correct(det_result, current_frame_id=frame_id)
active_tracks = tracker.update(frame)
display_or_downstream(frame, active_tracks)