前言
在本文中我将对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时需要注意转换。
解析提取部分代码:
ini
复制代码
# 求出框左上角右下角 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上来。
ini
复制代码
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
组合
ini
复制代码
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的讲解。如大家遇到一些迁移过程的问题 可以在本文下方留言,我将会一一解答!希望本文能够帮助大家。另,由于本文写的较为匆忙,没有仔细校对文中的错误,还望大家发现了错误能够及时指正!谢谢!