|
在YoloV8中添加EIoU,SIoU,AlphaIoU,FocalEIoU,Wise-IoU.2023-2-7更新yolov8添加Wise-IoUB站链接重磅!!!!!YOLO模型改进集合指南-CSDNyolov8中box_iou其默认用的是CIoU,其中代码还带有GIoU,DIoU,文件路径:ultralytics/yolo/utils/metrics.py,函数名为:bbox_ioudefbbox_iou(box1,box2,xywh=True,GIoU=False,DIoU=False,CIoU=False,eps=1e-7):#ReturnsIntersectionoverUnion(IoU)ofbox1(1,4)tobox2(n,4)#Getthecoordinatesofboundingboxesifxywh:#transformfromxywhtoxyxy(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/2b1_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=box1b1_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)#Intersectionareainter=(b1_x2.minimum(b2_x2)-b1_x1.maximum(b2_x1)).clamp(0)*\(b1_y2.minimum(b2_y2)-b1_y1.maximum(b2_y1)).clamp(0)#UnionAreaunion=w1*h1+w2*h2-inter+eps#IoUiou=inter/unionifCIoUorDIoUorGIoU:cw=b1_x2.maximum(b2_x2)-b1_x1.minimum(b2_x1)#convex(smallestenclosingbox)widthch=b1_y2.maximum(b2_y2)-b1_y1.minimum(b2_y1)#convexheightifCIoUorDIoU:#DistanceorCompleteIoUhttps://arxiv.org/abs/1911.08287v1c2=cw**2+ch**2+eps#convexdiagonalsquaredrho2=((b2_x1+b2_x2-b1_x1-b1_x2)**2+(b2_y1+b2_y2-b1_y1-b1_y2)**2)/4#centerdist**2ifCIoU:#https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47v=(4/math.pi**2)*(torch.atan(w2/h2)-torch.atan(w1/h1)).pow(2)withtorch.no_grad():alpha=v/(v-iou+(1+eps))returniou-(rho2/c2+v*alpha)#CIoUreturniou-rho2/c2#DIoUc_area=cw*ch+eps#convexareareturniou-(c_area-union)/c_area#GIoUhttps://arxiv.org/pdf/1902.09630.pdfreturniou#IoU123456789101112131415161718192021222324252627282930313233343536373839'运行运行我们可以看到函数顶部,有GIoU,DIoU,CIoU的bool参数可以选择,如果全部为False的时候,其会返回最普通的Iou,如果其中一个为True的时候,即返回设定为True的那个Iou。那么重点来了,我们怎么在这个函数里面添加EIoU,SIoU,AlphaIoU,FocalEIoU呢?我们只需要把上面提及到的这个函数替换成以下,代码出自:github链接,这个github上还有一些yolov5的改进源码和一些常用的脚本,有兴趣可以去看看,请各位也帮忙点个star支持下,谢谢!defbbox_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):#ReturnsIntersectionoverUnion(IoU)ofbox1(1,4)tobox2(n,4)#Getthecoordinatesofboundingboxesifxywh:#transformfromxywhtoxyxy(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/2b1_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=box1b1_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)#Intersectionareainter=(b1_x2.minimum(b2_x2)-b1_x1.maximum(b2_x1)).clamp(0)*\(b1_y2.minimum(b2_y2)-b1_y1.maximum(b2_y1)).clamp(0)#UnionAreaunion=w1*h1+w2*h2-inter+eps#IoU#iou=inter/union#oriiouiou=torch.pow(inter/(union+eps),alpha)#alphaiouifCIoUorDIoUorGIoUorEIoUorSIoU:cw=b1_x2.maximum(b2_x2)-b1_x1.minimum(b2_x1)#convex(smallestenclosingbox)widthch=b1_y2.maximum(b2_y2)-b1_y1.minimum(b2_y1)#convexheightifCIoUorDIoUorEIoUorSIoU:#DistanceorCompleteIoUhttps://arxiv.org/abs/1911.08287v1c2=(cw**2+ch**2)**alpha+eps#convexdiagonalsquaredrho2=(((b2_x1+b2_x2-b1_x1-b1_x2)**2+(b2_y1+b2_y2-b1_y1-b1_y2)**2)/4)**alpha#centerdist**2ifCIoU:#https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47v=(4/math.pi**2)*(torch.atan(w2/h2)-torch.atan(w1/h1)).pow(2)withtorch.no_grad():alpha_ciou=v/(v-iou+(1+eps))ifFocal:returniou-(rho2/c2+torch.pow(v*alpha_ciou+eps,alpha)),torch.pow(inter/(union+eps),gamma)#Focal_CIoUelse:returniou-(rho2/c2+torch.pow(v*alpha_ciou+eps,alpha))#CIoUelifEIoU:rho_w2=((b2_x2-b2_x1)-(b1_x2-b1_x1))**2rho_h2=((b2_y2-b2_y1)-(b1_y2-b1_y1))**2cw2=torch.pow(cw**2+eps,alpha)ch2=torch.pow(ch**2+eps,alpha)ifFocal:returniou-(rho2/c2+rho_w2/cw2+rho_h2/ch2),torch.pow(inter/(union+eps),gamma)#Focal_EIouelse:returniou-(rho2/c2+rho_w2/cw2+rho_h2/ch2)#EIouelifSIoU:#SIoULosshttps://arxiv.org/pdf/2205.12740.pdfs_cw=(b2_x1+b2_x2-b1_x1-b1_x2)*0.5+epss_ch=(b2_y1+b2_y2-b1_y1-b1_y2)*0.5+epssigma=torch.pow(s_cw**2+s_ch**2,0.5)sin_alpha_1=torch.abs(s_cw)/sigmasin_alpha_2=torch.abs(s_ch)/sigmathreshold=pow(2,0.5)/2sin_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=(s_cw/cw)**2rho_y=(s_ch/ch)**2gamma=angle_cost-2distance_cost=2-torch.exp(gamma*rho_x)-torch.exp(gamma*rho_y)omiga_w=torch.abs(w1-w2)/torch.max(w1,w2)omiga_h=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)ifFocal:returniou-torch.pow(0.5*(distance_cost+shape_cost)+eps,alpha),torch.pow(inter/(union+eps),gamma)#Focal_SIouelse:returniou-torch.pow(0.5*(distance_cost+shape_cost)+eps,alpha)#SIouifFocal:returniou-rho2/c2,torch.pow(inter/(union+eps),gamma)#Focal_DIoUelse:returniou-rho2/c2#DIoUc_area=cw*ch+eps#convexareaifFocal:returniou-torch.pow((c_area-union)/c_area+eps,alpha),torch.pow(inter/(union+eps),gamma)#Focal_GIoUhttps://arxiv.org/pdf/1902.09630.pdfelse:returniou-torch.pow((c_area-union)/c_area+eps,alpha)#GIoUhttps://arxiv.org/pdf/1902.09630.pdfifFocal:returniou,torch.pow(inter/(union+eps),gamma)#Focal_IoUelse:returniou#IoU12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182'运行运行注意事项我认为Focal_EIoU的思想是可以用作与其他IoU的变种,因此我对里面所有的IoU都支持Focal_EIoU的思想,只需要设定Focal参数为True即可,我自己测试的过程中,除了Focal_SIoU出现loss为inf之外,其他的都正常,不过这个不同的数据集可能出现不一样,具体可以自行测试下。gamma参数是Focal_EIoU中的gamma参数,一般就是为0.5,有需要可以自行更改。alpha参数为AlphaIoU中的alpha参数,默认为1,1的意思就是跟正常的IoU一样,如果想采用AlphaIoU的话,论文alpha默认值为3。(比如我不想使用AlphaIoU的特性,我就把alpha设置为1就可以,如果我想使用AlphaIoU的特性,我可以设置alpha为3)。跟Focal_EIoU一样,我认为AlphaIoU的思想同样可以用在其他的IoU变种上,简单来说就是如果你设置了alpha为3,其他IoU设定的参数(GIoU,DIoU,CIoU,EIoU,SIoU)为False的时候,那就是AlphaIoU,如果你设置了alpha为3,CIoU为True的时候,那就是AlphaCIoU,效果的话就因数据集和模型而已,具体可以自行测试下。想用那个IoU变种,就直接设置参数为True即可。AlphaIoU理论上与Focal_EIoU没有直接的冲突,但是作者这边没有详细测试过,这两者一起用会是什么效果,有兴趣可以自行测试下。除了以上这个函数替换,还需要在ultralytics/yolo/utils/loss.py中BboxLossClass中的forward函数中修改一下:原本的forward函数如下:主要对红框部分替换为以下代码:iou=bbox_iou(pred_bboxes[fg_mask],target_bboxes[fg_mask],xywh=False,CIoU=True)iftype(iou)istuple:loss_iou=((1.0-iou[0])*iou[1].detach()*weight).sum()/target_scores_sumelse:loss_iou=((1.0-iou)*weight).sum()/target_scores_sum12345最后修改参数就在调用bbox_iou中进行修改即可,比如上面的代码就是使用了CIoU,如果你想使用Focal_EIoU那么你可以修改为下:iou=bbox_iou(pred_bboxes[fg_mask],target_bboxes[fg_mask],xywh=False,EIoU=True,Focal=True)1YoloV8中在标签分配规则中也有用到bbox_iou的函数,具体在:ultralytics/yolo/utils/tal.py的TaskAlignedAssignerclass中的get_box_metrics函数:对于这个我个人修改建议就是跟你计算IoULoss的时候选择一样即可,但是这里不需要开启Focal选项,因为这里只是单纯求交并比。意思就是你在计算IoULoss的时候,比如选择了Focal=True和CIoU=True,那么在这里你只需要选择CIoU=True即可。最后希望这篇文章可以帮助到大家。博文求点赞,github求star,谢谢啦!
|
|