当前位置:   article > 正文

【目标检测系列】目标检测算法综述

目标检测算法综述

零  写在前面:

浏览器被不小心关闭了,编辑了半天的东西全没了,就简单写写吧,360真坑

object detection,就是在给定的图片中精确找到物体所在位置,并标注出物体的类别。再进一步简化说就是:

                                目标定位 + 识别

一,目标检测算法分类:

目前目标检测算法大体分为3类。

1.传统方法

         如adaboost+harr用来检测    hog + svm用来识别。

  流程:a.穷举搜索框,设置目标大小范围以及高宽比例,穷举N种框。

              b.提取特征如hog harr lbp等,将其归一化到固定尺寸如30*30这样 然后提取特征。

              c.过分类器如adaboost ,svm等做最终分类。结果就是这个穷举的框的位置。

2.two stages

        代表作是R-CNN SPP-net Fast-RCNN Faster-RCNN R-FCN等等。演化过程是RCNN->SppNET->Fast-RCNN->Faster-RCNN,每个新版本都是为了解决老版本存在的一些致命问题而改进。

2.1. R-CNN算法介绍:

        先说R-CNN算法,将深度学习引入了目标检测领域。

算法流程:

       a.先弄个backbone,随便一个例如alexnet VGGnet等都行,确定下自己准备检测几类,就训练一个对应的分类网络或者直接fine-tuning一个现成网络改吧改吧。

        b.利用选择性搜索方法select search提取待识别区域。这个select search算法是基于图分割的基础,利用各种规则做合并,得到的不同区域,疑似目标就包含在其中。减少了上面穷举法的弊端,搜索框限定在2000个左右,大大缩短时间了啊。对于每一个区域,修正区域大小以适合CNN的输入,做一次前向运算,将最后一个池化层的输出(就是对候选框提取到的特征)存到硬盘。

        c.训练一个SVM分类器(二分类)来判断这个候选框里物体的类别每个类别对应一个SVM,判断是不是属于这个类别,是就是positive,反之nagative。

        d.使用回归器精细修正候选框位置:对于每一个类,训练一个线性回归模型去判定这个框是否框得完美。边框回归详细介绍见我的博文:

显然R-CNN只是将神经网络作为一个特征提取器,最后识别是需要svm的,边框定位是用回归算法。

算法代码:没去特意关注,因为此算法显然不符合实际应用啊。

较上一版本改进点:鼻祖!

算法优缺点:深度学习进入目标检测领域。缺点很明显,2000个候选框看似少,但是每一个都输入CNN去做特征提取去,那效率比adaboost的穷举框不如啊。而且最后和adaboost一样是用svm做分类器的。

2.2. Fast R-CNN算法介绍:

       Fast R-CNN 要先说下sppnet。sppnet是为了解决任意尺寸输入而生,输入数据每次都需要放缩到固定大小以适应全连接层,而放缩会导致目标形变,形变肯定影响识别结果啊。详细SPPnet看我的博文https://blog.csdn.net/gbz3300255/article/details/105843416

算法流程:

       a.与RCNN一样

        b.前半部分select search提取待识别区域与RCNN一致,后面将整图都输入CNN网络中去提取特征了。这样就不用做2000多次特征提取了,一次就完事了,然后按框与特征图的映射关系去提取每一部分的特征图就好

        c.2000多个小patch对应的特征图直接分别放入sppnet,获得输出特征就好,不用对提取出的小patch进行resize了。

        d.后面一样了,过svm分类器去做类别判断,用边框回归方法做位置修正。

算法代码:没去特意关注,因为此算法显然不符合实际应用啊。

较上一版本改进点:显然fast R-CNN 特征提取部分做了大修正,特征提取一次且不用对其resize,提升了效率和准确性

算法优缺点:较上一版本效率提升,准确率提升,还是略显麻烦,不易用啊。

2.3. Faster R-CNN算法介绍:

        Fast R-CNN 看上去很美,但前面那个选择性搜索耗时还是多,想法让这个搜索也网络来做就好了,就有大神提出了RPN网络,RPN网络说白了就是一个粗搜索的网络框架,输出结果是一堆候选框,详情可看我的博文:https://mp.csdn.net/console/editor/html/105493407

算法流程:

        a. 对整张图片输进CNN,得到feature map
        b. 将卷积特征feature map输入到RPN,得到候选框的特征信息。
        c. 对候选框中提取出的特征,使用分类器判别是否属于一个特定类 
        d. 对于属于某一特征的候选框,用回归器进一步调整其位置 

算法代码:没去特意关注,因为此算法显然不符合实际应用啊。

较上一版本改进点:显然去掉了候选框在外面提取的步骤,将此步骤用神经网络完成,进一步简化了步骤,算法性能又进一步提升了

