Backbone
、Neck
、Head
、注意力机制
、IoU损失函数
、NMS
、Loss计算方式
、自注意力机制
、数据增强部分
、激活函数
等部分,详情可以关注 YOLOAir 的说明文档。附带各种改进点原理及对应的代码改进方式教程
,用户可根据自身情况快速排列组合,在不同的数据集上实验, 应用组合写论文!新的仓库链接:YOLOAir仓库:https://github.com/iscyy/yoloair
可以 fork 和 star,持续同步更新完善
本篇是《关于一系列Soft-NMS》的修改 演示
包括:NMS、Soft-NMS、Soft-SIoUNMS、Soft-CIoUNMS、Soft-DIoUNMS、Soft-EIoUNMS、Soft-GIoUNMS
使用YOLOv5网络作为示范,可以无缝加入到 YOLOv7、YOLOX、YOLOR、YOLOv4、Scaled_YOLOv4、YOLOv3等一系列YOLO算法模块
理论部分论文:https://arxiv.org/abs/1704.04503)
在NMS算法中,直接将IoU 超过阈值的检测框的得分设置为 0,而 soft NMS 则将其得分进行惩罚衰减,有两种衰减方式。第一种是使用1-IoU与得分的乘积作为衰减后的值,但这种方式在略低于阈值和略高于阈值的部分,经过惩罚衰减函数后,很容易导致得分排序的顺序打乱,合理的惩罚函数应该是具有高IoU的有高的惩罚,低IoU的有低的惩罚,它们中间应该是逐渐过渡的,因此提出高斯惩罚函数。
在general.py
文件中增加
代码
def soft_nms(prediction, conf_thres=0.25, iou_thres=0.45, multi_label=False):
"""Runs Non-Maximum Suppression (NMS) on inference results
Returns:
list of detections, on (n,6) tensor per image [xyxy, conf, cls]
"""
nc = prediction.shape[2] - 5 # number of classes
# Checks
assert 0 <= conf_thres <= 1, f'Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0'
assert 0 <= iou_thres <= 1, f'Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0'
# Settings
min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height
time_limit = 10.0 # seconds to quit after
multi_label &= nc > 1 # multiple labels per box (adds 0.5ms/img)
soft_nms = True
t = time.time()
output = [torch.zeros((0, 6), device=prediction.device)] * prediction.shape[0]
for xi, x in enumerate(prediction): # image index, image inference
x = x[x[:, 4] > conf_thres] # confidence
x = x[(x[:, 2:4] > min_wh).all(1) & (x[:, 2:4] < max_wh).all(1)]
if len(x) == 0:
continue
# Compute conf
x[:, 5:] *= x[:, 4:5] # conf = obj_conf * cls_conf
# Box (center x, center y, width, height) to (x1, y1, x2, y2)
box = xywh2xyxy(x[:, :4])
# Detections matrix nx6 (xyxy, conf, cls)
if multi_label:
i, j = (x[:, 5:] > conf_thres).nonzero(as_tuple=False).T
x = torch.cat((box[i], x[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1)
else: # best class only
conf, j = x[:, 5:].max(1)
x = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1)[conf.view(-1) > conf_thres]
if len(x) == 0:
continue
x = x[x[:, 4].argsort(descending=True)] # sort by confidence
# Batched NMS
det_max = []
cls = x[:, -1] # classes
for c in cls.unique():
dc = x[cls == c]
n = len(dc)
#print(n)
if n == 1:
det_max.append(dc)
continue
elif n > 30000:
dc = dc[:30000]
if soft_nms:
sigma = 0.5
while len(dc):
det_max.append(dc[:1])
if len(dc) == 1:
break
iou = bbox_iou(dc[0], dc[1:]) # 修改
dc = dc[1:]
dc[:, 4] *= torch.exp(-iou ** 2 / sigma)
dc = dc[dc[:, 4] > conf_thres]
if len(det_max):
det_max = torch.cat(det_max)
#output[xi] = det_max[(-det_max[:, 4]).argsort()]
output[xi] = det_max[(-det_max[:, 4]).argsort()]
if (time.time() - t) > time_limit:
print(f'WARNING: NMS time limit {time_limit}s exceeded')
break # time limit exceeded
return output
在val.py
将
out = non_max_suppression(out, conf_thres, iou_thres, labels=lb, multi_label=True, agnostic=single_cls)
替换为
out = soft_nms(out, conf_thres, iou_thres, multi_label=True)
调用
即可
在
def soft_nms(prediction, conf_thres=0.25, iou_thres=0.45, multi_label=False):
函数中,
找到
iou = bbox_iou(dc[0], dc[1:])
这句,
将其替换为
iou = bbox_iou(dc[0], dc[1:], CIoU=True)
即可
在
def soft_nms(prediction, conf_thres=0.25, iou_thres=0.45, multi_label=False):
函数中,
找到
iou = bbox_iou(dc[0], dc[1:])
这句,
将其替换为
iou = bbox_iou(dc[0], dc[1:], DIoU=True)
即可
在
def soft_nms(prediction, conf_thres=0.25, iou_thres=0.45, multi_label=False):
函数中,
找到
iou = bbox_iou(dc[0], dc[1:])
这句,
将其替换为
iou = bbox_iou(dc[0], dc[1:], EIoU=True)
即可
在
def soft_nms(prediction, conf_thres=0.25, iou_thres=0.45, multi_label=False):
函数中,
找到
iou = bbox_iou(dc[0], dc[1:])
这句,
将其替换为
iou = bbox_iou(dc[0], dc[1:], SIoU=True)
即可
在
def soft_nms(prediction, conf_thres=0.25, iou_thres=0.45, multi_label=False):
函数中,
找到
iou = bbox_iou(dc[0], dc[1:])
这句,
将其替换为
iou = bbox_iou(dc[0], dc[1:], GIoU=True)
即可
参考用PyTorch实现CIoU NMS,DIoU NMS和GIoU NMS博文的末尾提示
不过试了一下,效果很一般,看看就行了,当作分享吧