@@ -25,7 +25,7 @@ import torchvision | |||
import yaml | |||
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 | |||
# Settings | |||
@@ -469,84 +469,6 @@ def clip_coords(boxes, img_shape): | |||
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, | |||
labels=(), max_det=300): | |||
"""Runs Non-Maximum Suppression (NMS) on inference results |
@@ -3,7 +3,7 @@ | |||
import torch | |||
import torch.nn as nn | |||
from utils.general import bbox_iou | |||
from utils.metrics import bbox_iou | |||
from utils.torch_utils import is_parallel | |||
@@ -1,5 +1,6 @@ | |||
# Model validation metrics | |||
import math | |||
import warnings | |||
from pathlib import Path | |||
@@ -7,8 +8,6 @@ import matplotlib.pyplot as plt | |||
import numpy as np | |||
import torch | |||
from . import general | |||
def fitness(x): | |||
# Model fitness as a weighted combination of metrics | |||
@@ -128,7 +127,7 @@ class ConfusionMatrix: | |||
detections = detections[detections[:, 4] > self.conf] | |||
gt_classes = labels[:, 0].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) | |||
if x[0].shape[0]: | |||
@@ -184,6 +183,84 @@ class ConfusionMatrix: | |||
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 ---------------------------------------------------------------------------------------------------------------- | |||
def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()): |