算法优缺点:较上一版本效率提升,准确率提升,初步可用。

3.one stages

3.1 yolov1

        上面的两阶段法效率低下,有大神提出了YOLO检测算法,该方法基于回归,一次将检测和识别搞定,所以叫one stages方法。you only look once。one stages 的开山之作。

算法流程:

       a. 如下图,输入图像大小为448*448,经过若干个卷积层与池化层,变为7*7*1024张量(图一中倒数第三个立方体),最后经过两层全连接层,输出张量维度为7*7*N,这就是Yolo v1的整个神经网络结构。这个N与检测类别有关,计算公式为:7 * 7 * (框个数 * 5 + 类别数那么多的置信度) 其中5为框的坐标 (x0,y0)(x1,y1) + 框存在的置信度。具体例子:例如要检测10类,每个锚点有2种框(长宽比为1:2与2:1).那么就是7*7*(2 * 5 + 10)。yolov1的锚点框大小是人为设定的哦,v2v3开始是用聚类方法自己算的,更符合实际应用感觉。
        b.进行非极大值抑制,筛选Boxes,作为输出结果。非极大值抑说白了就是去除重叠的伪结果。非极大值抑制流程:(1)将所有框的得分排序,选中最高分及其对应的框 (2)遍历其余的框,如果和当前最高分框的重叠面积(IOU)大于一定阈值,我们就将框删除。 (3)从未处理的框中继续选一个得分最高的,重复上述过程。

算法代码:没去特意关注,因为直接看的yolov3哈哈。v1是开山之作但小目标检测效果差。

算法损失函数:

        损失函数的设计目标就是让坐标(x,y,w,h),confidence,classification 这个三个方面达到很好的平衡。 简单的全部采用了sum-squared error loss来做这件事会有以下不足: a) 8维的localization error和20维的classification error同等重要显然是不合理的。 b) 如果一些栅格中没有object(一幅图中这种栅格很多),那么就会将这些栅格中的bounding box的confidence 置为0,相比于较少的有object的栅格,这些不包含物体的栅格对梯度更新的贡献会远大于包含物体的栅格对梯度更新的贡献,这会导致网络不稳定甚至发散。

        更重视8维的坐标预测,给这些损失前面赋予更大的loss weight, 记为 λcoord ,在pascal VOC训练中取5。(上图蓝色框) 
对没有object的bbox的confidence loss,赋予小的loss weight,记为 λnoobj ,在pascal VOC训练中取0.5。(上图橙色框) 
有object的bbox的confidence loss (上图红色框) 和类别的loss (上图紫色框)的loss weight正常取1。

找了个yolov1的损失函数pytorch版本的,加深下理解吧。

首先明确一概念,网格就是最终特征图(7*7*30)上的一个预测目标了,v1版本这样的预测结果网格一共有49个,每个维度为1*30.这30的向量含义为【x0,y0,w0, h0,I0,x1,y1,w1, h1,I1,C0,C1,C2.....C19】前面10位代表了2个box框信息以及其置信度,后20位表示了分类概率值。后面的损失函数都是针对网格中的一些属性来干活的。

        a.标注图像某位置有目标,预测为有==>计算not response loss 未响应损失以及box框的坐标等的信息对应红色框蓝色框

  1. coo_response_mask = torch.cuda.ByteTensor(box_target.size())
  2. coo_response_mask.zero_()
  3. coo_not_response_mask = torch.cuda.ByteTensor(box_target.size())
  4. coo_not_response_mask.zero_()
  5. for i in range(0,box_target.size()[0],2):
  6. box1 = box_pred[i:i+2]
  7. box1_xyxy = Variable(torch.FloatTensor(box1.size()))
  8. box1_xyxy[:,:2] = box1[:,:2] -0.5*box1[:,2:4]
  9. box1_xyxy[:,2:4] = box1[:,:2] +0.5*box1[:,2:4]
  10. box2 = box_target[i].view(-1,5)
  11. box2_xyxy = Variable(torch.FloatTensor(box2.size()))
  12. box2_xyxy[:,:2] = box2[:,:2] -0.5*box2[:,2:4]
  13. box2_xyxy[:,2:4] = box2[:,:2] +0.5*box2[:,2:4]
  14. iou = self.compute_iou(box1_xyxy[:,:4],box2_xyxy[:,:4]) #[2,1]
  15. max_iou,max_index = iou.max(0)
  16. max_index = max_index.data.cuda()
  17. coo_response_mask[i+max_index]=1
  18. coo_not_response_mask[i+1-max_index]=1
  19. box_pred_response = box_pred[coo_response_mask].view(-1,5)
  20. box_target_response = box_target[coo_response_mask].view(-1,5)
  21. contain_loss = F.mse_loss(box_pred_response[:,4],box_target_response[:,4],size_average=False)
  22. loc_loss = F.mse_loss(box_pred_response[:,:2],box_target_response[:,:2],size_average=False) + F.mse_loss(torch.sqrt(box_pred_response[:,2:4]),torch.sqrt(box_target_response[:,2:4]),size_average=False)

