引言
- 记录相关深度学习及目标检测领域的论文
1 经典backbone总结
1.2 ResNet
ResNet 模型比 VGG 网络具有更少的滤波器数量和更低的复杂性
注意,论文中算的
FLOPs,把乘加当作1次计算。
不同层数的 Resnet 网络参数表如下图所示

ResNet是Backone领域划时代的工作了,因为它让深层神经网络可以训练,基本解决了深层神经网络训练过程中的梯度消失问题,并给出了系统性的解决方案(两种残差结构),即系统性的让网络变得更“深”了
1.7 DenseNet
在密集块(DenseBlock)结构中,每一层都会将前面所有层 concate 后作为输入
DenseBlock(类似于残差块的密集块结构)结构的 3 画法图如下所示:

可以看出 DenseNet 论文更侧重的是 DenseBlock 内各个卷积层之间的密集连接(dense connection)关系,另外两个则是强调每层的输入是前面所有层 feature map 的叠加,反映了 feature map 数量的变化
1.8 CSPNet
CSPDenseNet 的一个阶段是由局部密集块和局部过渡层组成(a partial dense block and a partial transition layer)

CSP 方法可以减少模型计算量和提高运行速度的同时,还不降低模型的精度,是一种更高效的网络设计方法,同时还能和 Resnet、Densenet、Darknet 等 backbone 结合在一起
1.9 一些结论
- 当卷积层的输入输出通道数相等时,内存访问代价(
MAC)最小 - 影响 CNN 功耗的主要因素在于内存访问代价 MAC,而不是计算量 FLOPs
- GPU 擅长并行计算,Tensor 越大,GPU 使用效率越高,把大的卷积操作拆分成碎片的小操作不利于 GPU 计算
- 1x1 卷积可以减少计算量,但不利于 GPU 计算
2 经典网络精读
2.1 ResNet
Deep Residual Learning for Image Recognition
2.1.1 摘要
残差网络(ResNet)的提出是为了解决深度神经网络的“退化”(优化)问题。
有论文指出,神经网络越来越深的时候,反传回来的梯度之间的相关性会越来越差,最后接近白噪声。即更深的卷积网络会产生梯度消失问题导致网络无法有效训练。
而 ResNet 通过设计残差块结构,调整模型结构,让更深的模型能够有效训练更训练。目前 ResNet 被当作目标检测、语义分割等视觉算法框架的主流 backbone。
2.1.2 残差网络介绍
作者提出认为,假设一个比较浅的卷积网络已经可以达到不错的效果,那么即使新加了很多卷积层什么也不做,模型的效果也不会变差。但,之所以之前的深度网络出现退化问题,是因为让网络层什么都不做恰好是当前神经网络最难解决的问题之一!
因此,作者可以提出残差网络的初衷,其实是让模型的内部结构至少有恒等映射的能力(什么都不做的能力),这样可以保证叠加更深的卷积层不会因为网络更深而产生退化问题!
2.1.2.1 残差结构原理
对于 VGG 式的卷积网络中的一个卷积 block,假设 block 的输入为 ,期望输出为 ,block 完成非线性映射功能。
那么,如何实现恒等映射呢?
假设直连(plain)卷积 block 的输入为 ,block 期望输出为 ,我们一般第一反应是直接让学习 ,但是这很难!
对此,作者换了个角度想问题,既然 很难学习到,那我就将 学习成其他的,而让恒等映射能力通过其他结构来实现,比如,直接加个 shorcut 不就完事了!这样只要直连 block 网络输出学习为 0 就行了。而让直连卷积 block 输出学习为 0 比学习成恒等映射的能力是要简单很多的!毕竟前者通过 L2 正则化就能实现了!
因此,作者将网络设计为 ,即直接把恒等映射作为网络的一部分,只要 ,即实现恒等映射: 。残差块结构(resdiual block)。基本残差块结构如下图所示:

从图中可以看出,一个残差块有 条路径 和 , 路径拟合残差 ,可称为残差路径, 路径为恒等映射(identity mapping),称其为”shortcut”。图中的 为逐元素相加(element-wise addition),要求参与运算的 和 的尺寸必须相同!
这就把前面的问题转换成了学习一个残差函数 。
综上总结:可以认为 Residual Learning 的初衷(原理),其实是让模型的内部结构至少有恒等映射的能力。以保证在堆叠网络的过程中,网络至少不会因为继续堆叠而产生退化!
注意,很多博客片面解释 resnet 解决了梯度消失问题所以有效的的观点是片面的且方向也错了!resnet 到底解决了什么问题以及为什么有效问题的更细节回答,可以参考这个回答。
2.1.2.2 两种不同的残差路径
在 ResNet 原论文中,残差路径的设计可以分成 种,
- 一种没有
bottleneck结构,如图3-5左所示,称之为“basic block”,由 2 个 卷积层构成。2 层的残差学习单元其两个输出部分必须具有相同的通道数(因为残差等于目标输出减去输入,即 ,所以输入、输出通道数目需相等)。 - 另一种有
bottleneck结构,称之为 “bottleneck block”,对于每个残差函数 ,使用 层堆叠而不是 2 层,3 层分别是 , 和 卷积。其中 卷积层负责先减小然后增加(恢复)维度,使 卷积层的通道数目可以降低下来,降低参数量减少算力瓶颈(这也是起名 bottleneck 的原因 )。50层以上的残差网络都使用了 bottleneck block 的残差块结构,因为其可以减少计算量和降低训练时间。

3 层的残差学习单元是参考了 Inception Net 结构中的
Network in Network方法,在中间 的卷积前后使用 卷积,实现先降低维度再提升维度,从而起到降低模型参数和计算量的作用。
2.1.2.3 两种不同的 shortcut 路径
shortcut 路径大致也分成 种,一种是将输入 直接输出,另一种则需要经过 卷积来升维或降采样,其是为了将 shortcut 输出与 F(x) 路径的输出保持形状一致,但是其对网络性能的提升并不明显,两种结构如图3-6所示。

Residual Block(残差块)之间的衔接,在原论文中, 是经过 ReLU 后直接作为下一个 block 的输入 。
2.1.3 ResNet18 模型结构分析
残差网络中,将堆叠的几层卷积 layer 称为残差块(Residual Block),多个相似的残差块串联构成 ResNet。ResNet18 和 ResNet34 Backbone用的都是两层的残差学习单元(basic block),更深层的ResNet则使用的是三层的残差学习单元(bottle block)。
ResNet18 其结构如下图所示。

ResNet18 网络具体参数如下表所示。

假设图像输入尺寸为,,ResNet 共有五个阶段。
- 其中第一阶段的
conv1 layer为一个 的卷积核,stride为 2,然后经过池化层处理,此时特征图的尺寸已成为输入的1/4,即输出尺寸为 。 - 接下来是四个阶段,也就是表格中的四个
layer:conv2_x、conv3_x、conv4_x、conv5_x,后面三个都会降低特征图尺寸为原来的1/2,特征图的下采样是通过步长为2的 conv3_1, conv4_1 和 conv5_1 执行。所以,最后输出的 feature_map 尺寸为输入尺寸降采样 倍。
在工程代码中用 make_layer 函数产生四个 layer 即对应 ResNet 网络的四个阶段。根据不同层数的 ResNet(N):
- 输入给每个 layer 的
blocks是不同的,即每个阶段(layer)里面的残差模块数目不同(即layers列表不同) - 采用的
block类型(basic还是bottleneck版)也不同。
本文介绍的 ResNet18,使用 basic block,其残差模块数量(即units数量)是 [2, 2, 2, 2],又因为每个残差模块中只包含了 2 层卷积,故残差模块总的卷积层数为 (2+2+2+2)*2=16,再加上第一层的卷积和最后一层的分类,总共是 18 层,所以命名为 ResNet18。
ResNet50 为 [3, 4, 6, 3]。
ResNet的一个重要设计原则是:当feature map大小降低一半时,feature map的数量增加一倍,这保持了网络层的复杂度。
2.2 ResNetV2
Identity Mappings in Deep Residual Networks
前言
本文的主要贡献在于通过理论分析和大量实验证明使用恒等映射(
identity mapping)作为快捷连接(skip connection)对于残差块的重要性。同时,将BN/ReLu这些activation操作挪到了Conv(真正的weights filter操作)之前,提出“预激活“操作,并通过与”后激活“操作做对比实验,表明对于多层网络,使用了预激活残差单元(Pre-activation residual unit) 的resnet v2都取得了比resnet v1(或 resnet v1.5)更好的结果。
摘要
近期已经涌现出很多以深度残差网络(deep residual network)为基础的极深层的网络架构,在准确率和收敛性等方面的表现都非常引人注目。本文主要分析残差网络基本构件(residual building block)中的信号传播,本文发现当使用恒等映射(identity mapping)作为快捷连接(skip connection)并且将激活函数移至加法操作后面时,前向-反向信号都可以在两个 block 之间直接传播而不受到任何变换操作的影响。同时大量实验结果证明了恒等映射的重要性。本文根据这个发现重新设计了一种残差网络基本单元(unit),使得网络更易于训练并且泛化性能也得到提升。
注意这里的实验是深层 ResNet( 110 layers) 的实验,所以我觉得,应该是对于深层 ResNet,使用”预激活”残差单元(
Pre-activation residual unit)的网络(ResNet v2)更易于训练并且精度也更高。
1、介绍
深度残差网络(ResNets)由残差单元(Residual Units)堆叠而成。每个残差单元(图1 (a))可以表示为:

其中, 和 是 第 个残差单元的输入和输出, 是残差函数。在 ResNet 中, 是恒等映射(identity), 是 ReLU 激活函数。在 ImageNet 数据集和 COCO 数据集上,超过 1000 层的残差网络都取得了当前最优的准确率。残差网络的核心思想是在 的基础上学习附加的残差函数 ,其中很关键的选择就是使用恒等映射 ,这可以通过在网络中添加恒等快捷连接(skip connection) shortcut 来实现。
本文中主要在于分析在深度残差网络中构建一个信息“直接”传播的路径——不只是在残差单元直接,而是在整个网络中信息可以“直接”传播。如果 和 都是恒等映射,那么信号可以在单元间直接进行前向-反向传播。实验证明基本满足上述条件的网络架构一般更容易训练。本文实验了不同形式的 ,发现使用恒等映射的网络性能最好,误差减小最快且训练损失最低。这些实验说明“干净”的信息通道有助于优化。各种不同形式的 见论文中的图 1、图2 和 图4 中的灰色箭头所示。

为了构建 的恒等映射,本文将激活函数(ReLU 和 BN)移到权值层(Conv)之前,形成一种“预激活(pre-activation)”的方式,而不是常规的“后激活(post-activation)”方式,这样就设计出了一种新的残差单元(见图 1(b))。基于这种新的单元我们在 CIFAR-10/100 数据集上使用1001 层残差网络进行训练,发现新的残差网络比之前(ResNet)的更容易训练并且泛化性能更好。同时还考察了 200 层新残差网络在 ImageNet 上的表现,原先的残差网络在这个层数之后开始出现过拟合的现象。这些结果表明网络深度这个维度还有很大探索空间,毕竟深度是现代神经网络成功的关键。
2、深度残差网络的分析
原先 ResNets 的残差单元的可以表示为:

在 ResNet 中,函数 是恒等映射,即 。公式的参数解释见下图:

如果函数 也是恒等映射,即 ,公式 (1)(2) 可以合并为:

那么任意深层的单元 与浅层单元 之间的关系为:

公式 (4) 有两个特性:
- 深层单元的特征可以由浅层单元的特征和残差函数相加得到;
- 任意深层单元的特征都可以由起始特征 与先前所有残差函数相加得到,这与普通(
plain)网络不同,普通网络的深层特征是由一系列的矩阵向量相乘得到。残差网络是连加,普通网络是连乘。
公式 (4) 也带来了良好的反向传播特性,用 $\varepsilon $ 表示损失函数,根据反向传播的链式传导规则,反向传播公式如下:

