Aller au contenu principal

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 :

  1. Générer quelques milliers de régions candidates susceptibles de contenir un objet, sans se soucier de la classe.
  2. 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).

Ne pas oublier de convertir les scores

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.

Commencer par un Faster R-CNN préentraîné

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.

En résumé

  • Un détecteur en deux étapes propose des régions candidates, puis classe et corrige chacune. C'est plus précis, plus lent, et souvent meilleur sur les petits objets denses.
  • Fast R-CNN partage le calcul du tronc entre tous les candidats ; Faster R-CNN remplace Selective Search par un Region Proposal Network entraîné, qui rend le pipeline entièrement bout à bout.
  • RoI Align remplace RoI Pooling en évitant l'arrondi entier des coordonnées : indispensable dès qu'on annote des objets fins ou qu'on produit un masque.
  • Faster R-CNN reste la référence quand la précision prime, notamment sur les petits objets nombreux. Le compromis avec les détecteurs en une étape est le sujet du module suivant.

Module suivant : les détecteurs en une étape, YOLO et SSD, qui font tout en un seul passage.