← Назад к вопросам
Как работает IoU (Intersection over Union)?
2.0 Middle🔥 181 комментариев
#Глубокое обучение#Метрики и оценка моделей
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
IoU (Intersection over Union)
IoU (Intersection over Union), также известен как Jaccard Index — это метрика, используемая для оценки качества предсказаний моделей, особенно в компьютерном зрении для задач обнаружения объектов (object detection) и семантической сегментации. IoU измеряет, насколько хорошо предсказанный объект совпадает с истинным объектом.
Математическое определение
Формула
IoU = Area of Intersection / Area of Union
= |Pred AND True| / |Pred OR True|
Визуально:
Предсказанный bbox (красный) Истинный bbox (синий)
Intersection (пересечение)
/\\
____/ \\____
|___ /\\ ___| <- Union (объединение)
|/____\\|
IoU = (жёлтая площадь) / (вся затенённая площадь)
IoU для Bounding Boxes (Object Detection)
Пример расчёта с прямоугольниками
import numpy as np
from matplotlib.patches import Rectangle
import matplotlib.pyplot as plt
def bbox_iou(box1, box2):
"""
Вычислить IoU для двух bounding box-ов
box: [x1, y1, x2, y2] — координаты левого верхнего и правого нижнего углов
"""
# Вычислить координаты пересечения
xi1 = max(box1[0], box2[0])
yi1 = max(box1[1], box2[1])
xi2 = min(box1[2], box2[2])
yi2 = min(box1[3], box2[3])
# Если нет пересечения, IoU = 0
if xi2 < xi1 or yi2 < yi1:
return 0.0
# Площадь пересечения
intersection_area = (xi2 - xi1) * (yi2 - yi1)
# Площадь каждого бокса
box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
# Площадь объединения (Union)
union_area = box1_area + box2_area - intersection_area
# IoU
iou = intersection_area / union_area
return iou
# Пример
pred_box = [50, 50, 200, 200] # Предсказание: x1, y1, x2, y2
true_box = [100, 100, 250, 250] # Истинный бокс
iou = bbox_iou(pred_box, true_box)
print(f'IoU: {iou:.4f}')
# Визуализация
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
ax.add_patch(Rectangle((pred_box[0], pred_box[1]),
pred_box[2] - pred_box[0],
pred_box[3] - pred_box[1],
linewidth=2, edgecolor='red', facecolor='none', label='Predicted'))
ax.add_patch(Rectangle((true_box[0], true_box[1]),
true_box[2] - true_box[0],
true_box[3] - true_box[1],
linewidth=2, edgecolor='blue', facecolor='none', label='Ground Truth'))
ax.set_xlim(0, 300)
ax.set_ylim(0, 300)
ax.set_aspect('equal')
ax.legend()
ax.set_title(f'IoU = {iou:.4f}')
plt.show()
Пример расчёта вручную
Предсказанный бокс: [50, 50, 200, 200]
Истинный бокс: [100, 100, 250, 250]
Пересечение:
x1 = max(50, 100) = 100
y1 = max(50, 100) = 100
x2 = min(200, 250) = 200
y2 = min(200, 250) = 200
Intersection Area = (200 - 100) * (200 - 100) = 100 * 100 = 10000
Площади:
Pred Area = (200 - 50) * (200 - 50) = 150 * 150 = 22500
True Area = (250 - 100) * (250 - 100) = 150 * 150 = 22500
Union Area = 22500 + 22500 - 10000 = 35000
IoU = 10000 / 35000 = 0.2857
IoU для семантической сегментации (Pixel-level)
Работа с масками пиксельного уровня
import numpy as np
from sklearn.metrics import jaccard_score
def mask_iou(pred_mask, true_mask):
"""
Вычислить IoU для масок пикселей
pred_mask: предсказанная маска (2D/3D массив с 0 и 1)
true_mask: истинная маска
"""
# Пересечение
intersection = np.logical_and(pred_mask, true_mask).sum()
# Объединение
union = np.logical_or(pred_mask, true_mask).sum()
# Если оба массива нулевые
if union == 0:
return 1.0 if intersection == 0 else 0.0
return intersection / union
# Пример
pred_mask = np.array([
[0, 1, 1, 0],
[1, 1, 1, 0],
[1, 1, 0, 0],
[0, 0, 0, 0]
])
true_mask = np.array([
[0, 1, 1, 1],
[0, 1, 1, 1],
[0, 1, 1, 0],
[0, 0, 0, 0]
])
iou = mask_iou(pred_mask, true_mask)
print(f'IoU: {iou:.4f}')
# Альтернативно: использовать sklearn
iou_sklearn = jaccard_score(true_mask.flatten(), pred_mask.flatten())
print(f'IoU (sklearn): {iou_sklearn:.4f}')
mAP (Mean Average Precision) — использует IoU
В object detection используется метрика mAP, которая основана на IoU с порогом (обычно IoU > 0.5).
def calculate_map(predictions, ground_truths, iou_threshold=0.5):
"""
predictions: список [box, confidence, class_id]
ground_truths: список [box, class_id]
"""
# Сортировать предсказания по confidence
predictions = sorted(predictions, key=lambda x: x[1], reverse=True)
tp = [] # True Positives
fp = [] # False Positives
for pred_box, confidence, pred_class in predictions:
max_iou = 0
matched_gt = None
# Найти лучший совпадающий ground truth
for gt_box, gt_class in ground_truths:
if pred_class != gt_class:
continue
iou = bbox_iou(pred_box, gt_box)
if iou > max_iou:
max_iou = iou
matched_gt = (gt_box, gt_class)
# Проверить, превышает ли IoU порог
if max_iou > iou_threshold:
tp.append(1)
fp.append(0)
if matched_gt:
ground_truths.remove(matched_gt) # Бокс уже использован
else:
tp.append(0)
fp.append(1)
# Вычислить Precision и Recall
tp_cumsum = np.cumsum(tp)
fp_cumsum = np.cumsum(fp)
recall = tp_cumsum / len(ground_truths)
precision = tp_cumsum / (tp_cumsum + fp_cumsum)
# AP = площадь под P-R кривой
ap = np.trapz(precision, recall)
return ap
Интерпретация значений IoU
IoU значение Интерпретация
───────────────── ──────────────────────────────────
0.9 - 1.0 Отлично, почти идеальное совпадение
0.7 - 0.9 Хорошо, сильное совпадение
0.5 - 0.7 Приемлемо, разумное совпадение
0.3 - 0.5 Слабо, слабое совпадение
0.0 - 0.3 Плохо, очень слабое совпадение
Сравнение IoU с другими метриками
| Метрика | Область применения | Формула |
|---|---|---|
| IoU | Object Detection, Segmentation | Intersection / Union |
| Dice | Segmentation | 2 * Intersection / (Pred + True) |
| Precision | Classification | TP / (TP + FP) |
| Recall | Classification | TP / (TP + FN) |
| mAP | Object Detection | Среднее AP по всем классам |
Когда использовать какую метрику
# IoU — лучше для object detection
# Потому что штрафует неправильную локализацию
# Dice — альтернатива для segmentation
# Формула Dice аналогична F1-score для пикселей
def dice_coefficient(pred_mask, true_mask):
intersection = np.logical_and(pred_mask, true_mask).sum()
return 2 * intersection / (pred_mask.sum() + true_mask.sum())
Практический пример с YOLO или Faster R-CNN
import torch
from torchvision.ops import box_iou
# Bounding boxes в формате [x1, y1, x2, y2]
pred_boxes = torch.tensor([
[50.0, 50.0, 200.0, 200.0],
[100.0, 100.0, 300.0, 300.0]
])
true_boxes = torch.tensor([
[100.0, 100.0, 250.0, 250.0]
])
# Вычислить IoU между всеми парами
iou_matrix = box_iou(pred_boxes, true_boxes)
print(f'IoU Matrix:\n{iou_matrix}')
# Максимальное совпадение для каждого предсказания
max_iou, _ = torch.max(iou_matrix, dim=1)
print(f'Max IoU for each prediction: {max_iou}')
Выводы
- IoU — универсальная метрика для задач локализации (detection, segmentation)
- Формула простая: пересечение / объединение
- Диапазон: от 0 (нет совпадения) до 1 (идеальное совпадение)
- IoU >= 0.5 — стандартный порог для object detection
- Лучше использовать IoU, чем просто accuracy для локализационных задач
- mAP в detection — это среднее precision при разных IoU порогах