从公式 (5) 中可以看出,反向传播也是两条路径,其中之一直接将信息回传,另一条会经过所有的带权重层。另外可以注意到第二项的值在一个 mini-batch 中不可能一直是 -1,也就是说回传的梯度不会消失,不论网络中的权值的值再小都不会发生梯度消失现象。
3、On the Importance of Identity Skip Connection
考虑恒等映射的重要性。假设将恒等映射改为 ,则:

像公式 (4) 一样递归的调用公式 (3),得:

其中, 表示将标量合并到残差函数中,与公式 (5) 类似,反向传播公式如下:

与公式 (5) 不同,公式 (8) 的第一个加法项由因子 进行调节。对于一个极深的网络( 极大),考虑第一个连乘的项,如果所有的 都大于 1,那么这一项会指数级增大;如果所有 都小于 1,那么这一项会很小甚至消失,会阻断来自 shortcut 的反向传播信号,并迫使其流过权重层。本文通过实验证明这种方式会对模型优化造成困难。
另外其他不同形式的变换映射也都会阻碍信号的有效传播,进而影响训练进程。

4、On the Usage of Activation Functions
第 3 章考察使用不同形式映射(见图 2)来验证函数 是恒等映射的重要性,这章讨论公式(2)中的 ,如果 也是恒等映射,网络的性能会不会有所提升。通过调节激活函数 (ReLU and/or BN) 的位置,来使 是恒等映射。图 4 展示了激活函数在不同位置的残差单元结构图去。
图
4(e)的”预激活“操作是本文提出的一种对于深层残差网络能够更有效训练的网络结构(ResNet v2)。

4.1、Experiments on Activation
本章,我们使用 ResNet-110 和 164 层瓶颈结构(称为 ResNet-164)来进行实验。瓶颈残差单元包含一个 的层来降维,一个 的层,还有一个 的层来恢复维度。如 ResNet 论文中描述的那样,它的计算复杂度和包含两个 卷积层的残差单元相似。
BN after addition
效果比基准差,BN 层移到相加操作后面会阻碍信号传播,一个明显的现象就是训练初期误差下降缓慢。
ReLU before addition
这样组合的话残差函数分支的输出就一直保持非负,这会影响到模型的表示能力,而实验结果也表明这种组合比基准差。
Post-activation or pre-activation
原来的设计中相加操作后面还有一个 ReLU 激活函数,这个激活函数会影响到残差单元的两个分支,现在将它移到残差函数分支上,快捷连接分支不再受到影响。具体操作如图 5 所示。

根据激活函数与相加操作的位置关系,我们称之前的组合方式为“后激活(post-activation)”,现在新的组合方式称之为“预激活(pre-activation)”。原来的设计与预激活残差单元之间的性能对比见表 3。预激活方式又可以分为两种:只将 ReLU 放在前面,或者将 ReLU 和 BN都放到前面,根据表 2 中的结果可以看出 full pre-activation 的效果要更好。


4.2、Analysis
使用预激活有两个方面的优点:1) 变为恒等映射,使得网络更易于优化;2)使用 BN 作为预激活可以加强对模型的正则化。
Ease of optimization
这在训练 1001 层残差网络时尤为明显,具体见图 1。使用原来设计的网络在起始阶段误差下降很慢,因为 是 ReLU 激活函数,当信号为负时会被截断,使模型无法很好地逼近期望函数;而使用预激活网络中的 是恒等映射,信号可以在不同单元直接直接传播。本文使用的 1001层网络优化速度很快,并且得到了最低的误差。
为 ReLU 对浅层残差网络的影响并不大,如图 6-right 所示。本文认为是当网络经过一段时间的训练之后权值经过适当的调整,使得单元输出基本都是非负,此时 不再对信号进行截断。但是截断现象在超过 1000层的网络中经常发生。

Reducing overfitting
观察图 6-right,使用了预激活的网络的训练误差稍高,但却得到更低的测试误差,本文推测这是 BN 层的正则化效果所致。在原始残差单元中,尽管BN 对信号进行了标准化,但是它很快就被合并到捷径连接(shortcut)上,组合的信号并不是被标准化的。这个非标准化的信号又被用作下一个权重层的输入。与之相反,本文的预激活(pre-activation)版本的模型中,权重层的输入总是标准化的。
5、Results
表 4、表 5 分别展示了不同深层网络在不同数据集上的表现。使用的预激活单元的且更深层的残差网络(ResNet v2)都取得了最好的精度。


6、结论
恒等映射形式的快捷连接和预激活对于信号在网络中的顺畅传播至关重要。
2.3 DenseNet
摘要
ResNet 的工作表面,只要建立前面层和后面层之间的“短路连接”(shortcut),就能有助于训练过程中梯度的反向传播,从而能训练出更“深”的 CNN 网络。DenseNet 网络的基本思路和 ResNet 一致,但是它建立的是前面所有层与后面层的密集连接(dense connection)。传统的 层卷积网络有 个连接——每一层与它的前一层和后一层相连—,而 DenseNet 网络有 个连接。
在 DenseNet 中,让网络中的每一层都直接与其前面层相连,实现特征的重复利用;同时把网络的每一层设计得特别“窄”(特征图/滤波器数量少),即只学习非常少的特征图(最极端情况就是每一层只学习一个特征图),达到降低冗余性的目的。
网络结构
DenseNet 模型主要是由 DenseBlock 组成的。
用公式表示,传统直连(plain)的网络在 层的输出为:
对于残差块(residual block)结构,增加了一个恒等映射(shortcut 连接):
而在密集块(DenseBlock)结构中,每一层都会将前面所有层 concate 后作为输入:
表示网络层 输出特征图的拼接。这里暗示了,在 DenseBlock 中,每个网络层的特征图大小是一样的。 是非线性转化函数(non-liear transformation),它由 BN(Batch Normalization),ReLU 和 Conv 层组合而成。
DenseBlock 的结构图如下图所示。

在 DenseBlock 的设计中,作者重点提到了一个参数 ,被称为网络的增长率(growth of the network),其实是 DenseBlock 中任何一个 卷积层的滤波器个数(输出通道数)。如果每个 函数都输出 个特征图,那么第 层的输入特征图数量为 , 是 DenseBlock 的输入特征图数量(即第一个卷积层的输入通道数)。DenseNet 网络和其他网络最显著的区别是, 值可以变得很小,比如 ,即网络变得很“窄”,但又不影响精度。如表 4 所示。

为了在 DenseNet 网络中,保持 DenseBlock 的卷积层的 feature map 大小一致,作者在两个 DenseBlock 中间插入 transition 层。其由 average pool, stride=2,和 conv 层组合而成,具体为 BN + ReLU + 1x1 Conv + 2x2 AvgPooling。transition 层完成降低特征图大小和降维的作用。
CNN网络一般通过 Pooling 层或者 stride>1 的卷积层来降低特征图大小(比如 stride=2 的 3x3 卷积层),
下图给出了一个 DenseNet 的网路结构,它共包含 3 个(一半用 4 个)DenseBlock,各个 DenseBlock 之间通过 Transition 连接在一起。

和 ResNet 一样,DenseNet 也有 bottleneck 单元,来适应更深的 DenseNet。Bottleneck 单元是 BN-ReLU-Conv(1x1)-BN-ReLU-Conv(3x3)这样连接的结构,作者将具有 bottleneck 的密集单元组成的网络称为 DenseNet-B。
Bottleneck译为瓶颈,一端大一端小,对应着 1x1 卷积通道数多,3x3 卷积通道数少。
对于 ImageNet 数据集,图片输入大小为 ,网络结构采用包含 4 个 DenseBlock 的DenseNet-BC,网络第一层是 stride=2 的 卷积层,然后是一个 stride=2 的 MaxPooling 层,而后是 DenseBlock。ImageNet 数据集所采用的网络配置参数表如表 1 所示:

网络中每个阶段卷积层的 feature map 数量都是 32。
优点
- 省参数
- 省计算
- 抗过拟合
注意,后续的 VoVNet 证明了,虽然 DenseNet 网络参数量少,但是其推理效率却不高。
在 ImageNet 分类数据集上达到同样的准确率,DenseNet 所需的参数量和计算量都不到 ResNet 的一半。对于工业界而言,小模型(参数量少)可以显著地节省带宽,降低存储开销。
参数量少的模型,计算量肯定也少。
作者通过实验发现,DenseNet 不容易过拟合,这在数据集不是很大的情况下表现尤为突出。在一些图像分割和物体检测的任务上,基于 DenseNet 的模型往往可以省略在 ImageNet 上的预训练,直接从随机初始化的模型开始训练,最终达到相同甚至更好的效果。
对于 DenseNet 抗过拟合的原因,作者给出的比较直观的解释是:神经网络每一层提取的特征都相当于对输入数据的一个非线性变换,而随着深度的增加,变换的复杂度也逐渐增加(更多非线性函数的复合)。相比于一般神经网络的分类器直接依赖于网络最后一层(复杂度最高)的特征,DenseNet 可以综合利用浅层复杂度低的特征,因而更容易得到一个光滑的具有更好泛化性能的决策函数。
DenseNet 的泛化性能优于其他网络是可以从理论上证明的:去年的一篇几乎与 DenseNet 同期发布在 arXiv 上的论文(AdaNet: Adaptive Structural Learning of Artificial Neural Networks)所证明的结论(见文中 Theorem 1)表明类似于 DenseNet 的网络结构具有更小的泛化误差界。
问题
1,这么多的密集连接,是不是全部都是必要的,有没有可能去掉一些也不会影响网络的性能?
作者回答:论文里面有一个热力图(heatmap),直观上刻画了各个连接的强度。从图中可以观察到网络中比较靠后的层确实也会用到非常浅层的特征。
注意,后续的改进版本 VoVNet 设计的 OSP 模块,去掉中间层的密集连接,只有最后一层聚合前面所有层的特征,并做了同一个实验。热力图的结果表明,去掉中间层的聚集密集连接后,最后一层的连接强度变得更好。同时,在 CIFAR-10 上和同 DenseNet 做了对比实验,OSP 的精度和 DenseBlock 相近,但是 MAC 减少了很多,这说明 DenseBlock 的这种密集连接会导致中间层的很多特征冗余的。
2.4 CSPNet
摘要
CSPNet是作者Chien-Yao Wang于2019发表的论文CSPNET: A NEW BACKBONE THAT CAN ENHANCE LEARNING CAPABILITY OF CNN。也是对DenseNet网络推理效率低的改进版本。
作者认为网络推理成本过高的问题是由于网络优化中的梯度信息重复导致的。CSPNet 通过将梯度的变化从头到尾地集成到特征图中,在减少了计算量的同时可以保证准确率。CSP(Cross Stage Partial Network,简称 CSPNet) 方法可以减少模型计算量和提高运行速度的同时,还不降低模型的精度,是一种更高效的网络设计方法,同时还能和Resnet、Densenet、Darknet 等 backbone 结合在一起。
1,介绍
虽然已经出现了 MobileNetv1/v2/v3 和 ShuffleNetv1/v2 这种为移动端(CPU)设计的轻量级网络,但是它们所采用的基础技术-深度可分离卷积技术并不适用于 NPU 芯片(基于专用集成电路 (ASIC) 的边缘计算系统)。
CSPNet 和不同 backbone 结合后的效果如下图所示。

和目标检测网络结合后的效果如下图所示。

CSPNet 提出主要是为了解决三个问题:
- 增强 CNN 的学习能力,能够在轻量化的同时保持准确性。
- 降低计算瓶颈和 DenseNet 的梯度信息重复。
- 降低内存成本。
2,相关工作
CNN 架构的设计。
实时目标检测器。
3,改进方法
原论文命名为
Method,但我觉得叫改进方法更能体现章节内容。
3.1,Cross Stage Partial Network
1,DenseNet

