所谓的小目标,要看是绝对小目标(像素),和相对小目标(相对原图的长宽来看的)。大目标小目标只跟receptive field(感受野)有关,cnn本身可以检测任何尺度的物体。ssd对小目标检测不太适用,但R-FCN速度和鲁棒存在问题。
小目标分为很多种,背景单一还是比较好做的。有一篇小人脸检测用的是 fullyconvolutionalnetwork(FCN) + ResNet ,此篇论文检测小目标用了其周边的信息,如头发,肩膀。
小目标像素特征少,不明显,因此和大目标相比,小目标的检测率低,这个用任何算法上都是无法避免的。SSD,YOLO等单阶段多尺度算法,小目标检测需要高分辨率,但是SSD对小目标的检测是在浅层特征上进行,而深层的特征用来检测大目标,但是!深层的特征语义信息非常丰富,这是一个矛盾。例如底层conv4_3anchor设置的是0.1~0.2:30x60,对于720p的图像检测尺寸就有72个像素,还是太大了。事实上SSD的源码允许一个特征层做多个尺度的滑窗,将参数min_sizes里的每个元素初始化为一个列表,就可以在相应特征层中生成不同尺度的anchor,如果你设计的足够仔细,基本就可以覆盖足够小的目标了,不过此时anchor的数量估计会涨不少,速度也会降下来。
faster rcnn,yolo,ssd对小目标检测结果都不好,原因在于卷积网络结构的最后一层feature map太小,例如32*32的目标经过vgg后变成2*2,导致之后的检测和回归无法满足要求。卷积网络越深语义信息越强,而越低层则是描述的局部外观信息越多,而且我想VGG16卷积层设计成这么多肯定是有意义的,如果靠前的效果好,VGG的研究者应该想到减少层数了,我觉得可以考虑提取多层的特征这样表达能力强些。比如样本猫狗图像,较小的猫的ground truth只是出现在底层,高层没有猫的ground truth,而较大物体狗匹配到的ground truth在高层feature map上),其他层的信息只是简单拼接(所以小物体检测的语义信息,contex信息差一些)。
SSD是多尺度的特征图进行paopasal提取,ssd相对于yolo来说对小目标更稳定。yolo则是通过全局特征去直接得到预测结果,完全要靠数据堆积起来,对待小目标我觉得要考虑减少pooling;
SSD里负责检测小目标的层为conv4_3(38*38)对应的尺度为0.2(可人为设置)。这就对应了SSD所能检测的尺度大概为0.2上下。在这种情况下,如果物体过于小的话,甚至在训练阶段,GT都没法找到相应的的default box与它匹配,效果怎么可能会好。如果不介意整体检测效果的话,可以把尺度调低,看看对于小目标的检测效果是否有提升。另外,利用多尺度进行检测也能提高小物体的检测效果。
SSD使用的VGG16作为特征抽取,在conv4_3 feature map 的分辨率已经缩小了8倍,在conv5_3缩小了16倍,比如一个32*32大小的物体,在vgg16 的 conv5_3的feature map 对应仅为2*2,位置信息有较大的损失。有两种方法可解决这个问题:1.使用不同层的特征,比如hyperNet,MultiPath。2.保证感受也不缩小的情况下feature map的分辨率不至于缩小太多,如采用DeepLab中采用的Hole algorithm,在保证感受野的同时分辨变化较小。
他们对小目标检测不好的原因主要是,SSD/YOLO 对原图做了缩放,因为感受野的原因,导致“相对尺寸小”目标检测困难。如果说RCNN系列,并没有对原图进行缩放,但是如果”绝对尺寸小“的话,也没有办法,因为到了一定深度的Feature map,小目标可能已经丢失response了。
1.小目标往往更依赖浅层特征,因为浅层特征有更高的分辨率,然而对语义区分较差。
2.SSD检测和分类一起做,会把一些检测到但是分类模糊,分数不高的结果过滤掉。而rpn不会,前200个候选继续分类,都会有个结果。
3.为了速度,本来是全卷积网络,却也固定了输入尺寸,对大图的小目标影响很大。
一些比较好的观点
CNN特征的分辨率较差,这点不比其它low-level(浅层)的特征,证据就是在pedestrian detection(行人检测)上, 一些hand-crafted features(手工制作特征)的效果还是不错的;Faster-rcnn和SSD本身的问题,原始的Faster-rnn在RPN中将input的最短边固定resize到600>SSD512>SSD300,SSD使用300和512的原因是为了提高detection speed,所以SSD才这样快;同时为保证精度,SSD才加上了multi-scale和data augmentation(尤其值得注意这个augmentation,数据增强)。
yolo和ssd确实对小物体很无力,而有些普通的图像算法对小物体检测反而好的多,只是不太鲁棒。可以尝试下R-FCN,我测试了几张,好像对小物体还可以,但是速度慢些。在970下0.18s一张的样子。我之前在VGG16上做过R-FCN的实验,使用相同的res101-proposal(只关注detection的效果所以使用的一样),效果不如fast rcnn。同理,在google-v1上(也是全卷积)也是不如,我估计是浅网络的overfitting问题(因为用VGG的proposal去做效果很不好)。
SSD是一种基于全卷积的网络的检测器,用不同层检测不同大小的物体。这中间有个矛盾,前面的 feature map大,但semantic(语义)不够,后面的sematic够了,但经过太多的pooling,feature map太小了。要检测小物体,既需要一张足够大的feature map来提供更加精细的特征和做更加密集的采样,同时也需要足够的semantic meaning来与背景区分开。参会时问过SSD的作者,如果将最后的feature map放大接上前面的话,是不是能够改善性能,作者说值得一试。
SSD is a class aware RPN with a lot of bells and whistles。每一个feature map上面的pixel对应几个anchor,这个网络对anchor进行训练,以此驱动对feature进行训练。这是前言。作为小物体,其所对应的anchor比较少 (gt overlap > 0.5 的 anchor),也就是说对应feature map上的pixel难以得到充分训练。读者可以脑补每一个大的ROI可能覆盖很多 anchor,那么这些 anchor 均有机会得到训练。然而一个小物体并不能覆盖很多 anchor。没有得到充分训练有什么问题?在test的时候这个pixel的预测结果可能就是乱的,会极大干扰正常结果。为什么SSD的data augmentation能涨这么多点,就是因为通过randomly crop,让每一个anchor都得到充分训练(也就是说,crop出一个小物体,在新图里面就变成大物体了)只能说这种without region propisal的结果 naturally 不擅长小物体。通过往上堆 hack 才能慢慢比上吧。
我试过SSD最前面的卷积为深度残差网络,检测小物体效果还不错,比YOLO要好得多。
另外SSD原论文中,多级别的物体基本尺寸从0.1到0.8,实际上0.1的比例还是很大的,如1024*1024的输入,0.1都到102了,其实不小。可以根据需求调整级别,我使用的为1/64~1,即不同级别格子本身大小。当然,级别从线性分割变成指数分割后,在基本大小之上的各个变形也需要调整一下(主要是变大),不然有可能覆盖不到有些位于两个格子中间的某些大小的物体。YOLO比较坑的地方在于倒数第二层为全连接,后面的7*7格子不能扩张太大,不然前面的全连接要爆。格子大了,同一个格子可能会包括多个小物体,检测就不好搞了。而YOLO全连接的作用又是整合全局信息,要去掉全连接,就需要增加最后点的感受野,所以深度残差就非常适合。提到深度残差,再说另外一点。在深度残差的作者kaiming大神另一篇文章R-FCN: Object Detection via Region-based Fully Convolutional Networks,中有使用空间pooling,发现深度残差就是天然的自带空间pooling效果的结构啊。补充一点,SSD前面的CNN结构,一定要是全对称的,特别是pooling的时候,这样最后输出点的感受野中心才与每个格子的中心是重合的。如果是非对称的,CNN前面特征提取的时候,它会纠结,造成大量的小物体不好学习。而YOLO最后有全连接都还好,问题不大。最后一句,深度残差就是自带空间pooling结构,这个怎么理解呢。深度残差中的最小单元,一边为两个卷积垒在一起,假设作用只是把图像平移,另一个为直连,那最后接合在一起,就是一个空间相关的组合了嘛。