随着深度学习的发展,基于深度学习的目标检测方法因其优异的性能已经得到广泛的使用。目前经典的目标检测方法主要包括单阶段(YOLO、SSD、RetinaNet,还有基于关键点的检测方法等)和多阶段方法(Fast RCNN、Faster RCNN、Cascade RCNN等)。下面主要介绍单阶段的目标检测方法(SSD、YOLO系列、RetinaNet等)、多阶段目标检测方法(RCNN系列)以及其他方法(FPN、关键点等)。分析粗中有细,适合小白入门学习(需要多看代码)以及大佬回顾。
一、单阶段
单阶段目标检测方法是指只需一次提取特征即可实现目标检测,其速度相比多阶段的算法快,一般精度稍微低一些。
1、YOLO v1
YOLO目标检测算法是2016年CVPR《You Only Look Once: Unified, Real-Time Object Detection》,其直接完成从特征到分类、回归的预测,分类和回归使用同一个全连接层实现,其框架图如下:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第1张图片](http://img.e-com-net.com/image/info8/220241620ded4503a0fa1fd461b91c62.jpg)
- 输入
输入图像448×448×3通道。
- Backbone
采用类似GoogLeNet的网络结构用24层Conv+2层FC,用1×1的reduction layer(将某一通道通过sum、mean等操作降成1维度,类似于Conv 1×1)跟着3×3的Conv替代inception模块,在ImageNet上将前20层网络+maxpooling+FC进行预训练(预训练224×224,目标检测训练448×448)。
- 输出
输出是7×7×30的检测结果,7×7表示最后一层特征层大小,30表示2两个检测尺度×5个检测结果(x,y,w,h,score)+20类,其中score表示框的置信度,即该位置是否包含目标以及包含目标的准确性(IoU),表示为:
P r ( C l a s s i ∣ O b j e c t ) ∗ P r ( O b j e c t ) ∗ I o U p r e d t r u t h = P r ( C l a s s i ) ∗ I o U p r e d t r u t h Pr(Class_i|Object)*Pr(Object)*IoU^{truth}_{pred}=Pr(Class_i)*IoU^{truth}_{pred} Pr(Classi∣Object)∗Pr(Object)∗IoUpredtruth=Pr(Classi)∗IoUpredtruth
训练时,当该位置不在目标的中心点时,值为0(Pr_class为0);当位置在目标的中心点时置信度为IoU(Pr_class为1)。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第2张图片](http://img.e-com-net.com/image/info8/dcc8dde49da1425a8cb0cf0d7e67de58.jpg)
- 损失函数
损失函数设计时考虑以下几个方面:
(1)由于包含目标中心位置的cell较少,因此需要增大置信度损失的权重(λ_coord=5);对于不包含目标中心位置的cell,降低置信度损失的权重(λ_noobj=0.5);
(2)避免大小目标损失的差异,对长宽求平方根,减小差异;
(3)每个cell可以预测B个目标框,为了提高训练的稳定性,每个cell预测时指定IoU最高的Ground Truth。
注意:预测中心位置是预测的是中心位置相对所在grid左上角的x、y偏差;预测长宽是相对于原图的目标长宽。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第3张图片](http://img.e-com-net.com/image/info8/4a9cf0cb181c46fb9d08b5d46377871b.jpg)
其中 1 i o b j 1_i^{obj} 1iobj表示目标出现在此cell中, 1 i j o b j 1_{ij}^{obj} 1ijobj表示第i个cell负责第j个目标框。
- 缺陷分析
(1)每个cell只能预测一个类别和几个框;
(2)对于小目标检测效果不好;
(3)用全连接层预测丢失了位置信息;
(4)只能检测与训练时固定尺度的图像(后面全连接层的限制)。
2、YOLO v2
YOLO v2来源于这篇论文《YOLO9000: Better, Faster, Stronger》。这篇论文介绍很多涨点的方法,同时也是针对YOLO v1的改进。
- Better
(1)Batch Normalization
BN可以对每一层输出的特征进行归一化,提高模型的鲁棒性。在每一层Conv之后加上BN可以涨2个点。
(2)High Resolution Classifier
采用更高分辨率的图像作为输入。YOLO v1输入224,这里输入448进行微调,可以提高4个点。
(3)Convolutional With Anchor Boxes
移除后面的FC层,引入Anchor预测目标与Ground Truth的偏差,输入416×416,输出特征13×13。YOLO v1只能预测98个目标,引入anchor之后可以预测上千个,mAP下降0.3,但是召回率明显提高。
(4)Dimension Clusters
引入anchor时,用k-means聚类的方式找到合适的anchor尺度和比例,避免手工设计的不足。具体思想是利用ground truth和anchor的IoU进行聚类,避免目标尺度大小的影响。最终聚类之后每个位置5个anchor可以达到9个anchor的性能。
(5)Direct location prediction
利用Anchor进行训练时,预测中心点与长宽的偏差,刚开始训练时没有约束会导致训练不稳定。因此,将预测边框的中心约束固定在特定的网格内,即对中心点的预测利用Sigmoid进行处理。
b x = σ ( t x ) + c x b y = σ ( t y ) + c y b w = p w e t w b h = p h e t h b_x=σ(t_x)+c_x\\ b_y=σ(t_y)+c_y\\ b_w=p_we^{t_w}\\ b_h=p_he^{t_h} bx=σ(tx)+cxby=σ(ty)+cybw=pwetwbh=pheth
其中 t x t_x tx和 t y t_y ty是预测的值,然后 σ ( ) σ() σ()表示Sigmoid,这样处理之后,预测结果都会在Grid中; p w p_w pw和 p h p_h ph是anchor的宽和长。涨5个点。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第4张图片](http://img.e-com-net.com/image/info8/0546260f461c41e3872cf4f442cd770a.png)
(6)Fine-Grained Features
由于图像中目标大小不一,经过下采样过后小目标可能会丢失。这里提出passthrough,即在最后特征经过pooling之前,先将特征图进行拆成4份,然后将其与pooling之后的特征进行通道维度的拼接。涨1个点。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第5张图片](http://img.e-com-net.com/image/info8/822a1990c88a42919e6558a88a7fac34.png)
(7)Multi-Scale Training
多尺度训练,在320-608之间中随机选择32的倍数作为训练尺度,以适应不同尺度的目标大小。最后以512尺度进行测试,可以达到78.6mAP。
(8)不同tirck得到的性能对比实验:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第6张图片](http://img.e-com-net.com/image/info8/a2854f69f50b4230ae84e39b9845847a.jpg)
- Faster
为了让速度更快提出新的BackBone,Darknet-19。采用3×3的小卷积核、每次池化之后通道倍数增加、BN,共有19层Conv、5层maxpooling,采用全局平均池化,在ImageNet上先进行1000类的预训练。在检测时用3×3、1024通道的卷积后跟1×1卷积替换掉之前的最后一层卷积。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第7张图片](http://img.e-com-net.com/image/info8/46abc74287574bbf82ed1e44a34d9777.jpg)
- Stronger
COCO数据集有80类,ImageNet有1000类,如何来预测更多类别的目标呢?YOLO9000提出结合分类和检测的数据集进行层级预测。构建WordTree:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第8张图片](http://img.e-com-net.com/image/info8/8fbd15b3fc39447ba1107d2cc143d427.jpg)
类似于决策树一样,把相同或者属于同一类别的放在同一个节点;多个节点层次连接到根结点上。损失函数设计:如果有目标框,同时进分类和回归损失计算;如果没有目标,只进行分类的损失计算;分类的损失采用Softmax,即对同一层次的目标进行Softmax操作;最终某一个类别的概率为此节点的概率与所有根结点的概率乘积。分类头由1000变成1369,而标签是以同一层级进行Softmax计算,一个目标假如是狗,同级还存在猫、猴等;那么父节点假如是动物,同级还有植物等。而类别标签设置时,将叶子到根节点所有的路径都设置为1,其余为0(不同于one-hot编码,可能会有多个1)。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第9张图片](http://img.e-com-net.com/image/info8/d6206fb8f5a9452d9c980166511a0a2f.jpg)
此部分有参考博文。
3、YOLO v3
YOLO v3来自此论文《YOLOv3: An Incremental Improvement》(论文看起来像实验报告,细节说的不清楚,还是需要看代码)。YOLO v3主要提出新的BackBone,特征金字塔结构用于不同尺度目标检测、采用Leaky ReLU等。
- DarkNet-53
BackBone是DarkNet-53,没有FC和池化层:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第10张图片](http://img.e-com-net.com/image/info8/c02e79b01da84b91964447e604839449.jpg)
注意每一个模块都加入了残差结构,通过卷积核实现特征尺度的缩小(通道增加)。最终图像尺度缩小32倍,而DarkNet-19(YOLO v2)里面用池化操作实现的特征图的缩小。
- FPN
YOLO v3这里采用FPN自顶向下的特征融合结构,用于融合的三层特征尺度分别是32×32×256、16×16×512、8×8×512,特征融合时采用concat的方式(区别于Resnet相加的结构),最终用于检测的特征尺度是32×32×255、16×16×255、8×8×255。小尺度特征上采样时采用最近邻插值的方式实现。
- 检测头
最终输出的通道数是255,即W×H×[3×(4+1+80)],其中3表示三种anchor尺度(仍然采用YOLO v2的方案进行K-means聚类实现的),4表示(x,y,w,h),1表示score,80表示coco数据集的所有类别。
- 损失函数
损失函数仍然是分类损失+回归损失,其中分类损失采用Sigmoid替代了YOLO v2中的Softmax,更加灵活并且避免了类间互斥(YOLO v2用Softmax是同一类别层级的)。
- 样本筛选策略
正样本即为anchor与目标的最大IoU的(即使IoU没有大于阈值),并且每个anchor唯一匹配一个ground truth;忽略样本即为IoU大于阈值的,但是不是正样本的;负样本即为IoU小于阈值并且不是正样本的。负样本只训练置信度,即objectness,标签为0.
4、YOLO v4
YOLO v4《YOLOv4: Optimal Speed and Accuracy of Object Detection》并不是之前YOLO的作者了。作者用了各种trick在YOLO v3的基础上进行改进,主要从**Bag of freebies(改变训练过程,不改变计算量)和Bag of specials(稍微增加一点计算量)**两个方面进行分析,基本把目标检测上面的trick都用了一遍。
- 数据增强
数据增强有旋转、裁剪、翻转、混淆(多张图像混淆在一起)、复制粘贴(将目标抠出来贴在别的位置)、拼接(多张图像拼接在一起)、局部模糊等。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第11张图片](http://img.e-com-net.com/image/info8/5967e2ad88d04438a99b6b937fd0b84c.jpg)
- BackBone
论文中有提到CSPDarknet53相比CSPResNext50在检测上的效果好,但是后者在分类效果更好。其中CSP结构看这个,就是在每一个block之前,把通道拆分为两部分,一部分进行卷积的计算;到之后再把前一部分concat一起,在降低计算量的同时能够保证精度不下降(会涨一点)。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第12张图片](http://img.e-com-net.com/image/info8/58a3632ce8814c05b57042c0facc88a2.jpg)
- 激活函数
激活函数考虑ReLU、leaky-ReLU、parameter-ReLU、ReLU6、SELU、Swish、Mish。
(1) R e L U ( x ) = m a x ( 0 , x ) ReLU(x)=max(0,x) ReLU(x)=max(0,x),这个很好理解,即当x>0时,梯度为1,其余为0;
(2)LeakyReLU相比ReLu而言在x<0时仍然还有一定的梯度(α,一般设置比较小,如0.1)。
L e a k y R e L U = { x ; i f x > 0 α x ; o t h e r w i s e LeakyReLU=\left\{\begin{array}{c} x; if x>0\\ αx ; otherwise\end{array}\right. LeakyReLU={x;ifx>0αx;otherwise
(3)ReLU6就是ReLU,限制最大输出是6,理由是在移动设备采用低精度float16,限制6也能保证很好的精度;如果不加限制,数值太大float16无法进行精确表示。
(4)parameter-ReLU(PReLU),计算公式与LeakyReLU,区别在于α是学习的参数;
(5)SELU中计算如下,其中α≈1.67326324…,λ≈1.050900987。SELU的作用主要是使输出归一化(不同于BN进行归一化),这里主要是使神经网络能够输出归一化的特征。
S E L U ( x ) = λ { x ; i f x > 0 α e x − α ; i f x ≤ 0 SELU(x)=λ\left\{\begin{array}{c}x; if x>0\\ αe^x-α; if x≤0 \end{array}\right. SELU(x)=λ{x;ifx>0αex−α;ifx≤0
下面引用此博客的翻译解释SELU:
SELU 允许构建一个映射 g,其性质能够实现 SNN(自归一化神经网络)。SNN 不能通过(扩展型)修正线性单元(ReLU)、sigmoid 单元、tanh 单元和 Leaky ReLU 实现。
这个激活函数需要有:
①负值和正值,以便控制均值;
②饱和区域(导数趋近于零),以便抑制更低层中较大的方差;
③大于 1 的斜率,以便在更低层中的方差过小时增大方差;
④连续曲线。后者能确保一个固定点,其中方差抑制可通过方差增大来获得均衡。我们能通过乘上指数线性单元(ELU)来满足激活函数的这些性质,而且 λ>1 能够确保正值净输入的斜率大于 1。
(6) S w i s h ( x ) = x ∗ s i g m o i d ( x ) Swish(x)=x*sigmoid(x) Swish(x)=x∗sigmoid(x);
(7) M i s h ( x ) = x ∗ t a n h ( l n ( 1 + e x ) ) Mish(x)=x*tanh(ln(1+e^x)) Mish(x)=x∗tanh(ln(1+ex)).
水平有限,哎!这些激活函数无法进行理论分析。
可以参考这些讲解1、讲解2.
- 损失函数
损失函数对比MSE、IoU、GIoU、CIoU、DIoU,这里分析见此文结尾部分。
- 正则化方法
正则化方法这里用了DropOut、DropPath、Spatial DropOut、DropBlock。
(1)DropOut简单说来就是在网络训练的时候按照一定的概率(0.2-0.5)随机丢掉一部分的神经元(失活),让网络在训练的过程中避免依赖于极少数的神经元,而在测试的时候所有的神经元都是激活状态的。
(2)Spatial DropOut按通道随机扔;
(3)DropBlock在每个特征图上按照spatial块随机扔。
这部分还没有详细研究。
- 归一化方法
归一化方法用了BN、CBN、FRN等,都是BN的变体,简单说下BN的细节吧!BN(Batch Normalization),就是在一个Batch内计算均值和方差进行归一化处理,学习两个参数对归一化之后的数据进行复原。
训练阶段,均值和方差是该批次内的相应维度的均值和方差(比如N个图像特征中同一通道的数据)。测试阶段,均值和方差是基于所有的Batch求期望和方差的。
均值 u = 1 / m ∑ i x i u=1/m∑_ix_i u=1/m∑ixi,方差 σ = 1 / m ∑ i ( x i − u ) 2 σ=1/m∑_i(x_i-u)^2 σ=1/m∑i(xi−u)2,数据经过均值和方差计算之后变成 x ′ = ( x − u ) / s q r t ( σ 2 + ε ) x'=(x-u)/sqrt(σ^2+ε) x′=(x−u)/sqrt(σ2+ε)其中ε是避免除数为0。然后再经过γ和β进行反归一化。 y = γ x ′ + β y=γx'+β y=γx′+β,如果γ和β分别是方差和均值,可以发现y=x,通过γ和β可以避免数据被归一化的太严重,防止网络无法学习到准确的特征。
- skip-connection
这里是指一些残差用了Residual connections(常规残差), Weighted
residual connections(不是直接残差相加,进行加权), Multi-input weighted residual
connections(多层加权残差融合), or Cross stage partial connections (见上文Backbone)。
- 特征融合
尝试了不少特征融合方法,FPN、PAN、ASFF、BiFPN等,此部分分析见下文中的FPN。
实验的结果就贴一部分,有兴趣可以看下论文中的数据,实验数据相当丰富。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第13张图片](http://img.e-com-net.com/image/info8/6494d083c994441bb6f739301f914430.jpg)
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第14张图片](http://img.e-com-net.com/image/info8/710a8eef09aa41d3895ddd9dbed8b08a.jpg)
5、SSD
SSD来源于此篇论文《SSD: Single Shot MultiBox Detector》,整个网络是全卷积网络,即经过VGG16进行特征提取后,提取38×38、19×19、10×10、5×5、3×3、1×1共六层不同尺度特征用于分类和回归。每一个特征层输出为: H×W×(N×(classes+4)),其中N表示这一层中的Anchor数量、classes表示类别数目、4表示(x,y,w,h)相对于Anchor的四个偏移量。下图表示整个网络的结构。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第15张图片](http://img.e-com-net.com/image/info8/0a154c058f754a2086704b0145e558fc.jpg)
- 训练匹配原则
匹配Ground Truth时,选择IoU最大的Anchor;这样会导致很多Anchor都是负样本,因此对于剩余未匹配的Anchor,如果IoU>0.5,也会进行匹配。最后每个Ground Truth会匹配多个Anchor。
- 损失函数
损失函数即为分类损失Softmax loss和回归损失Smooth L1 loss(定位的中心点和长宽偏差与Faster RCNN相似)。
- Anchor的尺度选择
每一层预测时选择的anchor的尺度不同,这里作者给出一个计算方式:
s k = s m i n + ( k − 1 ) ( s m a x − s m i n ) / m − 1 s_k=s_{min}+(k-1)(s_{max}-s_{min})/m-1 sk=smin+(k−1)(smax−smin)/m−1
其中 s m i n = 0.2 , s m a x = 0.9 s_{min}=0.2,s_{max}=0.9 smin=0.2,smax=0.9,即anchor最小尺度为0.2/2*300=30;长宽比例设置为 1 , 2 , 3 , 1 / 2 , 1 / 3 , 1 ′ {1,2,3,1/2,1/3,1'} 1,2,3,1/2,1/3,1′,其中 1 ′ 1' 1′表示尺度为 √ s k √ s k + 1 √s_k√s_{k+1} √sk√sk+1,长宽比为1;长宽的计算方式分别是: w k a = s k √ a r ; h k a = s k √ a r w^a_k=s_k√a_r;h^a_k=s_k√a_r wka=sk√ar;hka=sk√ar,这样操作之后一个anchor的大小没有变,但是长宽的比例变了。
这些anchor分布在各个特征图中所有特征点的中心,计算方式为: ( ( i + 0.5 ) / ∣ f k ∣ , ( j + 0.5 ) / ∣ f k ∣ ) ((i+0.5)/|f_k|,(j+0.5)/|f_k|) ((i+0.5)/∣fk∣,(j+0.5)/∣fk∣)。
最终,整个网络预测的结果总个数为8732个,即:
38 × 38 × 4 + 19 × 19 × 6 + 10 × 10 × 6 + 5 × 5 × 6 + 3 × 3 × 4 + 1 × 1 × 4 = 8732 38×38×4+19×19×6+10×10×6+5×5×6+3×3×4+1×1×4=8732 38×38×4+19×19×6+10×10×6+5×5×6+3×3×4+1×1×4=8732,其中×6、×4表示使用几个尺度的anchor,如果是×6即为{1,2,3,1/2,1/3,1’},×4表示{1,2,1/2,1’}。
- 先验框匹配
先验框匹配的原则是,对于每个Ground Truth,先找到最大IoU的先验框进行匹配;保证每个Ground Truth都有先验框匹配;对于剩余未匹配的先验框,如果和Ground Truth的IoU大于阈值(0.5),则也进行匹配;即一个Ground Truth可能匹配多个先验框,但是一个先验框最多匹配一个Ground Truth。为了保证正负样本均衡,对负样本进行抽样,即选取误差最大的top-k作为训练的负样本,保证负样本的比例接近1:3。
- 数据增强
数据增强就是普通的旋转、翻转、随机裁剪+颜色扭曲等。
6、RetinaNet
RetinaNet来源于《Focal Loss for Dense Object Detection》这篇论文。主要提出的问题是单阶段目标检测相比多阶段目标检测算法性能较差的原因在于正负样本的筛选不均衡。多阶段目标检测过程中,通过Selective Search、RPN等方式可以过滤掉大量的背景框,然后通过筛选正负样本(如1:3)的方式进行训练。但是单阶段的目标检测算法无法过滤这些背景框,导致正负样本严重不均衡(SSD上面提到了,选择loss最大的top-k,使得正负样本比例1:3左右)!因此提出Focal loss在训练的时候自适应调整损失权重,使得模型关注难样本的训练,同时提出RetinaNet目标检测框架。
- Focal loss提出用于解决分类中的正负样本不均衡问题,基于Cross Entropy loss进行改进的。交叉熵损失是这个,进行分类时采用one-hot编码形式可以进一步化简:
L o s s ( y k , p k ) = − y k l o g ( p k ) − ( 1 − y k ) l o g ( 1 − p k ) o n e − h o t − l a b e l : L o s s ( y k , p k ) = − l o g ( p k ) Loss(y_k,p_k)=-y_klog(p_k)-(1-y_k)log(1-p_k)\\ one-hot-label:Loss(y_k,p_k)=-log(p_k) Loss(yk,pk)=−yklog(pk)−(1−yk)log(1−pk)one−hot−label:Loss(yk,pk)=−log(pk)
提出的Focal loss损失是这个:
F o c a l L o s s ( p k ) = − ( 1 − p k ) γ l o g ( p k ) Focal Loss(p_k)=-(1-p_k)^γlog(p_k) FocalLoss(pk)=−(1−pk)γlog(pk)
Cross Entropy Loss存在的问题主要就是,当分类的准确率很高的时候,仍然会产生很大的loss,使得模型训练中那些很难的样例(hard negative)被淹没在简单样本产生的损失中。而Focal 正是解决这个问题,即分类误差较低时,给予较低的权重;分类误差较大时,给予较高的损失权重;使得模型能够更加关注难分的样本(这一部分对比分析可见最后损失分析部分)。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第16张图片](http://img.e-com-net.com/image/info8/c674435403a745458e5e413f08109ab3.jpg)
- RetinaNet
RetinaNet可以看成是一个RPN网络,经过Backbone进行特征提取之后,接FPN然后进行分类和回归的检测。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第17张图片](http://img.e-com-net.com/image/info8/60ab9042fa204039877810c64f060f18.jpg)
(1)在FPN中,采用的特征是P3、P4、P5,然后在P5上面进行一次卷积得到P6、在P6上进行一次卷积得到P7,最终特征为P3、P4、P5、P6、P7相对于图像下采样了8、16、32、64、128倍。
(2)关于Anchor,这里P3-P7对应的Anchor的基本尺度是32、64、128、256、512;三种尺度比例分别是{1,1/2,2};在每一个anchor的基础上,进行三种尺度缩放 2 0 , 2 1 / 3 , 2 2 / 3 {2^0,2^{1/3},2^{2/3}} 20,21/3,22/3,所以每个位置(不同位置之间会有步长)共有9个anchor。
(3)分类头经过几层卷积操作最后输出为W×H×KA,其中A表示anchor的数量(这里是9,K表示类别的数量),即每个anchor都预测所有类别。
(4)回归头同样经过几层卷积操作,最后输出为W×H×4A,4表示 x , y , w , h {x,y,w,h} x,y,w,h相对于anchor的偏差。
(5)正负样本匹配,Anchor与Ground Truth的IoU>0.5视为正样本,小于0.4视为负样本,[0.4,0.5)是忽略样本。
二、多阶段RCNN系列
1、RCNN
RCNN是比较早的利用CNN进行目标检测的算法。其思想是使用selective search提取2000个左右的预选框,然后resize到统一的尺度(因为后面接FC分类)进行CNN特征提取,最后用FC进行分类。具体流程如下:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第18张图片](http://img.e-com-net.com/image/info8/631f2524ac494e5bbac611bf345cf5f3.jpg)
- 预训练模型
选取图像分类的预训练模型,然后用图像中的目标(通过selective search筛选的预选框,选择与Ground Truth 的IoU>0.5)对最后的全连接层(N+1类)进行重新训练;
这里简单介绍下Selective Search算法。
(1)先通过计算近邻区域的像素之间相似度,划分为一块块小的区域;
(2)再计算近邻区域之间的相似度,这里有用到颜色相似、纹理相似、尺寸相似、填充相似(所谓填充相似是指两个不规则区域的外接矩形差不多,也就是你中有我我中有你的这种情况)等。
- 提取预选框特征
利用Selective Search算法提取2000个预选框,并调整成固定的大小,以满足CNN的输入(最后全连接层限制),最后将pool层的特征保存下来(保存到本地,后面用SVM进行分类和回;正样本与Ground Truth的IoU>0.5,最大IoU;负样本IoU<0.3);
- 训练SVM分类器
使用SVM进行分类训练,这里每个类别都训练一个二进制SVM(此类和其它,其它包含其它类别);
- 边界框回归
边界框回归,训练一个具有校正因子的线性回归分类器(FC),损失函数是L2损失。
回归分类器预测的是Ground Truth相对于预选框的中心点、长宽的偏差,其中G表示Ground Truth,P表示预选框(Proposal)。中心点使用相对坐标便于优化(区间在0~1),并且可以很好的应对不同尺度的目标、图像大小;长宽用log,是因为G=P exp(dP),反过来就是log了。
![在这里插入图片描述](http://img.e-com-net.com/image/info8/c880abb331de41ec89adf953139b5d9e.jpg)
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第19张图片](http://img.e-com-net.com/image/info8/4b81f7ecfe244853a530dbb979eb1c8f.jpg)
参考:《Rich feature hierarchies for accurate object detection and semantic segmentation》
2、Fast RCNN
Fast RCNN相比RCNN而言只需要对整幅图像进行一次特征提取,并且直接利用FC进行分类和回归,实现end-to-end的多任务协同优化。具体过程是图像先经过Backbone网络提取图像的feature map;利用selective search搜索的预选框到特征上提取RoI的特征;通过RoI Pooling将RoI的特征转化为固定的大小;最后输入到分类和回归头分别进行分类和回归。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第20张图片](http://img.e-com-net.com/image/info8/dda00468d8554ae0bda89aa6a90dc877.jpg)
-
RoI(Region of Interest)
RoI仍然是通过Selective Search进行搜索得到的一个个预选框;
-
RoI Pooling
(1)RoI Pooling的有两个输入,一个是feature map,即整个图像经过Backbone提取的特征;另一个是RoI的坐标5维,[idx,x1,y1,x2,y2]表示左上角和右下角的坐标。坐标尺度是相对原图的尺度,而在feature上根据图像下采样的比例(即feature/原图尺度)找到对应的坐标。
(2)将映射后的区域划分为相同大小的区间(比如7×7),这样就可以从不同大小的RoI中获得固定大小的feature map,最终输出[H,W,C]维度的特征图,C表示通道个数,然后进行分类和回归处理。
值得注意的是: 当proposal在特征图上的尺度大于7×7时(比如RoI Pooling输出的是7×7),比较好理解,直接计算特征图到7×7映射的每个bin的最大值;当proposal小于7×7咋办呢?其实还是一样的,仍然这样强行处理,只不过会有一部分值是重复的。参考 在Mask RCNN中对RoI Pooling进行了修改,采用线性插值的方式来做的。
-
损失函数
损失函数分为分类和回归损失函数,与RCNN不同的是这里直接用FC进行分类和回归,分类损失函数Cross Entropy和Smooth L1。
分类共有N+1类,+1表示背景类;
回归用Smooth L1损失,对[x,y,w,h]进行回归,其中回归的约束目标仍然是中心点和长宽的相对值,与RCNN相似。Smooth L1损失:
![在这里插入图片描述](http://img.e-com-net.com/image/info8/e760fd1fce8b426d914eaf994145e200.jpg)
当回归损失较大时,梯度是1,将回归损失较小时梯度是x;这样损失较大梯度大,下降快;损失较小,梯度小,损失下降慢。
参考:《Fast R-CNN》
3、Faster RCNN
Fast RCNN的RoI仍然是通过Selective Search的方式进行搜索,其速度较慢。Faster RCNN在Fast RCNN的基础上提出RPN(Region Proposal Network)自动生成RoI,极大的提高了预选框生成的效率。RPN过程如下:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第21张图片](http://img.e-com-net.com/image/info8/fbb7c92eda434148b44711ef298b434b.jpg)
图像经过Backbone网络之后得到feature map;将feature map输入到RPN网络中获得预选框(proposal);后续过程处理与Fast RCNN一致。
- RPN网络是什么?
RPN网络是用于预测RoI的,输入是feature map,输出是RoI及分类结果(二分类,前景和背景);其中RoI是anchor的偏差(加上anchor之后就形成了RoI),分类头和回归头均采用卷积结构。
(1)分类头输入W×H×C的特征,输出为W×H×(K×Cls),K表示anchor的个数,Cls表示类别数,一般就是两类,前景背景;这样就获得了每个anchor的类别了;
(2)回归头输入W×H×C的特征,输出为W×H×(K×4),其中K表示anchor的个数,4表示RoI相对于anchor的中心点和长宽的偏差。
- anchor是什么?
anchor是在特征图上画密集的框,如下所示:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第22张图片](http://img.e-com-net.com/image/info8/b429c5ccea3b4340a08b457eadcab606.jpg)
在特征图上,每一个位置(或有间隔)都按照一定的长宽、尺度比例画出N个框,比如3种尺度、3种长宽比例共9个框;假如特征图大小是H×W,则有H×W×9个框,这些框基本可以包括所有的目标。
- RPN整体流程
(1)生成anchor,并利用RPN网络计算所有的RoI(anchor的偏差)和分类结果;
(2)正负样本划分,RPN网络中,选取RoI与Ground Truth的IoU>0.7作为正样本,IoU<0.3作为负样本(区别于最后的检测头,最后的检测头一般选取IoU>0.5作为正样本,<0.5作为负样本),正负样本选取的比例大概是1:3;
(3)对分类结果进行分数排序,获得前N个预选框(比如2000个);
(4)边界框处理,避免超出特征边界;
(5)进行NMS,对重叠的框的IoU>阈值(比如0.5)进行剔除;
(6)最后将RPN网络预测的RoI送入到RoI Pooling中进行特征提取,此特征与输入RPN网络的特征图是同一个,后续接分类头和回归头(与Fast RCNN类似,损失也一样)。
- 损失函数
损失函数是RPN的分类损失+RPN的回归损失+最终检测头的分类和回归损失。
RPN中分类损失采用Cross Entropy,回归损失采用Smooth L1损失。
参考:《Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks》
4、Cascade RCNN
Cascade RCNN可以说是基于Faster RCNN进行改进的版本。Faster RCNN是通过RPN网络预测出Proposal然后利用分类头和回归头完成分类和定位,但是存在一个问题,训练时我们知道Ground Truth,可以直接筛选高质量的Proposal用于最后的分类和回归,但是在测试阶段,我们并不知道Ground Truth,导致所有的Proposal都进行最后的分类和定位,这就是训练和测试阶段的不匹配问题。直接暴力提高IoU的阈值,则会导致性能下降(召回率),经过实验发现当训练和测试时Proposal自身的阈值与训练的阈值接近时(就是训练和测试时后面检测头接收的proposal差不多),效果才会好。Cascade RCNN提出级联多个检测头来解决这个问题,如下图:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第23张图片](http://img.e-com-net.com/image/info8/3c3081b26b684fbc97e276af706934fd.jpg)
- 整体流程
级联多个检测头,每个检测头的IoU呈现递增的情况,比如0.5、0.6、0.7,并不是采用相同的阈值(区别于Iterative BBox)。低级检测头采用低IoU阈值可以提高召回率,避免目标丢失;后续的高级检测头在前一阶段的基础之上提高阈值可以提高检测精度。
- 损失函数
损失函数就是多个检测头的分类损失+回归损失,与Faster RCNN检测头的损失一样。分类用Cross Entropy,回归用Smooth L1 Loss。
参考:《Cascade R-CNN: Delving into High Quality Object Detection》
5、Mask RCNN
Mask RCNN是一个实例分割的算法,是在Faster RCNN目标检测+FCN的基础上进行分割。过程图如下:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第24张图片](http://img.e-com-net.com/image/info8/961ee712c1ca43f885c5de02638971c7.jpg)
- 流程介绍
图像先经过BackBone进行特征提取;然后经过RPN网络预测Proposal;再利用RoI Align进行特征提取;然后接分类和检测头;最后接Mask检测头,即每一个类别都预测一个Mask。
- RoI Align
RoI Align的作用于RoI Pooling的作用一样,都是提取Proposal在原特诊图上的特征。前面的介绍中我们知道RoI Pooling通过取整在feature map上进行池化操作提取固定尺度的特征(比如7×7×C),但是这里有两次取整操作会导致误差较大。
(1)第一次取整是RPN的Proposal在映射到feature map进行取整;
(2)第二次取整是feature map映射到原图上时由于图像下采样导致坐标的偏差;
(3)这两次取整会导致像素点在特征图上的偏移很大,假如特征下采样32次,那么RoI Pooling就会导致32像素的偏差,对于小目标的检测极其不友好。
因此RoI Align通过两种方式解决这个问题;
(1)保留proposal映射到feature map位置的小数部分;
(2)采用双线性插值的方式对proposal所在的feature map进行处理,避免边界导致的特征不准确(RoI Pooling会进行重复采样);
(3)每个proposal到feature map映射的bin中,由4个(如2×2、3×3)周围的值进行加权得到。
如图所示,虚线表示特征图,实线表示采样的proposal,利用双线性插值的方法计算每个黑点的值,然后每个bin(2×2)内的四个值(四个黑点)再求最大值或者均值,实现RoI Align。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第25张图片](http://img.e-com-net.com/image/info8/3a5e8ca54f2642f989c1f4c3f77c1ca4.jpg)
因此在目标检测时使用RoI Align效果要比RoI Pooling好,尤其是对于小目标的精度影响。
- 损失函数
损失函数计算就是分类损失+回归损失+mask损失,其中分类和回归损失参考Faster RCNN,mask损失是每个类别的mask二进制损失(用sigmoid处理之后,binary entropy loss)。
- 结果输出/损失计算
(1)结果输出:经过backbone提取到roi align特征之后,缩放成指定维度的特征,比如14×14,28×28,然后经过mask head进行上采样回原图像尺度比例(upsample,反卷积),再进行sigmoid进行映射,设定大于阈值为1,否则为0.
(2)损失计算:采用cross entropy损失等,计算的特征以mask head输出进行计算(比如28×28,并不是upsample回原图),最后进行均值化。
参考《Mask R-CNN》
三、旋转目标检测
旋转目标检测这里只介绍一个RoI Transformer吧!《Learning RoI Transformer for Oriented Object Detection in Aerial Images》旋转目标检测与水平目标检测不同的是需要检测目标的方向,在遥感图像目标检测、文字检测等任务中比较常见。预测的结果包含类别、位置坐标、长宽、角度。
RoI Transformer基于Faster RCNN检测算法,加上一个旋转RoI特征提取模块(Rotated RoI),整个过程分为两个阶段:
(1)第一阶段,即Faster RCNN算法,经过RPN、水平RoI预测一个粗略的旋转框(利用水平RoI特征预测{x,y,w,h,θ},这里θ表示一个旋转角度);
(2)第二阶段,基于第一阶段的粗略旋转框,提取旋转RoI的特征,再进行精确的{x’,y’,w’,h’,θ’},即在第一阶段的结果上进行修正。
整个思路过程大致如下:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第26张图片](http://img.e-com-net.com/image/info8/50b00a8b6f134af9b8488224eceec23a.jpg)
(3)旋转RoI,旋转RoI特征提取是基于RoIAlign实现的,即在水平RoIAlign的基础上,每一个采样点(x,y)都根据角度θ进行坐标偏移得到(x’,y’),最终实现旋转RoI特征提取。偏移计算公式如下:
![在这里插入图片描述](http://img.e-com-net.com/image/info8/a5d5309d836b401b8329b08917587b82.jpg)
(4)预测目标,这里预测的坐标需要考虑角度的偏差,即:
t x ′ = 1 / w r ( ( x ′ − x r ) c o s θ r + ( y ′ − y r ) s i n θ r ) t y ′ = 1 / h r ( ( y ′ − y r ) c o s θ r + ( x ′ − x r ) s i n θ r ) t w ′ = l o g ( w ′ / w r ) ; t h ′ = l o g ( h ′ / h r ) t θ ′ = ( ( θ ′ − θ r ) m o d 2 π ) / 2 π t'_x=1/w_r((x'-x_r)cosθ_r+(y'-y_r)sinθ_r)\\ t'_y=1/h_r((y'-y_r)cosθ_r+(x'-x_r)sinθ_r)\\ t'_w=log(w'/w_r);t'_h=log(h'/h_r)\\ t'_θ=((θ'-θ_r)mod2π)/2π tx′=1/wr((x′−xr)cosθr+(y′−yr)sinθr)ty′=1/hr((y′−yr)cosθr+(x′−xr)sinθr)tw′=log(w′/wr);th′=log(h′/hr)tθ′=((θ′−θr)mod2π)/2π
分类损失函数是Cross Entropy Loss,回归损失是Smooth L1 Loss。最终的损失由RPN(分类、回归)+水平框损失(分类、回归)+选择框损失(分类、回归)。
(5)这里旋转目标检测有一点不一样的是需要计算旋转目标的IoU,计算的时候用shapely这个包计算的多边形IoU。
四、其他
1、FPN及其变体
这一部分介绍一下FPN的一些变体结构吧(FPN、PAFPN、ASFF、CARAFE)!今年的一篇CVPR2021论文《You Only Look One-level Feature》提到FPN网络提高检测性能的主要原因在于不同尺度的分治,对于自顶向下的特征融合对于性能影响不大!(其实这个也比较好理解,分治的作用肯定比融合特征性能提升的多)。
- FPN
FPN由这篇论文提出《Feature Pyramid Networks for Object Detection》,思路就是由BackBone网络提取出不同层级的特征用于多尺度目标检测。在提取多尺度特征的同时,浅层特征位置信息准确(下采样的倍数较小)、深层特征语义信息更加丰富(网络结构更深,语义信息更准确),因此采用自顶向下的特征融合方法,提升浅层特征表达的准确性。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第27张图片](http://img.e-com-net.com/image/info8/93741757d61347a586d33122f8c08f9f.jpg)
由上图可见,左边表示经过BackBone网络提取出的不同层级的特征,然后经过右边的FPN网络进行自顶向下的特征融合,最终将融合之后的特征用于预测。
(1)由于不同层级的特征经过BackBone网络提取时,通道不一样(深层特征通道深、浅层特征通道浅)。因此,先进行Conv1×1的卷积,进行通道降维,使得不同层级的特征能够进行融合!
(2)深层特征尺度小,浅层特征尺度大,进行融合时通过上采样操作保持特征尺度一致;
(3)特征融合时直接进行相加,然后再对融合之后的特征进行Conv3×3操作,最终进行预测。
- PANet
FPN是进行自顶向下的特征融合,而PANet提出用于自底向上的特征融合。论文《Path Aggregation Network for Instance Segmentation》,具体结构图如下:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第28张图片](http://img.e-com-net.com/image/info8/f475e4834d8641ec8f29cfe58e6293c9.jpg)
(1)上图可见(a)部分是常规的FPN及自顶向下的特征融合结构,增加了底层到深层的融合分支(红色虚线);
(2)经过左边的FPN特征融合之后,进行(b)所示的自底向上的特征融合,另外将底层特征再次融合到深层特征中;
(3)经过特征融合之后,对于任意一个Proposal,提取其在不同特征层上的特征经过MaxPooling或SUM操作进行融合,最终得到新的RoI特征,最终用于分类和回归(同时对于语义分割的mask预测同理,用过全卷积实现)。
- ASFF
前面的FPN及PANet通过自顶向下、自顶向下再向上等方式进行特征融合,而ASFF则提出更加复杂的融合方法。论文《Learning Spatial Fusion for Single-Shot Object Detection》
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第29张图片](http://img.e-com-net.com/image/info8/e47f1dfabf1847ccae9912ef87f8e6d9.jpg)
(1)从上图可以看到,ASFF同时融合多层特征并加上权重进行自适应的融合;
(2)每个层级的特征权重之和为1,经过Softmax进行计算,权重预测也是有卷积实现;
(3)权重预测结构中,输入为FPN的特征,分别是三个H×W×C(三个H、W不同),输出为三个H×W×C’,这里C’为通道;然后进行concat拼接,最后再经过卷积输出H×W×3得到3通道的权值特征,最终通过Softmax进行权重归一化。
- CARAFE
这个来源于论文《CARAFE: Content-Aware ReAssembly of FEatures》,所提出的问题在FPN进行特征融合时,深层特征尺度小需要进行上采样使得和低层特征尺度一致,但是普通的方法采用线性插值或者最近邻插值的方式,导致局部特征不准确。主要包括两个结构,核预测结构(Kernel Prediction Module)和语义信息重组结构(Content-aware Reassembly Module)。整体结构如下:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第30张图片](http://img.e-com-net.com/image/info8/10f91b7083224e9c8d76f57099c5bc45.jpg)
(1)KPM
先说上一个模块。输入特征,经过Conv1×1进行通道压缩;接着进行特征编码,也就是把不同通道的特征经过重组形成新的大尺度特征;最后在每一个通道进行Softmax正则化。
(2)CRM
下一个是将上一个模块学习到的权重模块按照通道对每一个位置特征进行近邻加权融合,即每一个特征点及其周围特征乘以这个加权的结果;最后得到新的大尺度的特征,用以将深层特征融合到低层特征中。
(为什么要讲个呢?之前的FPN融合都是各种尺度特征排列组合式的融合,这个主要解决融合过程中的特征偏差,并且经过实验,确实能涨点哦)。
- 关于FPN的先讲这么多吧!其实还有很多经典的FPN魔改结构,比如BiFPN、NAS-FPN等。可以看看这些大佬讲的,链接1,链接2.
2、Anchor Free
本人研究Anchor Free相关的算法比较少(YOLO v1是比较早的Anchor Free算法了),这里主要介绍几篇关于关键点检测的算法。FCOS、CenterNet等。
- FCOS
FCOS来源于此篇论文《FCOS: Fully Convolutional One-Stage Object Detection》主要的思想是预测目标的中心点(不一定是中心)和上下左右四个距离,表示中心点到边界的距离。如下图:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第31张图片](http://img.e-com-net.com/image/info8/a1e1f51963fe4af3a55e31103f4c897c.jpg)
(1)整体结构经过FPN之后,到分类头、检测头、center-ness头。分类头输出H×W×C,C表示类别,其中C=0表示背景类,这里采用多个二分类器,使用Focal Loss;检测头即输出H×W×4,表示预测中心点到四个边的距离,用IoU Loss;Center ness的目的是使中心点尽可能的居中,目的是为了过滤掉低质量的样本(比如一个目标的中心点处于目标区域内的很多,但是处于边缘的中心点质量就比较低),这里用binary cross entropy。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第32张图片](http://img.e-com-net.com/image/info8/741b9d2046c3405589ddd08e57709349.jpg)
(2)上文提到,位置落在目标内部即可视为中心点,如果一个位置处于多个目标内部怎么办呢(二义性样本)?这里只选择面积最小的目标(因为面积大的目标可以有更多的位置选择,另外还进行多标签预测,也可以避免漏检问题)。如果确定一个位置 ( x , y ) (x,y) (x,y)是目标的中心点,关联的目标框是 B i B_i Bi为:
l ∗ = x − x 0 ( i ) , t ∗ = y − y 0 ( i ) , r ∗ = x 1 ( i ) − x , b ∗ = y 1 ( i ) − y l^*=x-x_0^{(i)},t^*=y-y_0^{(i)},r^*=x_1^{(i)}-x,b^*=y_1^{(i)}-y l∗=x−x0(i),t∗=y−y0(i),r∗=x1(i)−x,b∗=y1(i)−y并且这里用exp(x)将映射到(0,∞)
(3)采用FPN主要从两个角度考虑,一方面是预测不同尺度的目标;另一方面是避免目标重叠时一个中心点无法预测多个目标。为了使不同尺度目标在对应合适的特征层上进行预测,按照 m a x ( l ∗ , t ∗ , r ∗ , b ∗ ) > m i max(l^*,t^*,r^*,b^*)>m_i max(l∗,t∗,r∗,b∗)>mi或者 m a x ( l ∗ , t ∗ , r ∗ , b ∗ ) > m i − 1 max(l^*,t^*,r^*,b^*)>m_{i-1} max(l∗,t∗,r∗,b∗)>mi−1即按照预测的目标尺度映射到对应的特征层上。
(4)Center-ness主要的目的是使目标位置尽可能处于中心点。
c e n t e r n e s s ∗ = s q r t ( m i n ( l ∗ , r ∗ ) / m a x ( l ∗ , r ∗ ) × m i n ( t ∗ , b ∗ ) / m a x ( t ∗ , b ∗ ) ) centerness^*=sqrt(min(l^*,r^*)/max(l^*,r^*)×min(t^*,b^*)/max(t^*,b^*)) centerness∗=sqrt(min(l∗,r∗)/max(l∗,r∗)×min(t∗,b∗)/max(t∗,b∗))用binary cross entropy loss,可见当损失越小,centerness越接近于1,也就是回归框的中心接近于Ground Truth。
- CenterNet
CenterNet来源于这篇论文《Objects as Points》,直接检测目标的中心点和目标长宽,即可获得检测结果,速度比较快。
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第33张图片](http://img.e-com-net.com/image/info8/23ab78a6dc5e4c10891c2fa2b2a20de7.jpg)
(1)关键点预测:输入为H×W×3的图像,输出为 Y ∈ [ 0 , 1 ] W / R × H / R × C Y∈[0,1]^{W/R×H/R×C} Y∈[0,1]W/R×H/R×C的热点图(C表示目标的类别),即表示该点为某类目标的中心点。当 Y x , y , c = 1 Y_{x,y,c}=1 Yx,y,c=1时表示对应的关键点;当 Y x , y , c = 0 Y_{x,y,c}=0 Yx,y,c=0表示为背景。关键点的坐标即为中心点的坐标 p = ( ( x 1 + x 2 ) / 2 , ( y 1 + y 2 ) / 2 ) p=((x_1+x_2)/2,(y_1+y_2)/2) p=((x1+x2)/2,(y1+y2)/2),图像经过下采样之后对应到特征上的坐标为下取整的坐标 p ′ = f l o o r ( p / R ) p'=floor(p/R) p′=floor(p/R)。需要注意的是,这里关键点的Ground Truth并不是一个点,而是经过高斯核处理之后变成了一个高亮的区域,高斯核为 Y x y c = e x p ( − ( ( x − p x ) 2 + ( y − p y ) 2 ) / 2 σ p 2 ) Y_{xyc}=exp(-((x-p_x)^2+(y-p_y)^2)/2σ^2_p) Yxyc=exp(−((x−px)2+(y−py)2)/2σp2)。其中 2 σ p 2 2σ^2_p 2σp2是一个与目标长宽相关的标准差。如果多个目标的热点图重叠,那么取最大值。
(2)关键点预测的损失函数是
L k = − 1 / N ∑ x y c { ( 1 − Y x y c ′ ) α l o g ( Y x y c ′ ) ) ; i f Y x y c = 1 ( 1 − Y x y c ) β ( Y x y c ′ ) α l o g ( 1 − Y x y c ′ ) ; o t h e r w i s e L_k=-1/N∑_{xyc}\left\{ \begin{array}{c} (1-Y'_{xyc})^αlog(Y'_{xyc})); if Y_{xyc}=1\\ \\ (1-Y_{xyc})^β(Y'_{xyc})^αlog(1-Y'_{xyc});otherwise\end{array}\right. Lk=−1/Nxyc∑⎩⎨⎧(1−Yxyc′)αlog(Yxyc′));ifYxyc=1(1−Yxyc)β(Yxyc′)αlog(1−Yxyc′);otherwise其中α和β是Focal loss的超参数,N是图像的关键点个数,实验中设置α=2,β=4。这里的思想也就是降低易检测样本的权重,提升难检测样本的权重。(这里用focal loss我感觉也是因为正负样本不均衡的问题,即关键点相对于整个图像来说占据很少的一部分)。下面一个公式,即预测结果不在中心点时,当预测结果越大,权重越大 ( Y x ′ y c ) α (Y'_xyc)^α (Yx′yc)α,但是标签值又对权重进行调整 ( 1 − Y x y c ) β (1-Y_{xyc})^β (1−Yxyc)β,即标签值越大,权重越小;这样做的目的即靠近中心点的损失权重大,标签权重小;远离中心点的,损失权重小,标签权重大。
(3)目标位置偏差预测由于下采样,关键点的位置是有一定偏差的,因此用L1 Loss作为中心点偏差的损失计算。其中 p ′ = f l o o r ( p / R ) p'=floor(p/R) p′=floor(p/R),这里主要预测的偏差就是下采样取整导致的偏差。
L o f f = 1 / N ∑ p ∣ O p ′ − ( p / R − p ′ ) ∣ L_off=1/N∑_p|O'_p-(p/R-p')| Loff=1/Np∑∣Op′−(p/R−p′)∣
(4)目标长宽预测,即采用目标在特征图上缩放之后的长宽进行预测。
L s i z e = 1 / N ∑ k = 1 ∣ S p k − s k ∣ L_{size}=1/N∑_{k=1}|S_{pk}-s_k| Lsize=1/Nk=1∑∣Spk−sk∣最终的损失是由 关键点预测损失+目标位置偏差损失+目标长宽预测损失 加权。
L d e t = L k + λ s i z e L s i z e + λ o f f L o f f L_{det}=L_k+λ_{size}L_{size}+λ_{off}L_{off} Ldet=Lk+λsizeLsize+λoffLoff这里 λ s i z e = 0.1 , λ o f f = 1 λ_{size}=0.1,λ_{off}=1 λsize=0.1,λoff=1,网络输出共有C+4个维度,其中C表示类别,4表示中心点和长宽。
(5)在测试阶段,为了找到中心点,找到当前值比近邻8个最大的点作为特征点。
五、目标检测中的损失函数
目标检测中的损失函数主要分为分类损失函数和回归损失函数。在检测任务中用的分类损失函数基本都是Cross Entropy Loss,关于分类任务这方面的变体比较多;在回归任务中,基本都是L1、L2、Smooth L1以及IoU相关的损失。下面就简单介绍下相关的损失函数。
1、分类损失(图像分类、目标检测中分类)
- Softmax Loss(Cross Entropy Loss)
分类中,为了保证所有的类别预测结果求和是1,用Softmax进行处理,Softmax计算公式如下:
p ( z k ) = e z k / ∑ j e z j p(z_k)=e^{z_k}/∑_je^{z_j} p(zk)=ezk/j∑ezj
上式表示预测第k个类别的概率。通过Softmax进行计算时,会分配给较大的值高概率、较小的值低概率。而Cross Entropy Loss是对Softmax处理时候的概率进行损失计算。下式中y表示标签,z表示预测概率,第k个类别的损失(所有损失是对所有类别求和):
L o s s ( y k , p k ) = − y k l o g ( p k ) − ( 1 − y k ) l o g ( 1 − p k ) Loss(y_k,p_k)=-y_klog(p_k)-(1-y_k)log(1-p_k) Loss(yk,pk)=−yklog(pk)−(1−yk)log(1−pk)
在很多分类任务中标签是one-hot编码的形式,因此对于标签为1和0可以换算为(也就是只对有标签的分类概率进行惩罚,其他的损失全部为0):
L o s s o n e − h o t ( 1 , p ) = − l o g ( p ) ; L o s s o n e − h o t ( 0 , p ) = − l o g ( 1 ) = 0 Loss_{one-hot}(1,p)=-log(p);\\ Loss_{one-hot}(0,p)=-log(1)=0 Lossone−hot(1,p)=−log(p);Lossone−hot(0,p)=−log(1)=0
不感兴趣可以不看: 这里简单说下Cross Entropy的推导过程吧!Cross Entropy是由信息熵演化过来的,用于衡量两种概率分布的相似性。信息熵是随机变量不确定性的度量,也就是混乱程度越大、包含信息越大(可以这样理解,感觉不咋准确,因为信息是一个相对值),信息熵就越大。公式如下:
H ( X ) = − ∑ k ∈ K p ( k ) l o g p ( k ) H(X)=-∑_{k∈K}p(k)logp(k) H(X)=−k∈K∑p(k)logp(k)
那么如何衡量两种信息的相似性呢?下面引入了KL散度,也就是计算两个分布之间的不同。下面给出KL散度的计算方式:
D K L ( A ∣ ∣ B ) = ∑ k P A ( x k ) l o g ( P A ( x k ) / P B ( x k ) ) = ∑ k P A ( x k ) l o g ( P A ( x k ) ) − P A ( x k ) l o g ( P B ( x k ) ) D_{KL}(A||B)=∑_kP_A(x_k)log(P_A(x_k)/P_B(x_k))\\ =∑_kP_A(x_k)log(P_A(x_k))-P_A(x_k)log(P_B(x_k)) DKL(A∣∣B)=k∑PA(xk)log(PA(xk)/PB(xk))=k∑PA(xk)log(PA(xk))−PA(xk)log(PB(xk))
从上式可以看到,P_A的某一属性概率越大,那么给予P_B上的权重越大,就是偏向于信息量大的属性(可以这样理解KL(A||B)就是以A作为参考,KL(B||A)就是以B作为参考)。那么这样来看,KL散度不是对称的(也就是参考系不一样),即:
D K L ( A ∣ ∣ B ) ≠ D K L ( B ∣ ∣ A ) D_{KL}(A||B)≠D_{KL}(B||A) DKL(A∣∣B)=DKL(B∣∣A)
那么扯了这么多,交叉熵是什么呢?聪明的小伙伴已经看出来了,交叉熵就是A与B的KL散度-A的熵。
C ( A , B ) = D K L ( A ∣ ∣ B ) − H ( A ) = ∑ k P A ( x k ) l o g ( P B ( x k ) ) C(A,B)=D_KL(A||B)-H(A)=∑_kP_A(x_k)log(P_B(x_k)) C(A,B)=DKL(A∣∣B)−H(A)=k∑PA(xk)log(PB(xk))
参考知乎回答。
- Balanced Cross Entropy
Cross Entropy无法解决正负样本不均衡的问题,因此在上面加一个权重系数,对于正样本为α,负样本为(1-α),其中(α∈[0,1]),下面只给出了正样本的加权交叉熵损失:
B C E = − α k l o g ( p k ) BCE=-α_klog(p_k) BCE=−αklog(pk)
- Focal Loss
Focal loss是在RetinaNet中提出来用于解决正负样本不均的情况。在训练过程中负样本过多、正样本较少,导致模型优化并不很均衡,而交叉熵损失对所有样本权重都一样。因此在交叉熵损失的基础上提出Focal Loss,可以根据预测的概率,自适应调整损失的权重:
F o c a l L o s s ( p k ) = − ( 1 − p k ) γ l o g ( p k ) Focal Loss(p_k)=-(1-p_k)^γlog(p_k) FocalLoss(pk)=−(1−pk)γlog(pk)
γ是调制系数,当γ=0时就是交叉熵损失;当γ>0时,p_k的值越大(接近1)表明此样本越简单(分类正确的情况下),所以给的权重就越小;p_k的值越小(接近0),说明样本分类的置信度不高,需要加大权重(权重接近1)。最后再加上权重系数:
F o c a l L o s s ( p k ) = − α k ( 1 − p k ) γ l o g ( p k ) Focal Loss(p_k)=-α_k(1-p_k)^γlog(p_k) FocalLoss(pk)=−αk(1−pk)γlog(pk)
在论文中γ取2,α取0.25效果最好。
2、回归损失
关于回归损失主要是L1、L2、Smooth L1和IoU的变体,下面逐一介绍。
- L1、L2、Smooth L1系列
L 1 ( x ) = ∣ x ∣ ; L 2 = x 2 ; S m o o t h L 1 = { 0.5 x 2 ; i f ∣ x ∣ < 1 ∣ x ∣ − 0.5 ; o t h e r w i s e L_1(x)=|x|;L_2=x^2;\\ Smooth_{L1}=\left\{ \begin{array}{c} 0.5x^2 ; if|x|<1\\ |x|-0.5 ; otherwise \end{array}\right. L1(x)=∣x∣;L2=x2;SmoothL1={0.5x2;if∣x∣<1∣x∣−0.5;otherwise
通过公式可以直观的看到,L1损失无论何时梯度都是1,当损失较小时,如果学习率不变会在ground truth附近震荡;L2损失的梯度一直是2x,当损失较大值,梯度较大,可能会导致梯度爆炸;而Smooth L1当损失较大梯度是1,加快收敛速度;当损失较小时梯度是x,可以减缓收敛,趋近于ground truth。由此可见,Smooth L1可以很好的避免以上缺点。
- IoU系列损失
IoU系列损失是考虑到目标检测中mAP的依据IoU进行计算,那么如果直接以IoU作为监督条件,可以很好的提升回归的准确性。
(1)IoU损失 相比L1、L2、Smooth L1损失具有一定的尺度不变性,即和目标大小无关,其IoU都是在[0,1]区间内。
I o U = ( A ∩ B ) / ( A ∪ B ) I o U L o s s = 1 − I o U IoU=(A∩B)/(A∪B)\\ IoULoss = 1-IoU IoU=(A∩B)/(A∪B)IoULoss=1−IoU
IoU损失有一个致命的缺点,当IoU为0时,梯度无法回传。(很多人都这样说,但是其实是悖论,既然IoU为0时,proposal就不会当做 正样本。)。
(2)GIoU损失 IoU损失是以IoU作为衡量目标,但是当目标倾斜或者偏差时,不能衡量目标框的质量。如下图:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第34张图片](http://img.e-com-net.com/image/info8/fcf721633a3844ec80fe276bc0eb4dd7.jpg)
因此GIoU提出:
G I o U ( A , B ) = ( A ∩ B ) / ( A ∪ B ) − ( C − A ∪ B ) / C G I o U L o s s ( A , B ) = 1 − G I o U ( A , B ) GIoU(A,B)=(A∩B)/(A∪B)-(C-A∪B)/C\\ GIoULoss(A,B)=1-GIoU(A,B) GIoU(A,B)=(A∩B)/(A∪B)−(C−A∪B)/CGIoULoss(A,B)=1−GIoU(A,B)
其中C表示A和B的最小外接矩形面积。可见-1≤GIoU≤1,当A和B不想交时,GIoU(A,B)=-1,当A和B重合时GIoU(A,B)=1,因此损失合理。从宏观角度来看,损失可以理解为:1-IoU+外接矩形中背景/外接矩形。
- DIoU损失 GIoU Loss解决IoU Loss中当两个目标IoU为0时损失为0的问题,但是当两个目标距离很近或者嵌套出现时,无法进行有效约束,如下图所示,这种情况下GIoU退化到和IoU一样的情况,但是对于质量不同的样本(比如中心点位置)无法形成有效的约束:
![基于深度学习的目标检测综述(单阶段、多阶段、FPN变体、旋转目标检测等)_第35张图片](http://img.e-com-net.com/image/info8/7595ca6ae2bf4c3fb32a0043306ffcf1.jpg)
因此提出DIoU Loss
D I o U L o s s ( A , B ) = 1 − I o U ( A , B ) + ρ 2 ( A , B ) / C 2 DIoULoss(A,B)=1-IoU(A,B)+ρ^2(A,B)/C^2 DIoULoss(A,B)=1−IoU(A,B)+ρ2(A,B)/C2
其中,ρ2表示A和B的中心点的欧氏距离,C2表示A、B最小外接矩形的对角线欧氏距离。通过这样的约束方式,使得DIoU在IoU约束的同时对两个框的中心点距离进行约束,使得两个目标尽可能靠近。
- CIoU损失 与DIoU损失来自同一篇论文,提出目标框的回归需要考虑中心点和边框,但是DIoU损失并没有很好的对目标的长宽进行直接约束(通过面积进行间接约束的)。因此在DIoU的基础上增加了影响因子αv,把预测框的纵横比一致性考虑进行,增加约束项:
α = v / [ ( 1 − I o U ) + v ] v = 4 / π 2 ( a r c t a n ( w g / h g ) − a r c t a n ( w / h ) ) 2 α=v/[(1-IoU)+v]\\ v=4/π^2(arctan(w^g/h^g)-arctan(w/h))^2 α=v/[(1−IoU)+v]v=4/π2(arctan(wg/hg)−arctan(w/h))2
完整的CIoU损失如下,具体推导见论文,这里不进行推导:
C I o U L o s s ( A , B ) = 1 − I o U ( A , B ) + ρ 2 ( A , B ) / C 2 + α v CIoULoss(A,B)=1-IoU(A,B)+ρ^2(A,B)/C^2+αv CIoULoss(A,B)=1−IoU(A,B)+ρ2(A,B)/C2+αv
- EIoU损失是最近新出的,在DIoU损失的基础上进行改进,也就是替换掉了CIoU损失中对于长宽的约束项,直接对目标的长宽进行约束:
E I o U L o s s ( A , B ) = 1 − I o U ( A , B ) + ρ 2 ( A , B ) / C 2 + ρ 2 ( w A , w B ) / C w 2 + ρ 2 ( h A , h B ) / C h 2 EIoULoss(A,B)=1-IoU(A,B)+ρ^2(A,B)/C^2+ρ^2(w^A,w^B)/C_w^2+ρ^2(h^A,h^B)/C_h^2 EIoULoss(A,B)=1−IoU(A,B)+ρ2(A,B)/C2+ρ2(wA,wB)/Cw2+ρ2(hA,hB)/Ch2
其中 ρ 2 ( w A , w B ) 、 C w 、 C h ρ^2(w^A,w^B)、C_w、C_h ρ2(wA,wB)、Cw、Ch分别表示A和B两框中心点的欧氏距离、A和B的最小外接矩形的宽、A和B最小外接矩形的高。考虑到目标框回归的样本不均衡问题(可以理解为高质量目标框少、低质量样本少),结合Focal Loss提出Focal EIoU Loss:
F o c a l E I o U L o s s = I o U γ E I o U L o s s Focal EIoU Loss=IoU^γEIoU_Loss FocalEIoULoss=IoUγEIoULoss
这里和分类中的Focal Loss相反,给IoU高的样本更大的损失权重,即提高样本回归的质量。
此部分有参考此篇博文
最后强烈安利mmdetection目标检测框架,由pytorch开发,目前很多经典算法都有集成,可以快速上手,成为一个快乐的调包侠。
最后对所有引用的论文、博客、知乎等各位大佬们表示衷心的感谢!你们是推动科研进步的主力军!
未完待续
应该写的差不多了,若有错误,欢迎各位大佬批评指正!感谢!