其中 为权值更新函数, 为传播到第 个密集层的梯度。从公式 (2) 可以发现,大量的度信息被重用来更新不同密集层的权值,这将导致无差异的密集层反复学习复制的梯度信息。
2,Cross Stage Partial DenseNet.
作者提出的 CSPDenseNet 的单阶段的架构如图 2(b) 所示。CSPDenseNet 的一个阶段是由局部密集块和局部过渡层组成(a partial dense block and a partial transition layer)。

总的来说,作者提出的 CSPDenseNet 保留了 DenseNet 重用特征特性的优点,但同时通过截断梯度流防止了过多的重复梯度信息。该思想通过设计一种分层的特征融合策略来实现,并应用于局部过渡层(partial transition layer)。
3,Partial Dense Block.
设计局部密集块(partial dense block)的目的是为了
- 增加梯度路径:通过分块归并策略,可以使梯度路径的数量增加一倍。由于采用了跨阶段策略,可以减轻使用显式特征图 copy 进行拼接所带来的弊端;
- 每一层的平衡计算:通常,DenseNet 基层的通道数远大于生长速率。由于在局部稠密块中,参与密集层操作的基础层通道仅占原始数据的一半,可以有效解决近一半的计算瓶颈;
- 减少内存流量: 假设
DenseNet中一个密集块的基本特征图大小为 ,增长率为 ,共有 个密集块。则该密集块的 CIO为 ,而局部密集块(partial dense block)的CIO为 。虽然 和 通常比 小得多,但是一个局部密集的块最多可以节省网络一半的内存流量。
4,Partial Transition Layer.
设计局部过渡层的目的是使梯度组合的差异最大。局部过渡层是一种层次化的特征融合机制,它利用梯度流的聚合策略来防止不同的层学习重复的梯度信息。在这里,我们设计了两个 CSPDenseNet 变体来展示这种梯度流截断是如何影响网络的学习能力的。

Transition layer 的含义和 DenseNet 类似,是一个 1x1 的卷积层(没有再使用 average pool)。上图中 transition layer 的位置决定了梯度的结构方式,并且各有优势:
- © 图 Fusion First 方式,先将两个部分进行 concatenate,然后再进行输入到Transion layer 中,采用这种做法会是的大量特梯度信息被重用,有利于网络学习;
- (d) 图 Fusion Last 的方式,先将部分特征输入 Transition layer,然后再进行concatenate,这样梯度信息将被截断,损失了部分的梯度重用,但是由于 Transition 的输入维度比(c)图少,大大减少了计算复杂度。
- (b) 图中的结构是论文
CSPNet所采用的,其结合了 ©、(d) 的特点,提升了学习能力的同时也提高了一些计算复杂度。 作者在论文中给出其使用不同 Partial Transition Layer 的实验结果,如下图所示。具体使用哪种结构,我们可以根据条件和使用场景进行调整。

5,Apply CSPNet to Other Architectures.
将 CSP 应用到 ResNeXt 或者 ResNet 的残差单元后的结构图如下所示:

3.2,Exact Fusion Model
Aggregate Feature Pyramid.
提出了 EFM 结构能够更好地聚集初始特征金字塔。

4,结论
CSPNet 是能够用于移动 gpu 或 cpu 的轻量级网络架构
作者认为论文最主要的贡献是认识到冗余梯度信息问题,及其导致的低效优化和昂贵的推理计算。同时也提出了利用跨阶段特征融合策略和截断梯度流来增强不同层间学习特征的可变性
此外,还提出了一种 EFM 结构,它结合了 Maxout 操作来压缩从特征金字塔生成的特征映射,这大大降低了所需的内存带宽,因此推理的效率足以与边缘计算设备兼容
实验结果表明,本文提出的基于 EFM 的 CSPNet 在移动GPU 和 CPU 的实时目标检测任务的准确性和推理率方面明显优于竞争对手
3 目标检测相关论文
3.1 Faster-RCNN
Faster RCNN 网络概述

backbone 为 vgg16 的 faster rcnn 网络结构如下图所示,可以清晰的看到该网络对于一副任意大小 PxQ 的图像,首先缩放至固定大小 MxN,然后将 MxN 图像送入网络;而 Conv layers 中包含了 13 个 conv 层 + 13 个 relu 层 + 4 个 pooling 层;RPN 网络首先经过 3x3 卷积,再分别生成 positive anchors 和对应 bounding box regression 偏移量,然后计算出 proposals;而 Roi Pooling 层则利用 proposals 从 feature maps 中提取 proposal feature 送入后续全连接和 softmax 网络作 classification(即分类: proposal 是哪种 object)。

Conv layers
论文中
Faster RCNN虽然支持任意图片输入,但是进入Conv layers网络之前会对图片进行规整化尺度操作,如可设定图像短边不超过 600,图像长边不超过 1000,我们可以假定 (如果图片少于该尺寸,可以边缘补 0,即图像会有黑色边缘)。
13个conv层:kernel_size=3, pad=1, stride=1,卷积公式:N = (W − F + 2P )/S+1,所以可知conv层不会改变图片大小13个relu层: 激活函数,增加非线性,不改变图片大小4个pooling层:kernel_size=2,stride=2,pooling层会让输出图片变成输入图片的 1/2。
所以经过 Conv layers,图片大小变成 ,即:;则 Feature Map 尺寸为 -d (注:VGG16 是512-d, ZF 是 256-d,d 是指特征图通道数,也叫特征图数量),表示特征图的大小为 ,数量为 512。
RPN 网络

RPN 在 Extractor(特征提取 backbone )输出的 feature maps 的基础之上,先增加了一个 3*3 卷积(用来语义空间转换?),然后利用两个 1x1 的卷积分别进行二分类(是否为正样本)和位置回归。RPN 网络在分类和回归的时候,分别将每一层的每一个 anchor 分为背景和前景两类,以及回归四个位移量,进行分类的卷积核通道数为9×2(9 个 anchor,每个 anchor 二分类,使用交叉熵损失),进行回归的卷积核通道数为 9×4(9个anchor,每个 anchor 有 4 个位置参数)。RPN是一个全卷积网络(fully convolutional network),这样对输入图片的尺寸就没有要求了。
RPN 完成 positive/negative 分类 + bounding box regression 坐标回归两个任务。
Anchors
在RPN中,作者提出了anchors,在代码中,anchors 是一组由 generate_anchors.py 生成的矩形框列表。运行官方代码的 generate_anchors.py 可以得到以下示例输出.这里生成的坐标是在原图尺寸上的坐标,在特征图上的一个像素点,可以对应到原图上一个 大小的区域。
[[ -84. -40. 99. 55.]
[-176. -88. 191. 103.]
[-360. -184. 375. 199.]
[ -56. -56. 71. 71.]
[-120. -120. 135. 135.]
[-248. -248. 263. 263.]
[ -36. -80. 51. 95.]
[ -80. -168. 95. 183.]
[-168. -344. 183. 359.]]
其中每行的 4 个值 表矩形左上和右下角点坐标。9 个矩形共有 3 种形状,长宽比为大约为 三种,如下图。实际上通过 anchors 就引入了检测中常用到的多尺度方法。

注意,
generate_anchors.py生成的只是 base anchors,其中一个 框的左上角坐标为 (0,0) 坐标(特征图左上角)的 9 个 anchor,后续还需网格化(meshgrid)生成其他 anchor。同一个 scale,但是不同的 anchor ratios 生成的 anchors 面积理论上是要一样的。
然后利用这 9 种 anchor 在特征图左右上下移动(遍历),每一个特征图上的任意一个点都有 9 个 anchor,假设原图大小为 MxN,经过 Conv layers 下采样 16 倍,则每个 feature map 生成 (M/16)*(N/16)*9个 anchor。例如,对于一个尺寸为 62×37 的 feature map,有 62×37×9 ≈ 20000 个 anchor,并输出特征图上面每个点对应的原图 anchor 坐标。这种做法很像是暴力穷举,20000 多个 anchor,哪怕是蒙也能够把绝大多数的 ground truth bounding boxes 蒙中。
因此可知,anchor 的数量和 feature map 大小相关,不同的 feature map 对应的 anchor 数量也不一样。
生成 RPN 网络训练集
在这个任务中,RPN 做的事情就是利用(AnchorTargetCreator)将 20000 多个候选的 anchor 选出 256 个 anchor 进行分类和回归位置。选择过程如下:
- 对于每一个 ground truth bounding box (
gt_bbox),选择和它重叠度(IoU)最高的一个anchor作为正样本; - 对于剩下的 anchor,从中选择和任意一个 gt_bbox 重叠度超过
0.7的 anchor ,同样作为正样本;特殊情况下,如果正样本不足128(256 的 1/2),则用负样本凑。 - 随机选择和
gt_bbox重叠度小于0.3的 anchor 作为负样本。
本和正样本的总数为256,正负样本比例1:1。
positive/negative 二分类
由 卷积实现,卷积通道数为 (每个点有 9 个 anchor,每个 anchor 二分类,使用交叉熵损失),后面接 softmax 分类获得 positive anchors,也就相当于初步提取了检测目标候选区域 box(一般认为目标在 positive anchors 中)。所以可知,RPN 的一个任务就是在原图尺度上,设置了大量的候选 anchor,并通过 AnchorTargetCreator 类去挑选正负样本比为 1:1 的 256 个 anchor,然后再用 CNN ( 卷积,卷积通道数 ) 去判断挑选出来的 256 个 anchor 哪些有目标的 positive anchor,哪些是没目标的 negative anchor。
在挑选 1:1 正负样本比例的 anchor 用作 RPN 训练集后,还需要计算训练集数据对应的标签。对于每个 anchor, 对应的标签是 gt_label 和 gt_loc。gt_label 要么为 1(前景),要么为 0(背景),而 gt_loc 则是由 4 个位置参数 组成,它们是 anchor box 与 ground truth bbox 之间的偏移量,因为回归偏移量比直接回归座标更好。在 Faster RCNN原文,positive anchor 与 ground truth 之间的偏移量 与尺度因子 计算公式如下:
参数解释:where and denote the box’s center coordinates and its width and height. Variables ,and are for the predicted box, anchor box, and groundtruth box respectively (likewise for ).
计算分类损失用的是交叉熵损失,计算回归损失用的是 Smooth_L1_loss。在计算回归损失的时候,只计算正样本(前景)的损失,不计算负样本的位置损失。RPN 网络的 Loss 计算公式如下:

公式解释:Here, is the index of an anchor in a mini-batch and is the predicted probability of anchor i being an object. The ground-truth label is 1 if the anchor is positive, and is 0 if the anchor is negative. is a vector representing the 4 parameterized coordinates of the predicted bounding box, and is that of theground-truth box associated with a positive anchor.
RPN 生成 RoIs(Proposal Layer)
RPN 网络在自身训练的同时,还会由 Proposal Layer 层产生 RoIs(region of interests)给 Fast RCNN(RoIHead)作为训练样本。RPN 生成 RoIs 的过程( ProposalCreator )如下:
- 对于每张图片,利用它的
feature map, 计算(H/16)× (W/16)×9(大概 20000)个anchor属于前景的概率,以及对应的位置参数,并选取概率较大的12000个 anchor; - 利用回归的位置参数,修正这
12000个anchor的位置,得到RoIs; - 利用非极大值((Non-maximum suppression, NMS)抑制,选出概率最大的
2000个RoIs。
在 RPN 中,从上万个 anchor 中,选一定数目(2000 或 300),调整大小和位置生成
RoIs,用于 ROI Head/Fast RCNN 训练或测试,然后ProposalTargetCreator再从RoIs中会中选择128个RoIs用以 ROIHead 的训练)。
注意:RoIs 对应的尺寸是原图大小,同时在 inference 的时候,为了提高处理速度,12000 和 2000 分别变为 6000 和 300。Proposal Layer 层,这部分的操作不需要进行反向传播,因此可以利用 numpy/tensor 实现。
RPN 网络总结
- RPN 网络结构:生成 anchors -> softmax 分类器提取 positvie anchors -> bbox reg 回归 positive anchors -> Proposal Layer 生成 proposals
- RPN 的输出:
RoIs(region of interests)(形如2000×4或者300×4的tensor)
ROIHead/Fast R-CNN
RPN 只是给出了 2000 个 候选框,RoI Head 在给出的 2000 候选框之上继续进行分类和位置参数的回归。ROIHead 网络包括 RoI pooling + Classification(全连接分类)两部分,网络结构如下:

