标签 目标检测 下的文章

整体思路

​ 创建DataSet首先需要继承torch.utils.data.Dataset这个类,然后再init函数中完成数据的一些预处理,比如xml文件的解析/类与序号的映射/图片路径的存储等。

​ 接下来需要重载__len____getitem__两个方法,分别返回数据长度和某个序号对应的图片(包括图片本身和标注)

如果用到多GPU训练,按照Pytorch官方的建议,最好再实现get_height_and_wight这个方法,节约内存.(因为这样可以避免pytorch将所有图片读入计算宽高)

源码细节

1. xml解析

​ 在init方法中调用了parse_xml_to_dict方法解析xml文件,获取其中的object信息.(物体的类别/位置/边界框)

image-20230321230712153

​ 而parse_xml_to_dict具体使用递归的方法遍历标签信息,返回字典类型的数据

image-20230321230939717

2.__getitem__方法

​ 首先通过上述的给出的xml解析方法解析图片对应的xml文件,将结果存入data变量.图片也通过Image.open打开

image-20230321231804715

​ 接下来将data中的边界框和类别数据进行读取,丢到boxes和labels列表中.

image-20230321231948677

之后注意将这些数据转换成Tensor类型

​ 最后将信息都整理到target中,作为整体的标签返回.

image-20230321232106426

最后还需要判断是否对图片进行data augmentation

3.Transform

​ transform有很多类型,这里简单介绍一下水平翻转的实现.需要注意的是图片翻转之后,边界框的标注位置也需要翻转.

​ 对于水平翻转: y坐标不需要改变,xmax变为width-xmin,xmin变为width-xmax

image-20230321232427257

4.collate_fn

​ 为了之后实现dataloaer,这里需要实现collate_fn函数.

​ 不同于分类网络中dataset只返回一张图片和一个label(形式比较固定),目标识别网络中需要返回图片加标注,而标注是不等长的,使用默认的stack有可能出现问题.所以需要手动用collate_fn方法进行堆叠.

image-20230321232235799

下图是dataloader的实现,这里传入了collate_fn.不传入这个参数默认使用torch.stack()对__getitem__的每个返回值进行堆叠

image-20230321234927729

摘要

​ RCNN可以说是利用深度学习进行目标检测的开山之作。在当时的VOC 2012数据集上,将mAP提升了30%以上,达到了53.3%。

​ 这篇论文主要提出两个关键见解:

  • 可以将高容量的卷积神经网络应用在自底向上的区域建议(region proposal),以此来定位和分割对象。
  • 当训练数据不足时,可以选择进行辅助任务的监督预训练,再针对具体任务进行fine-tuning,以此获得显著的性能提升。

算法流程

  • 一张图像生成1k~2k个候选区域(使用Selective Search)
  • 对每个候选区域,使用深度网络提取特征
  • 特征送入每一类的SVM分类器,判别种类
  • 使用回归器对候选框进行微调

image-20230307094945946

候选区域生成

​ 使用Selective Search算法。算法大致思路是通过聚类的方法在图像上初步分割,找到

颜色/纹理/大小/相似度比较相似的区域,再根据这些区域进行加权合并,最后(希望)得到一些包括了GT box的候选框。

image-20230307095455683

AlexNet 提取特征

​ 对于每个候选框,将框中的内容提取出来,并缩放至227x227的大小,送入AlexNet中提取特征,产生4096维的向量

这里之所以一定要缩放到固定大小,是因为CNN里面有全连接层

image-20230307100723121

SVM分类

​ 将2000x4096的特征矩阵与20个SVM(20个类别)组成的4096x20权值矩阵相乘,得到2000x20的分数矩阵,行表示每个候选区域,列表是该候选区域对应类别的分数(概率).

​ 针对分数矩阵,在每一列中应用greed NMS剔除重叠的建议框,得到该列中得分较高的一些候选框。

之所以用SVM而不是直接softmax在论文附录中有提到,第一个原因是训练神经网络和训练SVM时采用的参数(IoU阈值)不一致,无法直接实现端到端。第二个原因是softmax无法实现难例挖掘(存疑)

回归器修正候选框位置

​ 回归器同样是利用CNN输出的特征向量(4096维)进行预测,通过预测相对于候选框的宽高偏移和位置偏移,可以对候选框的位置进行微调,更接近GT Box。

​ 预测时通过四个函数dx/dy/dw/dh来拟合GT Box,前两个公式拟合GTBox的中心位置,后两个位置拟合宽高的指数偏移。

