Lire honnêtement les métriques de détection
Lance la validation, examine ensemble la précision, le rappel, mAP50-95, l’AP par classe et la matrice de confusion, puis choisis un seuil de mise en production à partir d’un objectif.
Un chiffre unique est rassurant : mAP 0,83, et voilà. Mais le même mAP peut masquer une classe qui échoue une fois sur deux, des boîtes systématiquement trop larges ou un seuil qui déclenche une alerte chaque minute. Tu vas lancer une vraie validation et l’examiner ligne par ligne, jusqu’à ce qu’elle t’indique quoi corriger et où fixer le seuil.
Pratique
Comment chaque prédiction est évaluée#
La validation compare chaque boîte prédite à la vérité terrain. Une prédiction est un vrai positif (TP) si sa classe est correcte et si son IoU avec une boîte de vérité terrain qui n’a pas encore été appariée dépasse un seuil ; sinon, c’est un faux positif (FP). Chaque objet de vérité terrain qui reste sans correspondance est un faux négatif (FN).
| Indicateur | Formule | Question à laquelle elle répond |
|---|---|---|
| Précision | TP / (TP + FP) | Lorsque le modèle dessine une boîte, à quelle fréquence est-elle correcte ? |
| Rappel | TP / (TP + FN) | Parmi les objets réels, combien en a-t-il détecté ? |
| F1 | 2 × P × R / (P + R) | Un chiffre qui équilibre les deux |
Abaisser le seuil de confiance ajoute des boîtes : le rappel augmente et la précision diminue. La courbe précision-rappel représente ce compromis pour tous les seuils, et l’aire sous cette courbe correspond à la précision moyenne (AP) pour une classe. mAP50 calcule la moyenne de l’AP sur les classes avec un IoU de 0,5, où même une boîte nettement trop large reste comptabilisée. mAP50-95 calcule la moyenne sur dix seuils d’IoU, de 0,5 à 0,95, et récompense donc les boîtes bien ajustées ; c’est le chiffre principal des tableaux de modèles Ultralytics.
Lancer une validation#
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
metrics = model.val(data="coco8.yaml")
print(f"precision={metrics.box.mp:.3f} recall={metrics.box.mr:.3f}")
print(f"mAP50={metrics.box.map50:.3f} mAP50-95={metrics.box.map:.3f}") Class Images Instances Box(P R mAP50 mAP50-95)
all 4 17 0.551 0.962 0.943 0.669
person 3 10 0.551 0.8 0.848 0.387
dog 1 1 0.36 1 0.995 0.597
horse 1 2 0.36 1 0.995 0.696
elephant 1 2 0.656 0.969 0.828 0.545
umbrella 1 1 0.543 1 0.995 0.895
potted plant 1 1 0.833 1 0.995 0.895Lis les résultats de haut en bas :
- Instances 17, images 4. COCO8 est un test rapide de bon fonctionnement. Quatre images ne suffisent pas pour décider d’une mise en production ; considère chaque chiffre comme une illustration.
- mAP50 0,943 contre mAP50-95 0,669. La plupart des objets sont détectés, mais de nombreuses boîtes sont trop larges. Un écart important indique que le problème vient de la localisation, pas de la détection.
personAP50-95 0,387. La classe la plus fréquente est la plus faible. C’est ton goulot d’étranglement.- P 0,551, R 0,962. Ces colonnes sont calculées au seuil de confiance unique qui maximise le F1 sur toutes les classes — ici, un seuil bas — et non au seuil de 0,25 que tu utilises pour les prédictions. Ne les cite pas comme « la précision du modèle ».
AP par classe et seuil de mise en production#
La même exécution fournit l’AP par classe ainsi que la précision et le rappel à chaque seuil de confiance. Tu peux donc choisir un seuil en fonction d’un objectif plutôt que de le deviner :
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
metrics = model.val(data="coco8.yaml", plots=False, verbose=False)
box = metrics.box
# Per-class AP from the same run: the average hides the weakest class
for i, c in enumerate(box.ap_class_index):
print(f"{model.names[int(c)]:13} AP50={box.ap50[i]:.3f} AP50-95={box.ap[i]:.3f}")
# Precision and recall at every confidence threshold for one class
row = list(box.ap_class_index).index(0) # class 0 = person
for conf in (0.1, 0.25, 0.5, 0.75):
j = int(conf * (len(box.px) - 1))
print(f"person @ conf {conf:.2f}: precision {box.p_curve[row, j]:.2f}, recall {box.r_curve[row, j]:.2f}") all 4 17 0.551 0.962 0.943 0.669
person AP50=0.848 AP50-95=0.387
dog AP50=0.995 AP50-95=0.597
horse AP50=0.995 AP50-95=0.696
elephant AP50=0.828 AP50-95=0.545
umbrella AP50=0.995 AP50-95=0.895
potted plant AP50=0.995 AP50-95=0.895
person @ conf 0.10: precision 0.63, recall 0.80
person @ conf 0.25: precision 1.00, recall 0.54
person @ conf 0.50: precision 1.00, recall 0.40
person @ conf 0.75: precision 1.00, recall 0.14Le seuil devient alors une règle de décision, et non une intuition :
| Objectif défini par ta règle de décision | Choix | Sur cette exécution |
|---|---|---|
| Au maximum 5 % des alertes peuvent être fausses (précision ≥ 0,95) | Le seuil le plus bas qui atteint cet objectif, pour conserver le rappel le plus élevé | 0,25 : précision 1,00, rappel 0,54 |
| Ne manquer au maximum qu’une personne sur cinq (rappel ≥ 0,80) | Le seuil le plus élevé qui atteint cet objectif, pour conserver la précision la plus élevée | 0,10 : précision 0,63, rappel 0,80 |
Aucun des deux choix n’est satisfaisant ici : une précision élevée fait perdre la moitié des personnes, et un rappel élevé laisse passer un tiers des alertes. C’est une raison d’« itérer », pas un problème de seuil. La validation enregistre également BoxPR_curve.png, BoxP_curve.png, BoxR_curve.png, BoxF1_curve.png et confusion_matrix.png dans le dossier d’exécution, pour que tu puisses observer le même compromis sur les graphiques ; le guide des métriques de performance explique chacune d’elles.
Que corriger ensuite#
La matrice de confusion t’indique à quoi une classe faible est confondue. Si l’AP de forklift est faible et que les chariots élévateurs sont prédits comme pallet_jack, il s’agit d’une confusion entre classes, et non d’un problème de localisation : ajoute des exemples qui montrent la différence visuelle ou fusionne les classes si aucun code en aval n’a besoin de les distinguer. Le guide sur les enseignements tirés de l’évaluation du modèle détaille le processus.

