实用目标检测器 | 性能超YoloV5,推理耗时不变(附github源码)

提升输入尺寸可以增强目标面积,因此小尺度的目标信息可以更好的保持,进而可以提升模型性能
一、简要

在实际应用场景中,有效性与高效性对于目标检测器非常重要。为了满足这两个问题,研究者全面评估了现有的改进的集合,以提高PP-YOLO的性能,同时几乎保推理时间不变

图片

百度研究者对现有改进措施进行了分析并通过增强消融研究评估了其对最终模型的影响,此外,那些不起作用的也进行了讨论。通过组合多种有效改进,将PP-YOLO在COCO2017 test-dev数据上的性能从45.9%mAP提升到了49.5%mAP,并将所得到的模型称之为PP-YOLOv2。在推理速度方面,PP-YOLOv2可以达到68.9FPS(输入尺寸为640*640);采用Paddle推理引擎+TensorRT+FP16+bs1,可以进一步将PP-YOLOv2的推理速度提升到106.5FPS。优秀的性能完全超越了同等参数量的YOLOv4-CSP、YOLOv5l等模型。除此之外,采用ResNet101为主干网络的PP-YOLOv2可以在COCO2017 test-dev数据集上取得50.3%mAP。

二、背景及PP-YOLO

图片

目标检测是各种现实世界应用程序的一个关键组成部分,如自动驾驶、人脸识别和人的重识别。近年来,随着深度卷积神经网络(CNNs)的兴起,目标探测器的性能得到了迅速的提高。虽然最近的工作集中在新的检测pipeline(即 Cascade RCNN和HTC),复杂的网络架构设计(DetectoRS和CBNET)推动了最先进的目标检测方法,YOLOv3仍然是工业中使用最广泛的检测器之一。因为,在各种实际应用中,不仅计算资源有限,而且软件支持不足。没有必要的技术支持,two-stage检测器(如Faster RCNN,Cascade RCNN)可能会非常慢。

图片

同时,在YOLOv3和two-stage检测器的精度之间存在着显著的差距。因此,如何在保持推理速度的同时提高YOLOv3的有效性是实际使用的一个重要问题。为了同时满足两个问题,研究者添加了一堆改进,几乎不增加推理时间来提高PP-YOLO的整体性能。要注意,尽管大量的方法声称可以独立地提高目标检测器的精度,但在实践中,有些方法在结合时是不有效的。因此,需要对这些技巧的组合进行实际的测试。研究者遵循增量的方法来逐一评估它们的有效性。所有的实验都是基于PaddlePaddle实现。

PP-YOLO

最近出现了yolov4和yolov5模型,这些模型也是基于yolo3算法改进得来。但PP-YOLO并不像yolov4探究各种复杂的backbone和数据增广手段,也不是靠nas暴力搜索得到一个结构。在resnet主干网络系列,数据增广仅靠mixup的条件下,通过合理的tricks组合,不断提升模型性能。最终与其他模型对比图如下:

图片

一个单阶段的Anchor based的检测模型通常是由一个主干网络一个neck(通常是FPN),以及一个head(用于分类+定位)组成。PP-YOLO选择了ResNet50-vd-dcn作为骨架网络。

图片

Backbone

直接用ResNet50-vd替换掉Darknet53会导致一部分的性能损失。因此,尝试替换了一些ResNet中的卷积为可变形卷积(Deformable Convolution Network)。可变形卷积的效果已经被很多论文证明了其有效性,但是过多的添加DCN层会导致增加预测时间。论文这里使用的一个平衡的方案就是替换了最后一个stage的3x3卷积为DCNs。

Detection Neck

使用FPN,将backbone的3,4,5个stage的输出作为FPN的输入,输出的大小变为输入大小的一半。

Detection Head

常规来说Head的组成都是很简单的,包含两个卷积层,一个3x3和一个1x1。当输出类别是K的时候,输出的维度就是3(K+5),每一个预测的特征图上的每一个预测位置都与三个不同的anchors相关。针对每一个anchor,前K个维度确定了类别,后4个确定了bounding box的定位,最后一个确定了是否有目标。然后CE和L1用于对这些预测值计算损失。

图片

A->B

首先就是搭建基础版本的PP-YOLO,在尝试替换backbone后,虽然参数小了很多,但是mAP也下降了不少。我们通过增加了DCN卷积,将mAP提高到39.1%,增加的参数仍远远小于原始yolo3。

B->C

基础模型搭建好后,尝试优化训练策略,选用的是更大的batch和EMA,并且加入DropBlock防止过拟合,mAP提升到了41.4%。

C->F

我们在这个阶段分别增加了IOU Loss,IOU Aware,Grid Sensitive这三个损失函数的改进。分别得到了0.5%, 0.6%, 0.3%的提升,将mAP提升到了42.8%,推理速度下降仍属于可接受范围内。

F->G

检测框的处理部分也是能提升性能的,通过增加Matrix NMS,mAP提高了0.6%。这个表格暂时不考虑NMS对推理时间的影响,在实际测试中,MatrixNMS是能比传统NMS降低推理时间的。

G->I

