在尝试做simota的标签分配时,发现会出现nan值,仔细对head部分的代码跟踪,发现出现在计算iou的函数里,以下是发现的过程。
下图是sim-ota分配出的正样本点。
首先,自己选取一张图片,用cv2去读取,并根据图片名字,拿coco的api去查找对应的注释(做循环,找到该图片id,在get注释,拿到标签框gt)。
然后,加载训练好的权重,以及初始化模型,就可以model.train(). 然后我们在对应的head里就可以做可视化了。取消掉如下代码的注释,就可以画出上图。
import cv2
import random
import numpy as np
img = (imgs[batch_idx].cpu().numpy().transpose(1,2,0)) #我们的批是1,B=1
img = img.astype(np.uint8)
img = np.clip(img.copy(),0,255)
coords = np.stack([(x_shifts*expanded_strides)[0][fg_mask].cpu().numpy(),(y_shifts*expanded_strides)[0][fg_mask].cpu().numpy()], 1)
coords[:,0] = (x_shifts*expanded_strides+0.5*expanded_strides)[0][fg_mask].cpu().numpy()
coords[:,1] = (y_shifts*expanded_strides+0.5*expanded_strides)[0][fg_mask].cpu().numpy()
for coord in coords:
cv2.circle(img, (int(coord[0]), int(coord[1])), 3, (255,0,0), -1)
for bbox in gt_bboxes_per_image:
cv2.rectangle(img, (int(bbox[0]-bbox[2]/2),int(bbox[1]-bbox[3]/2)),(int(bbox[0]+bbox[2]/2),int(bbox[1]+bbox[3]/2)), (0,255,0),2)
cv2.imwrite('/data/debug_vis/'+str(random.randint(0,1000))+'.png', img[:,:,::-1])
但我们可以打印相关变量,得到如下信息:
最后的那一串张量就是所有尺度point拉直后,每个点是否被分配为正样本的bool值。大部分都不是,只有36个值应该为True。但是我们查看标签分配get_assignment的返回值:
会发现其中有nan。然后我们进一步去查看,发现nan最开始出现在计算预测框和GT框的iou的函数中,该函数为bboxes_iou:
def bboxes_iou(bboxes_a, bboxes_b, xyxy=True): # 批量计算GT框们和预测框们的IOU,最后得到一个矩阵,代表每一个gt和每一个预测的IOU
if bboxes_a.shape[1] != 4 or bboxes_b.shape[1] != 4:
raise IndexError
if xyxy:
tl = torch.max(bboxes_a[:, None, :2], bboxes_b[:, :2])
br = torch.min(bboxes_a[:, None, 2:], bboxes_b[:, 2:])
area_a = torch.prod(bboxes_a[:, 2:] - bboxes_a[:, :2], 1)
area_b = torch.prod(bboxes_b[:, 2:] - bboxes_b[:, :2], 1)
else:
tl = torch.max(
(bboxes_a[:, None, :2] - bboxes_a[:, None, 2:] / 2),
(bboxes_b[:, :2] - bboxes_b[:, 2:] / 2),
)
br = torch.min(
(bboxes_a[:, None, :2] + bboxes_a[:, None, 2:] / 2),
(bboxes_b[:, :2] + bboxes_b[:, 2:] / 2),
)
area_a = torch.prod(bboxes_a[:, 2:], 1)
area_b = torch.prod(bboxes_b[:, 2:], 1)
en = (tl < br).type(tl.type()).prod(dim=2)
area_i = torch.prod(br - tl, 2) * en # * ((tl < br).all())
return area_i / (area_a[:, None] + area_b - area_i)
进一步查看,我们发现,在计算交集的area_i=torch.prod() 这行,会第一次出现inf,导致后面的计算出现nan。如下:
print(torch.prod(br - tl, 2))
但查看该br-tl的值,我们发现仅仅只是一个40*8的数,为什么会出现inf?