文章目录
单阶段目标检测重要论文总结
目标检测的常见结构:

Backbone:从图像中提取必要的特征,然后利用这些特征去实现分类和定位。常使用ImageNet Pretrained model,以减少训练时间。常见的有VGG-16,ResNet-50,ResNet-101,ResNeXT,ResNet+DCN,DarkNet,CSPResNet,Mobile-Net,ShuffleNet。
Neck:将backbone提取出的信息整合。常见的有FPN,SPP,RFB,ASPP,SAM,PAN。
Detection Head:输出分类与定位结果。这一模块通常就是普通的卷积。
一、Yolov1
1、论文简介
论文名称:You Only Look Once: Unified, Real-Time Object Detection
论文链接:yolov1
论文源码:yolov1的简单复现
摘要:我们提出了一种新的目标检测方法YOLO。以前目标检测的工作是重新利用分类器来执行检测,而我们将目标检测视为一个空间上分离的BBox和有联系的类概率的回归问题。YOLO 从输入图像仅仅经过一个 神经网络就能直接得到 bounding boxes 以及每个 bounding box 所属类别的概率。由于整个检测管道是一个单一的网络,因此可以直接对检测性能进行端到端优化。正因为整个的检测过程仅仅有一个网络,所以它可以直接在检测性能上进行端到端优化。
我们的统一架构非常快。基本YOLO模型能以每秒45帧的速度实时处理图像。该网络的一个较小版本Fast YOLO处理图像速度能达到每秒155帧,同时还较其他实施检测器的mAP提升了两倍。但是较之前目标检测的SOTA相比,YOLO在物体定位时更容易出错,但是在背景上预测出假阳性(不存在的物体)的情况会少一些。最后要说的是YOLO比DPM、R-CNN等物体检测系统能够学到更加抽象的物体的特征,这使得YOLO可以从真实图像领域迁移到其他领域,如艺术。
提出的问题:DPM,RCNN等目标检测器太慢又不好优化,RCNN太慢是因为要经过生成RP和分类RP这两个阶段,又要经过NMS后处理,难以优化是因为两阶段所用模型要分开训练。那么怎么解决这种太慢有不好优化的问题?
解决方案:将目标检测重建为一个单回归问题,直接从图像像素输出BBox坐标和分类概率。提出YOLO框架。

YOLO检测系统运作流程:
①将输入图resize到448×448;
②将resize后的图像喂到单个CNN中运作;
③根据模型的置信度对得到的检测结果进行阈值化。
YOLO优点:
①单个网络可以同时预测多个BBox和这些BBox的分类概率;
②在整张图片上训练且可以直接优化检测性能;
③速度快,可以做到实时检测。
④mAP较其他实时检测器提升了两倍之多。
⑤在做预测时YOLO 使用的是全局图像。YOLO在训练和测试时都是“看”的整张图,所以它可以将各类别的整体信息和外观信息进行编码。(Fast R-CNN较容易误将图像中的背景的一个小块看成是物体,因为它“看”的范围比较小,而YOLO犯的背景错误比 Fast R-CNN 少一半多)
⑥能够学到物体更泛化的特征表示。(当在自然场景图像上训练 YOLO,再在艺术图像上去测试 YOLO 时,YOLO 的表现要优于 DPM、R-CNN)
⑦仅使用一个卷积神经网络就可以端到端地实现检测物体的目的
YOLO缺点:较目标检测的SOTA系统定位精度欠缺,尤其对于小物体
2、检测原理
YOLO工作原理:将图片分成S×S的网格,如果物体中心落在一个网格上,那么这个网格就要被拿来检测这个物体(即只有GT处的网格才会被训练)。每个网格预测B个BBox和这些BBox的置信分数。每个BBox包含5个预测值,即置信分数和矩形框参数(x,y,w,h), ( x , y ) (x,y) (x,y)坐标代表BBox的中心与网格边界的相对值, ( w , h ) (w,h) (w,h)代表相对于整张图像来说BBox的宽高。注意:实际训练过程中, ( w , h ) (w,h) (w,h)的值使用图像的宽度和高度进行归一化到[0,1]区间内; ( x , y ) (x,y) (x,y)是BBox中心位置相对于当前网格位置的偏移值,并且被归一化到[0,1]。置信分数代表BBox和GT之间的IOU,这个IOU可看做是是正样本的标签。同时每个网格还要预测C个类别的概率,即在一个网格包含一个物体的前提下它属于某个类的概率,只为每个网格预测一组(C个)类的概率,不考虑BBox B的数量。因此特征图的通道数为: ( 5 B + C ) × S × S (5B+C)×S×S (5B+C)×S×S。其中 S = 输入图像尺寸 网络最大的 s t r i d e S=\frac{输入图像尺寸}{网络最大的stride} S=网络最大的stride输入图像尺寸。

