Thuta Learning
IntermediateAIintermediate

Evaluating Vision Models

What you'll walk away with

  • Explain the core ideas behind Evaluating Vision Models
  • Run the sample code and verify its output
  • Apply the technique correctly to the Tutorial Platform and production scenarios

Build the mental model

Evaluating a classification model is straightforward — a single binary question of whether the predicted label matches the true label exactly ('correct' or not). Object detection is not that simple: you can't reasonably expect a predicted box to match the ground-truth box pixel-for-pixel (even two human annotators labeling the same object will draw slightly different boxes), so you need a threshold defining 'how close counts as correct.' This is exactly where IoU comes in as the metric behind that threshold-based decision — if IoU ≥ 0.5 (for example), the prediction counts as a true positive; below that (a box exists but is misaligned), it's treated as a false positive.

Rather than settling on a single threshold, computing precision/recall across multiple IoU thresholds (0.5, 0.75, and so on) and averaging them is the core idea behind mAP (mean Average Precision) — it reveals that a model performing well at a loose threshold (0.5) might degrade sharply at a strict one (0.9), giving a much more detailed picture of localization precision. This gives richer information than classification accuracy ever could: classification has essentially no notion of 'partially correct,' while detection's localization quality is a genuinely continuous spectrum.

Connect it to a real scenario

Suppose the Tutorial Platform is preparing to ship a feature that auto-detects watermark/logo regions in course video slide screenshots. Before deploying, you'd evaluate the model's predicted watermark boxes against a hand-labeled test set using an IoU ≥ 0.5 threshold to decide correct versus incorrect, and use that detection rate as a decision gate — only shipping once it clears an acceptance bar like 90%.

Try the working example

python
import torch

def compute_iou(box1, box2):
    x1 = torch.max(box1[0], box2[0])
    y1 = torch.max(box1[1], box2[1])
    x2 = torch.min(box1[2], box2[2])
    y2 = torch.min(box1[3], box2[3])

    inter_width = (x2 - x1).clamp(min=0)
    inter_height = (y2 - y1).clamp(min=0)
    intersection = inter_width * inter_height

    area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
    area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
    union = area1 + area2 - intersection

    return intersection / union

def is_correct_detection(pred_box, gt_box, iou_threshold=0.5):
    iou = compute_iou(pred_box, gt_box)
    return iou.item() >= iou_threshold

ground_truth = torch.tensor([0.0, 0.0, 10.0, 10.0])

good_prediction = torch.tensor([1.0, 1.0, 11.0, 11.0])
bad_prediction = torch.tensor([8.0, 8.0, 18.0, 18.0])

for name, pred in [("good_prediction", good_prediction), ("bad_prediction", bad_prediction)]:
    iou = compute_iou(pred, ground_truth)
    correct = is_correct_detection(pred, ground_truth, iou_threshold=0.5)
    print(f"{name}: IoU={iou.item():.4f}, correct={correct}")
You should see
Prints two lines: 'good_prediction: IoU=0.6807, correct=True' and 'bad_prediction: IoU=0.0204, correct=False'. good_prediction ([1,1,11,11]) overlaps ground_truth ([0,0,10,10]) with intersection area 81 and union 119, giving IoU=81/119≈0.6807 (above the 0.5 threshold, so correct); bad_prediction ([8,8,18,18]) overlaps only in area 4 with union 196, giving IoU=4/196≈0.0204 (below threshold, so incorrect).

5-minute try-it

Write a function that takes a list of predicted boxes and a corresponding list of ground-truth boxes and returns a 'detection accuracy' — the count of correct detections divided by the total number of predictions. Then observe how the detection accuracy changes when iou_threshold is raised from 0.5 to 0.75.

One important caution

Directly applying classification-style accuracy to detection — checking only whether the class label matches, ignoring localization entirely — can wrongly mark a prediction 'correct' even when its box is badly misaligned.

Always defaulting iou_threshold to 0.5 regardless of the task's actual precision requirements (e.g. a feature that needs a tight auto-crop) can let genuinely misaligned boxes get counted as correct simply because the threshold is too loose for that use case.

Wikipedia — Jaccard indexComputer Vision

Easy traps

  • Directly applying classification-style accuracy to detection — checking only whether the class label matches, ignoring localization entirely — can wrongly mark a prediction 'correct' even when its box is badly misaligned.
  • Always defaulting iou_threshold to 0.5 regardless of the task's actual precision requirements (e.g. a feature that needs a tight auto-crop) can let genuinely misaligned boxes get counted as correct simply because the threshold is too loose for that use case.
  • Validate sample code in a local or test environment before applying it to a production system.

Exercise

Write a function that takes a list of predicted boxes and a corresponding list of ground-truth boxes and returns a 'detection accuracy' — the count of correct detections divided by the total number of predictions. Then observe how the detection accuracy changes when iou_threshold is raised from 0.5 to 0.75.

You'll know it worked when: Prints two lines: 'good_prediction: IoU=0.6807, correct=True' and 'bad_prediction: IoU=0.0204, correct=False'. good_prediction ([1,1,11,11]) overlaps ground_truth ([0,0,10,10]) with intersection area 81 and union 119, giving IoU=81/119≈0.6807 (above the 0.5 threshold, so correct); bad_prediction ([8,8,18,18]) overlaps only in area 4 with union 196, giving IoU=4/196≈0.0204 (below threshold, so incorrect).

Evaluating Vision Models | Thuta Learning