由于 RoIs 给出的 2000 个 候选框,分别对应 feature map 不同大小的区域。首先利用 ProposalTargetCreator 挑选出 128 个 sample_rois, 然后使用了 RoI Pooling 将这些不同尺寸的区域全部 pooling 到同一个尺度 上,并输出 大小的 feature map 送入后续的两个全连接层。两个全连接层分别完成类别分类和 bbox 回归的作用:
FC 21用来分类,预测RoIs属于哪个类别(20个类+背景)FC 84用来回归位置(21个类,每个类都有4个位置参数)
论文中之所以设定为 pooling 成 7×7 的尺度,其实是为了网络输出是固定大小的
vector or matrix,从而能够共享 VGG 后面两个全连接层的权重。当所有的 RoIs 都被pooling 成(512×7×7)的 feature map 后,将它 reshape 成一个一维的向量,就可以利用 VGG16 预训练的权重来初始化前两层全连接(FC 4096)。
Roi pooling
RoI pooling 负责将 128 个 RoI 区域对应的 feature map 进行截取,而后利用 RoI pooling 层输出 大小的 feature map,送入后续的全连接网络。从论文给出的 Faster R-CNN 网络结构图中,可以看到 Rol pooling 层有 2 个输入:
- 原始的
feature maps RPN输出的RoIs(proposal boxes, 大小各不相同)
RoI Pooling 的两次量化过程:
(1) 因为 proposals是对应 的原图尺寸,所以在原图上生成的 region proposal 需要映射到 feature map 上(坐标值缩小 16 倍),需要除以 (下采样倍数),这时候边界会出现小数,自然就需要量化。
(2) 将 proposals 对应的 feature map 区域水平划分成 () 的 bins,并对每个 bin 中均匀选取多少个采样点,然后进行 max pooling,也会出现小数,自然就产生了第二次量化。
Mask RCNN 算法中的 RoI Align 如何改进:
ROI Align 并不需要对两步量化中产生的浮点数坐标的像素值都进行计算,而是设计了一套优雅的流程。如下图,其中虚线代表的是一个 feature map,实线代表的是一个 roi (在这个例子中,一个 roi 是分成了 个 bins),实心点代表的是采样点,每个 bin 中有 4 个采样点。我们通过双线性插值的方法根据采样点周围的四个点计算每一个采样点的值,然后对着四个采样点执行最大池化操作得到当前 bin 的像素值。

RoI Align 具体做法:假定采样点数为 4,即表示,对于每个 的 bin,平分四份小矩形,每一份取其中心点位置,而中心点位置的像素,采用双线性插值法进行计算,这样就会得到四个小数坐标点的像素值。
更多细节内容可以参考 RoIPooling、RoIAlign笔记。
ROI Head 训练
RPN 会产生大约 2000 个 RoIs ,ROI Head 在给出的 2000 个 RoIs 候选框基础上继续分类(目标分类)和位置参数回归。注意,这 2000 个 RoIs 不是都拿去训练,而是利用 ProposalTargetCreator(官方源码可以查看类定义) 选择 128 个 RoIs 用以训练。选择的规则如下:
- 在和
gt_bboxes的IoU大于0.5的RoIs内,选择一些(比如32个)作为正样本 - 在和
gt_bboxes的IoU小于等于0(或者0.1)RoIs内,的选择一些(比如 个)作为负样本
选择出的 128 个 RoIs,其正负样本比例为 3:1,在源码中为了便于训练,还对他们的 gt_roi_loc 进行标准化处理(减去均值除以标准差)。
- 对于分类问题, 和
RPN一样,直接利用交叉熵损失。 - 对于位置的回归损失,也采用 Smooth_L1 Loss, 只不过只对正样本计算损失,而且是只对正样本中的对应类别的 个参数计算损失。举例来说:
- 一个
RoI在经过FC84后会输出一个84维的loc向量。 如果这个RoI是负样本, 则这84维向量不参与计算L1_Loss。 - 如果这个
RoI是正样本,且属于 类别 , 那么向量的第 这 位置的值参与计算损失,其余的不参与计算损失。
- 一个
ROI Head 测试
ROI Head 测试的时候对所有的 RoIs(大概 300 个左右) 计算概率,并利用位置参数调整预测候选框的位置,然后再用一遍极大值抑制(之前在 RPN 的ProposalCreator 也用过)。这里注意:
- 在
RPN的时候,已经对anchor做了一遍NMS,在Fast RCNN测试的时候,还要再做一遍,所以在Faster RCNN框架中,NMS操作总共有 2 次。 - 在
RPN的时候,已经对anchor的位置做了回归调整,在Fast RCNN阶段还要对RoI再做一遍。 - 在
RPN阶段分类是二分类,而Fast RCNN/ROI Head阶段是21分类。
概念理解
在阅读 Faster RCNN 论文和源码中,我们经常会涉及到一些概念的理解。
四类损失
在训练 Faster RCNN 的时候有四个损失:
RPN分类损失:anchor是否为前景(二分类)RPN位置回归损失:anchor位置微调RoI分类损失:RoI所属类别(21分类,多了一个类作为背景)RoI位置回归损失:继续对RoI位置微调
四个损失相加作为最后的损失,反向传播,更新参数。
三个 creator
Faster RCNN 官方源码中有三个 creator 类分别实现不同的功能,不能弄混,各自功能如下:
AnchorTargetCreator: 负责在训练RPN的时候,从上万个anchors中选择一些(比如256)进行训练,并使得正负样本比例大概是1:1。同时给出训练的位置参数目标,即返回gt_rpn_loc和gt_rpn_label。ProposalTargetCreator: 负责在训练RoIHead/Fast R-CNN的时候,从RoIs选择一部分(比如128个,正负样本比例1:3)用以训练。同时给定训练目标, 返回(sample_RoI,gt_RoI_loc,gt_RoI_label)。ProposalCreator: 在RPN中,从上万个anchor中,选择一定数目(2000或者300),调整大小和位置,生成RoIs,用以Fast R-CNN训练或者测试。
其中 AnchorTargetCreator 和 ProposalTargetCreator 类是为了生成训练的目标,只在训练阶段用到,ProposalCreator 是 RPN 为 Fast R-CNN 生成 RoIs ,在训练和测试阶段都会用到。三个 creator 的共同点在于他们都不需要考虑反向传播(因此不同框架间可以共享 numpy 实现)。
3.2 FPN
论文背景
FPN(feature pyramid networks) 是何凯明等作者提出的适用于多尺度目标检测算法。原来多数的 object detection 算法(比如 faster rcnn)都是只采用顶层特征做预测,但我们知道低层的特征语义信息比较少,但是目标位置准确;高层的特征语义信息比较丰富,但是目标位置比较粗略。另外虽然也有些算法采用多尺度特征融合的方式,但是一般是采用融合后的特征做预测,而本文不一样的地方在于预测是在不同特征层独立进行的。
引言(Introduction)

从上图可以看出,(a)使用图像金字塔构建特征金字塔。每个图像尺度上的特征都是独立计算的,速度很慢。(b)最近的检测系统选择(比如 Faster RCNN)只使用单一尺度特征进行更快的检测。(c)另一种方法是重用 ConvNet(卷积层)计算的金字塔特征层次结构(比如 SSD),就好像它是一个特征化的图像金字塔。(d)我们提出的特征金字塔网络(FPN)与(b)和(c)类似,但更准确。在该图中,特征映射用蓝色轮廓表示,较粗的轮廓表示语义上较强的特征。
特征金字塔网络 FPN
作者提出的 FPN 结构如下图:这个金字塔结构包括一个自底向上的线路,一个自顶向下的线路和横向连接(lateral connections)。

自底向上其实就是卷积网络的前向过程。在前向过程中,feature map 的大小在经过某些层后会改变,而在经过其他一些层的时候不会改变,作者将不改变 feature map 大小的层归为一个 stage,因此这里金字塔结构中每次抽取的特征都是每个 stage 的最后一个层的输出。在代码中我们可以看到共有C1、C2、C3、C4、C5五个特征图,C1 和 C2 的特征图大小是一样的,所以,FPN 的建立也是基于从 C2 到 C5 这四个特征层上。
自顶向下的过程采用上采样(upsampling)进行,而横向连接则是将上采样的结果和自底向上生成的相同大小的 feature map 进行融合(merge)。在融合之后还会再采用 3*3 的卷积核对每个融合结果进行卷积,目的是消除上采样的混叠效应(aliasing effect)。并假设生成的 feature map 结果是 P2,P3,P4,P5,和原来自底向上的卷积结果 C2,C3,C4,C5一一对应。
这里贴一个 ResNet 的结构图:论文中作者采用 conv2_x,conv3_x,conv4_x 和 conv5_x 的输出,对应 C1,C2,C3,C4,C5,因此类似 Conv2就可以看做一个stage。

FPN网络建立
这里自己没有总结,因为已经有篇博文总结得很不错了,在这。
通过 ResNet50 网络,得到图片不同阶段的特征图,最后利用 C2,C3,C4,C5 建立特征图金字塔结构:
- 将 C5 经过 256 个 1*1 的卷积核操作得到:32*32*256,记为 P5;
- 将 P5 进行步长为 2 的上采样得到 64*64*256,再与 C4 经过的 256 个 1*1 卷积核操作得到的结果相加,得到 64*64*256,记为 P4;
- 将 P4 进行步长为 2 的上采样得到 128*128*256,再与 C3 经过的 256 个 1*1 卷积核操作得到的结果相加,得到 128*128*256,记为 P3;
- 将 P3 进行步长为 2 的上采样得到 256*256*256,再与 C2 经过的 256 个 1*1 卷积核操作得到的结果相加,得到 256*256*256,记为 P2;
- 将 P5 进行步长为 2 的最大池化操作得到:16*16*256,记为 P6;
结合从 P2 到 P6 特征图的大小,如果原图大小 1024*1024, 那各个特征图对应到原图的步长依次为 [P2,P3,P4,P5,P6]=>[4,8,16,32,64]。
Anchor锚框生成规则
当 Faster RCNN 采用 FPN 的网络作 backbone 后,锚框的生成规则也会有所改变。基于上一步得到的特征图 [P2,P3,P4,P5,P6],再介绍下采用 FPN 的 Faster RCNN(或者 Mask RCNN)网络中 Anchor 锚框的生成,根据源码中介绍的规则,与之前 Faster-RCNN 中的生成规则有一点差别。
- 遍历
P2 到 P6这五个特征层,以每个特征图上的每个像素点都生成Anchor锚框; - 以 P2 层为例,P2 层的特征图大小为 256*256,相对于原图的步长为4,这样 P2上的每个像素点都可以生成一个基于坐标数组 [0,0,3,3] 即 4*4 面积为 16 大小的Anchor锚框,当然,可以设置一个比例 SCALE,将这个基础的锚框放大或者缩小,比如,这里设置 P2 层对应的缩放比例为 16,那边生成的锚框大小就是长和宽都扩大16倍,从 4*4 变成 64*64,面积从 16 变成 4096,当然在保证面积不变的前提下,长宽比可以变换为 32*128、64*64 或 128*32,这样以长、宽比率 RATIO = [0.5,1,2] 完成了三种变换,这样一个像素点都可以生成3个Anchor锚框。在 Faster-RCNN 中可以将
Anchor scale也可以设置为多个值,而在MasK RCNN 中则是每一特征层只对应着一个Anchor scale即对应着上述所设置的 16; - 以
P2层每个像素点位中心,对应到原图上,则可生成 256*256*3(长宽三种变换) = 196608 个锚框; - 以
P3层每个像素点为中心,对应到原图上,则可生成 128*128*3 = 49152 个锚框; - 以
P4层每个像素点为中心,对应到原图上,则可生成 64*64*3 = 12288 个锚框; - 以
P5层每个像素点为中心,对应到原图上,则生成 32*32*3 = 3072 个锚框; - 以
P6层每个像素点为中心,对应到原图上,则生成 16*16*3 = 768 个锚框。
从 P2 到 P6 层一共可以在原图上生成 个 Anchor 锚框。
实验
看看加入FPN 的 RPN 网络的有效性,如下表 Table1。网络这些结果都是基于 ResNet-50。评价标准采用 AR,AR 表示 Average Recall,AR 右上角的 100 表示每张图像有 100 个 anchor,AR 的右下角 s,m,l 表示 COCO 数据集中 object 的大小分别是小,中,大。feature 列的大括号 {} 表示每层独立预测。