本文使用S=7, B=2, VOC数据集的类别数C=20的配置,因此预测数有7 × 7 × 30。
本文的置信分数计算公式:
若BBox包含物体,则P(object) = 1;否则P(object) = 0。IOU(intersection over union)为预测BBox与GT之间的交集面积。object是一个二分类,即有物体还是无物体,也就是“边框的置信度”,没物体的标签显然就是0,而有物体的标签可以直接给1,也可以计算当前预测的bbox与GT之间的IoU作为有物体的标签,注意:这个IoU是object预测学习的标签。
测试时的置信分数计算公式:
这对每个BBox来说是一个特定类别的置信分数,这些分数对该类出现在框中的概率以及预测框与目标物体的匹配程度进行编码。
问题:对于这个公式最大的问题就在于IOU,因为测试阶段根本就没有真实框能够让我们去计算IoU。但是YOLO的objectness的学习标签就是预测框和GT之间的IoU,所以在测试阶段,这个IOU其实就是指YOLO预测的object-ness,它的物理意义就是:这个网格是否有物体。所以可以认为objectness隐含了IoU的概念,但本质就是有无物体的预测。基于这种问题,上面的置信分数公式可以写作:
这个IoU就是objectness预测,因为objectness在训练过程中的正样本标签就是IoU。
总的来说,yolov1一共有三部分输出,分别是object、class以及BBox:
- object就是框的置信度,用于表征该网格是否有物体;
- class就是类别预测;
- BBox就是Bounding Box
3、结构设计

YOLO的backbone:仿照GoogLeNet,但是没有Inception模块,而是替换成1×1和3×3卷积。24层卷积层+2个FC层,网络在最后的卷积层中将输出特征图做flatten操作,得到一个一维向量然后再接2个全连接层做预测。
以下就是YOLOv1的整体工作流程:

4、疑难问题
①训练阶段和测试阶段各做了些什么?
训练阶段:标签GT框中心点落在哪个网格,就由哪个网格预测这个物体,每个网格预测B个BBox,与GT的IOU最大的BBox负责预测这个物体,每个网格只能检测一个物体,包含/不包含GT的网格/BBox依损失函数分别处理。
测试阶段:直接获得 ( 5 B + C ) × S × S (5B+C)×S×S (5B+C)×S×S向量进行NMS后处理,得到目标检测结果。
②BBox怎么产生的?
答:是通过GT标签中的[xmin,xmax,ymin,ymax]计算得到GT的中心点坐标 ( b x , b y ) (b_x,b_y) (bx,by)和宽高,现通过这四个参数回归学习得到BBox的中心点坐标以及宽高。
③如何通过卷积操作将置信度+类别概率+位置偏移映射到卷积输出通道上?
答:因为CNN前向传播的同时要进行loss的反向传播,然后根据loss更新前向传播的这些预测值,因为这些预测值和反向传播的loss通道是一一对应的,所以是将预测值一一映射到卷积输出通道上了。至于为什么更新loss会对预测值产生影响:因为loss的计算离不开ground truth里的值和预测值,通用优化器如SGD根据loss对预测值进行更新,直到设置的epoch结束就可以输出预测值了。
5、论文总结
本文贡献:
①实现了使用单个卷积神经网络就可以端到端地实现检测物体的目的;
②提出的YOLO能够在整张图片上训练且可以直接优化检测性能;
③YOLO可以做到实时检测,mAP较其他实时检测器提升巨大;
④在做预测时YOLO 使用的是全局图像,使得检测器犯背景错误概率降低;
⑤能够学到物体更泛化的特征表示。
YOLOv1缺点:
①较目标检测的SOTA系统定位精度欠缺,召回率较低,尤其对于小物体;
②使用flatten操作破坏特征的空间结构信息;
③没有使用BN层(因为当时BN还不火)。
二、Yolov2
1、论文简介
论文名称:《YOLO9000: Better, Faster, Stronger》
论文链接:yolov2
论文源码:yolov2的简单复现
摘要:我们引进了YOLO9000,这是一个SOTA实时目标检测系统,可以检测9000多个目标类别。首先对YOLO检测方法提出了各种改进,在以前的工作上用了些创新点。yoov2模型在VOC和COCO数据集上已经达到SOTA。其次使用了一种新的多尺度训练方法,同样的一个YOLOv2模型可以在不同尺寸图片下运行,权衡了速度及精度。最后提出了一种联合训练目标检测和分类任务的方法,利用这种方法我们在COCO检测数据集和ImageNet分类数据集上同时对YOLO9000进行训练。联合训练允许YOLO9000预测那些没有检测数据标签的目标类别的检测。YOLO只能检测200多个类别,而YOLO9-000可以预测9000多个类别且可以实时运行。
本文提出的问题:检测数据集不会像分类数据集一样拥有很多类别,因此要怎么使得检测任务能够在有限类别的检测数据集上训练出能够检测更多类别的检测器呢?
解决方案:利用分类数据集且提出联合训练方案。(在YOLO中,边界框的预测其实并不依赖于物体的标签,所以YOLO可以实现在分类和检测数据集上的联合训练) 对于检测数据集,可以用来学习预测物体的边界框、置信度以及为物体分类;而对于分类数据集可以仅用来学习分类,但是其可以极大扩充模型所能检测的物体种类。
2、更好、更快、更强
1)为什么更好?
答:在提升召回率和定位精度做了提升,不改变分类精度。
①添加BN层

