前言
在本文中我将对bubbliiiing的yolo系列的代码进行解析。由于bubbliiiing的历代代码具有很强的相似性,因此我在这选择较为 简单的yolov5-v6.1(pytorch)版本的代码为例子为大家带来即插即用的代码更迭,便于大家作试验”写“论文。
在这里我的重点放在代码的迁移上,原理部分大家参考各iou的论文,链接如下
GIoU: arxiv.org/pdf/1902.09…
SIoU: arxiv.org/pdf/2205.12…
DIou&CIoU: arxiv.org/abs/1911.08…
iou解析
bubbliiiing解析:
预测与目标(pred(b1), target(b2))的shape组成:shape=(batch, feat_w, feat_h, anchor_num, 4) 其中解析出来的b1_xy为预测框的中心点坐标,b1_wh为预测框的宽和高,因此在计算x_min、y_min、x_max、ymin时需要注意转换。
解析提取部分代码:
# 求出框左上角右下角
b_xy = b[..., :2]
b_wh = b[..., 2:4]
b_wh_half = b_wh / 2.
b_mins = b_xy - b_wh_half
b_maxes = b_xy + b1_wh_half
b_x1 = b_mins[..., 0] # x_min
b_y1 = b_mins[..., 1] # y_max
b_x2 = b_maxes[..., 0] # x_max
b_y2 = b_maxes[..., 1] # y_max
我们别对b1 和 b2 的x_min、y_min、x_max、ymin提取后传入到iou全家桶函数中
iou集迁移
结合上篇文章内的内容,我们将计算迁移到torch上来。
def bbox_ious(b1_x1, b1_y1, b1_x2, b1_y2,b2_x1, b2_y1, b2_x2, b2_y2, GIoU=False, DIoU=False, CIoU=False, SIoU=True):
eps = 1e-7
# 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 or SIoU:
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 SIoU:
s_cw = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5
s_ch = (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5
sigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)
sin_alpha_1 = torch.abs(s_cw) / sigma
sin_alpha_2 = torch.abs(s_ch) / sigma
threshold = pow(2, 0.5) / 2
sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)
# angle_cost = 1 - 2 * torch.pow( torch.sin(torch.arcsin(sin_alpha) - np.pi/4), 2)
angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - np.pi / 2)
rho_x = (s_cw / cw) ** 2
rho_y = (s_ch / ch) ** 2
gamma = angle_cost - 2
distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)
omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)
omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)
shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)
return iou - 0.5 * (distance_cost + shape_cost)
if CIoU or DIoU:
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:
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:
c_area = cw * ch + eps # convex area
return iou - (c_area - union) / c_area # GIoU
else:
return iou # IoU
组合
def box_giou(self, b1, b2):
# 求出预测框左上角右下角
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
b1_x1 = b1_mins[..., 0] # x_min
b1_y1 = b1_mins[..., 1] # y_max
b1_x2 = b1_maxes[..., 0] # x_max
b1_y2 = b1_maxes[..., 1] # y_max
# 求出真实框左上角右下角
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
b2_x1 = b2_mins[..., 0] # x_min
b2_y1 = b2_mins[..., 1] # y_max
b2_x2 = b2_maxes[..., 0] # x_max
b2_y2 = b2_maxes[..., 1] # y_max
ious = bbox_ious(b1_x1, b1_y1, b1_x2, b1_y2, b2_x1, b2_y1, b2_x2, b2_y2,GIoU=False, DIoU=False, CIoU=False, SIoU=True)
return ious
对任意数据集测试结果如下:
结尾
经笔者测试,上述迁移代码可以正常运行,且loss曲线可收敛。代码运行环境大家可以自行参考bubbliiiing的讲解。如大家遇到一些迁移过程的问题 可以在本文下方留言,我将会一一解答!希望本文能够帮助大家。另,由于本文写的较为匆忙,没有仔细校对文中的错误,还望大家发现了错误能够及时指正!谢谢!