image-20230307101918729

​ 训练时的标签值可以由以下公式获得。也就是上面四个公式的逆变换。

image-20230307102128616

网络框架

image-20230307101120843

卷积可视化

​ 论文里提到一个卷积可视化的概念。具体来说,选择在神经网络的某一个神经元,将他作为一个独立的对象检测器使用。对于该神经元,输入10 million的region proposal,找到这些区域中使该神经元值最大的那些候选框。通过输出这些图像,可以发现每个神经元有自己偏好的识别模式.比如上半身/狗子/红花等等。

image-20230307102830346

​ 论文中也提到这些神经元选取的是POOL5中的神经元。POOL5在网络尾部,所以偏好的识别模式也是比较抽象的(上文提到的上半身等等)。同时论文中也说到在一个通道内,坐标y/x只影响感受野,不影响识别模式。(很好理解,卷积核是不变的)

image-20230307102533964

消融实验

​ 论文里还做了一些消融实验,比较了神经网络中卷积层和全连接层的作用。在不进行fine-tuning时,不加全连接的mAP比较高;加了fine-tuning后,加了全连接的mAP比较高。得出结论:

①在HOG意义上,通过仅使用CNN的卷积层来计算任意大小的图像的密集特征图方面具有潜在的实用性。这种表示将使得能够在pool5特征之上使用滑动窗口检测器(包括DPM)进行实验。(其实就是卷积层负责提取通用特征?)

②从ImageNet学习的pool5特征是通用的,并且大部分mAP改善是通过在其上学习特定的非线性分类器获得的。(全连接层负责整合特征)

RCNN存在的问题

  • 测试速度慢,测试一张图片需要53s(CPU),首先需要2秒提取候选框,随后对2k个候选框进行卷积操作(最耗时间),最后进行矩阵乘法和NMS(以及利用回归器)筛选(回归)候选框。其中神经网络抽取特征耗时最长,因为进行很多重复操作(2k个候选框难免会有很多重叠区域)
  • 训练速度慢,不是端到端的系统,SVM分类器,BBOX回归器都需要单独训练。
  • 训练所需空间大,训练SVM和回归器的时候需要将每个候选框的特征写入磁盘。对于VGG16,从VOC2007训练集上5k个图像提取的特征,需要数百GB的存储空间。

模型对比

不同版本的YOLOv5的表现如下,参数量从小到大为n-s-m-l-x,mAP也逐渐升高,不过推理速度也近乎翻了一倍(V100)

表格后一部分带6的模型是针对高分辨率图片的,参数更多,mAP更高,具体差异将在网络结构提及

image-20230305102634129

网络结构

网络主体

  • Backbone: New CSP-Darknet53
  • Neck: SPPF, New CSP-PAN
  • Head: YOLOv3 Head

​ YOLOv5针对不同大小(n, s, m, l, x)的网络整体架构都是一样的,只不过会在每个子模块中采用不同的深度和宽度,分别应对yaml文件中的depth_multiple和width_multiple参数。

官方除了n, s, m, l, x版本外还有n6, s6, m6, l6, x6,区别在于后者是针对更大分辨率的图片比如1280x1280,当然结构上也有些差异,后者会下采样64倍,采用4个预测特征层,而前者只会下采样到32倍且采用3个预测特征层

Backbone

​ YOLOv5在Backbone部分较于v4没太大变化。但是YOLOv5在v6.0版本后相比之前版本有一个很小的改动,把网络的第一层(原来是Focus模块)换成了一个6x6大小的卷积层。两者在理论上其实等价的,但是对于现有的一些GPU设备(以及相应的优化算法)使用6x6大小的卷积层比使用Focus模块更加高效。详情可以参考这个issue #4825。

​ 下图是原来的Focus模块(和之前Swin Transformer中的Patch Merging类似),将每个2x2的相邻像素划分为一个patch,然后将每个patch中相同位置(同一颜色)像素给拼在一起就得到了4个feature map,然后在接上一个3x3大小的卷积层。这和直接使用一个6x6大小的卷积层等效。

等效这个说法还是需要琢磨一下,形状确实等效。但是能达到同一效果应该是实验出来的?

image-20230322192111819

Neck

​ Neck部分把SPP换成了SPPF。传统SPP是几个最大池化层(k5,k9,k13)并行计算再将结果concat起来SPPF则是将最大池化层做串行处理。从数学角度来说,两个k5 maxpool串联等效于一个k9 maxpool,三个k5 maxpool串联等效于一个k13 maxpool。而较小的核可以提高计算量,所以效率提高了~

