Move IoU functions to metrics.py (#3820)
parent
3213d8713f
commit
5ea771d93d
|
@ -25,7 +25,7 @@ import torchvision
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from utils.google_utils import gsutil_getsize
|
from utils.google_utils import gsutil_getsize
|
||||||
from utils.metrics import fitness
|
from utils.metrics import box_iou, fitness
|
||||||
from utils.torch_utils import init_torch_seeds
|
from utils.torch_utils import init_torch_seeds
|
||||||
|
|
||||||
# Settings
|
# Settings
|
||||||
|
@ -469,84 +469,6 @@ def clip_coords(boxes, img_shape):
|
||||||
boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3]) # y2
|
boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3]) # y2
|
||||||
|
|
||||||
|
|
||||||
def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7):
|
|
||||||
# Returns the IoU of box1 to box2. box1 is 4, box2 is nx4
|
|
||||||
box2 = box2.T
|
|
||||||
|
|
||||||
# Get the coordinates of bounding boxes
|
|
||||||
if x1y1x2y2: # x1, y1, x2, y2 = box1
|
|
||||||
b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
|
|
||||||
b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
|
|
||||||
else: # transform from xywh to xyxy
|
|
||||||
b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2
|
|
||||||
b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2
|
|
||||||
b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2
|
|
||||||
b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2
|
|
||||||
|
|
||||||
# Intersection area
|
|
||||||
inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
|
|
||||||
(torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)
|
|
||||||
|
|
||||||
# Union Area
|
|
||||||
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
|
|
||||||
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
|
|
||||||
union = w1 * h1 + w2 * h2 - inter + eps
|
|
||||||
|
|
||||||
iou = inter / union
|
|
||||||
if GIoU or DIoU or CIoU:
|
|
||||||
cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width
|
|
||||||
ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height
|
|
||||||
if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
|
|
||||||
c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared
|
|
||||||
rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 +
|
|
||||||
(b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center distance squared
|
|
||||||
if DIoU:
|
|
||||||
return iou - rho2 / c2 # DIoU
|
|
||||||
elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
|
|
||||||
v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)
|
|
||||||
with torch.no_grad():
|
|
||||||
alpha = v / (v - iou + (1 + eps))
|
|
||||||
return iou - (rho2 / c2 + v * alpha) # CIoU
|
|
||||||
else: # GIoU https://arxiv.org/pdf/1902.09630.pdf
|
|
||||||
c_area = cw * ch + eps # convex area
|
|
||||||
return iou - (c_area - union) / c_area # GIoU
|
|
||||||
else:
|
|
||||||
return iou # IoU
|
|
||||||
|
|
||||||
|
|
||||||
def box_iou(box1, box2):
|
|
||||||
# https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py
|
|
||||||
"""
|
|
||||||
Return intersection-over-union (Jaccard index) of boxes.
|
|
||||||
Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
|
|
||||||
Arguments:
|
|
||||||
box1 (Tensor[N, 4])
|
|
||||||
box2 (Tensor[M, 4])
|
|
||||||
Returns:
|
|
||||||
iou (Tensor[N, M]): the NxM matrix containing the pairwise
|
|
||||||
IoU values for every element in boxes1 and boxes2
|
|
||||||
"""
|
|
||||||
|
|
||||||
def box_area(box):
|
|
||||||
# box = 4xn
|
|
||||||
return (box[2] - box[0]) * (box[3] - box[1])
|
|
||||||
|
|
||||||
area1 = box_area(box1.T)
|
|
||||||
area2 = box_area(box2.T)
|
|
||||||
|
|
||||||
# inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2)
|
|
||||||
inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2)
|
|
||||||
return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter)
|
|
||||||
|
|
||||||
|
|
||||||
def wh_iou(wh1, wh2):
|
|
||||||
# Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2
|
|
||||||
wh1 = wh1[:, None] # [N,1,2]
|
|
||||||
wh2 = wh2[None] # [1,M,2]
|
|
||||||
inter = torch.min(wh1, wh2).prod(2) # [N,M]
|
|
||||||
return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter)
|
|
||||||
|
|
||||||
|
|
||||||
def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False,
|
def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False,
|
||||||
labels=(), max_det=300):
|
labels=(), max_det=300):
|
||||||
"""Runs Non-Maximum Suppression (NMS) on inference results
|
"""Runs Non-Maximum Suppression (NMS) on inference results
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
|
|
||||||
from utils.general import bbox_iou
|
from utils.metrics import bbox_iou
|
||||||
from utils.torch_utils import is_parallel
|
from utils.torch_utils import is_parallel
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# Model validation metrics
|
# Model validation metrics
|
||||||
|
|
||||||
|
import math
|
||||||
import warnings
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
@ -7,8 +8,6 @@ import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from . import general
|
|
||||||
|
|
||||||
|
|
||||||
def fitness(x):
|
def fitness(x):
|
||||||
# Model fitness as a weighted combination of metrics
|
# Model fitness as a weighted combination of metrics
|
||||||
|
@ -128,7 +127,7 @@ class ConfusionMatrix:
|
||||||
detections = detections[detections[:, 4] > self.conf]
|
detections = detections[detections[:, 4] > self.conf]
|
||||||
gt_classes = labels[:, 0].int()
|
gt_classes = labels[:, 0].int()
|
||||||
detection_classes = detections[:, 5].int()
|
detection_classes = detections[:, 5].int()
|
||||||
iou = general.box_iou(labels[:, 1:], detections[:, :4])
|
iou = box_iou(labels[:, 1:], detections[:, :4])
|
||||||
|
|
||||||
x = torch.where(iou > self.iou_thres)
|
x = torch.where(iou > self.iou_thres)
|
||||||
if x[0].shape[0]:
|
if x[0].shape[0]:
|
||||||
|
@ -184,6 +183,84 @@ class ConfusionMatrix:
|
||||||
print(' '.join(map(str, self.matrix[i])))
|
print(' '.join(map(str, self.matrix[i])))
|
||||||
|
|
||||||
|
|
||||||
|
def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7):
|
||||||
|
# Returns the IoU of box1 to box2. box1 is 4, box2 is nx4
|
||||||
|
box2 = box2.T
|
||||||
|
|
||||||
|
# Get the coordinates of bounding boxes
|
||||||
|
if x1y1x2y2: # x1, y1, x2, y2 = box1
|
||||||
|
b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
|
||||||
|
b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
|
||||||
|
else: # transform from xywh to xyxy
|
||||||
|
b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2
|
||||||
|
b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2
|
||||||
|
b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2
|
||||||
|
b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2
|
||||||
|
|
||||||
|
# Intersection area
|
||||||
|
inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
|
||||||
|
(torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)
|
||||||
|
|
||||||
|
# Union Area
|
||||||
|
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
|
||||||
|
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
|
||||||
|
union = w1 * h1 + w2 * h2 - inter + eps
|
||||||
|
|
||||||
|
iou = inter / union
|
||||||
|
if GIoU or DIoU or CIoU:
|
||||||
|
cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width
|
||||||
|
ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height
|
||||||
|
if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
|
||||||
|
c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared
|
||||||
|
rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 +
|
||||||
|
(b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center distance squared
|
||||||
|
if DIoU:
|
||||||
|
return iou - rho2 / c2 # DIoU
|
||||||
|
elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
|
||||||
|
v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)
|
||||||
|
with torch.no_grad():
|
||||||
|
alpha = v / (v - iou + (1 + eps))
|
||||||
|
return iou - (rho2 / c2 + v * alpha) # CIoU
|
||||||
|
else: # GIoU https://arxiv.org/pdf/1902.09630.pdf
|
||||||
|
c_area = cw * ch + eps # convex area
|
||||||
|
return iou - (c_area - union) / c_area # GIoU
|
||||||
|
else:
|
||||||
|
return iou # IoU
|
||||||
|
|
||||||
|
|
||||||
|
def box_iou(box1, box2):
|
||||||
|
# https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py
|
||||||
|
"""
|
||||||
|
Return intersection-over-union (Jaccard index) of boxes.
|
||||||
|
Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
|
||||||
|
Arguments:
|
||||||
|
box1 (Tensor[N, 4])
|
||||||
|
box2 (Tensor[M, 4])
|
||||||
|
Returns:
|
||||||
|
iou (Tensor[N, M]): the NxM matrix containing the pairwise
|
||||||
|
IoU values for every element in boxes1 and boxes2
|
||||||
|
"""
|
||||||
|
|
||||||
|
def box_area(box):
|
||||||
|
# box = 4xn
|
||||||
|
return (box[2] - box[0]) * (box[3] - box[1])
|
||||||
|
|
||||||
|
area1 = box_area(box1.T)
|
||||||
|
area2 = box_area(box2.T)
|
||||||
|
|
||||||
|
# inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2)
|
||||||
|
inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2)
|
||||||
|
return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter)
|
||||||
|
|
||||||
|
|
||||||
|
def wh_iou(wh1, wh2):
|
||||||
|
# Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2
|
||||||
|
wh1 = wh1[:, None] # [N,1,2]
|
||||||
|
wh2 = wh2[None] # [1,M,2]
|
||||||
|
inter = torch.min(wh1, wh2).prod(2) # [N,M]
|
||||||
|
return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter)
|
||||||
|
|
||||||
|
|
||||||
# Plots ----------------------------------------------------------------------------------------------------------------
|
# Plots ----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()):
|
def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()):
|
||||||
|
|
Loading…
Reference in New Issue