②高分辨率分类器
YOLOv2做法:将已在224×224的低分辨率图像上训练好的分类网络在448×448的高分辨率图像上进行微调10个epoch。微调完之后再去掉最后的GAP层和softmax层作为最后的检测backbone网络。
YOLOv1做法:backbone网络先在ImageNet上进行预训练,预训练时所输入的图像尺寸是224×224,而做检测任务时,YOLOv1所接收的输入图像尺寸是448×448,不难想到,训练过程中,网络必须要先克服由分辨率尺寸的剧变所带来的问题。
③anchor box机制
从YOLOv1中移除FC层并用anchor框去预测BBox。移除一个池化层使得网络卷积层(32倍下采样)后的输出具有更高分辨率(13×13),再将输入图像缩小到416使得特征图有奇数个位置且仅有一个中心点。为每个anchor分别预测类别和置信分数(objec-tness),这两种预测遵从YOLOv1。
缺点:mAP下降且生成BBox数量过多。
优点:recall提升(意味着有更多提升的空间)
Faster RCNN中RPN的原理:RPN网络在这些预先放置好的锚框上去为后续的预测提供ROI区域。每个网格处设定了k个不同尺寸、不同宽高比的anchor box,RPN网络会为每一个anchor box学习若干偏移量:中心点的偏移量和宽高的偏移量。用这些偏移量去调整每一个anchor box,得到最终的边界框。anchor box的本质是提供边界框的尺寸先验,网络使用偏移量在这些先验值上进行调整,从而得到最终的尺寸,对于边界框的学习,不再是之前的“无中生有”了。
anchor box与BBox区别:
anchor box是预设的,用来作为参照框,得到与GT框的IOU,然后让CNN输出物体相对于anchor box的中心点偏移以及长宽比例,用来做位置形状预测。
BBox是根据CNN输出的相对于anchor box中心点偏移以及长宽比例计算出的框,是后面产生的框,用来做分类预测。
训练标注阶段:把anchor box作为训练样本,为了训练样本我们需要为每个锚框标注两类标签:一是锚框所含目标的类别,简称类别;二是真实边界框相对锚框的偏移量,简称偏移量(offset)。找出与每个anchor box交并比最大的GT框,然后GT框的标签作为anchor box的标签,然后计算anchor box相对于GT框的偏移量。在目标检测时,我们首先生成多个锚框,然后为每个锚框预测类别以及偏移量,接着根据预测的偏移量调整锚框位置从而得到预测边界框,最后筛选需要输出的预测边界框。
训练阶段触发anchor box:在经过一系列卷积和池化之后,在feature map层使用anchor box,如下图所示,经过一系列的特征提取,最后针对3×3的网格会得到一个3×3×2×8的特征层,其中2是anchor box的个数,8代表每个anchor box包含的变量数,分别是4个位置偏移量、3个类别(one-hot标注方式)、1个anchor box标注(如果anchor box与真实边框的交并比最大则为1,否则为0)。到了特征层之后对每个cell映射到原图中,找到预先标注的anchor box,然后计算这个anchor box与ground truth之间的损失,训练的主要目的就是训练出用anchor box去拟合GT框的模型参数。
预测阶段:首先在图像中生成多个anchor box,然后根据训练好的模型参数去预测这些anchor box的类别和偏移量,进而得到预测的边界框。由于阈值和anchor box数量选择的问题,同一个目标可能会输出多个相似的预测边界框,这样不仅不简洁,而且会增加计算量,为了解决这个问题,常用的措施是使用NMS。
④维度聚类
不需要人工设计先验框的参数(先验框的数量和大小),在训练集上的BBox做K-means聚类得到好的先验框。聚类的目标是数据集中所有检测框的宽和高,与类别无关。使用IoU作为聚类的衡量指标,如下公式所示:

优点:得到的结果要比手动设置先验框参数好。
缺点:聚类效果依赖于数据集。倘若数据集规模过小、样本不够丰富,那么由聚类得到的先验框也未必会提供足够好的尺寸先验信息。
⑤定位预测
换上新先验框之后,又对BBox的预测方法做了一些调整:首先对每一个BBox,YO LO仍旧去学习中心点偏移量 t x t_x tx和 t y t_y ty,YOLOv1中是直接用线性函数输出的,而现在改用sigmoid函数使得网络对偏移量的预测是处在0~1范围内的;其次对每个BBox ,由于有了BBox的尺寸先验信息,因此网络不用再去学习整个BBox的宽高,但是仍要学习BBox宽高偏移量。假设某个先验框的宽高分别为: p w p_w pw和 p h p_h ph,网络输出宽高的偏移量为 t w t_w tw和 t h t_h th,则使用下面公式可以算出BBox的宽和高。


⑥使用更高分辨率的特征
在前面的改进中,YOLOv1都是在最后一张大小为13×13×1024的特征图上进行检测,为了引入更多的细节信息,作者将backbone的第17层卷积输出的26×26×512特征图拿出来,做一次特殊的降采样操作,得到一个13×13×2048特征图,然后将二者在通道的维度上进行拼接,最后在这张融合了更多信息的特征图上去做检测。
特殊下采样操作:类似pixelshuffle的逆操作:passthrough。这种特殊降采样操作的好处就在于降低分辨率的同时,没丢掉任何细节信息,信息总量保持不变。

⑦多尺度训练
使用图像金字塔。通过使用图像金字塔的操作,网络能够在不同尺寸下去感知同一目标,从而增强了其本身对目标尺寸变化的鲁棒性,提升了YOLO对物体的尺度变化的适应能力。
2)为什么更快?
①全卷积网络结构
网络的输入图像尺寸从448改为416,去掉了YOLOv1网络中的最后一个池化层和所有的全连接层,修改后的网络的最大降采样倍数为32,最终得到的也就是13×13的网格,不再是7×7。每个网格处都预设了k个anchor box。

原先的YOLOv1中,每个网格处的B个边界框都有一个置信度,但是类别是共享的,因此每个网格处最终只会有一个输出,而不是B个输出(YOLOv1只输出置信度最高的那一个),倘若一个网格包含了两个以上的物体,那必然会出现漏检问题。加入anchor box后,YOLOv1改为每一个anchor box都预测一个类别和置信度,即每个网格处会有多个边界框的预测输出。YOLOv2的输出张量大小是S×S×k×(1+4+C),每个边界框的预测都包含1个置信度、4个边界框的位置参数和C个类别预测。
②Darknet-19
网络结构:

卷积层有19层:包括线性卷积、BN层以及LeakyReLU激活函数。
做法:首先将DarkNet19在ImageNet上进行预训练,预训练完毕后,去掉最后一层卷积层(与此同时添加3个大小为3×3卷积核数量为1024的卷积层,其中每个3×3卷积层之后都跟一个大小为1×1且数量同检测的输出数量的卷积核的卷积层,还从最后一个卷积层中添加了从最后一个3×3×512的层到第二个3×3×512的层的passthro-ugh层)、GAP层以及softmax层,然后换掉原先的backbone网络。
3)为什么更强? 此为YOLO9000内容
①在分类、检测数据集上联合训练
原理:使用专门为检测贴标签的图像去学习特定的检测信息(BBox坐标预测和object-ness置信分数),使用专门为分类贴标签的图像去扩展可检测的目标类别。
做法:混合检测、分类数据集,当网络看到检测标签图时,网络反向传播YOLOv2的全部loss;当网络看到分类标签图时,网络仅反向传播特定的分类loss。
问题:检测数据集仅有常见标签,而ImageNet类别太细化,怎么去融合标签?
解决方案:使用多标签模型组合标签不互斥的数据集。
②建立分类层级树:WordTree
结合分类数据集和检测数据集标签。计算类别概率就可以用条件概率/全概率来计算,如: P r ( N o r f o l k t e r r i e r ) = P r ( N o r f o l k t e r r i e r ∣ t e r r i e r ) ∗ P r ( t e r r i e r ∣ h u n t i n g d o g ) ∗ … … ∗ P r ( m a m m a l ∣ a n i m a l ) ∗ P r ( a n i m a l ∣ p y s i c a l o b j e c t ) Pr(Norfolk terrier)=Pr(Norfolk terrier|terrier)*Pr(terrier|hunting dog)*……*Pr(mammal|animal)*Pr(animal|pysical object) Pr(Norfolkterrier)=Pr(Norfolkterrier∣terrier)∗Pr(terrier∣huntingdog)∗……∗Pr(mammal∣animal)∗Pr(animal∣pysicalobject)

3、Darknet-19代码实现
class Conv_BN_LeakyReLU(nn.Module):
def __init__(self, in_channels, out_channels, ksize, padding=0, dilation=1):
super(Conv_BN_LeakyReLU, self).__init__()
self.convs = nn.Sequential(
nn.Conv2d(in_channels, out_channels, ksize, padding=padding, dilation=dilation),
nn.BatchNorm2d(out_channels),
nn.LeakyReLU(0.1, inplace=True)
)
def forward(self, x):
return self.convs(x)
class DarkNet_19(nn.Module):
def __init__(self, num_classes=1000):
print("Initializing the darknet19 network ......")
super(DarkNet_19, self).__init__()
# backbone network : DarkNet-19
# output : stride = 2, c = 32
self.conv_1 = nn.Sequential(
Conv_BN_LeakyReLU(3, 32, 3, 1),
nn.MaxPool2d((2,2), 2),
)
# output : stride = 4, c = 64
self.conv_2 = nn.Sequential(
Conv_BN_LeakyReLU(32, 64, 3, 1),
nn.MaxPool2d((2,2), 2)
)
# output : stride = 8, c = 128
self.conv_3 = nn.Sequential(
Conv_BN_LeakyReLU(64, 128, 3, 1),
Conv_BN_LeakyReLU(128, 64, 1),
Conv_BN_LeakyReLU(64, 128, 3, 1),
nn.MaxPool2d((2,2), 2)
)
# output : stride = 16, c = 256
self.conv_4 = nn.Sequential(
Conv_BN_LeakyReLU(128, 256, 3, 1),
Conv_BN_LeakyReLU(256, 128, 1),
Conv_BN_LeakyReLU(128, 256, 3, 1),
nn.MaxPool2d((2,2), 2)
)
# output : stride = 32, c = 512
self.conv_5 = nn.Sequential(
Conv_BN_LeakyReLU(256, 512, 3, 1),
Conv_BN_LeakyReLU(512, 256, 1),
Conv_BN_LeakyReLU(256, 512, 3, 1),
Conv_BN_LeakyReLU(512, 256, 1),
Conv_BN_LeakyReLU(256, 512, 3, 1),
nn.MaxPool2d((2,2), 2)
)
# output : stride = 32, c = 1024
self.conv_6 = nn.Sequential(
Conv_BN_LeakyReLU(512, 1024, 3, 1),
Conv_BN_LeakyReLU(1024, 512, 1),
Conv_BN_LeakyReLU(512, 1024, 3, 1),
Conv_BN_LeakyReLU(1024, 512, 1),
Conv_BN_LeakyReLU(512, 1024, 3, 1)
)
self.conv_7 = nn.Conv2d(1024, 1000, 1)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
def forward(self, x):
x = self.conv_1(x)
x = self.conv_2(x)
x = self.conv_3(x)
x = self.conv_4(x)
x = self.conv_5(x)
x = self.conv_6(x)
x = self.conv_7(x)
x = self.avgpool(x)
x = x.view(x.size(0), -1)
return x
4、论文总结
本文较YOLOv1改进点:只说YOLOv2
①移除了FC层,在卷积层上添加了BN层。
②在低分辨率图像上训练好的网络再放到高分辨率图像中微调,使得检测网络能够对高分辨率图像做出较快适应。
③用anchor box机制生成BBox,对BBox预测方法做了改进。
④使用多尺度训练,具体表现在使用图金字塔。
⑤将类似GoogLeNet的网络替换为Darknet-19网络。
⑤一个网格可以预测多个类别,漏检情况减少。
本文贡献:
①提出了YOLOv2和YOLO9000
②用维度聚类方法产生更好的先验框(anchor boxes)
③使用passthrough层从而可以使用更高分辨率的特征
④提出Darknet-19网络
本文缺点:
①YOLOv2输出量太大,使得运算时间加长了。
②anchor box机制会出现聚类所获得的先验框严重依赖于数据集本身的问题。
③YOLOv1只使用了最后一个经过32倍降采样的特征图即C5特征图,而尽管YOLOv2使用了passthrough技术将16倍降采样的特征图即C4特征图融合到了C5特征图中,但最终的检测仍是在C5尺度的特征图上进行的,最终结果便是导致了模型的小目标的检测性能较差(YOLOv1与YOLOv2的共同缺点)
三、Yolov3
1、论文简介
论文名称:《YOLOv3: An Incremental Improvement》
论文链接:yolov3
论文源码:yolov3实现
摘要:我们对YOLO进行了更新,做了一系列小的设计修改,使之更好,除此之外还训练了一个新网络DarkNet-53,虽然比YOLOv2使用的网络要大但是运行速度很快。在320×320图像中YOLOv3以28.2 mAP的速度在22毫秒内运行,与SSD一样精确,但速度快了三倍。相比之下RetinaNet与YOLOv3性能相似,但速度快3.8倍。
BBox预测:用均方差损失函数,每个BBox置信分数用罗杰思特回归计算得到。
类别预测:用单独的罗杰思特分类器,不用softmax,训练时用BCEloss。是多标签分类预测(即每个框不一定只有一类,而有多类)
2、结构设计
Darknet-53
特征提取器backbone——Darknet-53(融合了darknet-19和ResNet的方法)

