Évaluation des modèles de détection d'objets à l'aide de la précision moyenne moyenne (mAP)
Pour évaluer les modèles de détection d'objets tels que R-CNN et YOLO, la précision moyenne moyenne (mAP) est utilisée. Le mAP compare la boîte englobante de la vérité terrain à la boîte détectée et renvoie un score. Plus le score est élevé, plus le modèle est précis dans ses détections.
Dans mon dernier article, nous avons examiné en détail la matrice de confusion, l'exactitude, la précision et le rappel du modèle. Nous avons également utilisé la bibliothèque Scikit-learn pour calculer ces métriques. Nous allons maintenant étendre notre discussion pour voir comment la précision et le rappel sont utilisés pour calculer le mAP.
Voici les sections couvertes dans ce tutoriel :
- Du score de prédiction à l’étiquette de classe
- Courbe précision-rappel
- Précision moyenne (AP)
- Intersection sur Union (IoU)
- Précision moyenne moyenne (mAP) pour la détection d'objets
Conditions préalables
Afin de suivre cet article, expérience avec le code Python et compréhension du Deep Learning pour les débutants. Nous partirons du principe que tous les lecteurs ont accès à des machines suffisamment puissantes pour pouvoir exécuter le code fourni.
Si vous n'avez pas accès à un GPU, nous vous suggérons d'y accéder via le cloud. De nombreux fournisseurs de cloud proposent des GPU. Les droplets GPU DigitalOcean sont actuellement en disponibilité anticipée, apprenez-en plus et inscrivez-vous pour vous intéresser aux droplets GPU ici
Pour obtenir des instructions sur la façon de démarrer avec le code Python, nous vous recommandons d'essayer ce guide du débutant pour configurer votre système et vous préparer à exécuter des didacticiels pour débutants.
Du score de prédiction à l’étiquette de classe
Dans cette section, nous passerons en revue rapidement la manière dont une étiquette de classe est dérivée d'un score de prédiction.
Étant donné qu'il existe deux classes, Positive et Négative, voici les étiquettes de vérité terrain de 10 échantillons.
y_true = ["positive", "negative", "negative", "positive", "positive", "positive", "negative", "positive", "negative", "positive"]
Lorsque ces échantillons sont transmis au modèle, celui-ci renvoie les scores de prédiction suivants. Sur la base de ces scores, comment classer les échantillons (c'est-à-dire attribuer une étiquette de classe à chaque échantillon) ?
pred_scores = [0.7, 0.3, 0.5, 0.6, 0.55, 0.9, 0.4, 0.2, 0.4, 0.3]
Pour convertir les scores en étiquette de classe, un seuil est utilisé. Lorsque le score est égal ou supérieur au seuil, l’échantillon est classé dans une seule classe. Sinon, elle est classée dans l’autre classe. Admettons qu'un échantillon est positif si son score est supérieur ou égal au seuil. Sinon, c'est Négatif. Le bloc de code suivant convertit les scores en étiquettes de classe avec un seuil de 0,5.
import numpy
pred_scores = [0.7, 0.3, 0.5, 0.6, 0.55, 0.9, 0.4, 0.2, 0.4, 0.3]
y_true = ["positive", "negative", "negative", "positive", "positive", "positive", "negative", "positive", "negative", "positive"]
threshold = 0.5
y_pred = ["positive" if score >= threshold else "negative" for score in pred_scores]
print(y_pred)
['positive', 'negative', 'positive', 'positive', 'positive', 'positive', 'negative', 'negative', 'negative', 'negative']
Désormais, les étiquettes de vérité terrain et prédites sont disponibles dans les variables y_true
et y_pred
. Sur la base de ces étiquettes, la matrice de confusion, la précision et le rappel peuvent être calculés.
r = numpy.flip(sklearn.metrics.confusion_matrix(y_true, y_pred))
print(r)
precision = sklearn.metrics.precision_score(y_true=y_true, y_pred=y_pred, pos_label="positive")
print(precision)
recall = sklearn.metrics.recall_score(y_true=y_true, y_pred=y_pred, pos_label="positive")
print(recall)
Confusion Matrix (From Left to Right & Top to Bottom: True Positive, False Negative, False Positive, True Negative)
[[4 2]
[1 3]]
Precision = 4/(4+1)
0.8
Recall = 4/(4+2)
0.6666666666666666
Après cet aperçu rapide du calcul de la précision et du rappel, dans la section suivante, nous discuterons de la création de la courbe précision-rappel.
Courbe précision-rappel
D'après la définition de la précision et du rappel donnée dans la partie 1, rappelez-vous que plus la précision est élevée, plus le modèle est confiant lorsqu'il classe un échantillon comme positif. Plus le rappel est élevé, plus le modèle a correctement classé d'échantillons positifs comme positifs.
Lorsqu'un modèle a un rappel élevé mais une faible précision, alors le modèle classe correctement la plupart des échantillons positifs mais il contient de nombreux faux positifs (c'est-à-dire qu'il classe de nombreux échantillons négatifs comme positifs). Lorsqu'un modèle a une haute précision mais un faible rappel, alors le modèle est précis lorsqu'il classe un échantillon comme positif, mais il peut classer uniquement certains des échantillons positifs.
En raison de l'importance de la précision et du rappel, il existe une courbe précision-rappel qui montre le compromis entre les valeurs de précision et de rappel pour différents seuils. Cette courbe permet de sélectionner le meilleur seuil pour maximiser les deux métriques.
Certaines entrées sont nécessaires pour créer la courbe précision-rappel :
- Les étiquettes de vérité terrain.
- Les scores de prédiction des échantillons.
- Quelques seuils pour convertir les scores de prédiction en étiquettes de classe.
Le bloc de code suivant crée la liste y_true
pour contenir les étiquettes de vérité terrain, la liste pred_scores
pour les scores de prédiction, et enfin les seuils
liste pour différentes valeurs de seuil.
import numpy
y_true = ["positive", "negative", "negative", "positive", "positive", "positive", "negative", "positive", "negative", "positive", "positive", "positive", "positive", "negative", "negative", "negative"]
pred_scores = [0.7, 0.3, 0.5, 0.6, 0.55, 0.9, 0.4, 0.2, 0.4, 0.3, 0.7, 0.5, 0.8, 0.2, 0.3, 0.35]
thresholds = numpy.arange(start=0.2, stop=0.7, step=0.05)
Voici les seuils enregistrés dans la liste des seuils
. Comme il existe 10 seuils, 10 valeurs de précision et de rappel seront créées.
[0.2,
0.25,
0.3,
0.35,
0.4,
0.45,
0.5,
0.55,
0.6,
0.65]
La fonction suivante nommée precision_recall_curve()
accepte les étiquettes de vérité terrain, les scores de prédiction et les seuils. Il renvoie deux listes de longueur égale représentant les valeurs de précision et de rappel.
import sklearn.metrics
def precision_recall_curve(y_true, pred_scores, thresholds):
precisions = []
recalls = []
for threshold in thresholds:
y_pred = ["positive" if score >= threshold else "negative" for score in pred_scores]
precision = sklearn.metrics.precision_score(y_true=y_true, y_pred=y_pred, pos_label="positive")
recall = sklearn.metrics.recall_score(y_true=y_true, y_pred=y_pred, pos_label="positive")
precisions.append(precision)
recalls.append(recall)
return precisions, recalls
Le code suivant appelle la fonction precision_recall_curve()
après avoir passé les trois listes préparées précédemment. Il renvoie les listes precisions
et recalls
qui contiennent respectivement toutes les valeurs des précisions et des rappels.
precisions, recalls = precision_recall_curve(y_true=y_true,
pred_scores=pred_scores,
thresholds=thresholds)
Voici les valeurs renvoyées dans la liste precisions
.
[0.5625,
0.5714285714285714,
0.5714285714285714,
0.6363636363636364,
0.7,
0.875,
0.875,
1.0,
1.0,
1.0]
Voici la liste des valeurs de la liste rappels
.
[1.0,
0.8888888888888888,
0.8888888888888888,
0.7777777777777778,
0.7777777777777778,
0.7777777777777778,
0.7777777777777778,
0.6666666666666666,
0.5555555555555556,
0.4444444444444444]
Étant donné les deux listes de longueurs égales, il est possible de tracer leurs valeurs dans un tracé 2D comme indiqué ci-dessous.
matplotlib.pyplot.plot(recalls, precisions, linewidth=4, color="red")
matplotlib.pyplot.xlabel("Recall", fontsize=12, fontweight='bold')
matplotlib.pyplot.ylabel("Precision", fontsize=12, fontweight='bold')
matplotlib.pyplot.title("Precision-Recall Curve", fontsize=15, fontweight="bold")
matplotlib.pyplot.show()
La courbe précision-rappel est présentée dans la figure suivante. Notez qu'à mesure que le rappel augmente, la précision diminue. La raison en est que lorsque le nombre d’échantillons positifs augmente (rappel élevé), la précision de la classification correcte de chaque échantillon diminue (faible précision). Ceci est normal, car le modèle est plus susceptible d’échouer lorsqu’il existe de nombreux échantillons.
La courbe précision-rappel permet de déterminer facilement le point où la précision et le rappel sont élevés. D'après la figure précédente, le meilleur point est (recall, précision)=(0.778, 0.875)
.
Décider graphiquement des meilleures valeurs pour la précision et le rappel peut fonctionner en utilisant la figure précédente car la courbe n'est pas complexe. Une meilleure méthode consiste à utiliser une métrique appelée score f1
, qui est calculée en fonction de l'équation suivante.
La métrique f1
mesure l'équilibre entre précision et rappel. Lorsque la valeur de f1
est élevée, cela signifie que la précision et le rappel sont élevés. Un score f1
inférieur signifie un plus grand déséquilibre entre précision et rappel.
D'après l'exemple précédent, le f1
est calculé selon le code ci-dessous. Selon les valeurs de la liste f1
, le score le plus élevé est 0,82352941
. C'est le 6ème élément de la liste (c'est-à-dire l'index 5). Les 6èmes éléments des listes rappels
et précisions
sont respectivement 0,778
et 0,875
. La valeur seuil correspondante est 0,45
.
f1 = 2 * ((numpy.array(precisions) * numpy.array(recalls)) / (numpy.array(precisions) + numpy.array(recalls)))
[0.72,
0.69565217,
0.69565217,
0.7,
0.73684211,
0.82352941,
0.82352941,
0.8,
0.71428571, 0
.61538462]
La figure suivante montre, en bleu, l'emplacement du point qui correspond au meilleur équilibre entre le rappel et la précision. En conclusion, le meilleur seuil pour équilibrer la précision et le rappel est 0,45
auquel la précision est de 0,875
et le rappel est de 0,778
.
matplotlib.pyplot.plot(recalls, precisions, linewidth=4, color="red", zorder=0)
matplotlib.pyplot.scatter(recalls[5], precisions[5], zorder=1, linewidth=6)
matplotlib.pyplot.xlabel("Recall", fontsize=12, fontweight='bold')
matplotlib.pyplot.ylabel("Precision", fontsize=12, fontweight='bold')
matplotlib.pyplot.title("Precision-Recall Curve", fontsize=15, fontweight="bold")
matplotlib.pyplot.show()
Après avoir discuté de la courbe précision-rappel, la section suivante explique comment calculer la précision moyenne.
Précision moyenne (AP)
La précision moyenne (AP) est un moyen de résumer la courbe précision-rappel en une valeur unique représentant la moyenne de toutes les précisions. L'AP est calculé selon l'équation suivante. À l'aide d'une boucle qui parcourt toutes les précisions/rappels, la différence entre les rappels actuels et suivants est calculée puis multipliée par la précision actuelle. En d’autres termes, l’AP est la somme pondérée des précisions à chaque seuil où le poids est l’augmentation du rappel.
Il est important d'ajouter respectivement 0 et 1 aux listes de rappels et de précisions. Par exemple, si la liste rappels
est [0.8, 0.6], alors 0 doit être ajouté pour être [0.8, 0.6, 0.0]. La même chose se produit pour la liste précisions
mais ajoutez 1 au lieu de 0 (par exemple [0.8, 0.2, 1.0]).
Étant donné que recalls
et precisions
sont des tableaux NumPy, l'équation précédente est modélisée en fonction de la ligne Python suivante.
AP = numpy.sum((recalls[:-1] - recalls[1:]) * precisions[:-1])
Voici le code complet qui calcule l'AP.
import numpy
import sklearn.metrics
def precision_recall_curve(y_true, pred_scores, thresholds):
precisions = []
recalls = []
for threshold in thresholds:
y_pred = ["positive" if score >= threshold else "negative" for score in pred_scores]
precision = sklearn.metrics.precision_score(y_true=y_true, y_pred=y_pred, pos_label="positive")
recall = sklearn.metrics.recall_score(y_true=y_true, y_pred=y_pred, pos_label="positive")
precisions.append(precision)
recalls.append(recall)
return precisions, recalls
y_true = ["positive", "negative", "negative", "positive", "positive", "positive", "negative", "positive", "negative", "positive", "positive", "positive", "positive", "negative", "negative", "negative"]
pred_scores = [0.7, 0.3, 0.5, 0.6, 0.55, 0.9, 0.4, 0.2, 0.4, 0.3, 0.7, 0.5, 0.8, 0.2, 0.3, 0.35]
thresholds=numpy.arange(start=0.2, stop=0.7, step=0.05)
precisions, recalls = precision_recall_curve(y_true=y_true,
pred_scores=pred_scores,
thresholds=thresholds)
precisions.append(1)
recalls.append(0)
precisions = numpy.array(precisions)
recalls = numpy.array(recalls)
AP = numpy.sum((recalls[:-1] - recalls[1:]) * precisions[:-1])
print(AP)
Tout est question de précision moyenne. Voici un résumé des étapes pour calculer l’AP :
- Générez les scores de prédiction à l'aide du modèle.
- Convertissez les scores de prédiction en étiquettes de classe.
- Calculez la matrice de confusion.
- Calculez les métriques de précision et de rappel.
- Créez la courbe de rappel de précision.
- Mesurez la précision moyenne.
La section suivante parle de l'intersection sur union (IoU), qui correspond à la manière dont une détection d'objet génère les scores de prédiction.
Intersection sur Union (IoU)
Pour entraîner un modèle de détection d'objets, il y a généralement 2 entrées :
- Une image.
- Cadres de délimitation de la vérité terrain pour chaque objet de l'image.
Le modèle prédit les boîtes englobantes des objets détectés. On s’attend à ce que la boîte prédite ne corresponde pas exactement à la boîte de vérité terrain. La figure suivante montre une image de chat. La case de vérité terrain de l’objet est en rouge tandis que celle prédite est en jaune. Sur la base de la visualisation des 2 cases, le modèle fait-il une bonne prédiction avec un score de correspondance élevé ?
Il est difficile d’évaluer subjectivement les prédictions du modèle. Par exemple, quelqu’un peut conclure qu’il y a une correspondance à 50 % alors que quelqu’un d’autre remarquera qu’il y a une correspondance à 60 %.
Image sans étiquettes de Pixabay par susannp4
Une meilleure alternative consiste à utiliser une mesure quantitative pour évaluer la correspondance entre la vérité terrain et les cases prédites. Cette mesure est l'intersection sur l'union (IoU). L'IoU permet de savoir si une région possède un objet ou non.
L'IoU est calculé selon l'équation suivante en divisant l'aire d'intersection entre les 2 cases par l'aire de leur union. Plus l’IoU est élevé, meilleure est la prédiction.
La figure suivante montre 3 cas avec des IoU différents. Notez que les IoU en haut de chaque cas sont mesurées objectivement et peuvent différer un peu de la réalité mais cela a du sens.
Pour le cas A, la case prédite en jaune est loin d'être alignée sur la case rouge de vérité terrain et donc le score IoU est 0,2 (c'est-à-dire qu'il n'y a qu'un chevauchement de 20 % entre les 2 cases) .
Pour le cas B, la zone d'intersection entre les 2 cases est plus grande mais les 2 cases ne sont toujours pas bien alignées et donc le score IoU est 0,5.
Pour le cas C, les coordonnées des 2 cases sont si proches et donc leur IoU est 0,9 (c'est-à-dire qu'il y a un chevauchement de 90 % entre les 2 cases).
Notez que l'IoU est de 0,0 lorsqu'il y a un chevauchement de 0 % entre les cases de prédiction et de vérité terrain. L'IoU est 1,0 lorsque les 2 cases s'emboîtent à 100 %.
Pour calculer l'IoU d'une image, voici une fonction nommée intersection_over_union()
. Il accepte les 2 paramètres suivants :
gt_box
: cadre de délimitation de la vérité terrain.pred_box
: cadre de délimitation prédit.
Il calcule l'intersection et l'union entre les 2 cases dans les variables intersection
et union
, respectivement. De plus, l'IoU est calculé dans la variable iou
. Il renvoie toutes ces 3 variables.
def intersection_over_union(gt_box, pred_box):
inter_box_top_left = [max(gt_box[0], pred_box[0]), max(gt_box[1], pred_box[1])]
inter_box_bottom_right = [min(gt_box[0]+gt_box[2], pred_box[0]+pred_box[2]), min(gt_box[1]+gt_box[3], pred_box[1]+pred_box[3])]
inter_box_w = inter_box_bottom_right[0] - inter_box_top_left[0]
inter_box_h = inter_box_bottom_right[1] - inter_box_top_left[1]
intersection = inter_box_w * inter_box_h
union = gt_box[2] * gt_box[3] + pred_box[2] * pred_box[3] - intersection
iou = intersection / union
return iou, intersection, union
La boîte englobante transmise à la fonction est une liste de 4 éléments qui sont :
- L'axe X du coin supérieur gauche.
- L'axe Y du coin supérieur gauche.
- Largeur.
- Hauteur.
Voici la vérité sur le terrain et les cadres de délimitation prédits de l'image de la voiture.
gt_box = [320, 220, 680, 900]
pred_box = [500, 320, 550, 700]
Étant donné que l'image s'appelle cat.jpg
, voici la version complète qui dessine les cadres de délimitation sur l'image.
import imageio
import matplotlib.pyplot
import matplotlib.patches
def intersection_over_union(gt_box, pred_box):
inter_box_top_left = [max(gt_box[0], pred_box[0]), max(gt_box[1], pred_box[1])]
inter_box_bottom_right = [min(gt_box[0]+gt_box[2], pred_box[0]+pred_box[2]), min(gt_box[1]+gt_box[3], pred_box[1]+pred_box[3])]
inter_box_w = inter_box_bottom_right[0] - inter_box_top_left[0]
inter_box_h = inter_box_bottom_right[1] - inter_box_top_left[1]
intersection = inter_box_w * inter_box_h
union = gt_box[2] * gt_box[3] + pred_box[2] * pred_box[3] - intersection
iou = intersection / union
return iou, intersection, union
im = imageio.imread("cat.jpg")
gt_box = [320, 220, 680, 900]
pred_box = [500, 320, 550, 700]
fig, ax = matplotlib.pyplot.subplots(1)
ax.imshow(im)
gt_rect = matplotlib.patches.Rectangle((gt_box[0], gt_box[1]),
gt_box[2],
gt_box[3],
linewidth=5,
edgecolor='r',
facecolor='none')
pred_rect = matplotlib.patches.Rectangle((pred_box[0], pred_box[1]),
pred_box[2],
pred_box[3],
linewidth=5,
edgecolor=(1, 1, 0),
facecolor='none')
ax.add_patch(gt_rect)
ax.add_patch(pred_rect)
ax.axes.get_xaxis().set_ticks([])
ax.axes.get_yaxis().set_ticks([])
La figure suivante montre l'image avec les cadres de délimitation.
Pour calculer l'IoU, appelez simplement la fonction intersection_over_union()
. Sur la base des cadres de délimitation, le score IoU est 0,54
.
iou, intersect, union = intersection_over_union(gt_box, pred_box)
print(iou, intersect, union)
0.5409582689335394 350000 647000
Le score IoU 0,54 signifie qu'il existe un chevauchement de 54 % entre la vérité terrain et les cadres de délimitation prédits. En regardant les boîtes, quelqu'un peut avoir l'impression visuellement que c'est assez bon pour conclure que le modèle a détecté l'objet chat. Quelqu'un d'autre peut penser que le modèle n'est pas encore précis car la boîte prédite ne correspond pas bien à la boîte de vérité terrain.
Pour juger objectivement si le modèle a prédit correctement ou non l'emplacement de la boîte, un seuil est utilisé. Si le modèle prédit une boîte avec un score IoU supérieur ou égal au seuil, alors il existe un chevauchement élevé entre la boîte prédite et l'une des boîtes de vérité terrain. Cela signifie que le modèle a pu détecter un objet avec succès. La région détectée est classée comme Positive (c'est-à-dire qu'elle contient un objet).
D’un autre côté, lorsque le score IoU est inférieur au seuil, le modèle fait une mauvaise prédiction car la boîte prédite ne chevauche pas la boîte de vérité terrain. Cela signifie que la région détectée est classée comme Négative (c'est-à-dire qu'elle ne contient pas d'objet).
Prenons un exemple pour clarifier comment les scores IoU aident à classer une région comme un objet ou non. Supposons que le modèle de détection d'objets soit alimenté par l'image suivante où il y a 2 objets cibles avec leurs cases de vérité terrain en rouge et les cases prédites sont en jaune.
Le code suivant lit l'image (étant donné qu'elle s'appelle pets.jpg
), dessine les cases et calcule l'IoU pour chaque objet. L'IoU de l'objet de gauche est 0,76 tandis que l'autre objet a un score IoU de 0,26.
import matplotlib.pyplot
import matplotlib.patches
import imageio
def intersection_over_union(gt_box, pred_box):
inter_box_top_left = [max(gt_box[0], pred_box[0]), max(gt_box[1], pred_box[1])]
inter_box_bottom_right = [min(gt_box[0]+gt_box[2], pred_box[0]+pred_box[2]), min(gt_box[1]+gt_box[3], pred_box[1]+pred_box[3])]
inter_box_w = inter_box_bottom_right[0] - inter_box_top_left[0]
inter_box_h = inter_box_bottom_right[1] - inter_box_top_left[1]
intersection = inter_box_w * inter_box_h
union = gt_box[2] * gt_box[3] + pred_box[2] * pred_box[3] - intersection
iou = intersection / union
return iou, intersection, union,
im = imageio.imread("pets.jpg")
gt_box = [10, 130, 370, 350]
pred_box = [30, 100, 370, 350]
iou, intersect, union = intersection_over_union(gt_box, pred_box)
print(iou, intersect, union)
fig, ax = matplotlib.pyplot.subplots(1)
ax.imshow(im)
gt_rect = matplotlib.patches.Rectangle((gt_box[0], gt_box[1]),
gt_box[2],
gt_box[3],
linewidth=5,
edgecolor='r',
facecolor='none')
pred_rect = matplotlib.patches.Rectangle((pred_box[0], pred_box[1]),
pred_box[2],
pred_box[3],
linewidth=5,
edgecolor=(1, 1, 0),
facecolor='none')
ax.add_patch(gt_rect)
ax.add_patch(pred_rect)
gt_box = [645, 130, 310, 320]
pred_box = [500, 60, 310, 320]
iou, intersect, union = intersection_over_union(gt_box, pred_box)
print(iou, intersect, union)
gt_rect = matplotlib.patches.Rectangle((gt_box[0], gt_box[1]),
gt_box[2],
gt_box[3],
linewidth=5,
edgecolor='r',
facecolor='none')
pred_rect = matplotlib.patches.Rectangle((pred_box[0], pred_box[1]),
pred_box[2],
pred_box[3],
linewidth=5,
edgecolor=(1, 1, 0),
facecolor='none')
ax.add_patch(gt_rect)
ax.add_patch(pred_rect)
ax.axes.get_xaxis().set_ticks([])
ax.axes.get_yaxis().set_ticks([])
Étant donné que le seuil IoU est de 0,6, alors seules les régions avec des scores IoU supérieurs ou égaux à 0,6 sont classées comme Positive (c'est-à-dire ayant des objets). Ainsi, la case avec un score IoU de 0,76 est positive tandis que l'autre case avec un score IoU de 0,26 est Négative.
Image sans étiquettes de hindustantimes.com
Si le seuil passe à 0,2 au lieu de 0,6, alors les deux prédictions sont Positives. Si le seuil est 0,8, alors les deux prédictions sont Négatives.
En résumé, le score IoU mesure la proximité entre la boîte prédite et la boîte de vérité terrain. Il varie de 0,0 à 1,0, 1,0 étant le résultat optimal. Lorsque l'IoU est supérieur au seuil, alors la boîte est classée Positive car elle entoure un objet. Sinon, il est classé comme Négatif.
La section suivante montre comment bénéficier des IoU pour calculer la précision moyenne moyenne (mAP) pour un modèle de détection d'objets.
Précision moyenne moyenne (mAP) pour la détection d'objets
Habituellement, les modèles de détection d'objets sont évalués avec différents seuils IoU, chaque seuil pouvant donner des prédictions différentes des autres seuils. Supposons que le modèle soit alimenté par une image comportant 10 objets répartis dans 2 classes. Comment calculer la carte ?
Pour calculer le mAP, commencez par calculer l’AP pour chaque classe. La moyenne des AP pour toutes les classes est le mAP.
En supposant que l'ensemble de données utilisé ne comporte que 2 classes. Pour la première classe, voici les étiquettes de vérité terrain et les scores prédits dans les variables y_true
et pred_scores
, respectivement.
y_true = ["positive", "negative", "positive", "negative", "positive", "positive", "positive", "negative", "positive", "negative"]
pred_scores = [0.7, 0.3, 0.5, 0.6, 0.55, 0.9, 0.75, 0.2, 0.8, 0.3]
Voici les variables y_true
et pred_scores
de la deuxième classe.
y_true = ["negative", "positive", "positive", "negative", "negative", "positive", "positive", "positive", "negative", "positive"]
pred_scores = [0.32, 0.9, 0.5, 0.1, 0.25, 0.9, 0.55, 0.3, 0.35, 0.85]
La liste des seuils IoU commence de 0,2 à 0,9 avec un pas de 0,25.
thresholds = numpy.arange(start=0.2, stop=0.9, step=0.05)
Pour calculer l'AP pour une classe, introduisez simplement ses variables y_true
et pred_scores
dans le code suivant.
precisions, recalls = precision_recall_curve(y_true=y_true,
pred_scores=pred_scores,
thresholds=thresholds)
matplotlib.pyplot.plot(recalls, precisions, linewidth=4, color="red", zorder=0)
matplotlib.pyplot.xlabel("Recall", fontsize=12, fontweight='bold')
matplotlib.pyplot.ylabel("Precision", fontsize=12, fontweight='bold')
matplotlib.pyplot.title("Precision-Recall Curve", fontsize=15, fontweight="bold")
matplotlib.pyplot.show()
precisions.append(1)
recalls.append(0)
precisions = numpy.array(precisions)
recalls = numpy.array(recalls)
AP = numpy.sum((recalls[:-1] - recalls[1:]) * precisions[:-1])
print(AP)
Pour la première classe, voici sa courbe précision-rappel. Sur la base de cette courbe, l'AP est 0,949
.
La courbe précision-rappel de la deuxième classe est présentée ci-dessous. Son AP est de 0,958
.
Sur la base des AP des 2 classes (0,949 et 0,958), le mAP du modèle de détection d'objets est calculé selon l'équation suivante.
Sur la base de cette équation, le mAP est 0,9535
.
mAP = (0.949 + 0.958)/2 = 0.9535
Conclusion
Ce didacticiel explique comment calculer la précision moyenne moyenne (mAP) pour un modèle de détection d'objets. Nous avons commencé par expliquer comment convertir un score de prédiction en étiquette de classe. En utilisant différents seuils, une courbe précision-rappel est créée. A partir de cette courbe, la précision moyenne (AP) est mesurée.
Pour un modèle de détection d'objets, le seuil est l'intersection sur union (IoU) qui évalue les objets détectés. Une fois l'AP mesuré pour chaque classe de l'ensemble de données, le mAP est calculé.