目标检测算法之损失函数(IOU、GIOU、DIOU、CIOU、EIOU)
CIOU是在DIOU的基础上考虑了长宽比,许多目标检测任务中,物体的长宽比相对比较固定,那么将它们考虑进损失函数中,理论上是有利于回归框收敛的。GIOU是IOU的改进方式,它在IOU的基础上,考虑了俩个框之间的位置关系,同时也解决了IOU为0时难以优化的问题。IOU是衡量俩个目标框之间重叠程度的一个指标,常用于目标检测中,用于评估预测框的准确率。IOU损失的缺点有俩个,第一个是不能描述俩个框之间的
IOU损失函数
- IOU
- GIOU
- DIOU
- CIOU
- EIOU
IOU
IOU是衡量俩个目标框之间重叠程度的一个指标,常用于目标检测中,用于评估预测框的准确率。接下来简要介绍一下IOU原理和实现。
假设有俩个框,分别是框MMM和框NNN,记它们的面积为AMA_MAM和ANA_NAN。那么它们的IOU为IOU(M,N)=M∩NM∪NIOU(M,N) = \frac{M\cap N}{M\cup N}IOU(M,N)=M∪NM∩N其中M∩NM\cap NM∩N为区域MMM和区域NNN之间的交区域,记为AMNA_{MN}AMN,M∩NM\cap NM∩N为区域MMM和区域NNN之间的并区域。那么就有IOU(M,N)=M∩NM∪N=AMNAM+AN−AMNIOU(M,N) = \frac{M\cap N}{M\cup N} = \frac{A_{MN}}{A_M+A_N-A_{MN}}IOU(M,N)=M∪NM∩N=AM+AN−AMNAMN所以当AMN=0A_{MN}=0AMN=0(M和N之间不重叠)时有IOU(M,N)=0IOU(M,N) = 0IOU(M,N)=0,当AMN>0A_{MN}>0AMN>0(M和N之间有部分重叠)时有IOU(M,N)=0IOU(M,N)=0IOU(M,N)=0,当且仅当AMN=AM=ANA_{MN} =A_M=A_NAMN=AM=AN(区域MMM和区域NNN完全重叠,且它们的面积相等)时有IOU(M,N)=1IOU(M,N)=1IOU(M,N)=1。
直接用IOU来当损失有俩种,一种是Lossiou=−ln(IOU)Loss_iou = -ln(IOU)Lossiou=−ln(IOU),但实际使用中比较多的是Lossiou=1−IOULoss_iou = 1-IOULossiou=1−IOU。
IOU损失的缺点有俩个,第一个是不能描述俩个框之间的距离关系,只能描述重叠面积。第二个是
对于没有交集的框,IoU 的值为 0,这会导致梯度为 0,难以优化。
参考了yolov5的实现,加入eps和xywh的格式,可以使函数更加全面。
def bbox_iou(box1, box2, xywh=True, eps=1e-7):
if xywh: # transform from xywh to xyxy
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1, box2
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
b2_x1, b2_y1, b2_x2, b2_y2 = box2
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
inter_area = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp_(0) * (b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp_(0)
union = w1 * h1 + w2 * h2 - inter_area + eps #防止union为0
iou = inter_area / union
return iou
GIOU
GIOU是IOU的改进方式,它在IOU的基础上,考虑了俩个框之间的位置关系,同时也解决了IOU为0时难以优化的问题。GIOU的公式如下GIOU(M,N)=IOU(M,N)−∣C−(M∩N)∣∣C∣GIOU(M,N)=IOU(M,N)-\frac{|C-(M\cap N)|}{|C|}GIOU(M,N)=IOU(M,N)−∣C∣∣C−(M∩N)∣其中C是指MMM和NNN的最小外接矩阵。
通过引入俩个框最小外接矩阵,当∣M∩N∣=0|M\cap N|=0∣M∩N∣=0时,GIOU=−1GIOU=-1GIOU=−1,这就解决IOU梯度为0的问题。同时这种方式也能考虑到俩个框不相交的部分的关系。
但是GIOU需要计算它们的外接矩形,增加了计算量。同时由于俩个框的外接矩阵随着预测的不同而变动,或导致它很难有稳定的优化效果。
def bbox_giou(box1, box2, xywh=True, eps=1e-7):
if xywh: # transform from xywh to xyxy
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1, box2
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
b2_x1, b2_y1, b2_x2, b2_y2 = box2
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
inter_area = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp_(0) * (b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp_(0)
union = w1 * h1 + w2 * h2 - inter_area + eps #防止union为0
iou = inter_area / union
cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1)
ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1)
mini_rectangle = cw * ch + eps #计算最小外接矩形
return iou-(mini_rectangle-union)/mini_rectangle
DIOU
DIOU是基于IOU的改进,它通过俩个框的中心点的欧式距离ppp来表示俩个框的,同时借助俩个框的最小外接矩形的对角线来ccc归一化ppp从而有DIOU(M,N)=IOU−p2c2DIOU(M,N) = IOU-\frac{p^2}{c^2}DIOU(M,N)=IOU−c2p2
DIOU是一个比较好的方法,它考虑框相对位置关系,同时通过这种方式还能很好地衡量这个关系。所以在训练中它的收敛速度比较块, 是许多回归框损失函数不错的一个选择。
def bbox_giou(box1, box2, xywh=True, eps=1e-7):
if xywh: # transform from xywh to xyxy
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1, box2
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
b2_x1, b2_y1, b2_x2, b2_y2 = box2
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
inter_area = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp_(0) * (b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp_(0)
union = w1 * h1 + w2 * h2 - inter_area + eps #防止union为0
iou = inter_area / union
cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1)
ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1)
c2 = cw.pow(2) + ch.pow(2) + eps #计算对角线
rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2).pow(2) + (b2_y1 + b2_y2 - b1_y1 -b1_y2).pow(2)) / 4 #计算俩个中心的距离,这个实现很优雅,2倍的中心差,平方后除4
return iou-rho2/c2
CIOU
CIOU是在DIOU的基础上考虑了长宽比,许多目标检测任务中,物体的长宽比相对比较固定,那么将它们考虑进损失函数中,理论上是有利于回归框收敛的。CIOU为CIOU(M,N)=IOU−p2c2−αvCIOU(M,N) = IOU-\frac{p^2}{c^2}-\alpha vCIOU(M,N)=IOU−c2p2−αv
其中α\alphaα为权重参数,具体如下α=v(1−IOU)+v\alpha = \frac{v}{(1-IOU)+v}α=(1−IOU)+vv在实际中可以给α\alphaα一个固定的值。
其中vvv是指长框比的差。具体如下v=4π2(arctanwMhM−arctanwNhN)2v = \frac{4}{\pi^2}\left(\arctan\frac{w_{M}}{h_{M}}-\arctan\frac{w_N}{h_N}\right)^2v=π24(arctanhMwM−arctanhNwN)2由于长宽比的范围为[0,∞)[0,\infty)[0,∞),所以使用arctan\arctanarctan可以固定到(0,π2)(0,\frac{\pi}{2})(0,2π),而4π2\frac{4}{\pi^2}π24就是做了归一化的操作了。
def bbox_giou(box1, box2, xywh=True, eps=1e-7):
if xywh: # transform from xywh to xyxy
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1, box2
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
b2_x1, b2_y1, b2_x2, b2_y2 = box2
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
inter_area = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp_(0) * (b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp_(0)
union = w1 * h1 + w2 * h2 - inter_area + eps #防止union为0
iou = inter_area / union
cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1)
ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1)
c2 = cw.pow(2) + ch.pow(2) + eps #计算对角线
rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2).pow(2) + (b2_y1 + b2_y2 - b1_y1 -b1_y2).pow(2)) / 4 #计算俩个中心的距离,这个实现很优雅,2倍的中心差,平方后除4
v = (4 / math.pi**2) * ((w2 / h2).atan() - (w1 / h1).atan()).pow(2)#计算v
alpha = v / (v - iou + (1 + eps)) #计算a
return iou-rho2/c2-v*alpha
EIOU
EIOU是将长宽比改成了长长比和宽宽比,学习了中心点距离的方式。具体如下EIOU(M,N)=IOU−p(bM,bN)2c2−p(wM,wN)2cw2−p(hM,hN)2ch2EIOU(M,N) = IOU-\frac{p(b_M,b_N)^2}{c^2}-\frac{p(w_M,w_N)^2}{c_w^2}-\frac{p(h_M,h_N)^2}{c_h^2}EIOU(M,N)=IOU−c2p(bM,bN)2−cw2p(wM,wN)2−ch2p(hM,hN)2EIOU的计算会比CIOU更直接一点, 对长宽的约束更加的明显。
def bbox_giou(box1, box2, xywh=True, eps=1e-7):
if xywh: # transform from xywh to xyxy
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1, box2
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
b2_x1, b2_y1, b2_x2, b2_y2 = box2
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
inter_area = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp_(0) * (b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp_(0)
union = w1 * h1 + w2 * h2 - inter_area + eps #防止union为0
iou = inter_area / union
cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1)
ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1)
c2 = cw.pow(2) + ch.pow(2) + eps #计算对角线
rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2).pow(2) + (b2_y1 + b2_y2 - b1_y1 -b1_y2).pow(2)) / 4 #计算俩个中心的距离,这个实现很优雅,2倍的中心差,平方后除4
rhow = (w1-w2).pow(2)/(cw.pow(2)+eps)
rhoh = (h1-h2).pow(2)/(ch.pow(2)+eps)
return iou-rho2/c2-rhow-rhoh
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)