注意:Darknet-53降采样使用的是步长为2的卷积,而没用maxpooling。卷积层仍是线性卷机+BN层+LeakyReLU激活函数。
特点:比Darknet-19更强,比ResNet-101和ResNet-152更快。
整体结构

每个特征图上,YOLOv3在每个网格处放置3个先验框。由于YOLOv3一共使用3个尺度,因此,YOLOv3一共设定了9个先验框,这9个先验框仍旧是使用kmeans聚类的方法获得的。注意:YOLOv3的先验框尺寸不同于YOLOv2,后者是除以了32,而前者是在原图尺寸上获得的,没有除以32。
每个先验框预测依然是置信度+位置偏移+类别,因此每个尺度预测的张量通道数为3×(1+4+C)。如果输入图像尺寸为416×416,那么yolov3在一种尺度上最终会输出52×52×3×(1+4+C)、26×26×3×(1+4+C)、13×13×3×(1+4+C)三个预测张量,然后将这些预测结果汇总到一起,进行后处理并得到最终的检测结果。
3、Darknet-53代码实现
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import os
import sys
__all__ = ['darknet53']
class Conv_BN_LeakyReLU(nn.Module):
def __init__(self, c1, c2, k=1, p=0, s=1, d=1):
super(Conv_BN_LeakyReLU, self).__init__()
self.convs = nn.Sequential(
nn.Conv2d(c1, c2, k, padding=p, stride=s, dilation=d),
nn.BatchNorm2d(c2),
nn.LeakyReLU(0.1, inplace=True)
)
def forward(self, x):
return self.convs(x)
class resblock(nn.Module):
def __init__(self, ch, nblocks=1):
super().__init__()
self.module_list = nn.ModuleList()
for _ in range(nblocks):
resblock_one = nn.Sequential(
Conv_BN_LeakyReLU(ch, ch//2, k=1),
Conv_BN_LeakyReLU(ch//2, ch, k=3, p=1)
)
self.module_list.append(resblock_one)
def forward(self, x):
for module in self.module_list:
x = module(x) + x
return x
class DarkNet_53(nn.Module):
"""
DarkNet-53.
"""
def __init__(self, num_classes=1000):
super(DarkNet_53, self).__init__()
# stride = 2
self.layer_1 = nn.Sequential(
Conv_BN_LeakyReLU(3, 32, k=3, p=1),
Conv_BN_LeakyReLU(32, 64, k=3, p=1, s=2),
resblock(64, nblocks=1)
)
# stride = 4
self.layer_2 = nn.Sequential(
Conv_BN_LeakyReLU(64, 128, k=3, p=1, s=2),
resblock(128, nblocks=2)
)
# stride = 8
self.layer_3 = nn.Sequential(
Conv_BN_LeakyReLU(128, 256, k=3, p=1, s=2),
resblock(256, nblocks=8)
)
# stride = 16
self.layer_4 = nn.Sequential(
Conv_BN_LeakyReLU(256, 512, k=3, p=1, s=2),
resblock(512, nblocks=8)
)
# stride = 32
self.layer_5 = nn.Sequential(
Conv_BN_LeakyReLU(512, 1024, k=3, p=1, s=2),
resblock(1024, nblocks=4)
)
# self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
# self.fc = nn.Linear(1024, num_classes)
def forward(self, x, targets=None):
c1 = self.layer_1(x)
c2 = self.layer_2(c1)
c3 = self.layer_3(c2)
c4 = self.layer_4(c3)
c5 = self.layer_5(c4)
# x = self.avgpool(x)
# x = x.view(x.size(0), -1)
# x = self.fc(x)
return c3, c4, c5
4、论文总结
本文较yolov2改进点:
①从单级检测(只在C5特征图做检测)改变为使用FPN结构与多级检测方法(分别在C3\C4\C5特征图上针对目标大小有选择地做检测);
②特征提取backbone由不带残差结构的Darknet-19替换为带有残差结构的Darknet-53;

缺点:精度仍然落后于RetinaNet检测器
四、Yolov4
1、论文简介
论文名称:《YOLOv4: Optimal Speed and Accuracy of Object Detection》
论文链接:yolov4
论文源码:yolov4实现一
摘要:有大量的trick可以提高CNN的准确性。需要在大型数据集上对这些trick的组合进行实际测试,并对结果进行理论证明。某些trick只在某些模型上奏效,或者说只在某些问题上运行,或者只在小规模数据集上运行;而一些trick,如BN和残差连接适用于大多数模型、任务和数据集。我们假设这些通用trick包括加权残差连接(WRC)、跨阶段部分连接(CSP)、跨小批量标准化(CmBN)、自我对抗训练(SAT)和Mish激活。我们使用了新方法:WRC、CSP、CmBN、SAT、Mish激活、Masaic数据增强、CmBN、DropBlock正则化和CIoU loss,并结合这些trick中的一些以达到SOTA。
本文意图:欲解决目标检测系统速度和精度之间的平衡,并用1片GPU训练。设计一个更快速的目标检测器并优化并行计算。

作者总结目标检测器通常包含的元素有:输入、骨干网络、脖颈、头部。
输入包括:Image, Patches, Image Pyramid
Backbone包括:VGG-16、ResNet、ResNeXt、DenseNet、SpineNet、EfficientNet-B0/B7、CSPResNeXt50、CSPDarknet53
Neck包括:
①添加额外块:SPP、ASPP、RFB、SAM
②通路聚合块:FPN、PAN、NAS-FPN、FC-FPN、BiFPN、ASFF、SFAM
Head包括:
①密集预测(单阶段基于anchor):RPN、SSD、YOLO、RetinaNet
②密集预测(单阶段anchor-free):CornerNet、CenterNet、MatrixNet,、FCOS
③稀疏预测(两阶段基于anchor):Faster R-CNN、R-FCN、Mask RCNN
④稀疏预测(两阶段anchor-free):RepPoints
2、结构简介
Yolov4组成部分:
- Backbone: CSPDarkNet53
- Neck: SPP、FPN+PAN
- Head: YOLOV3
Yolov4用到的BoF:
①对backbone使用的:CutMix、Mosaic数据增强、DropBlock正则化、类标签平滑(Class Label Smoothing)。
②对检测器使用的:CIoU loss、CmBN(交叉小批量标准化)、DropBlock正则化、Mosaic数据增强、SAT自对抗训练、消除网格敏感性、为单个GT box使用多个anchor、余弦退火调度器、最优超参数、随机训练形状。
Yolov4用到的BoS:
①对backbone使用的:Mish激活函数、CSP:Cross-stage partial connections、MiWRC:Multi-input weighted residual connections。
②对检测器使用的:Mish激活函数、SPP、SAM(将空间上注意力改为点注意力)、PAN(将shrot-connect从相加修改为拼接)、DIoU NMS
Bag of Freebies:指的是那些不增加模型复杂度,也不增加推理的计算量的训练方法技巧,来提高模型的准确度。
主要代指:
1)数据增强:图像几何变换(随机缩放,裁剪,旋转),Cutmix,CutMix, Mosaic、SAT等
2)网络正则化:Dropout, Dropblock等
3)损失函数的设计:边界框回归的损失函数的改进如CIOU、GIOU等
4)数据不平衡问题:HEM、OHEM、focal loss、label smoothingBag-of-Specials:指的是那些增加少许模型复杂度或计算量的训练技巧,但可以显著提高模型的准确度。
主要代指:
1)增大模型感受野:SPP、ASPP等
2)引入注意力机制:SE、SAM
3)特征集成:PAN,BiFPN、FPN、ASFF、SFAM
4)激活函数改进:Swish、Mish、ReLU、Leaky-ReLU、ReLU6
5)后处理方法改进:soft NMS、DIoU NMS、NMS
YOLOv4的五个基本组件:
CBM:由Conv+Bn+Mish激活函数三者组成。
CBL:由Conv+Bn+Leaky_relu激活函数三者组成。
Res unit:借鉴Resnet网络中的残差结构,让网络可以构建的更深。
CSPX:借鉴CSPNet网络结构,由卷积层和X个Res unint模块Concat组成。
SPP:采用1×1,5×5,9×9,13×13的最大池化的方式,进行多尺度融合
2.1、输入端策略
a、Mosaic数据增强
Why?:在平时项目训练时,小目标的AP一般比中目标和大目标低很多。而COCO数据集中也包含大量的小目标,但比较麻烦的是小目标的分布并不均匀。在所有的训练集图片中,只有52.3%的图片有小目标,而中目标和大目标的分布相对来说更加均匀一些。
How?:采用了4张图片,用随机缩放、随机裁剪、随机排布的方式进行拼接。
效果:

