简介
本文分别从数据、检测模型、训练技巧、改进方案四个方面对AI识虫比赛进行了回顾,介绍了第二名的解决方案。该方案使用YoloV3作为目标检测器,并将检测结果输入到后置的SENet分类矫正网络中作进一步优化,最后将结果通过一个改进的NMS方法进行过滤,得到最终结果,以此获得了第二名的好成绩。目前比赛相关代码已在GitHub开源,有兴趣的话大家可以相互交流,地址是https://github.com/LKKlein/AI-Insects-Challenge
赛题背景
AI识虫比赛来自于课程《百度架构师手把手教深度学习》,该课程主要包含深度学习基础、计算机视觉、自然语言处理等各方面的内容。该比赛是计算机视觉阶段的结业比赛,是一个典型的目标检测任务,主要利用各种目标检测算法对图片中的七种林业病虫类别和位置进行预测。
数据简介
比赛数据来自于百度飞桨与北京林业大学合作开发的AI识虫项目,是一个偏向于产业实践的项目。数据总共包含2183张图片,且已经被划分为了训练集、验证集和测试集,分别包含1693张、245张和245张图片,比例约为78:11:11,分配比例合适。同时,经过简单的统计,训练集和验证集一共包含12203个真实框,如此量级的数据已经足够支撑一般的深度学习网络,再配合相关的数据增广策略,稍微更深的网络也应该没有问题。
图片 数量 | Box 数量 | 单张图Box数统计 [max, mean, min] | |
---|---|---|---|
训练集 | 1693 | 10347 | [10, 6.11, 4] |
验证集 | 245 | 1856 | [10, 7.57, 6] |
测试集 | 245 |
为了更深层次的了解一下数据,首先对数据集做了一个简单的分析。数据一共包含7种类型的虫子,大部分呈现褐色、黑色,少部分是淡色,背景皆为透明的圆形容器器皿,底色均为白色。
就数据的真实框而言,平均每张图真实框的数量最大为10,最少为4,平均在6-7左右,这个数据对nms后处理的参数设定相当重要。真实框的一些比例分析如下两图所示,真实框相对于原图的面积大概在0.1%到2%左右,长宽相对于原图的长宽也基本在2%到20%左右,而且相对于原图比例更小的部分,其数量占据绝大部分,中等比例的其次,比例最大的几乎没有,这说明该检测任务是以中小目标为主,在改进网络和训练时需要重点照顾这部分中小比例的目标。
除此之外,对于数据中各个类别的比例也需要关心,这里统计了训练集和验证集中不同类别的真实框数量。可以看到在训练集中,七个类别之间真实框的数量相差最大为1:3,并没有出现特别的类别不均衡现象。但是在验证集中,可以发现最后一个类没有数据,这可能导致验证评估的时候,对最后一个类的结果不能正确评估,因此验证集可能需要简单处理一下,从训练集抽取一部分包含最后一个类的真实框,随机贴到验证集的图中,从而生成新的验证集。
类别情况 | Boerner | Leconte | Linnaeus | acuminatus | armandi | coleoptera | linnaeus |
---|---|---|---|---|---|---|---|
训练集 | 1595 | 2216 | 818 | 953 | 1765 | 2091 | 909 |
验证集 | 318 | 594 | 292 | 235 | 231 | 186 | 0 |
数据增广策略
YoloV3论文的一个重要改进点就是使用了大量的数据增广策略,使得训练的模型拥有了更佳的泛化性能。在AI识虫比赛中,老师已经提供了多个数据增广的策略,包括随机色彩变换、随机填充、随机裁剪、随机缩放、随机翻转、真实框随机顺序、随机多尺度训练共七种策略,其中随机填充、随机裁剪、随机翻转需要同时对真实框进行处理,保证真实框永远与相应的物体对应。
除此之外,本方案中还加入了随机旋转和MixUp两个策略。由于比赛中的图像是圆形的器皿盘,而且虫子也是相对于不同方向摆放,因此旋转对于虫子的检测具有很强的现实意义,但目前利用旋转矩阵计算旋转的真实框结果相当不准确,旋转角度越接近45度,旋转后的框越大。因此,目前只能在0度和90度附近进行旋转,保证真实框的质量。MixUp是指按一定的权重随机混合两张图像,从而生成新的图像,新图像拥有两张图片的所有真实框。MixUp主要用于泛化被遮挡的物体,在AI识虫数据集中,会有部分虫子靠得很接近的情况,MixUp可以在一定程度上也能对这种数据进行泛化。
检测网络
本方案中使用一阶段检测方法中,高效又准确的YoloV3作为目标检测器。在YoloV3中,添加了SSD的特征金字塔,极大地改善了对小目标的检测效果,同时又使用route与上采样机制改进了SSD特征金字塔的特征提取不充分的缺陷,使其对小目标有了极佳的鲁棒性。而AI识虫任务中,大多都是小目标,因此YoloV3具有很好的适应性。
YoloV3中使用的原始BackBone是DarkNet53,这也是YoloV3中的一个提升点。而在本方案中,使用了更好的特征提取器ResNet50-vd替换了原始的DarkNet53作为新的BackBone,同时在后面还添加了一层可变形卷积DCN,用于突出特征图中有物体的区域,可以保证更好的特征提取。BackBone的更换为最终的结果贡献了1.5个mAP的提升。
训练技巧
训练技巧对于模型mAP的提升具有意想不到的效果。李沐大神的《Bag of Freebies for Training Object Detection Neural Networks》中,使用了6个训练技巧分别在VOC数据集上训练YoloV3和FasterRCNN,分别有了3.43和3.55个mAP的提升效果。本方案中也使用了6个训练技巧中的部分,同时添加了一些自己精调网络的技巧。这里没有记录各个技巧的具体提升效果,但是亲测这些方法都能有效提升最后的结果。
-
微调预训练参数
卷积本身也就是一个特征提取器,浅层卷积提取的基本是图像的轮廓、边缘、纹理等特征,这对所有图像而言是通用的。在大型数据集上充分训练过的卷积具有更好的特征提取能力,所以利用预训练迁移可以大大减小训练的时间,使损失下降得更快,同时还能更容易找到最优空间。
-
学习率调整策略
学习率的变化决定了网络的优化时间和优化方向,初期网络搜索空间较大,如果学习率过大会导致损失发散,无法收敛到好的极值点。根据李沐大神的建议,在优化初期使用WarmUp策略,可以使初期网络训练更加稳定;在后期使用余弦衰减策略,不仅可以让学习率变化更加平滑,还能提供周期性变化的学习率,使网络跳出局部最优。
-
标签平滑
标签平滑其实是一种正则化策略,降低网络对标签置信度的依赖,这对有漏标、错标数据具有很好地适应性,而AI识虫数据集中似乎存在这种情况。
-
逐层精调,减少网络搜索空间
网络搜索空间越大,训练时间越久,优化难度越高。因此,通过预训练微调,然后再通过冻结网络层进行精调,可以减小网络的搜索空间,从而降低优化的难度。在YoloV3的优化中,主要分为了四个部分,分别是BackBone的特征提取器以及三个Yolo层分支,逐步训练并冻结这四个部分再进行精调,可以让网络得到很好地提升。亲测冻结第一个Yolo的route层之后,精调二三层的中等物体和小物体训练,可以将网络的mAP提升1.5~2左右。
-
数据增广的配合
数据增广效果是否具有实际意义对后期的网络精调也有一定的影响,如之前随机旋转的真实框问题,对网络精调会产生较大的负面影响;MixUp可能导致大量的重叠,同时减小了对应类别的置信度,后期可能会让损失产生较大波动。因此,在精调的时候注意调整数据增广的策略。
-
减小动量
目前深度学习的优化器大都具备动量自适应,但是在最后精调阶段,动量过大也许会让网络又跳出了最优区域,适度的减小动量参数,可以让后期网络缓慢的朝着更优的方向优化。
-
不要忘记验证集
深度学习,数据为王,更多的数据往往会为网络优化带来新的方向。当其他参数都已固定时,联合训练集和验证集进一步训练,让网络看见更多数据,进一步加强训练。
改进提升
结果分析
检测模型的处理基本结束,如果按照默认的NMS参数进行后处理,在测试集上能得到99.04的mAP,看上去效果已经非常不错了,在AI识虫比赛中也能拿到一个非常好的成绩了。但是,这并不是最终的目标,还需要对检测结果进一步分析,找到错误的原因。
默认的NMS主要包含三个参数——NMS的IOU阈值、置信度score_threshold阈值、最终保留的最多框个数阈值。其中第一个参数在同类别靠得很近的时候也会产生较大的IOU,因此这个阈值并不能说明问题。第二个置信度分数默认值是0.01,但是在调大该值的时候,会出现mAP瞬间下降的情况,这表明结果中有出现分类错误的情况,调高score_threshold,导致正确的类别被过滤,相同的框只保留了错误的类别,mAP自然就降低了。第三个参数keep_topk默认值是100,通过查看结果可以发现,同一个框保留了多个类别的结果,这表明分类置信度不够高,无法过滤掉得分稍低的类别;除此之外,通过显示检测结果,可以发现还存在一些冗余和重复的候选框。
因此,主要是三个原因导致mAP没有更高,分别是分类置信度低;存在分类错误;候选框冗余、重复。
改进方案
针对上述存在的三个问题,本方案中主要从三个方面进行改进。
第一,提高NMS的score_threshold,减小keep_topk。提高置信度可以让同一框附近只保留得分较高的类别,尽管存在分类错误,但是只要预测框是对的就还能补救;减小keep_topk其实跟提高置信度效果一致,都可以删除大量冗余的候选框,根据之前的数据分析结果,平均每张图的真实框个数在4-10个,平均为6个,因此这里保留两倍的真实框数量,大概在12-20左右即可,可以在这其中进行调整。
第二,添加分类矫正网络,修正分类结果。Yolo中需要同时兼顾分类和检测框,可能导致分类训练不充分,或者受其他因素影响,使得分类结果不准确。因此通过重新训练一个分类网络,可以矫正分类效果,提升分类置信度。
第三,通过改进NMS处理,合并冗余候选框,进一步过滤低置信度框。
分类矫正网络
这里选择的分类方法是由Momenta公司在2017年提出的Squeeze-and-Excitation Networks(SENet),它通过对特征通道间的相关性进行建模,把重要的特征进行强化来提升准确率。这个结构是2017 ILSVR竞赛的冠军,top5的错误率只有2.251%,比2016年的第一名还要低25%,可谓提升巨大。因此,这里选择SE-ResNet50作为分类的网络架构,提升YoloV3检测结果的分类准确率。
这里分类网络的输入是原始图片中裁剪的检测框小图,输出是对应虫子的类别以及相应的置信度。在训练阶段,使用AI识虫训练集的真实框裁剪作为输入,同时增加随机填充、随机裁剪、随机旋转、随机色彩等数据增广方式,充分考虑YoloV3检测框可能出现的结果,最终训练的分类模型在验证集上能达到99%接近100%的准确率。
通过分类网络对检测结果进行分类矫正之后,验证集的检测结果从95.30增长到了97.41,上升了2.11个mAP;而测试集的mAP从95.36增长到了95.58,上升了0.22个mAP。那么,分类网络处理完成之后,通过对结果的可视化,可以观察到,分类以及置信度效果相当好,但同类别iou高的框也特别多,因而影响了结果的评估。
改进NMS处理
根据可视化的检测结果,本方案对传统NMS方法进行了改进,主要包含一下三个步骤:
-
对于两个同类别的检测框:
如果 iou > 阈值,则使用两个检测框的外接矩形作为最终的框,同时使用得分高的置信度作为最终置信度;
如果 iou < 阈值,保留两个检测框。
-
重复步骤1,但是将 iou 计算方式更换,替换为两个框交集面积占两个框各自面积的比例之中大的一个,主要用于过滤大框包含小框的情况,不过需要将阈值调得尽量高一些,避免相隔较近重叠较高的框被过滤。
-
剔除得分过低的检测框。
将分类矫正的结果通过改进的NMS之后,验证集提升了2.53个mAP,测试集提升了4.41个mAP,整体达到了非常好的识别效果。
后记
本次AI识虫比赛前前后后经历了一个月,这也是我第一次正式做 CV 的比赛,心里非常紧张,总是怕自己做不好,所以几乎每一天都在训练,每一天都在改进。虽然最后只使用了简单的YoloV3作为检测器,但是期间我尝试过SSD、Faster-RCNN、RetinaNet、模型融合、多尺度测试等等各种方法,最后在考虑效率和优化难度上,选择了YoloV3。所幸最后也取得了很好地成绩,证明了自己的实力。这一个月的各种专注、探索、脑洞,也让我学习到了很多新的东西,这是课堂上老师教不会的,这是真正自己的东西。所以,很感谢AI识虫比赛,也很感谢课程的所有老师,同时也要感谢百度的PaddlePaddle、PaddleDetection等框架,可以让想法快速得到实现,也才能有我现在的成绩。
另外,AI识虫涉及的相关代码已在GitHub开源,欢迎有兴趣的小伙伴一起交流讨论。