YOLO类算法,发展到现在有了3代,称之为v1、v2、v3(version)。v3算法现在可以毫不夸张的成为开源通用目标检测算法的领头羊,虽然本人一直都很欣赏SSD,但不得不说V3版本已经达到目前的颠覆。
两个甚至多个距离很近的重叠目标很难分辨出来是当下目标检测的一大难题,重叠目标可是同类目标或不同类目标。大多数算法会对图像进行尺度变化,缩放到较小的分辨率,但在这样小的分辨率下只会给出少量的bbox,容易造成目标的误判或者漏判。小目标检测一直以来也被看做是对算法的一种评估,v1和v2都不如SSD,而v3做到了,它对这种距离很近的物体或者小物体有很好的鲁棒性,虽然不能保证百分百,但是这个难题得到了很大程度的解决。
1.为什么v3和v2版本的测试性能提高很大,但速度却没有降低?
2.为什么v3性能上能有这么大的改进?或者说为什么v3在没有提高输入数据分辨率的前提下,对小目标检测变得这么好?
3.v2和v3相比,同样是416的feature map,为什么有这么大的提高?
要回答上述三个问题,必须要看看作者发布的v3论文了,v3的创新点:
Class Prediction:v3使用的是分类预测,使用了简单的logistic regression(逻辑回归)---binary cross-entropy loss(二元交叉熵损失)来代替softmax进行预测类别,由于每个点所对应的bbox少并且差异大,所以每个bbox与ground truth的matching策略变成了1对1。当预测的目标类别很复杂的时候,采用logistic regression进行分类是更合理的。比如Open Images Dataset数据集有很多重叠的标签,如女人和人,softmax每个候选框只对应着一个类别,而logistic regression使用multi-label classification(多标签分类)对数据进行更合理的建模。
Bounding Box Prediction
边界框预测。与之前YOLO版本一样,v3的anchor box也是通过聚类得到,每个bbox预测四个坐标值(tx,ty,tw,th),预测的cell图像左上角的偏移(cx,cy),及之前得到bbox的宽和高pw和ph可以对bbox按下图的方式进行预测,在训练这几个坐标值的时候采用了sum of squared error loss(平方和距离误差损失),因为这种方式的误差可以很快的计算出来。v3对每个bounding box通过逻辑回归预测一个物体的得分,如果预测的这个bbox与真实的边框值大部分重合且比其他所有预测的要好,那么这个值就为1。如果overlap没有达到一个阈值(v3阈值是0.5),那么这个预测的bbox将会被忽略,也就是会显示成没有损失值。
detection的策略不同:跨尺寸多级预测,解决了v1和v2颗粒度粗,对小目标无力的问题。v3提供了3种尺寸不一的边界框。用类似于FPN(feature pyramid network)网络提取这些尺寸的特征,以形成金字塔形网络。在基本特征提取器中增加了几个卷积层,并用最后的卷积层预测一个三维张量编码:边界框、框中目标和分类预测。在voc数据集实验中,神经网络分别为每种尺寸各预测了3个边界框,所以得到的张量是N×N×[3x(4+1+20)],其中包含4个边界框offset、1个目标置信度预测以及20种分类预测。v2只有一个detection,而v3有3个,一个下采样的,feature map为13*13,还有2个上采样的element-wise sum,feature map为26*26和52*52,而v2把多尺度考虑到训练的data采样上,最后也只是用到了13*13的feature map,获得更有意义的语义信息,这应该是对小目标影响最大的地方,v2--->v3经历了从单层预测五种bbox变成每层3种bbox。
element-wise sum
简称为Eltwise,有三种类型:product(点乘)、sum(求和)、max(取最大值)。sum把bottom对应元素相加,product是对应相乘,max是对应取最大,其中sum为默认操作。eltwise层要求对应bottom层的blob一致,得到的结果top层的blob和bottom层一致,这个过程想象成三维的过程很好理解。Concat层虽然利用到了上下文的语义信息,但仅仅是将其拼接起来,之所以能起到效果,在于它在不增加算法复杂度的情形下增加了channel数目。而Eltwise层直接关联上下文的语义信息,像这样的“encoder-decoder”的过程,有助于利用较高维度的feature map信息,有利于提高小目标的检测效果。
backbone不同:加入shortcut以加深网络,采用简化的residual block取代了原来1×1和3×3的block。这和上一点是有关系的,v2的darknet-19变成了v3的darknet-53,这是因为需要上采样,卷积层的数量自然就多了,另外作者还是用了一连串的3*3和1*1卷积,3*3的卷积增加channel,而1*1的卷积用于压缩3*3卷积后的特征表示,这样一增一减,效果超棒。v3一共有53个卷积层,所以称它为 Darknet-53,其在性能上远超Darknet-19,且在效率上同样优于ResNet-101和ResNet-152。Darknet-53在精度上可以与最先进的分类器相媲美,同时浮点运算(FLOPS,floating-point operations per second,每秒所执行的浮点运算次数)更少,速度也更快。Darknet-53的速度比ResNet-101快1.5倍,比ResNet-152快2倍,且还是在保证精度的前提下。Darknet-53可实现每秒最高的测量浮点运算,可更好利用GPU,使其预测效率更高,速度更快。这主要是因为ResNets的层数太多,效率不高。v2是一个纵向自上而下的网络架构,随着channel数目的不断增加,FLOPS是不断增加的,而v3网络架构是横纵交叉的,看着卷积层多,其实很多channel的卷积层没有继承性,另外虽然yolov3增加了anchor centroid,但是对ground truth的估计变得更加简单,每个ground truth只匹配一个先验框,而且每个尺度只预测3个框,v2预测5个框。这样的话也降低了复杂度。下表是在ImageNet上的实验结果:
router:由于top down 的多级预测,进而改变了router(或者说concatenate)时的方式,将原来诡异的reorg改成了upsample。
特征提取器不同:这次用了一个新的网络来提取特征,它融合了YOLOv2、Darknet-19以及其他新型残差网络,由连续的3×3和1×1卷积层组合而成,当然其中也添加了一些shortcut connection,
个人认为作者在创造v2的时候做了很多尝试和借鉴,实现了匹敌SSD的效果,但是他因为被借鉴的内容所困扰,只借鉴了皮毛而没领略其真谛,导致性能的停留。近几年涌现出各种别出心裁的目标检测佳作,像DSSD和FPN,说不定作者哪天茅塞顿开,一拍脑门,做成了v3,可能作者本人都没想到。但是作者目前没有写篇论文,认为没有创造性实质性的改变,写了一个report,科研的精神值得肯定!如果对比v2和v3你会发现反差确实很大,所以上面的问题才不奇怪。
失败尝试
1. Anchor box坐标的偏移预测
尝试了常规的Anchor box预测方法,比如利用线性激活将坐标x、y的偏移程度预测为边界框宽度或高度的倍数。但发现这种做法降低了模型的稳定性,且效果不佳。
2. 用线性方法预测x和y,而不是使用逻辑方法
尝试使用线性激活来直接预测x和y的offset,而不是逻辑激活,这降低了mAP成绩。
3. focal loss
尝试使用focal loss,但它使的mAP降低了2点。 对于focal loss函数试图解决的问题,YOLOv3从理论上来说已经很强大了,因为它具有单独的对象预测和条件类别预测。因此,对于大多数例子来说,类别预测没有损失?或者其他的东西?并不完全确定。
4. 双IOU阈值和真值分配
在训练期间,Faster RCNN用了两个IOU阈值,如果预测的边框与.7的ground truth重合,那它是个正面的结果;如果在[.3—.7]之间,则忽略;如果和.3的ground truth重合,那它就是个负面的结果。尝试了这种思路,但效果并不好。
官网介绍的关键点
Note: If during training you see nan values for avg (loss) field - then training goes wrong, but if nan is in some other lines - then training goes well.---nan只有出现在avg (loss)时才是错误
When should I stop training:When you see that average loss 0.xxxxxx avg no longer decreases at many iterations then you should stop training.Once training is stopped, you should take some of last .weights-files from darknet\build\darknet\x64\backup and choose the best of them.---什么时候可以停止训练,还能接着继续训练
Overfitting - is case when you can detect objects on images from training-dataset,but can't detect objects on any others images. You should get weights from Early Stopping Point.---什么情况是过拟合
IoU (intersect of union) - average instersect of union of objects and detections for a certain threshold = 0.24---交并比
How to improve object detection:---怎样提升检测效果
1.Before training:set flag random=1 in your .cfg-file - it will increase precision by training Yolo for different resolutions.---训练前设置flag random=1可提高精度
2.increase network resolution in your .cfg-file (height=608, width=608 or any value multiple of 32) - it will increase precision.---提高分辨率
3.recalculate anchors for your dataset for width and height from cfg-file:darknet.exe detector calc_anchors data/obj.data -num_of_clusters 9 -width 416 -height 416 then set the same 9 anchors in each of 3 [yolo]-layers in your cfg-file---设置锚点
4.desirable that your training dataset include images with objects at diffrent: scales, rotations, lightings, from different sides, on different backgrounds。---样本特点尽量多样化,亮度,旋转,背景,目标位置,尺寸
5.desirable that your training dataset include images with non-labeled objects that you do not want to detect - negative samples without bounded box (empty .txt files)---添加没有标注框的图片和其空的txt文件,作为negative数据
6.for training with a large number of objects in each image, add the parameter max=200 or higher value in the last layer [region] in your cfg-file.---
7.to speedup training (with decreasing detection accuracy) do Fine-Tuning instead of Transfer-Learning, set param stopbackward=1 in one of the penultimate convolutional layers before the 1-st [yolo]-layer, for example here: https://github.com/AlexeyAB/darknet/blob/0039fd26786ab5f71d5af725fc18b3f521e7acfd/cfg/yolov3.cfg#L598---可在第一个[yolo]层之前的倒数第二个[convolutional]层末尾添加 stopbackward=1,以此提升训练速度
8.After training - for detection:Increase network-resolution by set in your .cfg-file (height=608 and width=608) or (height=832 and width=832)or(any value multiple of 32) - this increases the precision and makes it possible to detect small objects,you do not need to train the network again, just use .weights-file already trained for 416x416 resolution.---即使在用416*416训练完之后,也可以在cfg文件中设置较大的width和height,增加网络对图像的分辨率,从而更可能检测出图像中的小目标,而不需要重新训练
9.if error Out of memory occurs then in .cfg-file you should increase subdivisions=16, 32 or 64 Out of memory.---出现这样的错误需要通过增大subdivisions来解决。
下面是GitHub中,提问的问题
mask
v3可进行3种不同尺度的预测。 使用检测层在三种不同尺寸的特征图上进行检测,分别具有stride=32、16、8,在输入图像为416 x 416的情况下,使用13x13、26x26、52x52的比例检测目标。网络下采样输入图像到第一检测层,即stride为32feature map为13x13的层进行检测,接着上采样2倍,并与具有相同特征图的先前层的特征图连接大小。 现在在具有stride=16的层上进行另一检测,重复相同的上采样过程,并且在stride=8处进行最终检测。在每个尺度上,每个单元使用3个anchor来预测3个bounding box,从而使用9个anchor的总数(anchor在不同尺度上是不同的)。作者在论文中说明,这有助于v3更好地检测小型物体,上采样可以帮助网络学习有助于检测小物体的细粒度特征。
每个尺度分配3个anchor,尺度指的是运用不同大小的feature map做detection。anchor是feature map上每个grid产生的不同大小和宽高比的box(不是bbox),用于确定该anchor中包含object的概率。与bbox的关系是:一旦anchor中包含某object的概率很大,然后对它的位置进行精修,接着进行非极大值抑制,得到的即是bbox。
不同尺度的3个detection是这样起作用的:1.对于小目标,大尺度feature map提供分辨率信息,小尺度feature map提供给语义信息;2.对于正常目标,小尺度feature map同时提供分辨率和语义信息。 因此不同尺度的3个detection可以有效检测不同尺度的object。 所有尺度下的检测结果都将做为预测结果,因为尺寸差异大的objects会分布在不同feature map上被检测到,即使同一个object出现在多个feature map上被检测到,也会因为nms取一个最佳的,所以不影响。 因此计算loss也是利用到了所有尺度,绝对不会只用某一个尺度。
分辨率信息直接反映的是构成object的像素的数量,一个object像素数量越多,对object的细节表现就越丰富越具体,这也就是为什么大尺度feature map提供的是分辨率信息了。语义信息在目标检测中指的是让object区分于背景的信息,即语义信息是让你知道这个是object,其余是背景。在不同类别中语义信息并不需要很多细节信息,分辨率信息大,反而会降低语义信息,因此小尺度feature map在提供必要的分辨率信息下语义信息会提供的更好,而对于小目标,小尺度feature map无法提供必要的分辨率信息,所以还需结合大尺度的feature map。
v3预测3种不同尺度的框(boxes),每个尺度的3个框,所以张量数量为NxNx[3x(4+1+80)]。网络会在预测三种尺度的特征N分别为13,26,52,分别对应各三种anchor :
13---(116×90); (156×198); (373×326)
26---(30×61); (62×45); (59×119);
52---(10×13); (16×30); (33×23)。 (大尺度用小anchor,提高小目标识别能力)
使用k-means聚类来确定bounding box priors,选择9个clusters和3个scales,然后在整个scales上均匀分割clusters,9个cluster即是上述9个anchor。
https://github.com/pjreddie/darknet/issues/567
according to paper, each yolo (detection) layer get 3 anchors with associated with its size, mask is selected anchor indices.
https://github.com/pjreddie/darknet/issues/558
Every layer has to know about all of the anchor boxes but is only predicting some subset of them. This could probably be named something better but the mask tells the layer which of the b