从(a)(b)(c)的对比可以看出 FPN 的作用确实很明显。另外(a)和(b)的对比可以看出高层特征并非比低一层的特征有效。
(d)表示只有横向连接,而没有自顶向下的过程,也就是仅仅对自底向上(bottom-up)的每一层结果做一个 1*1 的横向连接和 3*3 的卷积得到最终的结果,有点像 Fig1 的(b)。从 feature 列可以看出预测还是分层独立的。作者推测(d)的结果并不好的原因在于在自底向上的不同层之间的 semantic gaps 比较大。
(e)表示有自顶向下的过程,但是没有横向连接,即向下过程没有融合原来的特征。这样效果也不好的原因在于目标的 location 特征在经过多次降采样和上采样过程后变得更加不准确。
(f)采用 finest level 层做预测(参考 Fig2 的上面那个结构),即经过多次特征上采样和融合到最后一步生成的特征用于预测,主要是证明金字塔分层独立预测的表达能力。显然 finest level 的效果不如 FPN 好,原因在于 PRN 网络是一个窗口大小固定的滑动窗口检测器,因此在金字塔的不同层滑动可以增加其对尺度变化的鲁棒性。另外(f)有更多的 anchor,说明增加 anchor 的数量并不能有效提高准确率。

3.3 Mask-RCNN
ROI Pooling 和 ROI Align 的区别
Understanding Region of Interest — (RoI Align and RoI Warp)
Mask R-CNN 网络结构
Mask RCNN 继承自 Faster RCNN 主要有三个改进:
feature map的提取采用了FPN的多尺度特征网络ROI Pooling改进为ROI Align- 在
RPN后面,增加了采用FCN结构的mask分割分支
网络结构如下图所示:

可以看出,Mask RCNN 是一种先检测物体,再分割的思路,简单直接,在建模上也更有利于网络的学习。
骨干网络 FPN
卷积网络的一个重要特征:深层网络容易响应语义特征,浅层网络容易响应图像特征。Mask RCNN 的使用了 ResNet 和 FPN 结合的网络作为特征提取器。
anchor 锚框生成规则
在 Faster-RCNN 中可以将 SCALE 也可以设置为多个值,而在 Mask RCNN 中则是每一特征层只对应着一个SCALE 即对应着上述所设置的 16。
实验
何凯明在论文中做了很多对比单个模块试验,并放出了对比结果表格。

从上图表格可以看出:
sigmoid和softmax对比,sigmoid有不小提升;- 特征网络选择:可以看出更深的网络和采用
FPN的实验效果更好,可能因为 FPN 综合考虑了不同尺寸的feature map的信息,因此能够把握一些更精细的细节。 RoI Align和RoI Pooling对比:在 instance segmentation 和 object detection 上都有不小的提升。这样看来,RoIAlign 其实就是一个更加精准的 RoIPooling,把前者放到 Faster RCNN 中,对结果的提升应该也会有帮助
3.4 Retinanet
摘要
Retinanet 是作者 Tsung-Yi Lin 和 Kaiming He(四作) 于 2018 年发表的论文 Focal Loss for Dense Object Detection.
作者深入分析了极度不平衡的正负(前景背景)样本比例导致 one-stage 检测器精度低于 two-stage 检测器,基于上述分析,提出了一种简单但是非常实用的 Focal Loss 焦点损失函数,并且 Loss 设计思想可以推广到其他领域,同时针对目标检测领域特定问题,设计了 RetinaNet 网络,结合 Focal Loss 使得 one-stage 检测器在精度上能够达到乃至超过 two-stage 检测器。
1,引言
作者认为一阶段检测器的精度不能和两阶段检测相比的原因主要在于,训练过程中的类别不平衡,由此提出了一种新的损失函数-Focal Loss。
R-CNN(Fast RCNN) 类似的检测器之所以能解决类别不平衡问题,是因为两阶段级联结构和启发式采样。提取 proposal 阶段(例如,选择性搜索、EdgeBoxes、DeepMask、RPN)很快的将候选对象位置的数量缩小到一个小数目(例如,1-2k),过滤掉大多数背景样本(其实就是筛选 anchor 数量)。在第二个分类阶段,执行启发式采样(sampling heuristics),例如固定的前景背景比(1:3),或在线难样本挖掘(OHEM),以保持前景和背景之间的平衡。
相比之下,单级检测器必须处理在图像中定期采样的一组更大的候选对象位置。实际上,这通常相当于枚举 ∼100k 个位置,这些位置密集地覆盖空间位置、尺度和纵横。虽然也可以应用类似的启发式采样方法,但效率低下,因为训练过程仍然由易于分类的背景样本主导。
2,相关工作
Two-stage Detectors: 与之前使用两阶段的分类器生成 proposal 不同,Faster RCNN 模型的 RPN 使用单个卷积就可以生成 proposal。
One-stage Detectors:最近的一些研究表明,只需要降低输入图像分辨率和 proposal 数量,两阶段检测器速度就可以变得更快。但是,对于一阶段检测器,即使提高模型计算量,其最后的精度也落后于两阶段方法[17]。同时,作者强调,Reinanet 达到很好的结果的原因不在于网络结构的创新,而在于损失函数的创新。
论文 [17] Speed/accuracy trade-offs for modern convolutional object detectors(注重实验). 但是,从这几年看,一阶段检测器也可以达到很高的精度,甚至超过两阶段检测器,这几年的一阶段检测和两阶段检测器有相互融合的趋势了。
Class Imbalance: 早期的目标检测器 SSD 等在训练过程中会面临严重的类别不平衡(class imbalance)的问题,即正样本太少,负样本太多,这会导致两个问题:
- 训练效率低下:大多数候选区域都是容易分类的负样本,并没有提供多少有用的学习信号。
- 模型退化:易分类的负样本太多会压倒训练,导致模型退化。
通常的解决方案是执行某种形式的难负样本挖掘,如在训练时进行难负样本采样或更复杂的采样/重新称重方案。相比之下,Focla Loss 自然地处理了单级检测器所面临的类别不平衡,并且允许在所有示例上有效地训练,而不需要采样,也不需要容易的负样本来压倒损失和计算的梯度。
Robust Estimation: 人们对设计稳健的损失函数(例如 Huber loss)很感兴趣,该函数通过降低具有大错误的示例(硬示例)的损失来减少对总损失的贡献。相反, Focal Loss 对容易样本(inliers)减少权重来解决(address)类别不平衡问题(class imbalance),这意味着即使容易样本数量大,但是其对总的损失函数贡献也很小。换句话说,Focal Loss 与鲁棒损失相反,它侧重于训练稀疏的难样本。
3,网络架构
retinanet 的网络架构图如下所示。

3.1,Backbone
Retinanet 的 Backbone 为 ResNet 网络,ResNet 一般从 18 层到 152 层(甚至更多)不等,主要区别在于采用的残差单元/模块不同或者堆叠残差单元/模块的数量和比例不同,论文主要使用 ResNet50。
两种残差块结构如下图所示,ResNet50 及更深的 ResNet 网络使用的是 bottleneck 残差块。

