Module 2 — Détection en deux étapes : la famille R-CNN
Le module 1 a posé la question « où regarder ? » à côté de « qu'est-ce que je vois ? ». Les détecteurs en deux étapes répondent d'abord à la première, puis, pour chaque candidat, à la seconde. C'est l'héritage direct de la famille R-CNN, dont Faster R-CNN reste aujourd'hui la référence en précision — souvent au prix de la vitesse.
Le principe : proposer, puis classer
Un détecteur en deux étapes se lit comme un pipeline :
- Générer quelques milliers de régions candidates susceptibles de contenir un objet, sans se soucier de la classe.
- Pour chaque candidate, extraire ses caractéristiques et prédire une classe et une correction de boîte.
Sur une image de carrefour, l'étape 1 propose des rectangles qui couvrent véhicules, piétons, panneaux, fenêtres et mille zones sans intérêt. L'étape 2 tranche : « voiture, score 0,92 » ou « rien ». Le prix à payer est la latence, car la seconde étape s'exécute sur chaque candidat.
R-CNN : la version originale, à l'ancienne
R-CNN (2014) tirait 2 000 candidats par Selective Search, un algorithme classique fondé sur les similarités de couleur et de texture. Chaque candidat était redimensionné à 224 × 224 puis passé, indépendamment, dans un réseau convolutif préentraîné. La classification finale utilisait des séparateurs à vaste marge (SVM), un par classe.
Deux défauts rendaient R-CNN inutilisable en temps réel :
- Passer 2 000 images de 224 × 224 dans le réseau prenait plusieurs dizaines de secondes par image, même sur une carte graphique de l'époque.
- Chaque candidat était traité isolément, sans partage du calcul d'extraction des caractéristiques.
Fast R-CNN : partager le calcul
Fast R-CNN (2015) inverse le calcul. Le réseau convolutif s'applique une seule fois sur l'image entière et produit une carte de caractéristiques de résolution réduite. Chaque candidat de Selective Search projette sa boîte sur cette carte, découpe la sous-région correspondante et n'exécute plus que la tête de classification et de régression.
Le mécanisme clé s'appelle RoI Pooling. Une région d'intérêt d'une taille quelconque doit produire un tenseur de taille fixe — disons 7 × 7 — pour alimenter des couches denses.
import torch
from torchvision.ops import roi_pool
carte = torch.randn(1, 256, 50, 50) # image passee dans le tronc
boites = torch.tensor([[0, 10.0, 5.0, 40.0, 30.0]]) # batch_idx, x1, y1, x2, y2
sortie = roi_pool(carte, boites, output_size=(7, 7), spatial_scale=1/16)
print(sortie.shape) # (1, 256, 7, 7)
Le spatial_scale reflète le facteur de réduction du tronc : une image
divisée par 16 en résolution demande à roi_pool de convertir les
coordonnées en pixels vers les coordonnées de la carte.
Fast R-CNN divise le temps par un facteur 25 environ. Le goulot devient alors la génération des propositions par Selective Search, un algorithme externe qui n'est ni parallélisable ni entraînable.
Faster R-CNN : la proposition devient un réseau
Faster R-CNN (2015) remplace Selective Search par un Region Proposal Network (RPN), un petit réseau convolutif qui produit ses candidats à partir de la même carte de caractéristiques que la tête de détection. L'extraction et la proposition partagent désormais leur calcul.
Le RPN glisse une fenêtre sur la carte et, à chaque position, propose neuf boîtes de tailles et de rapports différents — les ancres. Le module 4 détaille ce mécanisme. Chaque ancre reçoit deux prédictions :
- Un score d'objectness : cette ancre contient-elle un objet, sans préciser lequel ?
- Une correction des coordonnées, pour ajuster l'ancre sur l'objet.
Les ancres au meilleur score, après suppression des non-maxima, deviennent les propositions qui alimentent la seconde étape.
from torchvision.models.detection import fasterrcnn_resnet50_fpn
from torchvision.models.detection.faster_rcnn import FasterRCNN_ResNet50_FPN_Weights
modele = fasterrcnn_resnet50_fpn(
weights=FasterRCNN_ResNet50_FPN_Weights.COCO_V1
).eval()
image = torch.rand(3, 800, 800) # une image, format C H W
with torch.no_grad():
sorties = modele([image]) # liste, une entree par image
boites = sorties[0]["boxes"] # tenseur (N, 4)
classes = sorties[0]["labels"] # (N,)
scores = sorties[0]["scores"] # (N,)
La sortie standard de torchvision est une liste de dictionnaires : un par
image, chacun avec les trois clés boxes, labels et scores. Filtrer
par un seuil sur scores reste à la charge de l'appelant.
RoI Pooling contre RoI Align
Sur les objets fins, comme un panneau routier lointain, RoI Pooling produit
des masques et des boîtes visiblement décalés. La cause est arithmétique :
la région se ramène à la carte par une division entière, qui arrondit
les coordonnées à des entiers de la grille. Sur une carte à
spatial_scale = 1/16, deux pixels d'image adjacents peuvent tomber dans
la même case de la carte, ce qui perd tout ce qui se joue à cette échelle.
RoI Align conserve les coordonnées en virgule flottante et interpole bilinéairement la valeur à quatre points par case avant l'agrégation. La perte de résolution disparaît, au prix d'un léger surcoût. C'est la version utilisée par tous les modèles modernes de la famille, y compris Mask R-CNN (module 7).
torchvision renvoie ses scores en probabilité entre 0 et 1, alors que
certaines exports ONNX renvoient des logits bruts. Filtrer avec un seuil
> 0,5 sur des logits laisse passer presque tout : les faux positifs
explosent silencieusement en évaluation. Vérifiez toujours la plage des
scores avant de fixer un seuil.
Précision contre vitesse
Sur COCO, Faster R-CNN avec un tronc ResNet-50 et un FPN atteint environ 41 mAP sur le split de validation à 15 images par seconde sur une carte graphique moderne. YOLOv8n atteint 37 mAP à 200 images par seconde. La famille R-CNN reste préférée quand :
- La précision compte plus que le temps réel — imagerie médicale, contrôle qualité industriel, comptage nocturne au carrefour hors urgence.
- Les objets sont petits ou nombreux — le RPN produit des propositions denses aux petites échelles quand le FPN alimente plusieurs niveaux.
- On a le luxe d'un GPU serveur et pas d'un carte embarquée.
Le module 3 traite l'exact opposé, quand les 25 images par seconde du flux vidéo interdisent tout modèle qui prend plus de 40 millisecondes.
Avant d'affiner un détecteur, exécutez fasterrcnn_resnet50_fpn en
inférence pure sur une centaine d'images de votre jeu. Les classes COCO
couvrent les véhicules et les piétons : vous obtenez immédiatement une
baseline solide, une idée du taux de détection avant tout entraînement et
souvent le constat que le préentraînement suffit à démarrer.