Understanding mAP, IoU, precision-recall, and segmentation metrics — with practical guidance on when each metric matters and how to interpret the numbers.
| Task | Primary Metric | What It Measures | Good Score |
|---|---|---|---|
| Classification | Accuracy | Fraction of correct predictions | >95% (ImageNet-scale) |
| Classification | F1 (macro) | Harmonic mean of precision and recall, averaged across classes | >85% |
| Detection | [email protected] | Mean average precision at 50% IoU | >60% (COCO), >80% (custom) |
| Detection | mAP@[.5:.95] | Mean average precision across 10 IoU thresholds | >40% (COCO) |
| Segmentation | mIoU | Mean intersection-over-union across classes | >70% |
IoU is the foundation of all detection and segmentation metrics. It measures how well a predicted region overlaps with the ground truth.
IoU = Area(Prediction ∩ Ground Truth) / Area(Prediction ∪ Ground Truth)
from cv_toolkit.evaluation import compute_iou
# Perfect overlap → IoU = 1.0
iou = compute_iou([0, 0, 100, 100], [0, 0, 100, 100])
# Partial overlap → 0 < IoU < 1
iou = compute_iou([0, 0, 100, 100], [50, 50, 150, 150])
# No overlap → IoU = 0.0
iou = compute_iou([0, 0, 50, 50], [100, 100, 200, 200])| IoU Threshold | Meaning |
|---|---|
| 0.50 | Loose match — box roughly covers the object. Standard for Pascal VOC. |
| 0.75 | Strict match — box tightly fits the object. Used in COCO's AP75 metric. |
| 0.90+ | Near-perfect alignment. Relevant for precise localization tasks (medical imaging, autonomous driving). |
Practical impact: At IoU=0.5, a detection that covers 50% of the object counts as correct. At IoU=0.75, the box must be much tighter. COCO's mAP@[.5:.95] averages across thresholds, rewarding models that produce tight boxes.
For segmentation, IoU is computed per-class at the pixel level:
from cv_toolkit.evaluation import compute_mask_iou, compute_mean_iou
# Predicted and ground truth masks (each pixel = class ID)
pred = [[0, 0, 1, 1],
[0, 0, 1, 1],
[2, 2, 2, 2],
[2, 2, 2, 2]]
gt = [[0, 0, 1, 1],
[0, 1, 1, 1],
[2, 2, 2, 2],
[2, 2, 0, 2]]
# Per-class IoU
class_ious = compute_mask_iou(pred, gt, num_classes=3)
# {0: 0.6, 1: 0.8, 2: 0.857}
# Mean IoU across all classes
miou = compute_mean_iou(pred, gt, num_classes=3)AP summarizes the precision-recall tradeoff for a detector at a specific IoU threshold. It answers: *"Across all confidence thresholds, how well does the model balance finding objects (recall) and avoiding false alarms (precision)?"*
1. Sort all detections by confidence (highest first)
2. Walk through the sorted list. For each detection:
3. At each step, compute:
4. Plot the precision-recall curve
5. Compute the area under this curve = AP
All-point interpolation (COCO style): compute the area under the smoothed PR curve using every unique recall value. More precise, the current standard.
11-point interpolation (Pascal VOC 2007): sample precision at 11 recall levels (0.0, 0.1, ..., 1.0) and average. Simpler but less accurate.
from cv_toolkit.evaluation import compute_ap_per_class, DetectionAnnotation
# Define ground truth and predictions
gt = [
DetectionAnnotation("img1", class_id=0, box=[10, 10, 50, 50]),
DetectionAnnotation("img1", class_id=0, box=[60, 60, 100, 100]),
]
preds = [
DetectionAnnotation("img1", class_id=0, box=[12, 8, 48, 52], confidence=0.95),
DetectionAnnotation("img1", class_id=0, box=[62, 58, 98, 102], confidence=0.80),
DetectionAnnotation("img1", class_id=0, box=[200, 200, 250, 250], confidence=0.30),
]
ap, recalls, precisions = compute_ap_per_class(
preds, gt, class_id=0, iou_threshold=0.5, method="all_points"
)
print(f"[email protected] for class 0: {ap:.4f}")mAP averages AP across all object classes. It is the single number that summarizes a detector's overall performance.
from cv_toolkit.evaluation import compute_map, compute_coco_map
# mAP at a single IoU threshold
result = compute_map(predictions, ground_truths, iou_threshold=0.5)
print(f"[email protected]: {result['mAP']}")
print(f"Per-class AP: {result['per_class_ap']}")
# COCO-style mAP across 10 thresholds (0.50, 0.55, ..., 0.95)
coco = compute_coco_map(predictions, ground_truths)
print(f"mAP@[.5:.95]: {coco['mAP@[.5:.95]']}")
print(f"[email protected]: {coco['[email protected]']}")
print(f"[email protected]: {coco['[email protected]']}")| [email protected] Range | Assessment |
|---|---|
| >80% | Excellent — production-ready for most applications |
| 60-80% | Good — usable with confidence filtering |
| 40-60% | Moderate — needs improvement for production |
| <40% | Poor — check data quality, model capacity, training config |
Important: mAP varies dramatically across datasets. An [email protected] of 50% on COCO (80 classes, small objects, occlusion) is much harder to achieve than 90% on a custom dataset with 5 large, well-separated classes.
Accuracy = Correct Predictions / Total Predictions
When accuracy lies: With imbalanced classes (99% negative, 1% positive), a model that always predicts "negative" gets 99% accuracy while being completely useless. Use F1 or precision/recall instead.
Precision = TP / (TP + FP) — "When I say positive, am I right?"
Recall = TP / (TP + FN) — "Did I find all the positives?"
F1 = 2 × P × R / (P + R) — harmonic mean of precision and recall
from cv_toolkit.evaluation import compute_classification_metrics
metrics = compute_classification_metrics(
y_true=[0, 0, 1, 1, 2, 2, 2],
y_pred=[0, 1, 1, 1, 2, 0, 2],
num_classes=3,
)
print(f"Overall accuracy: {metrics['accuracy']:.4f}")
for cls_id, cls_metrics in metrics['per_class'].items():
print(f" Class {cls_id}: P={cls_metrics['precision']:.3f} "
f"R={cls_metrics['recall']:.3f} F1={cls_metrics['f1']:.3f}")The confusion matrix shows exactly where the model confuses classes:
Predicted
Cat Dog Bird
Actual Cat [ 45 3 2 ]
Dog [ 5 38 7 ]
Bird [ 1 4 45 ]
Read row-by-row: "Of 50 actual cats, the model predicted 45 as cat, 3 as dog, and 2 as bird."
High off-diagonal values reveal which class pairs are confused — this tells you where to focus data collection or model improvement.
Never report metrics on data the model was trained on. Always hold out a validation set (10-20% of data) and ideally a test set that you only evaluate once.
If 95% of your images are "background" and 5% are "defect", a model that always predicts "background" gets 95% accuracy. Report per-class metrics and look at the minority class recall.
If you use test set metrics to choose hyperparameters, you're effectively training on the test set. Use a validation set for hyperparameter tuning and reserve the test set for final evaluation.
A single accuracy number is meaningless without context. Report the standard deviation across multiple runs (different seeds) or compute confidence intervals via bootstrapping.
Using [email protected] when your application needs precise localization (surgery, manufacturing inspection) gives a misleadingly optimistic picture. Use a stricter threshold that matches your deployment requirements.
Get the full Computer Vision Toolkit and unlock everything.
Get the complete guide with every chapter unlocked, including code samples, diagrams, and best practices.
Access all interactive tools with complete data, all workload profiles, and the full scenario library.
Downloadable source code, configuration files, and working examples from every chapter.
Free updates for life. Every new chapter, tool, and improvement included.