3.2,Neck
Neck 模块即为 FPN 网络结构。FPN 模块接收 c3, c4, c5 三个特征图,输出 P2-P7 五个特征图,通道数都是 256, stride 为 (8,16,32,64,128),其中大 stride (特征图小)用于检测大物体,小 stride (特征图大)用于检测小物体。P6 和 P7 目的是提供一个大感受野强语义的特征图,有利于大物体和超大物体检测。注意:在 RetinaNet 的 FPN 模块中只包括卷积,不包括 BN 和 ReLU。
3.3,Head
Head 即预测头网络。
YOLOv3 的 neck 输出 3 个分支,即输出 3 个特征图, head 模块只有一个分支,由卷积层组成,该卷积层完成目标分类和位置回归的功能。总的来说,YOLOv3 网络的 3 个特征图有 3 个预测分支,分别预测 3 个框,也就是分别预测大、中、小目标。
Retinanet 的 neck 输出 5 个分支,即输出 5 个特征图。head 模块包括分类和位置检测两个分支,每个分支都包括 4 个卷积层,但是 head 模块的这两个分支之间参数不共享,分类 Head 输出通道是 A*K,A 是类别数;检测 head 输出通道是 4*K, K 是 anchor 个数, 虽然每个 Head 的分类和回归分支权重不共享,但是 5 个输出特征图的 Head 模块权重是共享的。
4,Focal Loss
Focal Loss 是在二分类问题的交叉熵(CE)损失函数的基础上引入的,所以需要先学习下交叉熵损失的定义。
4.1,Cross Entropy
可额外阅读文章 理解交叉熵损失函数。
在深度学习中我们常使用交叉熵来作为分类任务中训练数据分布和模型预测结果分布间的代价函数。对于同一个离散型随机变量 有两个单独的概率分布 和 ,其交叉熵定义为:
P 表示真实分布, Q 表示预测分布。
$H(P,Q) = \mathbb{E}{\textrm{x}\sim P} log Q(x)= -\sum{i}P(x_i)logQ(x_i) \tag{1} $
但在实际计算中,我们通常不这样写,因为不直观。在深度学习中,以二分类问题为例,其交叉熵损失(CE)函数如下:
Loss = L(y, p) = -ylog(p)-(1-y)log(1-p) \tag{2}
其中 表示当预测样本等于 的概率,则 表示样本等于 的预测概率。因为是二分类,所以样本标签 取值为 ,上式可缩写至如下:
CE = \left\{\begin{matrix} -log(p), & if \quad y=1 \\ -log(1-p), & if\quad y=0 \tag{3} \end{matrix}\right.
为了方便,用 代表 , 定义如下:
则式可写成:
CE(p, y) = CE(p_t) = -log(p_t) \tag{4}
前面的交叉熵损失计算都是针对单个样本的,对于所有样本,二分类的交叉熵损失计算如下:
其中 为正样本个数, 为负样本个数, 为样本总数,。当样本类别不平衡时,损失函数 的分布也会发生倾斜,如 时,负样本的损失会在总损失占主导地位。又因为损失函数的倾斜,模型训练过程中也会倾向于样本多的类别,造成模型对少样本类别的性能较差。
再衍生以下,对于所有样本,多分类的交叉熵损失计算如下:
其中, 表示类别数量, 是符号函数,如果样本 的真实类别等于 取值 1,否则取值 0; 表示样本 预测为类别 的概率。
对于多分类问题,交叉熵损失一般会结合 softmax 激活一起实现,PyTorch 代码如下,代码出自这里。
4.2,Balanced Cross Entropy
对于正负样本不平衡的问题,较为普遍的做法是引入 参数来解决,上面公式重写如下:
对于所有样本,二分类的平衡交叉熵损失函数如下:
其中 ,即 参数的值是根据正负样本分布比例来决定的,
4.3,Focal Loss Definition
虽然 参数平衡了正负样本(positive/negative examples),但是它并不能区分难易样本(easy/hard examples),而实际上,目标检测中大量的候选目标都是易分样本。这些样本的损失很低,但是由于难易样本数量极不平衡,易分样本的数量相对来讲太多,最终主导了总的损失。而本文的作者认为,易分样本(即,置信度高的样本)对模型的提升效果非常小,模型应该主要关注与那些难分样本(这个假设是有问题的,是 GHM 的主要改进对象)
Focal Loss 作者建议在交叉熵损失函数上加上一个调整因子(modulating factor),把高置信度 (易分样本)样本的损失降低一些。Focal Loss 定义如下:
Focal Loss 有两个性质:
- 当样本被错误分类且 值较小时,调制因子接近于
1,loss几乎不受影响;当 接近于1,调质因子(factor)也接近于0,容易分类样本的损失被减少了权重,整体而言,相当于增加了分类不准确样本在损失函数中的权重。 - 参数平滑地调整容易样本的权重下降率,当 时,
Focal Loss等同于CE Loss。 在增加,调制因子的作用也就增加,实验证明 时,模型效果最好。
直观地说,调制因子减少了简单样本的损失贡献,并扩大了样本获得低损失的范围。例如,当 时,与 相比,分类为 的样本的损耗将降低 100 倍,而当 时,其损耗将降低 1000 倍。这反过来又增加了错误分类样本的重要性(对于 和 ,其损失最多减少 4 倍)。在训练过程关注对象的排序为正难 > 负难 > 正易 > 负易。
在实践中,我们常采用带 的 Focal Loss:
作者在实验中采用这种形式,发现它比非 平衡形式(non--balanced)的精确度稍有提高。实验表明 取 2, 取 0.25 的时候效果最佳。
网上有各种版本的 Focal Loss 实现代码,大多都是基于某个深度学习框架实现的,如 Pytorch和 TensorFlow,我选取了一个较为清晰的通用版本代码作为参考,代码来自 这里。
后续有必要自己实现以下,有时间还要去看看
Caffe的实现。这里的 Focal Loss 代码与后文不同,这里只是纯粹的用于分类的 Focal_loss 代码,不包含 BBox 的编码过程
3.5 YOLOv1
YOLOv1 出自 2016 CVPR 论文 You Only Look Once:Unified, Real-Time Object Detection.
YOLO 系列算法的核心思想是将输入的图像经过 backbone 提取特征后,将得到特征图划分为 S x S 的网格,物体的中心落在哪一个网格内,这个网格就负责预测该物体的置信度、类别以及坐标位置。
1. Introduction
之前的目标检测器是重用分类器来执行检测,为了检测目标,这些系统在图像上不断遍历一个框,并利用分类器去判断这个框是不是目标。像可变形部件模型(DPM)使用互动窗口方法,其分类器在整个图像的均匀间隔的位置上运行。
作者将目标检测看作是单一的回归问题,直接从图像像素得到边界框坐标和类别概率。
首先,YOLO 速度非常快,我们将检测视为回归问题,所以检测流程也简单。其次,YOLO 在进行预测时,会对图像进行全面地推理。第三,YOLO 模型具有泛化能力,其比 DPM 和R-CNN 更好。最后,虽然 YOLO 模型在精度上依然落后于最先进(state-of-the-art)的检测系统,但是其速度更快。
2. Unified Detectron
YOLO 系统将输入图像划分成 的网格(grid),然后让每个gird 负责检测那些中心点落在 grid 内的目标。
检测任务:每个网络都会预测 个边界框及边界框的置信度分数,所谓置信度分数其实包含两个方面:一个是边界框含有目标的可能性,二是边界框的准确度。前者记为 ,当边界框包含目标时, 值为 1,否则为 0;后者记为 ,即预测框与真实框的 IOU。因此形式上,我们将置信度定义为 。如果 grid 不存在目标,则置信度分数置为 0,否则,置信度分数等于预测框和真实框之间的交集(IoU)。
每个边界框(bounding box)包含 5 个预测变量:,,, 和 confidence。 坐标不是边界框中心的实际坐标,而是相对于网格单元左上角坐标的偏移(需要看代码才能懂,论文只描述了出“相对”的概念)。而边界框的宽度和高度是相对于整个图片的宽与高的比例,因此理论上以上 4 预测量都应该在 范围之内。最后,置信度预测表示预测框与实际边界框之间的 IOU。
值得注意的是,中心坐标的预测值 是相对于每个单元格左上角坐标点的偏移值,偏移量 = 目标位置 - grid的位置。

分类任务:每个网格单元(grid)还会预测 个类别的概率 。grid 包含目标时才会预测 ,且只预测一组类别概率,而不管边界框 的数量是多少。
在推理时,我们乘以条件概率和单个 box 的置信度。
它为我们提供了每个框特定类别的置信度分数。这些分数编码了该类出现在框中的概率以及预测框拟合目标的程度。
在 Pscal VOC 数据集上评测 YOLO 模型时,我们设置 , (即每个 grid 会生成 2 个边界框)。Pscal VOC 数据集有 20 个类别,所以 。所以,模型最后预测的张量维度是 。

总结:YOLO 系统将检测建模为回归问题。它将图像分成 的 gird,每个 grid 都会预测 个边界框,同时也包含 个类别的概率,这些预测对应的就是 。
这里其实就是在描述 YOLOv1 检测头如何设计:回归网络的设计 + 训练集标签如何构建(即 yoloDataset 类的构建)。
一张图片对应的标签张量 target 的维度是 。然后分别对各个目标框的 boxes: 和 labels:(0,0,...,1,0)(one-hot 编码的目标类别信息)进行处理,符合检测系统要求的输入形式。算法步骤如下:
- 计算目标框中心点坐标和宽高,并遍历各个目标框;
- 计算目标中心点落在哪个
grid上,target相应位置的两个框的置信度值设为1,同时对应类别值也置为1; - 计算目标中心所在
grid(网格)的左上角相对坐标:ij*cell_size,然后目标中心坐标相对于子网格左上角的偏移比例delta_xy; - 最后将
target对应网格位置的 分别赋相应wh、delta_xy值。
2.1. Network Design
YOLO 模型使用卷积神经网络来实现,卷积层负责从图像中提取特征,全连接层预测输出类别概率和坐标。
YOLO 的网络架构受 GooLeNet 图像分类模型的启发。网络有 24 个卷积层,最后面是 2 个全连接层。整个网络的卷积只有 和 卷积层,其中 卷积负责降维 ,而不是 GoogLeNet 的 Inception 模块。

图3:网络架构。作者在 ImageNet 分类任务上以一半的分辨率(输入图像大小 )训练卷积层,但预测时分辨率加倍。
Fast YOLO 版本使用了更少的卷积,其他所有训练参数及测试参数都和 base YOLO 版本是一样的。
网络的最终输出是 的张量。这个张量所代表的具体含义如下图所示。对于每一个单元格,前 20 个元素是类别概率值,然后 2 个元素是边界框置信度,两者相乘可以得到类别置信度,最后 8 个元素是边界框的 。之所以把置信度 和 都分开排列,而不是按照 这样排列,存粹是为了后续计算时方便。

划分 网格,共
98个边界框,2个框对应一个类别,所以YOLOv1只能在一个网格中检测出一个目标、单张图片最多预测49个目标。
2.2 Training
模型训练最重要的无非就是超参数的调整和损失函数的设计。
因为 YOLO 算法将检测问题看作是回归问题,所以自然地采用了比较容易优化的均方误差作为损失函数,但是面临定位误差和分类误差权重一样的问题;同时,在每张图像中,许多网格单元并不包含对象,即负样本(不包含物体的网格)远多于正样本(包含物体的网格),这通常会压倒了正样本的梯度,导致训练早期模型发散。
为了改善这点,引入了两个参数: 和 。对于边界框坐标预测损失(定位误差),采用较大的权重 ,然后区分不包含目标的边界框和含有目标的边界框,前者采用较小权重 。其他权重则均设为 0。
对于大小不同的边界框,因为较小边界框的坐标误差比较大边界框要更敏感,所以为了部分解决这个问题,将网络的边界框的宽高预测改为对其平方根的预测,即预测值变为 。
YOLOv1 每个网格单元预测多个边界框。在训练时,每个目标我们只需要一个边界框预测器来负责。我们指定一个预测器“负责”根据哪个预测与真实值之间具有当前最高的 IOU 来预测目标。这导致边界框预测器之间的专业化。每个预测器可以更好地预测特定大小,方向角,或目标的类别,从而改善整体召回率。
YOLO由于每个网格仅能预测2个边界框且仅可以包含一个类别,因此是对于一个单元格存在多个目标的问题,YOLO只能选择一个来预测。这使得它在预测临近物体的数量上存在不足,如钢筋、人脸和鸟群检测等。
最终网络总的损失函数计算公式如下:

指的是第 个单元格存在目标,且该单元格中的第 个边界框负责预测该目标。 指的是第 个单元格存在目标。
- 前 2 行计算前景的
geo_loss(定位loss)。 - 第 3 行计算前景的
confidence_loss(包含目标的边界框的置信度误差项)。 - 第 4 行计算背景的
confidence_loss。 - 第 5 行计算分类损失
class_loss。
值得注意的是,对于不存在对应目标的边界框,其误差项就是只有置信度,坐标项误差是没法计算的。而只有当一个单元格内确实存在目标时,才计算分类误差项,否则该项也是无法计算的。
2.4. Inferences
同样采用了 NMS 算法来抑制多重检测,对应的模型推理结果解码代码如下,这里要和前面的 encoder 函数结合起来看。
3.6 YOLOv2
摘要
YOLOv2 其实就是 YOLO9000,作者在 YOLOv1 基础上改进的一种新的 state-of-the-art 目标检测模型,它能检测多达 9000 个目标!利用了多尺度(multi-scale)训练方法,YOLOv2 可以在不同尺寸的图片上运行,并取得速度和精度的平衡。
在速度达到在 40 FPS 同时,YOLOv2 获得 78.6 mAP 的精度,性能优于backbone 为 ResNet 的 Faster RCNN 和 SSD 等当前最优(state-of-the-art) 模型。最后作者提出一种联合训练目标检测和分类的方法,基于这种方法,YOLO9000 能实时检测多达 9000 种目标。
YOLOv1 虽然速度很快,但是还有很多缺点:
- 虽然每个
grid预测两个框,但是只能对应一个目标,对于同一个grid有着两个目标的情况下,YOLOv1是检测不全的,且模型最多检测 个目标,即表现为模型查全率低。 - 预测框不够准确,之前回归 的方法不够精确,即表现为模型精确率低。
- 回归参数网络使用全连接层参数量太大,即模型检测头还不够块。
YOLOv2 的改进
1,中心坐标位置预测的改进
YOLOv1 模型预测的边界框中心坐标 是基于 grid 的偏移,这里 grid 的位置是固定划分出来的,偏移量 = 目标位置 - grid 的位置。
边界框的编码过程:YOLOv2 参考了两阶段网络的 anchor boxes 来预测边界框相对先验框的偏移,同时沿用 YOLOv1 的方法预测边界框中心点相对于 grid 左上角位置的相对偏移值。 的偏移值和实际坐标值的关系如下图所示。

各个字母的含义如下:
- :模型预测结果转化为
box中心坐标和宽高后的值 - :模型要预测的偏移量。
- :
grid的左上角坐标,如上图所示。 - :
anchor的宽和高,这里的anchor是人为定好的一个框,宽和高是固定的。
通过以上定义我们从直接预测位置改为预测一个偏移量,即基于 anchor 框的宽高和 grid 的先验位置的偏移量,位置上使用 grid,宽高上使用 anchor 框,得到最终目标的位置,这种方法叫作 location prediction。
预测偏移不直接预测位置,是因为作者发现直接预测位置会导致神经网络在一开始训练时不稳定,使用偏移量会使得训练过程更加稳定,性能指标提升了
5%左右。
边界框的解码过程:虽然模型预测的是边界框的偏移量 ,但是可通过以下公式计算出边界框的实际位置。
$
b_x = \sigma(t_x) + c_x \\
b_y = \sigma(t_y) + c_y \\
b_w = p_{w}e^{t_w} \\
b_h = p_{h}e^{t_h} $
其中, 为 grid 的左上角坐标,因为 表示的是 sigmoid 函数,所以边界框的中心坐标会被约束在 grid 内部,防止偏移过多。、 是先验框(anchors)的宽度与高度,其值相对于特征图大小 = 而言的,因为划分为 个 grid,所以最后输出的特征图中每个 grid 的长和宽均是 1。知道了特征图的大小,就可以将边界框相对于整个特征图的位置和大小计算出来(均取值 )。
在模型推理的时候,将以上 4 个值分别乘以图片的宽度和长度(像素点值)就可以得到边界框的实际中心坐标和大小。
在模型推理过程中,模型输出张量的解析,即边界框的解码函数如下:
2,1 个 gird 只能对应一个目标的改进
或者说很多目标预测不到,查全率低的改进
YOLOv2 首先把 个区域改为 个 grid(区域),每个区域有 5 个anchor,且每个 anchor 对应着 1 个类别,那么,输出的尺寸就应该为:[N,13,13,125]

值得注意的是之前 YOLOv1 的每个 grid 只能预测一个目标的分类概率值,两个 boxes 共享这个置信度概率。现在 YOLOv2 使用了 anchor 先验框后,每个 grid 的每个 anchor 都单独预测一个目标的分类概率值。
之所以每个 grid 取 5 个 anchor,是因为作者对 VOC/COCO 数据集进行 K-means 聚类实验,发现当 k=5 时,模型 recall vs. complexity 取得了较好的平衡。当然, 越好,mAP 肯定越高,但是为了平衡模型复杂度,作者选择了 5 个聚类簇,即划分成 5 类先验框。设置先验框的主要目的是为了使得预测框与 ground truth 的 IOU 更好,所以聚类分析时选用 box 与聚类中心 box 之间的 IOU 值作为距离指标:
与
Faster RCNN手动设置anchor的大小和宽高比不同,YOLOv2 的 anchor 是从数据集中统计得到的。
3,backbone 的改进
作者提出了一个全新的 backbone 网络:Darknet-19,它是基于前人经典工作和该领域常识的基础上进行设计的。Darknet-19 网络和 VGG 网络类似,主要使用 卷积,并且每个 pooling 操作之后将特征图通道数加倍。借鉴 NIN 网络的工作,作者使用 global average pooling 进行预测,并在 卷积之间使用 卷积来降低特征图通道数从而降低模型计算量和参数量。Darknet-19 网络的每个卷积层后面都是用了 BN 层来加快模型收敛,防止模型过拟合。
Darknet-19 网络总共有 19 个卷积层(convolution)、5 最大池化层(maxpooling)。Darknet-19 以 5.58 T的计算量在 ImageNet 数据集上取得了 72.9% 的 top-1 精度和 91.2% 的 top-5 精度。Darket19 网络参数表如下图所示。

检测训练。在 Darknet19 网络基础上进行修改后用于目标检测。首先,移除网络的最后一个卷积层,然后添加滤波器个数为 1024 的 卷积层,最后添加一个 卷积层,其滤波器个数为模型检测需要输出的变量个数。对于 VOC 数据集,每个 grid 预测 5 个边界框,每个边界框有 5 个坐标()和 20 个类别,所以共有 125 个滤波器。我们还添加了从最后的 3×3×512 层到倒数第二层卷积层的直通层,以便模型可以使用细粒度特征。
Yolov2 整个模型结构代码如下:
代码来源 这里。
4,多尺度训练
YOLOv1 输入图像分辨率为 ,因为使用了 anchor boxes,所以 YOLOv2 将输入分辨率改为 。又因为 YOLOv2 模型中只有卷积层和池化层,所以YOLOv2的输入可以不限于 大小的图片。为了增强模型的鲁棒性,YOLOv2 采用了多尺度输入训练策略,具体来说就是在训练过程中每间隔一定的 iterations 之后改变模型的输入图片大小。由于 YOLOv2 的下采样总步长为 32,所以输入图片大小选择一系列为 32 倍数的值: ,因此输入图片分辨率最小为 ,此时对应的特征图大小为 (不是奇数),而输入图片最大为 ,对应的特征图大小为 。在训练过程,每隔 10 个 iterations 随机选择一种输入图片大小,然后需要修最后的检测头以适应维度变化后,就可以重新训练。
采用 Multi-Scale Training 策略,YOLOv2 可以适应不同输入大小的图片,并且预测出很好的结果。
损失函数
YOLOv2 的损失函数的计算公式归纳如下
第 2,3 行: 是迭代次数,即前 12800 步我们计算这个损失,后面不计算了。即前 12800 步我们会优化预测的 与 anchor 的 的距离 + 预测的 与 GT 的 的距离,12800 步之后就只优化预测的 与 GT 的 的距离,原因是这时的预测结果已经较为准确了,anchor已经满足检测系统的需要,而在一开始预测不准的时候,用上 anchor 可以加速训练。
3.7 YOLOv3
摘要
我们对 YOLO 再次进行了更新,包括一些小的设计和更好的网络结构。在输入图像分辨率为 上运行 YOLOv3 模型,时间是 22 ms 的同时获得了 28.2 的 mAP,精度和 SSD 类似,但是速度更快。和其他阈值相比,YOLOv3 尤其在 0.5 IOU(也就是 )这个指标上表现非常良好。
2,改进
YOLOv3 大部分有意的改进点都来源于前人的工作,当然也训练了一个比其他人更好的分类器网络。
2.1,边界框预测
这部分内容和
YOLOv2几乎一致,但是内容更细致,且阈值的取值有些不一样。
和 YOLOv2 一样,我们依然使用维度聚类的方法来挑选 anchor boxes 作为边界框预测的先验框。每个边界框都会预测 个偏移坐标 。假设 为 grid 的左上角坐标,、 是先验框(anchors)的宽度与高度,那么网络预测值和边界框真实位置的关系如下所示:
假设某一层的
feature map的大小为 , 那么grid cell就有 个,则第 行第 列的grid cell的坐标 就是 。
$
b_x = \sigma(t_x) + c_x \\
b_y = \sigma(t_y) + c_y \\
b_w = p_{w}e^{t_w} \\
b_h = p_{h}e^{t_h} $

是边界框的实际中心坐标和宽高值。在训练过程中,我们使用平方误差损失函数。利用上面的公式,可以轻松推出这样的结论:如果预测坐标的真实值(ground truth)是 ,那么梯度就是真实值减去预测值 。
梯度变成 有什么好处呢?
注意,计算损失的时候,模型预测输出的 外面要套一个 sigmoid 函数 ,否则坐标就不是 范围内的,一旦套了 sigmoid,就只能用 BCE 损失函数去反向传播,这样第一步算出来的才是 ; 的预测没有使用 sigmoid 函数,所以损失使用 。
是预测坐标偏移的真实值(
ground truth)。
YOLOv3 使用逻辑回归来预测每个边界框的 objectness score(置信度分数)。如果当前先验框和 ground truth 的 IOU 超过了前面的先验框,那么它的分数就是 1。和 Faster RCNN 论文一样,如果先验框和 ground truth 的 IOU不是最好的,那么即使它超过了阈值,我们还是会忽略掉这个 box,正负样本判断的阈值取 0.5。YOLOv3 检测系统只为每个 ground truth 对象分配一个边界框。如果先验框(bonding box prior,其实就是聚类得到的 anchors)未分配给 ground truth 对象,则不会造成位置和分类预测损失,只有置信度损失(only objectness)。
2.2,分类预测
每个框使用多标签分类来预测边界框可能包含的类。我们不使用 softmax 激活函数,因为我们发现它对模型的性能影响不好。相反,我们只是使用独立的逻辑分类器。在训练过程中,我们使用二元交叉熵损失来进行类别预测。
在这个数据集 Open Images Dataset 中有着大量的重叠标签。如果使用 softmax ,意味着强加了一个假设,即每个框只包含一个类别,但通常情况并非如此。多标签方法能更好地模拟数据。
2.3,跨尺度预测
YOLOv3 可以预测 3 种不同尺度(scale)的框。
总的来说是,引入了类似 FPN 的多尺度特征图融合,从而加强小目标检测。与原始的 FPN 不同,YOLOv3 的 Neck 网络只输出 3 个分支,分别对应 3 种尺度,高层网络输出的特征图经过上采样后和低层网络输出的特征图融合是使用 concat 方式拼接,而不是使用 element-wise add 的方法。
首先检测系统利用和特征金字塔网络(FPN 网络)类似的概念,来提取不同尺度的特征。我们在基础的特征提取器基础上添加了一些卷积层。这些卷积层的最后会预测一个 3 维张量,其是用来编码边界框,框中目标和分类预测。在 COCO 数据集的实验中,我们每个输出尺度都预测 3 个 boxes,所以模型最后输出的张量大小是 ,其中包含 4 个边界框offset、1 个 objectness 预测(前景背景预测)以及 80 种分类预测。
objectness预测其实就是前景背景预测,有些类似YOLOv2的置信度c的概念。
然后我们将前面两层输出的特征图上采样 2 倍,并和浅层中的特征图,用 concatenation 方式把高低两种分辨率的特征图连接到一起,这样做能使我们同时获得上采样特征的有意义的语义信息和来自早期特征的细粒度信息。之后,再添加几个卷积层来处理这个融合后的特征,并输出大小是原来高层特征图两倍的张量。
按照这种设计方式,来预测最后一个尺度的 boxes。可以知道,对第三种尺度的预测也会从所有先前的计算中(多尺度特征融合的计算中)获益,同时能从低层的网络中获得细粒度( finegrained )的特征。
显而易见,低层网络输出的特征图语义信息比较少,但是目标位置准确;高层网络输出的特征图语义信息比较丰富,但是目标位置比较粗略。
依然使用 k-means 聚类来确定我们的先验边界框(box priors,即选择的 anchors),但是选择了 9 个聚类(clusters)和 3 种尺度(scales,大、中、小三种 anchor 尺度),然后在整个尺度上均匀分割聚类。
从上面的描述可知,YOLOv3 的检测头变成了 3 个分支,对于输入图像 shape 为 (3, 416, 416)的 YOLOv3 来说,Head 各分支的输出张量的尺寸如下:
- [13, 13, 3*(4+1+80)]
- [26, 2, 3*(4+1+80)]
- [52, 52, 3*(4+1+80)]
3 个分支分别对应 32 倍、16 倍、8倍下采样,也就是分别预测大、中、小目标。32 倍下采样的特征图的每个点感受野更大,所以用来预测大目标。
每个 sacle 分支的每个 grid 都会预测 3 个框,每个框预测 5 元组+ 80 个 one-hot vector类别,所以一共 size 是:3*(4+1+80)。
根据前面的内容,可以知道,YOLOv3 总共预测 个边界框。
2.4,新的特征提取网络
我们使用一个新的网络来执行特征提取。它是 Darknet-19和新型残差网络方法的融合,由连续的 和 卷积层组合而成,并添加了一些 shortcut connection,整体体量更大。因为一共有 $53 = (1+2+8+8+4)\times 2+4+2+1 $ 个卷积层,所以我们称为 Darknet-53。

总的来说,DarkNet-53 不仅使用了全卷积网络,将 YOLOv2 中降采样作用 pooling 层都换成了 convolution(3x3,stride=2) 层;而且引入了残差(residual)结构,不再使用类似 VGG 那样的直连型网络结构,因此可以训练更深的网络,即卷积层数达到了 53 层。(更深的网络,特征提取效果会更好)
3 个预测分支,对应预测 3 种尺度(大、种、小),也都采用了全卷积的结构。
Darknet-53 和 state-of-the-art 分类器相比,有着更少的 FLOPs 和更快的速度。Darknet-53 可以实现每秒最高的测量浮点运算。这意味着其网络结构可以更好地利用 GPU,从而使其评估效率更高,速度更快。这主要是因为 ResNets 的层数太多,效率不高。
2.5,训练
和 YOLOv2 一样,我们依然训练所有图片,没有 hard negative mining or any of that stuff。我们依然使用多尺度训练,大量的数据增强操作和 BN 层以及其他标准操作。
损失函数的计算公式如下。

YOLO v3 使用多标签分类,用多个独立的 logistic 分类器代替 softmax 函数,以计算输入属于特定标签的可能性。在计算分类损失进行训练时,YOLOv3 对每个标签使用二元交叉熵损失。
正负样本的确定:
- 正样本:与
GT的IOU最大的框。 - 负样本:与
GT的IOU<0.5的框。 - 忽略的样本:与
GT的IOU>0.5但不是最大的框。 - 使用 和 (而不是 和 )来计算损失。
注意:每个 GT 目标仅与一个先验边界框相关联。如果没有分配先验边界框,则不会导致分类和定位损失,只会有目标的置信度损失。
YOLOv3 网络结构图如下所示(这里输入图像大小为 608*608)。

2.5,推理
总的来说还是将输出的特侦图划分成 S*S(这里的S和特征图大小一样) 的网格,通过设置置信度阈值对网格进行筛选,只有大于指定阈值的网格才认为存在目标,即该网格会输出目标的置信度、bbox 坐标和类别信息,并通过 NMS 操作筛选掉重复的框。
4,失败的尝试
一些没有作用的尝试工作如下。
Anchor box x,y 偏移预测。我们尝试了常规的 Anchor box 预测方法,比如利用线性激活将坐标 的偏移程度,预测为边界框宽度或高度的倍数。但我们发现这种做法降低了模型的稳定性,且效果不佳。
用线性方法预测 x,y,而不是使用 logistic。我们尝试使用线性激活函数来直接预测 的偏移,而不是 ligistic 激活函数,但这降低了 mAP。
focal loss。我们尝试使用focal loss,但它使我们的 mAP降低了 2 点。 对于 focal loss 函数试图解决的问题,YOLOv3 已经具有鲁棒性,因为它具有单独的对象性预测(objectness predictions)和条件类别预测。因此,对于大多数示例来说,类别预测没有损失?或者其他的东西?我们并不完全确定。
双 IOU 阈值和真值分配。在训练过程中,Faster RCNN 用了两个IOU 阈值,如果预测的边框与的 ground truth 的 IOU 是 0.7,那它是正样本 ;如果 IOU 在 [0.3—0.7]之间,则忽略这个 box;如果小于 0.3,那它是个负样本。我们尝试了类似的策略,但效果并不好。
5,改进的意义
YOLOv3 是一个很好的检测器,速度很快,很准确。虽然它在 COCO 数据集上的 mAP 指标,即 到 之间的平均值上表现不好,但是在旧指标 上,它表现非常好。
总结 YOLOv3 的改进点如下:
- 使用金字塔网络来实现多尺度预测,从而解决小目标检测的问题。
- 借鉴残差网络来实现更深的
Darknet-53,从而提升模型检测准确率。 - 使用
sigmoid函数替代softmax激活来实现多标签分类器。 - 位置预测修改,一个
gird预测3个box。
3.8 YOLOv4
3,方法
3.2,Selection of BoF and BoS
为了更好的训练目标检测模型,CNN 通常使用如下方法:
- 激活函数:
ReLU,leaky-ReLU,parameter-ReLU,ReLU6,SELU,Swish或Mish; - 边界框回归损失:
MSE,IoU,GIoU,CIoU,DIoU损失; - 数据扩充:
CutOut,MixUp,CutMix - 正则化方法:
DropOut,DropPath,空间DropOut或DropBlock - 通过均值和方差对网络激活进行归一化:批归一化(BN),交叉-GPU 批处理规范化(
CGBN或SyncBN),过滤器响应规范化(FRN)或交叉迭代批处理规范化(CBN); - 跳跃连接:残差连接,加残差连接,多输入加权残差连接或跨阶段局部连接(
CSP)
3.3,额外的改进
这些方法是作者对现有方法做的一些改进。
为了让 YOLOv4 能更好的在单个 GPU 上训练,我们做了以下额外改进:
- 引入了新的数据增强方法:
Mosaic和自我对抗训练self-adversarial training(SAT)。 - 通过遗传算法选择最优超参数。
- 修改了
SAM、PAN和CmBN。
Mosaic 是一种新的数据增强方法,不像 cutmix 仅混合了两张图片,它混合了 张训练图像,从而可以检测到超出其正常上下文的对象。 此外,BN 在每层上计算的激活统计都是来自 4 张不同图像,这大大减少了对大 batch size 的需求。
CmBN 仅收集单个批次中的 mini-batch 之间的统计信息。
3.4 YOLOv4
YOLOv4 网络由以下部分组成:
Backbone:CSPDarknet53Neck:SPP,PANHead:YOLOv3
同时,YOLO v4 使用了:
- 用于
backbone的BoF:CutMix和Mosaic数据增强,DropBlock正则化,类标签平滑。 - 用于
backbone的BoS:Mish激活,跨阶段部分连接(CSP),多输入加权残余连接(MiWRC)。 - 用于检测器的
BoF:CIoU损失,CmBN,DropBlock正则化,mosaic数据增强,自我对抗训练,消除网格敏感性,在单个ground-truth上使用多个anchor,余弦退火调度器,最佳超参数,随机训练形状。 - 用于检测器
BoS:Mish激活,SPP模块,SAM模块,PAN路径聚集块,DIoU-NMS。
6,YOLOv4 主要改进点
6.1,Backbone 改进
Yolov4 的整体结构可以拆分成四大板块,结构图如下图所示。
.png)
YOLOv4 的五个基本组件如下:
- CBM:
Yolov4网络结构中的最小组件,由Conv+Bn+Mish激活函数三者组成。 - CBL:由
Conv+Bn+Leaky_relu激活函数三者组成。 - Res unit:借鉴
Resnet网络中的残差结构思想,让网络可以构建的更深,和ResNet的basic block由两个CBL(ReLU)组成不同,这里的Resunit由2个CBM组成。 - CSPX:借鉴
CSPNet网络结构,由三个卷积层和X个Res unint模块Concate组成。 - SPP:采用
1×1,5×5,9×9,13×13的最大池化的方式,进行多尺度融合。
其他基础操作:
- Concat:张量拼接,会扩充维度。
- add:逐元素相加操作,不改变维度(
element-wise add)。
因为每个 CSPX 模块有 个卷积层,因此整个 backbone 中共有 个卷积层
这里卷积层的数目
72虽然不等同于YOLOv3中53,但是backbone依然是由 [1、2、8、8、4] 个卷积模块组成的,只是这里的YOLOv4中的卷积模块替换为了CSPX卷积模块,猜想是这个原因所以YOLOv4的作者这里依然用来Darknet53命名后缀。
6.1.1,CSPDarknet53
YOLOv4 使用 CSPDarknet53 作为 backbone,它是在 YOLOv3 的骨干网络 Darknet53 基础上,同时借鉴 2019 年的 CSPNet 网络,所产生的新 backbone。
CSPNet作者认为,MobiletNet、ShuffleNet系列模型是专门为移动端(CPU)平台上设计的,它们所采用的深度可分离卷积技术(DW+PW Convolution)并不兼容用于边缘计算的ASIC芯片。
CSP 结构是一种思想,它和ResNet、DenseNet 类似,可以看作是 DenseNet 的升级版,它将 feature map 拆成两个部分,一部分进行卷积操作,另一部分和上一部分卷积操作的结果进行concate。
CSP 结构主要解决了四个问题:
- 增强 CNN 的学习能力,能够在轻量化的同时保持着准确性;
- 降低计算成本;
- 降低内存开销。CSPNet 改进了密集块和过渡层的信息流,优化了梯度反向传播的路径,提升了网络的学习能力,同时在处理速度和内存方面提升了不少。
- 能很好的和
ResNet、DarkNet等网络嵌入在一起,增加精度的同时减少计算量和降低内存成本。
6.1.2,Mish 激活
在 YOLOv4 中使用 Mish 函数的原因是它的低成本和它的平滑、非单调、无上界、有下界等特点,在表 2 的对比实验结果中,和其他常用激活函数如 ReLU、Swish 相比,分类器的精度更好。
Mish 激活函数是光滑的非单调激活函数,定义如下:
Mish 函数曲线图和 Swish 类似,如下图所示。

