NMS
总结了霹雳吧啦Wz大佬讲的SSD
源码中的NMS
算法
for object in all objects:
while(object.numel()):
(1):首先滤除概率特别小(比如0.05)的目标
(2):将概率排序取出前200个(自己设置)目标框
(3):取出其中概率最大的框,并将其余199个框与之计算IOU
(4):选出那些IOU大于阈值0.5(自己设置)的目标框
(5):将最大的目标框的信息进行保存
(6):舍弃掉最大目标框以及第(4)步筛选出的目标框
...
直至该类别所有的box都被丢弃
(7)对所有的目标框进行排序(无论类别),选出概率最大的前100个
# 非极大值抑制算法
# scores_in (Tensor 8732 x nitems), 遍历返回每一列数据,即8732个目标的同一类别的概率
for i, score in enumerate(scores_in.split(1, 1)):
# skip background
if i == 0:
continue
# [8732, 1] -> [8732]
score = score.squeeze(1)
# 虑除预测概率小于0.05的目标
mask = score > 0.05
bboxes, score = bboxes_in[mask, :], score[mask]
if score.size(0) == 0:
continue
# 按照分数从小到大排序
score_sorted, score_idx_sorted = score.sort(dim=0)
# select max_output indices
score_idx_sorted = score_idx_sorted[-max_num:]
candidates = []
while score_idx_sorted.numel() > 0:
idx = score_idx_sorted[-1].item()
# 获取排名前score_idx_sorted名的bboxes信息 Tensor:[score_idx_sorted, 4]
bboxes_sorted = bboxes[score_idx_sorted, :]
# 获取排名第一的bboxes信息 Tensor:[4]
bboxes_idx = bboxes[idx, :].unsqueeze(dim=0)
# 计算前score_idx_sorted名的bboxes与第一名的bboxes的iou
iou_sorted = calc_iou_tensor(bboxes_sorted, bboxes_idx).squeeze()
# we only need iou < criteria
# 丢弃与第一名iou > criteria的所有目标(包括自己本身)
score_idx_sorted = score_idx_sorted[iou_sorted < criteria]
# 保存第一名的索引信息
candidates.append(idx)
# 保存该类别通过非极大值抑制后的目标信息
bboxes_out.append(bboxes[candidates, :]) # bbox坐标信息
scores_out.append(score[candidates]) # score信息
labels_out.extend([i] * len(candidates)) # 标签信息
if not bboxes_out: # 如果为空的话,返回空tensor,注意boxes对应的空tensor size,防止验证时出错
return [torch.empty(size=(0, 4)), torch.empty(size=(0,), dtype=torch.int64), torch.empty(size=(0,))]
bboxes_out = torch.cat(bboxes_out, dim=0).contiguous()
scores_out = torch.cat(scores_out, dim=0).contiguous()
labels_out = torch.as_tensor(labels_out, dtype=torch.long)
# 对所有目标的概率进行排序(无论是什 么类别),取前max_num个目标
_, max_ids = scores_out.sort(dim=0)
max_ids = max_ids[-max_output:]
return bboxes_out[max_ids, :], labels_out[max_ids], scores_out[max_ids]