复习笔记——动手开撸“完美”IOU计算C++版本全家桶

复习笔记——动手撸IOU全家桶(C++版本)

最近需要调整下,故开此系列复习下基础,有些大厂面试会让你手撕IOU,这里我自己整理思路,编了一套C++版本的IOU礼包,该篇简单粗暴,不和你讲道理(您只需要关注我,免费获取)目的是自己造下轮子同时复习下基础知识,校招的同学们看完了可以直接反手打一个暴击,告诉面试的我不仅会IOU,我还给你写GIOU,CIOU,DIOU !EIOU!


动机:分享和自己复习,主要是算法分享系列写起来太累,有时候细节知识点我真的生疏或者理解没到位,需要再反复琢磨下!晚些更。


阅读本篇,您将收获以下:

1.面试遇到不怕啦,心理嘲讽:啥年代还问IOU,不知道IOU的弊端嘛?写完IOU继续写GIOU…balbalabal
2.您将获得我的一份C++ IOU代码,里面有完整的注释和计算思路。
3.真正了解IOU的思路和动机。

一、IOU礼包计算思路简述:

1.IOU简述

IOU交并比,无法衡量两框是相邻还是甚远:因为两种情况下iOU均为0,仅从IOU数值上无法判断两者距离较近还是较远,导致了一个很严重的缺点就是:IOU为0,Loss也为0,那么网络梯度不回传,无法进行训练,因此IoU作为 loss函数在回归任务中的表现并不好。

2 进化路线(以LOSS函数为时间线)

2.1 GIOU

所以GIOU它来了,就如图,我们计算到最小外接矩形C,然后C-AUB拿到绿色区域面积,GIOU=IOU-(C-(AUB))/C,作为LOSS:1-GIOU;也就是说GIOU<=IOU恒成立,解决了什么问题?

