def iou_t(boxes1, boxes2):
"""IoU vectorisee (N,4) x (M,4) en (x0,y0,w,h) -> (N,M)."""
b1, b2 = boxes1.to(DEVICE), boxes2.to(DEVICE)
ix0 = torch.maximum(b1[:, None, 0], b2[None, :, 0])
iy0 = torch.maximum(b1[:, None, 1], b2[None, :, 1])
ix1 = torch.minimum(b1[:, None, 0] + b1[:, None, 2], b2[None, :, 0] + b2[None, :, 2])
iy1 = torch.minimum(b1[:, None, 1] + b1[:, None, 3], b2[None, :, 1] + b2[None, :, 3])
iw = (ix1 - ix0).clamp(min=0)
ih = (iy1 - iy0).clamp(min=0)
inter = iw * ih
union = b1[:, None, 2] * b1[:, None, 3] + b2[None, :, 2] * b2[None, :, 3] - inter
return inter / (union + 1e-9)
def predict_boxes(model, idx):
"""Boites (N,4) xyxy + scores d'une image, seuils du 4.2c."""
r = model.predict(str(DS / "images" / "val" / f"{idx:05d}.png"),
conf=0.5, iou=0.45, imgsz=IMG, verbose=False,
device=DEVICE)[0].boxes
return (torch.tensor(r.xyxy.tolist(), dtype=torch.float32),
torch.tensor(r.conf.tolist(), dtype=torch.float32))
def xyxy_yolo(b_xywh):
t = torch.tensor(b_xywh, dtype=torch.float32)
return torch.stack([t[:, 0], t[:, 1], t[:, 0] + t[:, 2], t[:, 1] + t[:, 3]], dim=1)
def collect_pr_yolo(model, B, iou_thr=0.5):
tp_s, fp_s, ngt = [], [], 0
for i in range(len(B)):
dets, dscores = predict_boxes(model, i)
gts = xyxy_yolo(B[i])
matched = torch.zeros(len(gts), dtype=torch.bool)
for d in dscores.argsort(descending=True).tolist():
if len(gts):
ious = iou_t(dets[d:d + 1], gts)[0]
ious[matched] = -1
g = int(ious.argmax())
if ious[g] >= iou_thr:
matched[g] = True
tp_s.append(float(dscores[d]))
continue
fp_s.append(float(dscores[d]))
ngt += len(B[i])
return tp_s, fp_s, ngt
def ap_voc(tp_s, fp_s, ngt):
flags = np.array([1] * len(tp_s) + [0] * len(fp_s), dtype=np.float64)
scores = np.array(tp_s + fp_s, dtype=np.float64)
order = np.argsort(-scores)
flags, scores = flags[order], scores[order]
ctp, cfp = np.cumsum(flags), np.cumsum(1 - flags)
rec = ctp / max(ngt, 1)
prec = ctp / np.maximum(ctp + cfp, 1e-9)
mrec = np.concatenate([[0], rec, [1]])
mpre = np.concatenate([[0], prec, [0]])
for i in range(len(mpre) - 2, -1, -1):
mpre[i] = max(mpre[i], mpre[i + 1])
ap10 = float(np.sum((mrec[1:] - mrec[:-1]) * mpre[1:]))
ap07 = 0.0
for t in np.linspace(0, 1, 11):
sel = rec >= t
ap07 += (prec[sel].max() if sel.any() else 0.0) / 11
return ap07, ap10, rec, prec
tp_s, fp_s, ngt = collect_pr_yolo(MODEL_5N, [b.tolist() for b in Bva])
ap07, ap10, rec, prec = ap_voc(tp_s, fp_s, ngt)
print(f"yolov5nu mAP@0.5 sur 400 images / {ngt} objets GT : "
f"VOC07 11-point {ap07:.3f} | VOC10 all-point {ap10:.3f}")