优点:
- 丰富数据集:随机使用4张图片,随机缩放,再随机分布进行拼接,大大丰富了检测数据集,特别是随机缩放增加了很多小目标,让网络的鲁棒性更好。
- 减少GPU:Mosaic增强训练时,可以直接计算4张图片的数据,使得Mini-batch大小并不需要很大,一个GPU就可以达到比较好的效果。
2.2、特征提取策略
a、CSPDarknet53
why CSP?:推理计算过高的问题是由于网络优化中的梯度信息重复导致的,主要从网络结构设计的角度解决推理中从计算量很大的问题。
how?:采用CSP模块先将基础层的特征图划分为两部分,然后通过跨阶段层次结构将它们合并,在减少了计算量的同时可以保证准确率。
优点:
- 增强CNN的学习能力,使得在轻量化的同时保持准确性。
- 降低计算瓶颈,降低内存成本
CSPNet:跨阶段局部网络,从网络结构设计的角度来解决以往工作在推理过程中需要很大计算量的问题(推理计算量之所以过高是因为网络优化中的梯度信息重复导致)。
CSPNet怎么做:通过将梯度的变化从头到尾地集成到特征图中,减少计算量的同时保证了准确率。它是一种处理思想,可与ResNet,DenseNet等网络结合。
CSPNet具有的特点:①增强CNN的学习能力,在保持轻量化的同时保证准确率;②降低计算瓶颈;降低内存成本。
CSPNet示例一(应用于DenseNet):将输入的特征图按照通道数分成了两个部分,其中一个部分正常进行Dense Block操作,另一部分直接进行Concat操作。因每个DenseBlock操作的输入通道都变少了,所以计算量也减少了。
concat方式本文采取下图b的方式,结合了c和d的优点。c的优点是大量的梯度信息可以被重复利用,有利于学习;d因梯度流被阻断,不能重复利用梯度信息,但由于transition层的输入通道比c要少,计算复杂度也能够大大减少。
CSPNet示例二(应用于ResNe(X)t):两个分支都包含全部通道数,两部分先通过1×1卷积各得到1/2的输出通道。分支2在此之后还要通过没有BottleNeck的ResNet Block和一个1×1卷积之后才得到该分支的输出。
局部过渡层目的是最大化梯度联合的差异,使用梯度流阶段的手段避免不同的层学习到重复的梯度信息。
CSPDarkNet53:https://blog.csdn.net/Jaredzzz/article/details/108560087
注:YOLO V4使用时删去了最后的池化层、全连接层以及Softmax层。CSPDarkNet和CSPResNe(X)t整体思路相仿,沿用网络的卷积核尺寸和整体结构,在每组残差块都加上了一个跨阶段局部结构,同时取消了BottleNeck结构。
注:每个body在part1和part2之前都要经过下采样处理(卷积处理),这样能够很大程度上减少参数量和计算量,提高运行速度。
b、Dropblock正则化
why?:卷积层对于这种随机丢弃并不敏感。因为卷积层通常是三层连用:卷积+激活+池化层,池化层本身就是对相邻单元起作用。而且即使随机丢弃,卷积层仍然可以从相邻的激活单元学习到相同的信息。因此在全连接层上效果很好的Dropout在卷积层上效果并不好。
how?:将整个局部区域进行删减丢弃,借鉴了cutout数据增强,cutout是将输入图像的部分区域清零,而Dropblock是将Cutout应用到每一个特征图。而且并不是用固定的归零比率,而是在训练时以一个小的比率开始,随着训练过程线性的增加这个比率。
效果:
优点:
- cutout只能作用于输入层,而Dropblock则是将Cutout应用到网络中的每一个特征图上
- Dropblock可以定制各种组合,在训练的不同阶段可以修改删减的概率,从空间层面和时间层面,和cutout相比都有更精细的改进,效果也更好。
2.3、Neck策略
a、SPP模块

