损失函数代码实现和优缺点对比
- 一、几种IOU损失的优缺点对比
- 二、代码实现
-
- 1、IOU
- 2、DIOU
- 3、GIOU
- 4、CIOU
一、几种IOU损失的优缺点对比
二、代码实现
1、IOU
import numpy as np
def bboxes_iou(boxes1,boxes2):
'''
cal IOU of two boxes or batch boxes
such as: (1)
boxes1 = np.asarray([[0,0,5,5],[0,0,10,10],[0,0,10,10]])
boxes2 = np.asarray([[0,0,5,5]])
and res is [1. 0.25 0.25]
(2)
boxes1 = np.asarray([[0,0,5,5],[0,0,10,10],[0,0,10,10]])
boxes2 = np.asarray([[0,0,5,5],[0,0,10,10],[0,0,10,10]])
and res is [1. 1. 1.]
:param boxes1:[xmin,ymin,xmax,ymax] or
[[xmin,ymin,xmax,ymax],[xmin,ymin,xmax,ymax],...]
:param boxes2:[xmin,ymin,xmax,ymax]
:return:
'''
boxes1Area = (boxes1[...,2]-boxes1[...,0])*(boxes1[...,3]-boxes1[...,1])
boxes2Area = (boxes2[..., 2] - boxes2[..., 0]) * (boxes2[..., 3] - boxes2[..., 1])
left_up = np.maximum(boxes1[...,:2],boxes2[...,:2])
right_down = np.minimum(boxes1[...,2:],boxes2[...,2:])
inter_section = np.maximum(right_down-left_up,0.0)
inter_area = inter_section[...,0] * inter_section[...,1]
union_area = boxes1Area+boxes2Area-inter_area
ious = np.maximum(1.0*inter_area/union_area,np.finfo(np.float32).eps)
return ious
2、DIOU
import torch
def box_diou(b1, b2):
"""
输入为:
----------
b1: tensor, shape=(batch, feat_w, feat_h, anchor_num, 4), xywh
b2: tensor, shape=(batch, feat_w, feat_h, anchor_num, 4), xywh
返回为:
-------
ciou: tensor, shape=(batch, feat_w, feat_h, anchor_num, 1)
"""
b1_xy = b1[..., :2]
b1_wh = b1[..., 2:4]
b1_wh_half = b1_wh / 2.
b1_mins = b1_xy - b1_wh_half
b1_maxes = b1_xy + b1_wh_half
b2_xy = b2[..., :2]
b2_wh = b2[..., 2:4]
b2_wh_half = b2_wh / 2.
b2_mins = b2_xy - b2_wh_half
b2_maxes = b2_xy + b2_wh_half
intersect_mins = torch.max(b1_mins, b2_mins)
intersect_maxes = torch.min(b1_maxes, b2_maxes)
intersect_wh = torch.max(intersect_maxes - intersect_mins, torch.zeros_like(intersect_maxes))
intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]
b1_area = b1_wh[..., 0] * b1_wh[..., 1]
b2_area = b2_wh[..., 0] * b2_wh[..., 1]
union_area = b1_area + b2_area - intersect_area
iou = intersect_area / torch.clamp(union_area, min=1e-6)
center_distance = torch.sum(torch.pow((b1_xy - b2_xy), 2), axis=-1)
enclose_mins = torch.min(b1_mins, b2_mins)
enclose_maxes = torch.max(b1_maxes, b2_maxes)
enclose_wh = torch.max(enclose_maxes - enclose_mins, torch.zeros_like(intersect_maxes))
enclose_diagonal = torch.sum(torch.pow(enclose_wh, 2), axis=-1)
diou = iou - 1.0 * (center_distance) / torch.clamp(enclose_diagonal, min=1e-6)
return diou
import numpy as np
def bboxes_diou(boxes1,boxes2):
'''
cal DIOU of two boxes or batch boxes
:param boxes1:[xmin,ymin,xmax,ymax] or
[[xmin,ymin,xmax,ymax],[xmin,ymin,xmax,ymax],...]
:param boxes2:[xmin,ymin,xmax,ymax]
:return:
'''
boxes1Area = (boxes1[...,2]-boxes1[...,0])*(boxes1[...,3]-boxes1[...,1])
boxes2Area = (boxes2[..., 2] - boxes2[..., 0]) * (boxes2[..., 3] - boxes2[..., 1])
left_up = np.maximum(boxes1[...,:2],boxes2[...,:2])
right_down = np.minimum(boxes1[...,2:],boxes2[...,2:])
inter_section = np.maximum(right_down-left_up,0.0)
inter_area = inter_section[...,0] * inter_section[...,1]
union_area = boxes1Area+boxes2Area-inter_area
ious = np.maximum(1.0*inter_area/union_area,np.finfo(np.float32).eps)
outer_left_up = np.minimum(boxes1[..., :2], boxes2[..., :2])
outer_right_down = np.maximum(boxes1[..., 2:], boxes2[..., 2:])
outer = np.maximum(outer_right_down - outer_left_up, 0.0)
outer_diagonal_line = np.square(outer[...,0]) + np.square(outer[...,1])
boxes1_center = (boxes1[..., :2] + boxes1[...,2:]) * 0.5
boxes2_center = (boxes2[..., :2] + boxes2[...,2:]) * 0.5
center_dis = np.square(boxes1_center[...,0]-boxes2_center[...,0]) +\
np.square(boxes1_center[...,1]-boxes2_center[...,1])
dious = ious - center_dis / outer_diagonal_line
return dious
3、GIOU
import numpy as np
def bboxes_giou(boxes1,boxes2):
'''
cal GIOU of two boxes or batch boxes
such as: (1)
boxes1 = np.asarray([[0,0,5,5],[0,0,10,10],[15,15,25,25]])
boxes2 = np.asarray([[5,5,10,10]])
and res is [-0.49999988 0.25 -0.68749988]
(2)
boxes1 = np.asarray([[0,0,5,5],[0,0,10,10],[0,0,10,10]])
boxes2 = np.asarray([[0,0,5,5],[0,0,10,10],[0,0,10,10]])
and res is [1. 1. 1.]
:param boxes1:[xmin,ymin,xmax,ymax] or
[[xmin,ymin,xmax,ymax],[xmin,ymin,xmax,ymax],...]
:param boxes2:[xmin,ymin,xmax,ymax]
:return:
'''
boxes1Area = (boxes1[...,2]-boxes1[...,0])*(boxes1[...,3]-boxes1[...,1])
boxes2Area = (boxes2[..., 2] - boxes2[..., 0]) * (boxes2[..., 3] - boxes2[..., 1])
left_up = np.maximum(boxes1[...,:2],boxes2[...,:2])
right_down = np.minimum(boxes1[...,2:],boxes2[...,2:])
inter_section = np.maximum(right_down-left_up,0.0)
inter_area = inter_section[...,0] * inter_section[...,1]
union_area = boxes1Area+boxes2Area-inter_area
ious = np.maximum(1.0*inter_area/union_area,np.finfo(np.float32).eps)
enclose_left_up = np.minimum(boxes1[..., :2], boxes2[..., :2])
enclose_right_down = np.maximum(boxes1[..., 2:], boxes2[..., 2:])
enclose = np.maximum(enclose_right_down - enclose_left_up, 0.0)
enclose_area = enclose[..., 0] * enclose[..., 1]
gious = ious - 1.0 * (enclose_area - union_area) / enclose_area
return gious
import torch
def bboxes_giou(box1, box2):
"""
giou loss
:param box1: tensor [batch, w, h, num_anchor, 4], xywh 预测值
:param box2: tensor [batch, w, h, num_anchor, 4], xywh 真实值
:return: tensor [batch, w, h, num_anchor, 1]
"""
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
box1_xy, box1_wh = box1[..., :2], box1[..., 2:4]
box1_wh_half = box1_wh / 2.
box1_mines = box1_xy - box1_wh_half
box1_maxes = box1_xy + box1_wh_half
box2_xy, box2_wh = box2[..., :2], box2[..., 2:4]
box2_wh_half = box2_wh / 2.
box2_mines = box2_xy - box2_wh_half
box2_maxes = box2_xy + box2_wh_half
intersect_mines = torch.max(box1_mines, box2_mines)
intersect_maxes = torch.min(box1_maxes, box2_maxes)
intersect_wh = torch.max(intersect_maxes-intersect_mines, torch.zeros_like(intersect_maxes))
intersect_area = intersect_wh[..., 0]*intersect_wh[..., 1]
box1_area = box1_wh[..., 0]*box1_wh[..., 1]
box2_area = box2_wh[..., 0]*box2_wh[..., 1]
union_area = box1_area+box2_area-intersect_area
iou = intersect_area / torch.clamp(union_area, min=1e-6)
cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1)
ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1)
c_area = cw * ch + 1e-16
giou = iou - (c_area - union_area) / c_area
return giou
4、CIOU
import numpy as np
def bboxes_ciou(boxes1,boxes2):
'''
cal CIOU of two boxes or batch boxes
:param boxes1:[xmin,ymin,xmax,ymax] or
[[xmin,ymin,xmax,ymax],[xmin,ymin,xmax,ymax],...]
:param boxes2:[xmin,ymin,xmax,ymax]
:return:
'''
boxes1Area = (boxes1[...,2]-boxes1[...,0])*(boxes1[...,3]-boxes1[...,1])
boxes2Area = (boxes2[..., 2] - boxes2[..., 0]) * (boxes2[..., 3] - boxes2[..., 1])
left_up = np.maximum(boxes1[...,:2],boxes2[...,:2])
right_down = np.minimum(boxes1[...,2:],boxes2[...,2:])
inter_section = np.maximum(right_down-left_up,0.0)
inter_area = inter_section[...,0] * inter_section[...,1]
union_area = boxes1Area+boxes2Area-inter_area
ious = np.maximum(1.0*inter_area/union_area,np.finfo(np.float32).eps)
outer_left_up = np.minimum(boxes1[..., :2], boxes2[..., :2])
outer_right_down = np.maximum(boxes1[..., 2:], boxes2[..., 2:])
outer = np.maximum(outer_right_down - outer_left_up, 0.0)
outer_diagonal_line = np.square(outer[...,0]) + np.square(outer[...,1])
boxes1_center = (boxes1[..., :2] + boxes1[...,2:]) * 0.5
boxes2_center = (boxes2[..., :2] + boxes2[...,2:]) * 0.5
center_dis = np.square(boxes1_center[...,0]-boxes2_center[...,0]) +\
np.square(boxes1_center[...,1]-boxes2_center[...,1])
boxes1_size = np.maximum(boxes1[...,2:]-boxes1[...,:2],0.0)
boxes2_size = np.maximum(boxes2[..., 2:] - boxes2[..., :2], 0.0)
v = (4.0/np.square(np.pi)) * np.square((
np.arctan((boxes1_size[...,0]/boxes1_size[...,1])) -
np.arctan((boxes2_size[..., 0] / boxes2_size[..., 1])) ))
alpha = v / (1-ious+v)
cious = ious - (center_dis / outer_diagonal_line + alpha*v)
return cious
import torch
import math
def box_ciou(b1, b2):
"""
输入为:
----------
b1: tensor, shape=(batch, feat_w, feat_h, anchor_num, 4), xywh
b2: tensor, shape=(batch, feat_w, feat_h, anchor_num, 4), xywh
返回为:
-------
ciou: tensor, shape=(batch, feat_w, feat_h, anchor_num, 1)
"""
b1_xy = b1[..., :2]
b1_wh = b1[..., 2:4]
b1_wh_half = b1_wh/2.
b1_mins = b1_xy - b1_wh_half
b1_maxes = b1_xy + b1_wh_half
b2_xy = b2[..., :2]
b2_wh = b2[..., 2:4]
b2_wh_half = b2_wh/2.
b2_mins = b2_xy - b2_wh_half
b2_maxes = b2_xy + b2_wh_half
intersect_mins = torch.max(b1_mins, b2_mins)
intersect_maxes = torch.min(b1_maxes, b2_maxes)
intersect_wh = torch.max(intersect_maxes - intersect_mins, torch.zeros_like(intersect_maxes))
intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]
b1_area = b1_wh[..., 0] * b1_wh[..., 1]
b2_area = b2_wh[..., 0] * b2_wh[..., 1]
union_area = b1_area + b2_area - intersect_area
iou = intersect_area / torch.clamp(union_area,min = 1e-6)
center_distance = torch.sum(torch.pow((b1_xy - b2_xy), 2), axis=-1)
enclose_mins = torch.min(b1_mins, b2_mins)
enclose_maxes = torch.max(b1_maxes, b2_maxes)
enclose_wh = torch.max(enclose_maxes - enclose_mins, torch.zeros_like(intersect_maxes))
enclose_diagonal = torch.sum(torch.pow(enclose_wh,2), axis=-1)
ciou = iou - 1.0 * (center_distance) / (enclose_diagonal + 1e-7)
v = (4 / (math.pi ** 2)) * torch.pow((torch.atan(b1_wh[..., 0]/b1_wh[..., 1]) - torch.atan(b2_wh[..., 0]/b2_wh[..., 1])), 2)
alpha = v / (1.0 - iou + v)
ciou = ciou - alpha * v
return ciou