值得注意的是 Yolov4 的 Backbone 中的激活函数都使用了Mish 激活,但后面的 neck + head 网络则还是使用leaky_relu 函数。
6.1.3,Dropblock
Yolov4 中使用的 Dropblock ,其实和常见网络中的 Dropout 功能类似,也是缓解过拟合的一种正则化方式。
传统
dropout功能是随机删除减少神经元的数量,使网络变得更简单(缓解过拟合)。
6.2,Neck 网络改进
在目标检测领域中,为了更好的融合 low-level 和 high-level 特征,通常会在 backbone 和 head 网络之间插入一些网络层,这个中间部分称为 neck 网络,典型的有 FPN 结构。
YOLOv4 的 neck 结构采用了 SPP 模块 和 FPN+PAN 结构。
FPN 是自顶向下的,将高层的特征信息经过上采样后和低层的特征信息进行传递融合,从而得到进行预测的特征图 ①②③。
再看下图 YOLOv4 的 Neck 网络的立体图像,可以更清楚的理解 neck 是如何通过 FPN+PAN 结构进行融合的。

FPN 层自顶向下传达强语义特征,而特征金字塔则自底向上传达强定位特征,两两联手,从不同的主干层对不同的检测层进行参数聚合,这种正向反向同时结合的操作确实 6 啊。
值得注意的是,Yolov3 的 FPN 层输出的三个大小不一的特征图①②③直接进行预测。但Yolov4 输出特征图的预测是使用 FPN 层从最后的一个 76*76 特征图 ① 和而经过两次PAN 结构的特征图 ② 和 ③ 。
另外一点是,原本的 PANet 网络的 PAN 结构中,两个特征图结合是采用 shortcut + element-wise 操作,而 Yolov4 中则采用 concat(route)操作,特征图融合后的尺寸会变化。原本 PAN 和修改后的 PAN 结构对比图如下图所示。