contain_loss是计算预测为有目标的网格的confidence与真值的confidence的平方误差作为loss判定。只是两个值的计算对应红色框。

loc_loss是计算蓝色框的内容呢。

 b.标注图像某位置有目标,预测为无==>计算response loss响应损失,对应代码。

  1. box_pred_not_response = box_pred[coo_not_response_mask].view(-1,5)
  2. box_target_not_response = box_target[coo_not_response_mask].view(-1,5)
  3. not_contain_loss = F.mse_loss(box_pred_response[:,4],box_target_response[:,4],size_average=False)

not_contain_loss是计算预测为无的网格confidence与真值的confidence的平方误差作为loss判定,也只是两个值的计算对应红色框。       可见红色框是分了两部分计算的切记切记
     
        c.标注图像某位置无目标,预测为有==>计算不包含obj损失  只计算第4,9位的有无物体概率的loss ,对应代码是下面这行。

  1. noo_pred = pred_tensor[noo_mask].view(-1,30)
  2. noo_target = target_tensor[noo_mask].view(-1,30)
  3. noo_pred_mask = torch.cuda.ByteTensor(noo_pred.size())
  4. noo_pred_mask.zero_()
  5. # 将第49 即有物体的confidence置为1
  6. noo_pred_mask[:, 4] = 1
  7. noo_pred_mask[:, 9] = 1
  8. noo_pred_c = noo_pred[noo_pred_mask]
  9. noo_target_c = noo_target[noo_pred_mask]
  10. nooobj_loss = F.mse_loss(noo_pred_c,noo_target_c,size_average=False)

noo_mask记录的是所有网格在真实图像上目标存在与否的标签。

noo_pred是根据noo_mask标签取出的实际不含目标的预测网格的向量。其向量4,,9位置的值是预测值。

noo_target是根据noo_mask标签取出的实际不含目标的真值网格的向量。其向量第4 ,9位置值是0。

nooobj_loss只计算了这个些网格30维向量的4,9位置的损失值,其他位置都没用。对应上图中的橙色框。这样此部分的loss函数目标就是让预测值越接近0越好。符合了loss的目的了

      d.标注图像某位置无目标,预测为无==>无损失(不计算)

      e 类别的损失函数计算,代码如下:

class_loss = F.mse_loss(class_pred, class_target, size_average=False)

 class_loss计算的是类别的损失函数,是网格向量的后20个数据做最小平方误差来构建loss函数的。对应图中紫色框

至此v1的损失函数整体就完事了呀。

        目标检测神经网络的损失函数就用上面这4部分组成了。后续网络优化目的就是计量减少这个函数的值,换句话说就是如果此区域存在真值,就训练出一组权重让预测中心无限接近真值中心,让预测边框无限接近真值边框。

较上一版本改进点:真正的端到端的训练,开山之作,准确率不足,效率飞升。

算法优缺点:较上一版本效率提升,工业应用可期。但是它只在7*7这个特征图上做文章,丢失很多细节,也是小目标检测能力低下的根本原因。定位精度低,每个框内只能检出一个目标(例如鸟群)。略显粗糙啊。还有其用了全连接层,所以输入数据需要放缩到统一尺度才能进行检测。

3.2 SSD

        应该介绍v2,结果ssd横插一扛子,因为它对标的就是v1,解决了v1定位不准问题。然后yolov2又吊打它.........。

        SSD从YOLOV1中继承了将detection转化为regression的思路,一次完成目标定位与分类。基于Faster RCNN中的Anchor,提出了相似的Prior box;加入基于特征金字塔(Pyramidal Feature Hierarchy)的检测方式,即在不同感受野的feature map上预测目标,增加了小目标检测能力,但是因为小目标检测用的是低层特征,非线性表达能力欠缺,还不能达到很高的精度。

算法流程:

        a. 将整张图片输入VGG网络前半部分,得到A部分输出,其输出是relu之后的结果, 尺寸为38 * 38 * 512,在其上做一次Normalization,然后对此特征图做分类预测和边框的回归计算,输出A1
        b.将A部分作为输入放入VGG网络后半部分,其输出也是relu之后的结果记为B, 尺寸为19* 19 * 1024,然后对此特征图做分类预测和边框的回归计算,输出B1
        c. 将B部分作为输入放入extras网络,其输出都是卷积结果 记录C D E  F, 尺寸分别为10*10*512  5 *5 * 256   3*3 *256  1*1*256,然后对此特征图做分类预测和

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/775491
推荐阅读
相关标签
  

闽ICP备14008679号