image-20230322192118601

​ 除了SPP,Neck部分还在PAN结构中加入了CSP,这个以后再好好研究一下~

image-20230322192123175

Head

​ 检测头和v3/v4一样

数据增强

  • Mosaic:将四张图片拼成一张图片

image-20230322192130148

  • Copy paste:将部分目标随机粘贴到其他图片中,前提是数据要有segments数据。这个方法相当于扩充了数据集

在这里插入图片描述

  • Random affine(Rotation, Scale, Translation and Shear):随机进行仿射变换,但根据配置文件里的超参数发现只使用了ScaleTranslation即缩放和平移

image-20230322192135937

  • MixUp:就是将两张图片按照一定的透明度融合在一起,之前v4提到过

image-20230322192140739

  • 其他还有Albumentations/Augment HSV/Random horizaontal flip等等

训练策略

在YOLOv5源码中使用到了很多训练的策略

  • Multi-scale training(0.5~1.5x),多尺度训练,假设设置输入图片的大小为640 × 640 640 \times 640640×640,训练时采用尺寸是在0.5 × 640 ∼ 1.5 × 640 0.5 \times 640 \sim 1.5 \times 6400.5×640∼1.5×640之间随机取值,注意取值时取得都是32的整数倍(因为网络会最大下采样32倍)。
  • AutoAnchor(For training custom data),训练自己数据集时可以根据自己数据集里的目标进行重新聚类生成Anchors模板
  • Warmup and Cosine LR scheduler,训练前先进行Warmup热身,然后在采用Cosine学习率下降策略
  • EMA(Exponential Moving Average),可以理解为给训练的参数加了一个动量,让它更新过程更加平滑(类似于优化器里的momenten)。
  • Mixed precision,混合精度训练,能够减少显存的占用并且加快训练速度,前提是GPU硬件支持。
  • Evolve hyper-parameters,超参数优化,没有炼丹经验的人勿碰,保持默认就好。

损失计算

​ v5的损失计算和之前版本区别不大,都是三部分组成。

  • Classes loss || 使用BCE loss || 只计算正样本的分类损失
  • Objectness loss || 使用BCE损失 || label值是predict box和GT box的CIoU || 计算所有样本
  • Location loss || 定位损失 || 采用CIoU loss || 只计算正样本

权重因子

P3采用的权重是4.0,P4权重为1.0,P5权重为0.4。这是针对coco数据集设置的超参数。

解释性角度来说,小物体更难检测,所以权重自然就大(

$L_{obj}$=4.0⋅$L^{small}_{obj}$+1.0⋅$L^{medium}_{obj}$+0.4⋅$L^{large}_{obj}$

坐标映射

首先是bx/by,即预测框中心离grid cell左上角的偏移,这里给了sigmod函数一个常数2的因子,让bx/by的区间范围从-0.5~1.5,更容易取到1.

image-20230305105754849

image-20230305105940220

其次是bw/bh,即预测的相对于Anchor box的宽高偏移。

image-20230305110036898

原来是直接乘了一个指数函数,当预测值tw/th比较大的时候,容易出现梯度爆炸,所以改成上式,将范围缩减到0-4之间。(这个范围也影响了之后的正样本匹配)

正样本匹配

​ 在v3/v4中的正样本匹配一般只看锚框和GT Box的IoU大小。在v5中还比较了GT Box和Anchor的宽高比例。

image-20230305110302803

统计这些比例和它们倒数之间的最大值,这里可以理解成计算GT BoxAnchor Templates分别在宽度以及高度方向的最大差异(当相等的时候比例为1,差异最小)

image-20230305110323481

​ 接着统计$r_w^{max}$ 和$r_h^{max}$ 之间的最大值,即宽度和高度方向差异最大的值

image-20230305110415200

​ 如果GT Box和对应的Anchor的r^{max}小于阈值anchor_t(在源码中默认设置为4.0),即GT Box和对应的Anchor Template的高、宽比例相差不算太大,则将GT Box分配给该Anchor Template模板。

image-20230305110756988

图源CSDN 太阳花的小绿豆

​ 接下来步骤就和v4一样了.需要注意的是由于偏移tx/ty现在的范围是-0.5~1.5,所以可以增加GT Box分配的grid cell,增加一点正样本。

image-20230305110953638

参考博客

太阳花的小绿豆 YOLOv5网络详解_太阳花的小绿豆的博客-CSDN博客](https://blog.csdn.net/qq_37541097/article/details/123594351))