6.3,预测的改进
6.3.1,使用CIoU Loss
Bounding Box Regeression 的 Loss 近些年的发展过程是:Smooth L1 Loss-> IoU Loss(2016)-> GIoU Loss(2019)-> DIoU Loss(2020)->CIoU Loss(2020)
6.3.2,使用DIoU_NMS
6.4,输入端改进
6.4.1,Mosaic 数据增强
YOLOv4 原创的 Mosaic 数据增强方法是基于 2019 年提出的 CutMix 数据增强方法做的优化。CutMix 只对两张图片进行拼接,而 Mosaic 更激进,采用 4 张图片,在各自随机缩放、裁剪和排布后进行拼接。
针对这种状况,Yolov4 的作者采用了 Mosaic 数据增强的方式。主要有几个优点:
- 丰富数据集:随机使用
4张图片,随机缩放,再随机分布进行拼接,大大丰富了检测数据集,特别是随机缩放增加了很多小目标,让网络的鲁棒性更好。 - 减少训练所需
GPU数量:Mosaic增强训练时,可以直接计算4张图片的数据,使得Mini-batch大小并不需要很大,一个GPU就可以训练出较好的模型。
3.9 YOLOv5
5.1,网络架构
通过解析代码仓库中的 .yaml 文件中的结构代码,YOLOv5 模型可以概括为以下几个部分:
Backbone:Focus structure,CSP networkNeck:SPP block,PANetHead:YOLOv3 head using GIoU-loss
5.2,创新点
5.2.1,自适应anchor
在训练模型时,YOLOv5 会自己学习数据集中的最佳 anchor boxes,而不再需要先离线运行 K-means 算法聚类得到 k 个 anchor box 并修改 head 网络参数。总的来说,YOLOv5 流程简单且自动化了。
5.2.2, 自适应图片缩放
在常用的目标检测算法中,不同的图片长宽都不相同,因此常用的方式是将原始图片统一缩放到一个标准尺寸,再送入检测网络中。