用在backbone之后。本文在SPP模块中,使用k={1×1,5×5,9×9,13×13}的最大池化的方式,再将不同尺度的特征图进行Concat操作。
注意:这里最大池化采用padding操作,stride为1,比如13×13的输入特征图,使用池化核大小为5×5做池化,padding=2,因此池化后的特征图仍然是13×13大小。
b、FPN+PAN(路径聚合网络)
yolov4输入为608×608×3图片时结构图:

最后Prediction中用于预测的三个特征图:①76×76×255,②38×38×255 ③19×19×255。
FPN+PAN工作结构如下:

这样结合操作,FPN层自顶向下传达强语义特征,而特征金字塔则自底向上传达强定位特征,两两联手,从不同的主干层对不同的检测层进行特征聚合。
2.4、输出端策略
a、CIOU loss
①IOU loss

出现的问题:

问题1:即状态1的情况,当预测框和目标框不相交时,IOU=0,无法反应两个框距离的远近,此时损失函数不可导,IOU_Loss无法优化两个框不相交的情况。
问题2:即状态2和状态3的情况,当两个预测框大小相同,两个IOU也相同,IOU_Loss无法区分两者相交情况的不同。
②GIOU_loss

GIOU_Loss中,增加了相交尺度的衡量方式,缓解了IOU_Loss的一些问题
出现的问题:

问题:状态1、2、3都是预测框在目标框内部且预测框大小一致的情况,这时预测框和目标框的差集都是相同的,因此这三种状态的GIOU值也都是相同的,这时GIOU退化成了IOU,无法区分相对位置关系。基于这个问题,又提出DIOU_Loss
③DIOU_loss
好的目标框回归函数应该考虑三个重要几何因素:重叠面积、中心点距离,长宽比。
针对IOU和GIOU存在的问题,作者从两个方面进行考虑
一:如何最小化预测框和目标框之间的归一化距离?
二:如何在预测框和目标框重叠时,回归的更准确?
针对第一个问题提出了DIOU_loss,DIOU_Loss考虑了重叠面积和中心点距离,当目标框包裹预测框的时候,直接度量2个框的距离,因此DIOU_Loss收敛的更快。但就像前面好的目标框回归函数所说的,这时并没有考虑到长宽比。