在这里插入图片描述
这样的好处就是两个BOX即使不相交,那么IOU=0,GIOU的值就是一个负数,-(C-(AUB)/C,其实就是一个无限趋向于-1的数,因此LOSS如果设定为1-GIOU,那么之前IOU=0时候,计算LOSS没法传梯度的问题就解决了,说白了,就解决IOU=0的问题的!

2.2 DIOU

GIOU Loss引入了一个惩罚项的操作,使得梯度能够迭代训练,在不重叠的情况下,预测也能够向目标框移动。但是,同时仍然存在问题:

在这里插入图片描述
即如论文图中所示,当出现这类情况,GIOU完全等同于IOU了,这样LOSS就退化成IOU LOSS,所以DIOU它来了!
那就是再引入一个新的惩罚项,该项其实,C:(我们之前计算GIOU已经得到过两个BOX的最小外接矩形的对角线程度,p代表两个BOX之间中心点欧氏距离
在这里插入图片描述
因此,DIOU弥补了GIOU的不足,且具备: DIoU loss直接以中心点坐标去最小化两个目标框的距离,而GIOU loss优化的是两个目标框之间的面积,因此比GIoU loss收敛快得多.

2.3 CIOU

CIOU Loss是基于DIOU,又引入一个box长宽比的惩罚项,为了考虑了box的长宽比,定义如下:
在这里插入图片描述
就是加了一个项,首先V是一个衡量anchor框和目标框之间的shape比例,alpha则是调节比例的权重参数:
在这里插入图片描述
总结就是CIOU是全面版本,考虑的更多,这些IOU的本质侧重点都是基于IOU=0时候的优化手段!只是这些IOU由于参数需要训练的GT得到,所以这个只适合作LOSS训练。
清楚了这些,直接可以手撕IOU!没完呢,还有2021年的EIOU!

2.4 EIOU以及FOCAL-LOSS版本

在CIOU的惩罚项基础上将纵横比的影响因子拆开分别计算目标框和锚框的长和宽,该损失函数包含三个部分:重叠损失,中心距离损失,宽高损失,前两部分延续CIOU中的方法,但是宽高损失直接使目标盒与锚盒的宽度和高度之差最小,使得收敛更快,LOSS公式如下
在这里插入图片描述
其中 Cw 和 Ch 是覆盖两个Box的最小外接框的宽度和高度。

考虑到BBox的回归中也存在训练样本不平衡的问题,即在图像中回归误差小的高质量锚框的数量远少于误差大的低质量样本,质量较差的样本会产生过大的梯度影响训练过程。作者在EIOU的基础上结合Focal Loss提出一种Focal EIOU Loss,梯度的角度出发,把高质量的锚框和低质量的锚框分开,惩罚项公式如下:
在这里插入图片描述

二、C++代码

1.IOU全家桶

代码如下(示例):

#include<iostream>
#include<vector>
#include<algorithm>
#include <cmath>
#define pi 3.1415926
//默认BOX,左右角点的定义:(x0,y0)(x1,y1)
struct Box
{
 double x0;
 double x1;
 double y0;
 double y1;
 
 };
 // 解决IOU LOSS在回归的性能损失
 // input:BOX,GT_BOX,select IOU/GIOU/DIou/CIou
 // output:IOU's AREA
double IoU_compute(Box &a,Box &b,bool GIoU=false,bool DIoU=false, bool CIoU=false,bool EIoU=false,double eps=1e-9){
    
	double iou=0;
	//这里的原则就是算交集面积,两个BOX右角点最小的点-两个BOX左角点最大的点 就是交集的宽W,同理H也这么算
	double inter_width_line=std::min(a.x1,b.x1)-std::max(a.x0,b.x0);
	inter_width_line=std::max(inter_width_line,0.000);
	double inter_high_line =std::min(a.y1,b.y1)-std::max(a.y0,b.y0);
	inter_high_line=std::max(inter_high_line,0.000);
	//本来原始的判断两个BOX是否有交集,因为上一步计算的交集矩形宽和高如果小于0,证明两个BOX无任何交集,eps是给分母加一个很小的数
	//但是其实没必要,因为本来就是0,并且别GIOU算法是0也需要计算LOSS
	//if(inter_width_line or inter_high_line){
		//得到BOX之间交集和并集
	double inter_area=inter_width_line*inter_high_line;
	double union_area=(a.x1-a.x0)*(a.y1-a.y0)+(b.x1-b.x0)*(b.y1-b.y0)-inter_area+eps;
	iou=inter_area/union_area;
	//std::cout<<"iou:"<<iou<<std::endl;
	//}
	//建立在IOU上引申的三种IOU算法
	if(GIoU or DIoU or CIoU or EIoU){
		//计算最小外接矩形的宽和高,这是三个IOU都需要计算的,其实它们属于衍生关系GIOU->DIOU->CIoU
		//GIoU具有一下特性: 1.与IoU一样,具有非负性、尺度不变性等特性 2.任意B、G都存在,GIoU<=IoU 3.-1< GIoU <=1, 当IoU等于1时,GIoU也等于1 由此可见,只有当B与G重合时,GIoU Loss才会为0,相比IoU Loss,GIoU Loss在任意情况下都可以进行训练
		double smallest_w=std::max(a.x1,b.x1)-std::min(a.x0,b.x0);
	    double smallest_h=std::max(a.y1,b.y1)-std::min(a.y0,b.y0);
		if(CIoU or DIoU or EIoU){
			//根据公式,计算两个BOX最小外接矩形的对角线长度
			double c2=pow(smallest_w,2)+pow(smallest_h,2)+eps;  //对角线长度平方为C2
			//计算中心点距离,中心点坐标:(x0+x1)/2 ,(y0+y1)/2,作欧氏距离,得到平方值dis_center
			double dis_center=(pow(b.x0+b.x1-a.x0-a.x1,2)+pow(b.y0+b.y1-a.y0-a.y1,2))/4;
			if(DIoU)
				//相比GIoU,DIoU限制的不是最小外接矩与B与G并集面积的差值,而是直接限制了最小外接矩的面积和B与G中心点的位置,这会使得网络更倾向于移动bounding box的位置来减少Loss。同时也加入了IoU元素来使bounding box与ground truth的覆盖面积更加接近
				return iou-dis_center/c2;
			else if(CIoU ){
				//DIoU只考虑了覆盖面积和中心点距离,所以CIOU又在DIoU的基础上加入了长宽比的因素
			    //1.按照公式,需要就算两个BOX的长宽比v
				double v=(4 /pow(pi,2)) * pow(atan((b.x1-b.x0) / (b.y1-b.y0)) - atan((a.x1-a.x0) / (a.y1-a.y0)), 2);
				//2.计算权重alpha loss阶段
				double alpha=v/(1+eps-iou+v);
				return iou-(dis_center/c2+v*alpha);
			}	
			else{//EIoU ,在DIOU基础上-宽和高的损失 去替代IOU的是相对比,
				double w_dis=pow(a.x1-a.x0-b.x1+b.x0,2);
				//std::cout<<"w dis:"<<w_dis<<std::endl;
				double h_dis=pow(a.y1-a.y0-b.y1+b.y0,2);
				double cw2=pow(smallest_w,2)+eps;
				double ch2=pow(smallest_h,2)+eps;
				//std::cout<<"宽比;"<<w_dis/cw2<<std::endl;
				//std::cout<<"高比:"<<h_dis/ch2<<std::endl;
				//std::cout<<"中心点距离比:"<<dis_center/c2<<std::endl;
				return iou-(dis_center/c2+w_dis/cw2+h_dis/ch2);
			}	
        }			
        else{
				//GIOU:解决IoU Loss中当B与G不相交时,Loss为0的问题,保证在没有相交时也会有损失函数值,能够进行反向传播)
	            //计算其最小邻接矩形面积convex area
		    double convex_area=smallest_w*smallest_h+eps;
			return iou-(convex_area-union_area)/convex_area;
		}
	}
	else 
		return iou; 
 }
 
int main( int argc, char *argv[] ){
	//test 
	Box a{2,20,15,38};
	Box b{3,15,9,50};
	double iou=IoU_compute(a,b,false,false,false,true);
	std::cout<<"iou :"<<iou<<std::endl;
	
	return 1;	
	 
 }

总结

该篇初衷旨在防止自己的脑子“灾难性遗忘”,且分享给需要面试的朋友们,祝好!

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值