《Fast R-CNN》 论文中首次提出Smooth L1 Loss
论文地址: 《UnitBox: An Advanced Object Detection Network》
提出背景
三种Loss用于计算目标检测的Bounding Box Loss时,独立的求出4个点的Loss,然后进行相加得到最终的Bounding Box Loss,这种做法的假设是4个点是相互独立的,实际是有一定相关性的
IoU (Intersection over Union)的计算
IOU的计算是用预测框(A)和真实框(B)的交集除以二者的并集,其公式为:
I o U = A ∩ B A ∪ B I o U=\frac{A \cap B}{A \cup B} IoU=A∪BA∩B
IoU的值越高也说明A框与B框重合程度越高,代表模型预测越准确。反之,IoU越低模型性能越差。
IOU Loss
L I o U = − l n ( I o U ) L_{IoU}=-ln(IoU) LIoU=−ln(IoU)
当IoU趋近为1时(两个框重叠程度很高),Loss趋近于0。IoU越小(两个框的重叠程度变低),Loss越大。当IoU为0时(两个框不存在重叠),梯度消失。
IOU的特性
优点:
(1)IoU具有尺度不变性
(2)结果非负,且范围是(0, 1)
缺点:
(1)如果两个目标没有重叠,IoU将会为0,并且不会反应两个目标之间的距离,在这种无重叠目标的情况下,如果IoU用作于损失函数,梯度为0,无法优化。
(2)IoU无法精确的反映两者的重合度大小。如下图所示,三种情况IoU都相等,但看得出来他们的重合度是不一样的,左边的图回归的效果最好,右边的最差。
论文地址:《Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression》
提出背景
为了解决Iou的作为损失函数的缺点,提出了GIoU,在IoU后面增加了一项,计算两个框的最小外接矩形,用于表征两个框的距离,从而解决了两个目标没有交集时梯度为零的问题。
GIOU的计算
其中A表示真实框,B表示预测框,C表示两个框的最小外接矩形的面积。
G I o U = I o U − C − ( A ∪ B ) C G I o U=I o U-\frac{C-(A \cup B)}{C} GIoU=IoU−CC−(A∪B)
当IoU=0时(A和B没有交集):
G I o U = − 1 + A ∪ B C G I o U=-1+\frac{A \cup B}{C} GIoU=−1+CA∪B
当A和B两个框离得越远,GIOU越接近-1;当两框重合时,GIOU=1。所以GIOU的取值为(-1,1]。
GIOU Loss
L G I o U = 1 − G I o U L_{G I o U}=1-G I o U LGIoU=1−GIoU
当 A , B A,B A,B两框不相交时, A ∪ B A \cup B A∪B 不变,最大化 G I o U GIoU GIoU就是最小化C, 这样会促进两个框不断靠近。
GIoU的特性
优点:
(1)当IoU=0时,仍然可以很好的表示两个框的距离。
(2)GIoU不仅关注重叠区域,还关注其他的非重合区域,能更好的反映两者的重合度
缺点:
(1)当两个框属于包含关系时,GIoU会退化成IoU,无法区分其相对位置关系,如下图:
(2)由于GIoU仍然严重依赖IoU,因此在两个垂直方向,误差很大,很难收敛。两个框在相同距离的情况下,水平垂直方向时,此部分面积最小,对loss的贡献也就越小,从而导致在垂直水平方向上回归效果较差。
如下图,三种情况下GIoU的值一样,GIoU将很难区分这种情况。
论文地址:《Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression》
针对上述GIoU的两个问题,将GIoU中最小外接框来最大化重叠面积的惩罚项修改成最小化两个BBox中心点的标准化距离从而加速损失的收敛过程,这就诞生了DIoU。
DIoU要比GIou更加符合目标框回归的机制,将目标与预测之间的距离,重叠率以及尺度都考虑进去,使得目标框回归变得更加稳定,不会像IoU和GIoU一样出现训练过程中发散等问题。
论文地址:《Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression》
提出背景
CIoU与DIoU出自同一篇论文,CIoU大多数用于训练。DIoU的作者考虑到,在两个框中心点重合时,c与d的值都不变。所以此时需要引入框的宽高比
CLoU的计算
C I o U = I o U − ( ρ 2 ( b , b g t ) c 2 + α v ) C I o U=I o U-\left(\frac{\rho^2\left(b, b^{g t}\right)}{c^2}+\alpha v\right) CIoU=IoU−(c2ρ2(b,bgt)+αv)
其中 α \alpha α 是权重函数, v \mathrm{v} v 用来度量宽高比的一致性:
α = v ( 1 − I o U ) + v v = 4 π 2 ( arctan w g t h g t − arctan ( w h ) ) 2 \begin{gathered} \alpha=\frac{v}{(1-I o U)+v} \\ v=\frac{4}{\pi^2}\left(\arctan \frac{w_{g t}}{h_{g t}}-\arctan \left(\frac{w}{h}\right)\right)^2 \end{gathered} α=(1−IoU)+vvv=π24(arctanhgtwgt−arctan(hw))2
从 v v v可以看出, CIOU 中存在两个问题:
a. 使用的是预测框和目标框的宽高比,那当预测框的宽高满足 { ( w p = k w g t , h p = k h g t ) ∣ k ∈ R + } \left\{\left(w^{\mathrm{p}}=k w^{\mathrm{gt}}, h^{\mathrm{p}}=k h^{\mathrm{gt}}\right) \mid k \in \mathbb{R}^{+}\right\} {(wp=kwgt,hp=khgt)∣k∈R+}时,CloU 中此项的惩罚便失去了作用。
b. 根据下面 w p , h p w^{\mathrm{p}}, h^{\mathrm{p}} wp,hp 的梯度公式,
∂ v ∂ w p = 8 π 2 ( arctan w g t h g t − arctan w p h p ) ⋅ h p ( w p ) 2 + ( h p ) 2 \frac{\partial v}{\partial w^{\mathrm{p}}}=\frac{8}{\pi^2}\left(\arctan \frac{w^{\mathrm{gt}}}{h^{\mathrm{gt}}}-\arctan \frac{w^{\mathrm{p}}}{h^{\mathrm{p}}}\right) \cdot \frac{h^{\mathrm{p}}}{\left(w^{\mathrm{p}}\right)^2+\left(h^{\mathrm{p}}\right)^2} ∂wp∂v=π28(arctanhgtwgt−arctanhpwp)⋅(wp)2+(hp)2hp
∂ v ∂ h p = − 8 π 2 ( arctan w g t h g t − arctan w p h p ) ⋅ w p ( w p ) 2 + ( h p ) 2 \frac{\partial v}{\partial h^{\mathrm{p}}}=-\frac{8}{\pi^2}\left(\arctan \frac{w^{\mathrm{gt}}}{h^{\mathrm{gt}}}-\arctan \frac{w^{\mathrm{p}}}{h^{\mathrm{p}}}\right) \cdot \frac{w^{\mathrm{p}}}{\left(w^{\mathrm{p}}\right)^2+\left(h^{\mathrm{p}}\right)^2} ∂hp∂v=−π28(arctanhgtwgt−arctanhpwp)⋅(wp)2+(hp)2wp
可以得出, ∂ v ∂ w p = − h w ∂ v ∂ h p \frac{\partial v}{\partial w^{\mathrm{p}}}=-\frac{h}{w} \frac{\partial v}{\partial h^{\mathrm{p}}} ∂wp∂v=−wh∂hp∂v 两者的关系成反比。也就是说,训练时 w p , h p w^{\mathrm{p}}, h^{\mathrm{p}} wp,hp 中任意一者增大时, 另一者必然减小。
CIoU Loss
L C I o U = 1 − I o U + ρ 2 ( b , b g t ) c 2 + a v L_{C I o U}=1-I o U+\frac{\rho^2\left(b, b^{g t}\right)}{c^2}+a v LCIoU=1−IoU+c2ρ2(b,bgt)+av
CIoU的特性
优点:考虑了框的纵横比,可以解决DIoU的问题。
缺点: 通过CIoU公式中的v反映的纵横比的差异,而不是宽高分别与其置信度的真实差异,所以有时会阻碍模型有效的优化相似性。
论文地址:《Focal and Efficient IOU Loss for Accurate Bounding Box Regression》
EIOU的提出背景
CIoU不能真实的反映宽高分别与其置信度的真实差异,
且损失函数忽略了正负样本不平衡的问题,即大量与目标框重叠面积较小的预测框在最终的 bbox 优化中占用了绝大部分的贡献。
为了解决CIoU的问题,有学者在CIOU的基础上将纵横比拆开,提出了EIOU Loss,并且加入Focal聚焦优质的预测框,与CIoU相似的,EIoU是损失函数的解决方案,只用于训练。
EIOU LOSS
EIOU的惩罚项是在CIOU的惩罚项基础上将纵横比的影响因子拆开分别计算目标框和预测框的长和宽,该损失函数包含三个部分:重叠损失,中心距离损失,宽高损失,前两部分延续CIoU中的方法,但是宽高损失直接使目标框与预测框的宽度和高度之差最小,使得收敛速度更快。惩罚项公式如下:
L E I o U = L I o U + L d i c + L a s p = 1 − I o u + ρ 2 ( b , b g t ) ( c w ) 2 + ( c h ) 2 + ρ 2 ( w , w g t ) ( c w ) 2 + ρ 2 ( h , h g t ) ( c h ) 2 \begin{gathered} L_{E I o U}=L_{I o U}+L_{d i c}+L_{a s p} \\ =1-I o u+\frac{\rho^2\left(b, b^{g t}\right)}{\left(c_w\right)^2+\left(c_h\right)^2}+\frac{\rho^2\left(w, w^{g t}\right)}{\left(c_w\right)^2}+\frac{\rho^2\left(h, h^{g t}\right)}{\left(c_h\right)^2} \end{gathered} LEIoU=LIoU+Ldic+Lasp=1−Iou+(cw)2+(ch)2ρ2(b,bgt)+(cw)2ρ2(w,wgt)+(ch)2ρ2(h,hgt)
其中 b g t b^{gt} bgt和 b p b^p bp分别表示预测框和目标框中心点的坐标。 d ( b p , b g t ) d(b^p,b^{gt}) d(bp,bgt)表示二者的欧式距离。 c w c_w cw 和 c h c_h ch 是覆盖两个Box的最小外接框的宽度和高度。
FOCAL EIoU LOSS
GIOU 通过预测框和目标框的差集/最小外界矩形来作为惩罚项,一方面在预测框在目标框内部或目标框在预测框内部时,都无法处理比值相同的情况;另一方面,也导致 GIOU 存在先减小差集面积再优化 IoU 值的可能性。
CIOU 存在的问题是上面提到的预测框宽高比成反比,两者不能同时增大或缩小。如上图第二行,iter=50 中预测框的宽高都大于目标框,但是在 iter=150 中,预测框的高变小,但是宽却变大。
上面提到第二个动机,目标检测模型中预测框往往数量较大,其中与目标框 IOU 值较低的低质量样本占绝大多数。低质量样本在训练时容易造成损失值波动的情况。作者认为高低质量样本分布不均是影响模型收敛的一个重要因素。作者提到,一个优秀的损失函数应该具有下面几个性质:
当回归的 error 是 0 的时候,此时的梯度也应当是 0,因为我们这时不再需要对参数进行调整;
在错误率小的地方,梯度的值也应当小,反之在错误率大的地方,梯度也应当大,因为这时候我们需要对错误率小的情况进行微调,而错误率大的地方进行大刀阔斧的调整;
应该有一个参数可以抑制低质量样本对损失值的影响;
梯度值的范围应该在一定的范围内,例如 (0,1],避免造成梯度的剧烈波动。
借助 Focal Loss 的思想,作者提出了 Focal L1 Loss,具体过程大致为:作者通过设计出一个合适的梯度函数,并根据它的性质求出相关参数的关系,通过求积分得出最终的损失函数。具体推导见论文中。作者设计的 Focal L1 Loss 的梯度函数如下,
∂ L f ∂ x = { − α x ln ( β x ) , 0 < x ≤ 1 ; 1 e ≤ β ≤ 1 − α ln ( β ) , x > 1 ; 1 e ≤ β ≤ 1 \frac{\partial \mathcal{L}_f}{\partial x}= \begin{cases}-\alpha x \ln (\beta x) & , 0
最终得出的 Focal L1 Loss 损失函数公式为:
L f ( x ) = { − α x 2 ( 2 ln ( β x ) − 1 ) 4 , 0 < x ≤ 1 ; 1 e ≤ β ≤ 1 − α ln ( β ) x + C , x > 1 ; 1 e ≤ β ≤ 1 \mathcal{L}_f(x)= \begin{cases}-\frac{\alpha x^2(2 \ln (\beta x)-1)}{4} & , 0
L Focal-EIou = I o U γ L E I o U L_{\text {Focal-EIou }}=I o U^\gamma L_{E I o U} LFocal-EIou =IoUγLEIoU
其中,为了保证函数连续,令 L f ( 1 ) \mathcal{L}_f(1) Lf(1) 求得 C = 2 α ln β + α 4 C=\frac{2 \alpha \ln \beta+\alpha}{4} C=42αlnβ+α.
上图是 FocalL1 Loss 损失函数曲线 (a) 和其梯度曲线图 (b)。从 (b) 中可以看出,FocalL1 Loss 可以通过控制 β \beta β 的大小来控制损失值超过 1 之后的梯度大小,如当 β = 1.0 \beta=1.0 β=1.0 ,损失值大于 1 时,梯 度值恒为 0 。而且,梯度曲线呈现出上凸趋势。当损失值过大或过小时,产生的梯度值均较小。当低 质量样本产生损失值较大时,此时梯度值较小,以此来抑制低质量样本的贡献。
下图与上图类似,(a)是作者期望得到的损失函数梯度曲线;(b) 是 α = 1 , β \alpha=1, \beta α=1,β 取不同值得到的损 失函数图。
从以上两幅图中可以看出(论文中也有实验证明),当 β \beta β 越大时,低质量样本的梯度越小,即当 损失值越大时,其产生梯度值越小,这里作者认为 低质量样本会产生较大的梯度。与此相反,高质量 样本的梯度越大。实验发现当 β = 0.8 \beta=0.8 β=0.8 时效果最好。
在具体使用中,FocalL1 Loss 通过计算预测框和目标框 ( x , y , w , h ) (x, y, w, h) (x,y,w,h) 的位移偏差之和,来计算回 归损失,如下式:
L l o c = ∑ i ∈ { x , y , w , h } L f ( ∣ B i p − B i g t ∣ ) \mathcal{L}_{\mathrm{loc}}=\sum_{i \in\{x, y, w, h\}} \mathcal{L}_f\left(\left|B_i^{\mathrm{p}}-B_i^{\mathrm{gt}}\right|\right) Lloc=i∈{x,y,w,h}∑Lf( Bip−Bigt )
与 FocalL1 Loss 类似,作者还提出了 Focal-EloU Loss,如下:
L Focal E-IoU = I o U γ L E I o U \mathcal{L}_{\text {Focal E-IoU }}=\mathrm{IoU}^\gamma \mathcal{L}_{\mathrm{EIoU}} LFocal E-IoU =IoUγLEIoU
Focal-EloU Loss 提出的原因是,作者在实验中发现当 L E I o U \mathcal{L}_{\mathrm{EIoU}} LEIoU 接近零时,它的值非常小。同时, ∂ L f ∂ L E I o U \frac{\partial \mathcal{L}_f}{\partial \mathcal{L}_{\mathrm{EIoU}}} ∂LEIoU∂Lf 也非常小。当两者相乘后,会得到更小的梯度值,这会使 L E I o U \mathcal{L}_{\mathrm{EIoU}} LEIoU 较小的高质量样本的贡献大 大降低。为了解决这个问题,作者通过 loU 值对 L E I o U \mathcal{L}_{\mathrm{EIoU}} LEIoU 实现了权值的重置。以此来提高 L E I o U \mathcal{L}_{\mathrm{EIoU}} LEIoU 较小 的高质量样本的贡献。
同样是,通过实验发现较大的 γ \gamma γ 值对于困难样本 (低质量样本),即 IOU 较小的样本抑制效果 较大,可能会延缓收敛速度、影响最终精度。当 γ = 0.5 \gamma=0.5 γ=0.5 获得最好的效果。
论文地址:《Alpha-IoU: A Family of Power Intersection over Union Losses for Bounding Box Regression》
αIOU 的提出背景
针对之前一系列IoU形式多且繁杂,αIOU 提出了一个对 IoU loss 的统一形式,通过 power transformation 来生成 IoU 和其对应惩罚项的统一形式,来动态调整不同 IoU 目标的 loss 和 gradient。
αIOU的计算
Box-Cox 变换:方差稳定变换,可以改变变量的分布,使得方差不再依赖于均值
当原始数据非正态分布,或者原始数据左偏、右偏时,需要对原始数据做一定的变换,经常会使用 Box-Cox 变换。
y ( λ ) = { y λ − 1 λ , λ ≠ 0 ln y , λ = 0 \mathrm{y}(\lambda)=\left\{\begin{array}{l} \frac{y^\lambda-1}{\lambda}, \lambda \neq 0 \\ \ln y, \lambda=0 \end{array}\right. y(λ)={λyλ−1,λ=0lny,λ=0
首先,在 loU loss L I o U = 1 − I o U L_{I o U}=1-I o U LIoU=1−IoU 上使用 Box-Cox 变换,得到 α \alpha α-loU:
L α − I o U = ( 1 − I o U α ) α , α > 0 L_{\alpha-I o U}=\frac{\left(1-I o U^\alpha\right)}{\alpha}, \alpha>0 Lα−IoU=α(1−IoUα),α>0
对 α \alpha α 的分析如下,可以得到很多形式:
对 α \alpha α-loU 简化得到:
L α − I o U = { − log ( I o U ) , α → 0 1 − I o U α , α ↛ 0. \mathcal{L}_{\alpha-\mathrm{IoU}}=\left\{\begin{array}{l} -\log (I o U), \quad \alpha \rightarrow 0 \\ 1-I o U^\alpha, \quad \alpha \nrightarrow 0 . \end{array}\right. Lα−IoU={−log(IoU),α→01−IoUα,α↛0.
由于很多 loU-based 方法都是 α ↛ 0 \alpha \nrightarrow 0 α↛0 的,所以更多研究 α ↛ 0 \alpha \nrightarrow 0 α↛0 的情况,并且引入了一个惩罚项:
L α − I o U = 1 − I o U α 1 + P α 2 ( B , B g t ) \mathcal{L}_{\alpha-\mathrm{IoU}}=1-I o U^{\alpha_1}+\mathcal{P}^{\alpha_2}\left(B, B^{g t}\right) Lα−IoU=1−IoUα1+Pα2(B,Bgt)
论文地址:《SIoU Loss: More Powerful Learning for Bounding Box Regression Zhora Gevorgyan》
SIoU的提出背景
之前的IOU没有考虑到真实框与预测框框之间的方向,导致收敛速度较慢,对此SIoU引入真实框和预测框之间的向量角度,重新定义相关损失函数
SIoU的计算
(1) 角度损失(Angle cost)
,定义如下:
Λ = 1 − 2 ∗ sin 2 ( arcsin ( c h σ ) − π 4 ) = cos ( 2 ∗ ( arcsin ( c h σ ) − π 4 ) ) \Lambda=1-2 * \sin ^2\left(\arcsin \left(\frac{\mathrm{c}_{\mathrm{h}}}{\sigma}\right)-\frac{\pi}{4}\right)=\cos \left(2 *\left(\arcsin \left(\frac{\mathrm{c}_{\mathrm{h}}}{\sigma}\right)-\frac{\pi}{4}\right)\right) Λ=1−2∗sin2(arcsin(σch)−4π)=cos(2∗(arcsin(σch)−4π))
其中 c h c_h ch 为真实框和预测框中心点的高度差, σ \sigma σ 为真实框和预测框中心点的距离,事实上 arcsin ( c h σ ) \arcsin \left(\frac{\mathrm{ch}}{\sigma}\right) arcsin(σch) 等 于角度 α \alpha α
σ = ( b c x g t − b c x ) 2 + ( b c y g t − b c y ) 2 \sigma=\sqrt{\left(b_{c_x}^{g t}-b_{c_x}\right)^2+\left(b_{c_y}^{g t}-b_{c y}\right)^2} σ=(bcxgt−bcx)2+(bcygt−bcy)2
c h = max ( b c y g t , b c y ) − min ( b c y g t , b c y ) c_h=\max \left(b_{c_y}^{g t}, b_{c y}\right)-\min \left(b_{c_y}^{g t}, b_{c_y}\right) ch=max(bcygt,bcy)−min(bcygt,bcy)
( b c x g t , b c y g t ) \left(b_{c x}^{g t}, b_{c y}^{g t}\right) (bcxgt,bcygt) 为真实框中心坐标 ( b c x , b c y ) \left(b_{c_x}, b_{c_y}\right) (bcx,bcy) 为预测框中心坐标,可以注意到当 α \alpha α 为 π 2 \frac{\pi}{2} 2π 或 0 时,角度损失为 0 ,在训练过程中若 α < π 4 \alpha<\frac{\pi}{4} α<4π ,则最小化 α \alpha α ,否则最小化 β \beta β
(2)距离损失(Distance cost)
,定义如下:
Δ = ∑ t = x , y ( 1 − e − γ ρ t ) = 2 − e − γ ρ x − e − γ ρ y \Delta=\sum_{t=x, y}\left(1-\mathrm{e}^{-\gamma \rho_t}\right)=2-\mathrm{e}^{-\gamma \rho_{\mathrm{x}}}-\mathrm{e}^{-\gamma \rho_{\mathrm{y}}} Δ=t=x,y∑(1−e−γρt)=2−e−γρx−e−γρy
其中:
ρ x = ( b c x g t − b c x c w ) 2 , ρ y = ( b b y g t − b c y c h ) 2 γ = 2 − Λ \rho_{\mathrm{x}}=\left(\frac{b_{c_{\mathrm{x}}}^{g t}-b_{c_{\mathrm{x}}}}{c_w}\right)^2, \quad \rho_{\mathrm{y}}=\left(\frac{b_{\mathrm{b}_{\mathrm{y}}}^{\mathrm{gt}}-b_{c_{\mathrm{y}}}}{c_{\mathrm{h}}}\right)^2 \quad \gamma=2-\Lambda ρx=(cwbcxgt−bcx)2,ρy=(chbbygt−bcy)2γ=2−Λ
注意: 这里的 ( c w , c h ) \left(c_{\mathrm{w}}, \mathrm{c}_{\mathrm{h}}\right) (cw,ch) 为真实框和预测框最小外接矩形的宽和高
(3)形状损失(Shape cost)
,定义如下:
Ω = ∑ t = w , h ( 1 − e − w t ) θ = ( 1 − e − w w ) θ + ( 1 − e − w h ) θ \Omega=\sum_{\mathrm{t}=\mathrm{w}, \mathrm{h}}\left(1-\mathrm{e}^{-\mathrm{wt}}\right)^\theta=\left(1-\mathrm{e}^{-\mathrm{ww}}\right)^\theta+\left(1-\mathrm{e}^{-\mathrm{wh}}\right)^\theta Ω=t=w,h∑(1−e−wt)θ=(1−e−ww)θ+(1−e−wh)θ
其中:
w w = ∣ w − w g t ∣ max ( w , w g t ) , w h = ∣ h − h g t ∣ max ( h , h g t ) w_w=\frac{\left|\mathrm{w}-\mathrm{w}^{\mathrm{gt}}\right|}{\max \left(\mathrm{w}, \mathrm{w}^{\mathrm{gt}}\right)}, \quad \mathrm{w}_{\mathrm{h}}=\frac{\left|\mathrm{h}-\mathrm{h}^{\mathrm{gt}}\right|}{\max \left(\mathrm{h}, \mathrm{h}^{\mathrm{gt}}\right)} ww=max(w,wgt)∣w−wgt∣,wh=max(h,hgt)∣h−hgt∣
( w , h ) (w, h) (w,h) 和 ( w g t , h g t ) \left(w^{\mathrm{gt}}, h^{\mathrm{gt}}\right) (wgt,hgt) 分别为预测框和真实框的宽和高, θ \theta θ 控制对形状损失的关注程度,为了避免过于关 注形状损失而降低对预测框的移动,作者使用遗传算法计算出 θ \theta θ 接近 4 ,因此作者定于 θ \theta θ 参数范围为 [ 2 [2 [2, 6]
SIoU Loss
Loss S I o U = 1 − I o U + Δ + Ω 2 \operatorname{Loss}_{\mathrm{SIoU}}=1-\mathrm{IoU}+\frac{\Delta+\Omega}{2} LossSIoU=1−IoU+2Δ+Ω
论文地址:《Wise-IoU: Bounding Box Regression Loss with Dynamic Focusing Mechanism》
Focal EIoU v1被提出来解决质量较好和质量较差的样本间的BBR平衡问题,但由于其静态聚焦机制(FM),非单调FM的潜力没有被充分利用,基于这一思想,作者提出了一种基于IoU的损失,该损失具有动态非单调FM,名为Wise IoU(WIoU)。
主要贡献总结如下:
由于训练数据不可避免地包含低质量示例,几何因素(如距离和纵横比)将加重对低质量示例的惩罚,从而降低模型的泛化性能。当anchor box与目标box很好地重合时,一个好的损失函数应该会削弱几何因素的惩罚,而较少的训练干预将使模型获得更好的泛化能力。
代码参考:https://blog.csdn.net/athrunsunny/article/details/128862478
import math
import torch
def bbox_iou(box1,
box2,
xywh=True,
GIoU=False,
DIoU=False,
CIoU=False,
SIoU=False,
EIoU=False,
WIoU=False,
Focal=False,
alpha=1,
gamma=0.5,
scale=False,
monotonous=False,
eps=1e-7):
"""
计算bboxes iou
Args:
box1: predict bboxes
box2: target bboxes
xywh: 将bboxes转换为xyxy的形式
GIoU: 为True时计算GIoU LOSS (yolov5自带)
DIoU: 为True时计算DIoU LOSS (yolov5自带)
CIoU: 为True时计算CIoU LOSS (yolov5自带,默认使用)
SIoU: 为True时计算SIoU LOSS (新增)
EIoU: 为True时计算EIoU LOSS (新增)
WIoU: 为True时计算WIoU LOSS (新增)
Focal: 为True时,可结合其他的XIoU生成对应的IoU变体,如CIoU=True,Focal=True时为Focal-CIoU
alpha: AlphaIoU中的alpha参数,默认为1,为1时则为普通的IoU,如果想采用AlphaIoU,论文alpha默认值为3,此时设置CIoU=True则为AlphaCIoU
gamma: Focal_XIoU中的gamma参数,默认为0.5
scale: scale为True时,WIoU会乘以一个系数
monotonous: 3个输入分别代表WIoU的3个版本,None: origin v1, True: monotonic FM v2, False: non-monotonic FM v3
eps: 防止除0
Returns:
iou
"""
# 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)
# Intersection area
inter = (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 Area
union = w1 * h1 + w2 * h2 - inter + eps
if scale:
wise_scale = WIoU_Scale(1 - (inter / union), monotonous=monotonous)
# IoU
# iou = inter / union # ori iou
iou = torch.pow(inter / (union + eps), alpha) # alpha iou
if CIoU or DIoU or GIoU or EIoU or SIoU or WIoU:
cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1) # convex (smallest enclosing box) width
ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1) # convex height
if CIoU or DIoU or EIoU or SIoU or WIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
c2 = (cw ** 2 + ch ** 2) ** alpha + eps # convex diagonal squared
rho2 = (((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (
b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4) ** alpha # center dist ** 2
if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)
with torch.no_grad():
alpha_ciou = v / (v - iou + (1 + eps))
if Focal:
return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)), torch.pow(inter / (union + eps),
gamma) # Focal_CIoU
return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)) # CIoU
elif EIoU:
rho_w2 = ((b2_x2 - b2_x1) - (b1_x2 - b1_x1)) ** 2
rho_h2 = ((b2_y2 - b2_y1) - (b1_y2 - b1_y1)) ** 2
cw2 = torch.pow(cw ** 2 + eps, alpha)
ch2 = torch.pow(ch ** 2 + eps, alpha)
if Focal:
return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2), torch.pow(inter / (union + eps), gamma) # Focal_EIou
return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2) # EIou
elif SIoU:
# SIoU Loss https://arxiv.org/pdf/2205.12740.pdf
s_cw, s_ch = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5 + eps, (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5 + eps
sigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)
sin_alpha_1, sin_alpha_2 = torch.abs(s_cw) / sigma, torch.abs(s_ch) / sigma
threshold = pow(2, 0.5) / 2
sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)
angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - math.pi / 2)
rho_x, rho_y = (s_cw / cw) ** 2, (s_ch / ch) ** 2
gamma = angle_cost - 2
distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)
omiga_w, omiga_h = torch.abs(w1 - w2) / torch.max(w1, w2), torch.abs(h1 - h2) / torch.max(h1, h2)
shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)
if Focal:
return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha), torch.pow(
inter / (union + eps), gamma) # Focal_SIou
return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha) # SIou
elif WIoU:
if scale:
return getattr(WIoU_Scale, '_scaled_loss')(wise_scale), (1 - iou) * torch.exp((rho2 / c2)), iou # WIoU v3 https://arxiv.org/abs/2301.10051
return iou, torch.exp((rho2 / c2)) # WIoU v1
if Focal:
return iou - rho2 / c2, torch.pow(inter / (union + eps), gamma) # Focal_DIoU
return iou - rho2 / c2 # DIoU
c_area = cw * ch + eps # convex area
if Focal:
return iou - torch.pow((c_area - union) / c_area + eps, alpha), torch.pow(inter / (union + eps), gamma) # Focal_GIoU https://arxiv.org/pdf/1902.09630.pdf
return iou - torch.pow((c_area - union) / c_area + eps, alpha) # GIoU https://arxiv.org/pdf/1902.09630.pdf
if Focal:
return iou, torch.pow(inter / (union + eps), gamma) # Focal_IoU
return iou # IoU
class WIoU_Scale:
"""
monotonous: {
None: origin v1
True: monotonic FM v2
False: non-monotonic FM v3
}
momentum: The momentum of running mean
"""
iou_mean = 1.
_momentum = 1 - pow(0.5, exp=1 / 7000)
_is_train = True
def __init__(self, iou, monotonous=False):
self.iou = iou
self.monotonous = monotonous
self._update(self)
@classmethod
def _update(cls, self):
if cls._is_train: cls.iou_mean = (1 - cls._momentum) * cls.iou_mean + \
cls._momentum * self.iou.detach().mean().item()
@classmethod
def _scaled_loss(cls, self, gamma=1.9, delta=3):
if isinstance(self.monotonous, bool):
if self.monotonous:
return (self.iou.detach() / self.iou_mean).sqrt()
else:
beta = self.iou.detach() / self.iou_mean
alpha = delta * torch.pow(gamma, beta - delta)
return beta / alpha
return 1