出现的问题:

问题:比如上面三种状态,目标框包裹预测框,本来DIOU_Loss可以起作用。但预测框的中心点的位置都是一样的,因此按照DIOU_Loss的计算公式,三者的值都是相同的。针对这个问题,又提出了CIOU_Loss。
④CIOU_loss
CIOU_Loss和DIOU_Loss前面的公式都是一样的,不过在此基础上还增加了一个影响因子,将预测框和目标框的长宽比都考虑了进去。

其中v是衡量长宽比一致性的参数,我们也可以定义为:

这样CIOU_Loss就将目标框回归函数应该考虑三个重要几何因素:重叠面积、中心点距离,长宽比全都考虑进去了。
总结IOU loss:
IOU_Loss:主要考虑检测框和目标框重叠面积。
GIOU_Loss:在IOU的基础上,解决边界框不重合时的问题。
DIOU_Loss:在IOU和GIOU的基础上,考虑边界框中心点距离的信息。
CIOU_Loss:在DIOU的基础上,考虑边界框宽高比的尺度信息。
b、DIOU-NMS
为什么不用CIOU_nms,而用DIOU_nms?
答:因为CIOU_loss是在DIOU_loss的基础上添加了影响因子,包含groundtruth标注框的信息,在训练时用于回归。
但在测试过程中,并没有groundtruth的信息,不用考虑影响因子,因此直接用DIOU_nms即可。
效果:

3、论文总结
本文贡献:
①开发了一个集快速、精准度为一体的目标检测模型,使得任何人都可以用一片1080Ti或2080Ti去训练。
②检测器训练过程中验证了SOTA所使用的Bag-of-Freebies 和 Bag-of-Specials。
③修改了已有的SOTA并使之更高效、更适合于单个GPU训练,包括CBN、PAN、SAM
本文较yolov3改进点:
①将backbone改进为CSPDarkNet53
②用BoF和BoS中的部分有效方法,具体表现如下:
- 输入端:Mosaic数据增强、cmBN、SAT自对抗训练
- BackBone主干网络:CSPDarknet53、Mish激活函数(后面的网络仍然使用Leaky-ReLU)、Dropblock
- Neck:SPP、FPN+PAN结构
- Head:输出层的锚框机制和Yolov3相同,主要改进的是训练时的损失函数CIOU loss,以及预测框筛选的nms变为DIOU_nms
五、Yolov5
1、结构设计
整体结构设计为:
YOLOV5使用策略:
- 输入端:Mosaic数据增强,自适应anchor计算,自适应图片缩放
- Backbone:Focus结构,CSP结构
- Neck:FPN+PAN
- 输出端:GIOU_LOSS
2.1、输入端策略
a、自适应anchor计算
现在对于不同数据集的anchor计算都是如下策略:训练中网络在初始anchor的基础上输出预测框,和GT比对后计算两者的差距,再反向更新并迭代网络参数。
YOLOV3、YOLOV4是通过运行单独的K-means来计算初始anchor的值。
YOLOV5是将该功能嵌入训练中,每次训练自适应计算不同数据集中最佳anchor值。
YOLOV5的anchor预设值在models/hub/*.yaml中:

b、自适应图片缩放
改进的letterbox策略:对原始图像自适应的添加最少量的黑边。
| 策略 | 图片 |
|---|---|
| 原始图片(800×600) | ![]() |
| 初始letterbox策略(不保持原图像的宽高比)(416×416) | ![]() |
| 改进的letterbox策略(保持原图像的宽高比)(416×352) | ![]() |
letterbox具体步骤:
- 计算宽高缩放比例系数,选择小的缩放系数
- 计算缩放后的尺寸
- 计算黑边填充数值
注:
- 训练时采用的初始letterbox策略,推理使用的是改进的letterbox策略。
- np.mod函数之所以使用stride=32,是因为YOLOV5特征提取网络经过了5此下采样,每次下采样倍数为32。所以从原图上计算得到的像素也同样需要下采样32倍操作。
2.2、特征提取策略
a、Focus结构
关键操作是切片操作:如右图将特征图尺寸减半,维度增加4倍,此策略与YOLOV2中的passthrough相似。
Focus结构在yolov5s模型最后使用了32个卷积核,后续三种模型使用的卷积核数量则会有所增加。
b、CSP结构
YOLOV4只在Backbone使用了CSP思想,激活函数使用Mish,在分出两个分支之前进行下采样操作
YOLOV5在Backbone和Neck都有使用,激活函数使用LeakyReLu,取消了在分出两个分支之前的下采样操作
2.3、 Neck策略
FPN+PAN使用CSPNet思想
2.4、输出端策略
a、CIOU loss
b、官方NMS
可改进的策略:

文章全面回顾了YOLO系列(v1至v5)的发展,探讨了从YOLOv1首次提出统一实时目标检测框架,到YOLOv4引入CSPDarknet53、SPP模块等提升策略,再到YOLOv5的自适应设计与优化,以及后续的YOLOR、NanoDet等模型的创新。涵盖模型重参数化、模型缩放等关键技术,深入解析了CornerNet、CenterNet等独特结构,强调了单阶段检测模型的快速与优化趋势。










最低0.47元/天 解锁文章
7544

被折叠的 条评论
为什么被折叠?