La plupart des corrections concernent le premier et le troisième volets : améliorer les données et les étiquettes de la classe limitante. Ne modifie le modèle ou les paramètres d’entraînement qu’après avoir réussi les vérifications des données présentées dans les trois leçons précédentes.
| Éléments de preuve sur un ensemble de test figé | Décision |
|---|---|
| Chaque classe essentielle à l’activité atteint son objectif de précision et de rappel | Mettre en production, puis surveiller |
| Une classe ou une condition n’atteint pas son objectif | Itérer : ajouter des données et des étiquettes ciblées pour combler cet écart |
| Toutes les classes sont très éloignées de l’objectif, ou les classes se ressemblent visuellement | Revoir les spécifications de la tâche, les classes ou la configuration des caméras |
Pièges#
Un mAP de 0,83 peut masquer une classe à 0,40. Si cette classe porte la valeur métier, tu n’as pas un modèle à 0,83 — tu as un modèle défaillant caché derrière une moyenne flatteuse.
Symptôme : un modèle qui « obtient 0,94 » dessine des boîtes trop imprécises pour les mesures ou le recadrage. Solution : indique mAP50-95 et interprète l’écart avec mAP50 comme un indicateur de précision de localisation.
Symptôme : des chiffres parfaits en apparence, calculés sur quelques dizaines d’images ou sur des quasi-jumeaux du jeu d’entraînement. Solution : augmente le jeu de validation jusqu’à quelques centaines d’instances par classe importante et lance la vérification des quasi-doublons de la leçon précédente avant d’interpréter la moindre métrique.
Afficher la solution
Bilan : comptage de personnes sur yolo26n.pt, validation COCO8
Le goulot d’étranglement est person, avec un AP50-95 de 0.387 contre 0.669 au total. C’est aussi la classe qui compte le plus d’instances (10 sur 17) : c’est donc à la fois la moins performante et la plus importante pour un compteur de personnes. Son AP50 est de 0.848 : le modèle détecte la plupart des personnes, mais délimite les boîtes de façon approximative — ce qui importe moins pour le comptage que pour toute mesure de position ou de taille.
Pour une précision ≥ 0.95, le seuil admissible le plus bas est conf 0.25, avec une précision de 1.00, mais un rappel de seulement 0.54 : le compteur manquerait presque la moitié des personnes. Pour obtenir un rappel ≥ 0.80, il faudrait conf 0.10, auquel un tiers des comptages seraient des faux positifs.
Décision : itérer. Collecte et annote des personnes filmées par la caméra de déploiement — en particulier les personnes de petite taille, masquées ou en bordure de l’image — puis valide à nouveau sur un jeu de test figé de quelques centaines de personnes. Quatre images de validation ne suffisent pas pour décider de déployer ou non.