到了最后阶段,很难通过增加网络复杂度来提高mAP,因此我们将SPP和CoordConv放到这里再来考虑。这两个结构所带来的额外参数较少,而实验也证明了将mAP提高到44.3%。

I->J

分类模型的好坏不能代表整个检测模型的性能,因此我们最后才考虑是否用更好的预训练模型。仍然是在ImageNet上进行预训练得到了一个更好的模型,并且提升了0.3%的mAP。

三、新框架

图片

Path Aggregation Network

对不同尺度的目标进行检测是目标检测的一个基本挑战。实际上,检测Neck需要为所有尺度构建高级语义特征。研究者参考PAN的设计集成了top-down信息。可参见上面图示部分。




























def pan_module(self, input, filter_list, name=None):        for i in range(1, len(input)):            ch_out = input[i].shape[1] // 2            conv_left = self._conv_bn(                input[i],                ch_out=ch_out,                filter_size=1,                stride=1,                padding=0,                name=name + '.{}.left'.format(i))            ch_out = input[i - 1].shape[1] // 2            conv_right = self._conv_bn(                input[i - 1],                ch_out=ch_out,                filter_size=1,                stride=1,                padding=0,                name=name + '.{}.right'.format(i))            conv_right = self._upsample(conv_right)            pan_out = fluid.layers.concat([conv_left, conv_right], axis=1)            ch_list = [pan_out.shape[1] // 2 * k for k in [1, 2, 1, 2, 1]]            input[i] = self.stack_conv(                pan_out,                ch_list=ch_list,                filter_list=filter_list,                name=name + '.stack_conv.{}'.format(i))        return input

Mish Activation Function

已有研究YOLOv4与YOLOv5表明:Mish对于改进目标检测器的性能非常有效。由于已经有了一个非常强有力的预训练主干模型(82.4%top1精度),为保持主干结构不变,仅将Mish用到了Neck部分。



def mish(x):    return x * paddle.tanh(F.softplus(x))

Larger Input Size

提升输入尺寸可以增强目标面积,因此小尺度的目标信息可以更好的保持,进而可以提升模型性能。然而更大尺寸输入会占用更多内存,为使用这个技巧,需要减少batch。具体来说,将每个GPU的batch从24下降到12,并将输入尺寸从608提升到768。

IoU Aware Branch 

在PP-YOLO中,IoU损失采用了软加权方式;在这里采用软标签形式,IoU损失定义如下:

其中t表示锚点与其匹配真实框之间的IoU,p表示原始IoU分支的输出。

注:仅仅正样本的IoU损失进行了计算。通过替换损失函数,IoU损失分支表现更佳。
























@register@serializableclass IouAwareLoss(IouLoss):    """    iou aware loss, see https://arxiv.org/abs/1912.05992    Args:        loss_weight (float): iou aware loss weight, default is 1.0        max_height (int): max height of input to support random shape input        max_width (int): max width of input to support random shape input    """
   def __init__(self, loss_weight=1.0, giou=False, diou=False, ciou=False):        super(IouAwareLoss, self).__init__(            loss_weight=loss_weight, giou=giou, diou=diou, ciou=ciou)
   def __call__(self, ioup, pbox, gbox):        iou = bbox_iou(            pbox, gbox, giou=self.giou, diou=self.diou, ciou=self.ciou)        iou.stop_gradient = True        loss_iou_aware = F.binary_cross_entropy_with_logits(            ioup, iou, reduction='none')        loss_iou_aware = loss_iou_aware * self.loss_weight        return loss_iou_aware

四、实验及可视化

图片

首先,参考原始的PP-YOLO构建新框架的基线模型,由于CPU端的重度预处理会减慢训练,将每个GPU的图像数从24下调到了12,降低bs会导致0.2%mAP指标下降。

A->B

PP-YOLO上添加的第一个正向改进为PAN,为稳定训练,为PAN模块添加了几个跳过连接,具体可以参见前面的图示部分。可以看到:PAN+Mish的添加可以将模型的性能从45.4%mAP提升到47.1%mAP。尽管B模型要比A模型稍慢,但这种程度的性能提升促使将PAN应用到最终的模型中。

B->C

由于YOLOv4与YOLOv5评估过程中的输入尺寸为640,将训练与评估的输入尺寸同样调整到了640以进行公平对比。可以看到:模型性能得到了0.6%mAP提升。

C->D

持续输入尺寸应该受益更多,然而不可能同时采用大输入尺寸与大batch。因此采用更大输入尺寸+每个GPU12图像训练模型D。此时可以带来额外的0.6%mAP指标提升。

D->E

在训练阶段,改进IoU损失表现更好。通过该损失的替换,模型E的提升提升到了49.1%mAP指标且不造成推理效率的损失。

图片

上表给出了所提方法与其他SOTA方案的性能、效率对比,从中可以看到:

  • PP-YOLOv2显著优于YOLOv4-CSP与YOLOv5;

  • 在同等FPS下,PP-YOLOv2以2%mAP优于YOLOv4-CSP,以1.3%AP优于YOLOv5l;

  • 替换ResNet50为ResNet101后,PP-YOLOv2的性能与YOLOv5x相当且推理速度快15.9%。

图片