💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡
在目标检测领域内,尽管YOLO系列的算法傲视群雄,但在某些方面仍然存在改进的空间。在YOLOv5的损失函数中,默认是使用的CIoU,但是CIoU仍然存在一定的问题。例如CIOU的计算方式相对复杂,需要对边界框的坐标进行更多的处理和计算。本文给大家带来的教程是将原来的CIoU替换为EIoU、SIoU、WIoU、DIoU、FocusIoU。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。
专栏地址: YOLOv5改进+入门——持续更新各种有效涨点方法——点击即可跳转
1. ✒️CIoU
1.1 CIoU原理
论⽂考虑到bbox回归三要素中的⻓宽⽐还没被考虑到计算中,为此,进⼀步在DIoU的基础上提出了CIoU,同时考虑两个矩形的长宽比,也就是形状的相似性。所以CIOU在DIOU的基础上添加了长宽比的惩罚项。
其中, 是权重函数, 而用来度量长宽比的相似性。计算公式为:
☀️优点
更准确的相似性度量:CIOU考虑了边界框的中心点距离和对角线距离,因此可以更准确地衡量两个边界框之间的相似性,尤其是在目标形状和大小不规则的情况下。 鲁棒性更强:相比传统的IoU,CIOU对于目标形状和大小的变化更具有鲁棒性,能够更好地适应各种尺寸和形状的目标检测任务。
⚡️缺点
计算复杂度增加:CIOU引入了额外的中心点距离和对角线距离的计算,因此相比传统的IoU,计算复杂度有所增加,可能会增加一定的计算成本。 实现难度较高:CIOU的计算方式相对复杂,需要对边界框的坐标进行更多的处理和计算,因此在实现上可能会相对困难一些,需要更多的技术和经验支持。
1.3 📌CIoU代码实现
import numpy as np
import IoU
import DIoU
# box : [左上角x坐标,左上角y坐标,右下角x坐标,右下角y坐标]
box1 = [0, 0, 6, 8]
box2 = [3, 2, 9, 10]
# CIoU
def CIoU(box1, box2):
x1, y1, x2, y2 = box1
x3, y3, x4, y4 = box2
# box1的宽:box1_w,box1的高:box1_h,
box1_w = x2 - x1
box1_h = y2 - y1
# box2的宽:box2_w,box2的高:box2_h,
box2_w = x4 - x3
box2_h = y4 - y3
iou = IoU(box1, box2)
diou = DIoU(box1, box2)
# v用来度量长宽比的相似性
v = (4 / (np.pi) ** 2) * (np.arctan(int(box2_w / box2_h)) - np.arctan(int(box1_w / box1_h)))
# α是权重函数
a = v / ((1 + iou) + v)
ciou = diou - a * v
return ciou
print(CIoU(box1, box2))
输出结果:0.1589460263493413
2. ✒️EIOU(Efficient-IoU)
2.1 EIoU原理
EIOU是在 CIOU 的惩罚项基础上将预测框和真实框的纵横比的影响因子拆开,分别计算预测框和真实框的长和宽,并且加入Focal聚焦优质的锚框,来解决 CIOU 存在的问题。先前基于iou的损失,例如CIOU和GIOU,不能有效地测量目标盒和锚点之间的差异,这导致BBR(边界框回归)模型优化的收敛速度慢,定位不准确。
针对上述问题,对CIOU损失进行了修正,提出了一种更有效的IOU损失,即EIOU损失,定义如下:
其中和是覆盖两个盒子的最小围框的宽度和高度。也就是说,我们将损失函数分为三个部分:IOU损失LIOU,距离损失和方向损失。这样,我们可以保留CIOU损失的有效特点。同时,EIOU损失直接使目标盒与锚盒宽度和高度的差值最小化,从而使收敛速度更快,定位效果更好。
优点:
更稳定的训练过程:通过引入中心点距离和宽高比的惩罚项,即使在IoU为0的情况下,EIou也能提供有效的梯度信息,确保模型能够继续学习。
提高定位精度:通过综合考虑位置和尺寸的匹配,EIou可以显著提升目标检测模型的定位精度,尤其在目标物体大小和形状变化较大时表现更优。
2.2 代码实现
import numpy as np
def calculate_eiou(box1, box2):
# 计算嵌入向量(这里简化为使用中心点坐标作为嵌入向量)
center1 = np.array([(box1[0] + box1[2]) / 2, (box1[1] + box1[3]) / 2])
center2 = np.array([(box2[0] + box2[2]) / 2, (box2[1] + box2[3]) / 2])
# 计算嵌入向量之间的欧式距离
euclidean_distance = np.linalg.norm(center1 - center2)
# 计算目标框的面积
area_box1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
area_box2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
# 计算交集和并集的面积
intersection = max(0, min(box1[2], box2[2]) - max(box1[0], box2[0])) * \
max(0, min(box1[3], box2[3]) - max(box1[1], box2[1]))
union = area_box1 + area_box2 - intersection
# 计算EIOU
eiou = 1 - intersection / union + euclidean_distance
return eiou
box1 = [0, 0, 6, 8]
box2 = [3, 2, 9, 10]
print(calculate_eiou(box1, box2))
输出结果:4.374782044694758
3. 将EIoU、SIoU、WIoU、DIoU、FocusIoU添加到YOLOv5中
3.1 添加代码
关键步骤一: 在utils/metrics.py中,找到bbox_iou函数,可以把原有的注释掉,换成下面的代码:
def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, SIoU=False, EIoU=False, Focal=False, alpha=1, gamma=0.5, eps=1e-7):
# Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)
# Get the coordinates of bounding boxes
if xywh: # transform from xywh to xyxy
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_
else: # x1, y1, x2, y2 = box1
b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1)
b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)
w1, h1 = b1_x2 - b1_x1, (b1_y2 - b1_y1).clamp(eps)
w2, h2 = b2_x2 - b2_x1, (b2_y2 - b2_y1).clamp(eps)