浅读一下美团提出的YOLOV6

浅读一下美团视觉智能部提出的YOLOV6:专用于工业应用的单阶段目标检测框架

目前该项目已经开源:https://github.com/meituan/YOLOv6,但是没有看到相应的论文,然后去找了一下。
浅读一下美团提出的YOLOV6_第1张图片
浅读一下美团提出的YOLOV6_第2张图片
虽然没有更详细的论文介绍,不过人家代码已经开源了,还是值得看看的。
浅读一下美团提出的YOLOV6_第3张图片

一、相关知识:

1.1、FP16和FP32?

当前Pytorch的默认存储数据类型是整数INT64(8字节),浮点数FP32(4字节),PyTorch Tensor的默认类型为单精度浮点数FP32。随着模型越来越大,加速训练模型的需求就产生了。
在深度学习模型中使用FP32主要存在几个问题:

  1. 模型尺寸大,训练的时候对显卡的显存要求高;
  2. 模型训练速度慢;
  3. 模型推理速度慢。

解决方案就是使用低精度计算对模型进行优化。

与单精度浮点数float32(32bit,4个字节)相比,半精度浮点数float16仅有16bit,2个字节组成。使用FP16可以解决或者缓解上面FP32的两个问题:显存占用更少:通用的模型FP16占用的内存只需原来的一半,训练的时候可以使用更大的batchsize,计算速度更快。

一般采用混合精度(AMP, Automatic mixed precision),用半精度可能对acc的影响较大,Pytorch原生支持自动混合精度训练(torch.cuda.amp),AMP 训练能在 Tensor Core GPU (Tensor Core是一种矩阵乘累加的计算单元,每个Tensor Core每个时钟执行64个浮点混合精度操作,FP16矩阵相乘和FP32累加)上实现更高的性能并节省多达 50% 的内存,主要节省的还是内存开销问题,在实际测试中,训练时间并没有节省。低精度计算也是未来深度学习的一个重要趋势。

二、改进

2.1 Hardware-friendly Backbone

之前的YOLO系列模型主干都是采用的CSPNet,采用了多分支的方式和残差结构,如下图中yolox的主干:
浅读一下美团提出的YOLOV6_第4张图片
对于 GPU 等硬件来说,这种结构会一定程度上增加延时,同时减小内存带宽利用率。图 2 为计算机体系结构领域中的 Roofline Model介绍图,显示了硬件中计算能力和内存带宽之间的关联关系。
浅读一下美团提出的YOLOV6_第5张图片
基于硬件感知神经网络设计的思想,综合考虑硬件计算能力、内存带宽、编译优化特性、网络表征能力等。

2.1.1 RepVGG style 结构:

RepVGG为每一个3×3的卷积添加平行了一个1x1的卷积分支和恒等映射的分支。这种结构就构成了构成一个RepVGG Block。

该结构在训练时具有多分支拓扑,而在实际部署时可以等效融合为单个 3x3 卷积的一种可重参数化的结构(融合过程如下图 3 所示)。通过融合成的 3x3 卷积结构,可以有效利用计算密集型硬件计算能力(比如 GPU),同时也可获得 GPU/CPU 上已经高度优化的 NVIDIA cuDNN 和 Intel MKL 编译框架的帮助。
浅读一下美团提出的YOLOV6_第6张图片
具体结构为:
浅读一下美团提出的YOLOV6_第7张图片
将 Backbone 中 stride=2 的普通 Conv 层替换成了 stride=2 的 RepConv层。同时,将原始的 CSP-Block 都重新设计为 RepBlock,其中 RepBlock 的第一个 RepConv 会做 channel 维度的变换和对齐。

另外,原始的 SPPF 优化设计为更加高效的 SimSPPF。

2.1.2 SPP、SPPF、SimSPPF的区别

(1)SPP的应用背景
在卷积神经网络中我们经常看到固定输入的设计,但是如果我们输入的不能是固定尺寸的该怎么办呢?
通常来说,有以下几种方法:

  1. 对输入进行resize操作,让他们统统变成你设计的层的输入规格那样。但是这样过于暴力直接,可能会丢失很多信息或者多出很多不该有的信息(图片变形等),影响最终的结果;
  2. 替换网络中的全连接层,对最后的卷积层使用global average pooling,全局平均池化只和通道数有关,而与特征图大小没有关系;
  3. SPP结构:又称空间金字塔池化,能够将能将任意大小的特征图转换成固定大小的特征向量。

(2)SPP
浅读一下美团提出的YOLOV6_第8张图片
SPP的处理过程:
输入层:首先我们现在有一张任意大小的图片,其大小为w * h。
输出层:276个神经元 – 即我们希望提取到276个特征。
分别对 1 * 1分块,5* 5分块、9 * 9分块、13 * 13分块子图里分别取每一个框内的最大值,这一步就是作最大池化,这样最后提取出来的特征值(即取出来的最大值)一共有1 * 1 + 5 * 5 + 9 * 9+13 * 13 = 276个。得出的特征再concat在一起。

(3)SPPF:
浅读一下美团提出的YOLOV6_第9张图片
SPPF结构是将输入串行通过多个5x5大小的MaxPool层,这里需要注意的是串行两个5x5大小的MaxPool层是和一个9x9大小的MaxPool层计算结果是一样的,串行三个5x5大小的MaxPool层是和一个13x13大小的MaxPool层计算结果是一样的。

SPPF结构与SPP结构作用一样,但SPPF结构效率更高、速度更快

(4)SimSPPF
官方没有细说,直接看代码吧:

class SimSPPF(nn.Module):
    '''Simplified SPPF with ReLU activation'''
    def __init__(self, in_channels, out_channels, kernel_size=5):
        super().__init__()
        c_ = in_channels // 2  # hidden channels
        self.cv1 = SimConv(in_channels, c_, 1, 1)
        self.cv2 = SimConv(c_ * 4, out_channels, 1, 1)
        self.m = nn.MaxPool2d(kernel_size=kernel_size, stride=1, padding=kernel_size // 2)

    def forward(self, x):
        x = self.cv1(x)
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')
            y1 = self.m(x)
            y2 = self.m(y1)
            return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))
class SimConv(nn.Module):
    '''Normal Conv with ReLU activation'''
    def __init__(self, in_channels, out_channels, kernel_size, stride, groups=1, bias=False):
        super().__init__()
        padding = kernel_size // 2
        self.conv = nn.Conv2d(
            in_channels,
            out_channels,
            kernel_size=kernel_size,
            stride=stride,
            padding=padding,
            groups=groups,
            bias=bias,
        )
        self.bn = nn.BatchNorm2d(out_channels)
        self.act = nn.ReLU()

    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

    def forward_fuse(self, x):
        return self.act(self.conv(x))

和SPPF基本上一样。

2.2 Rep-PAN Neck

在 Neck 设计方面,为了让其在硬件上推理更加高效,以达到更好的精度与速度的平衡,基于硬件感知神经网络设计思想,设计了一个更有效的特征融合网络结构:Rep-PAN

Rep-PAN 基于 PAN拓扑方式,用 RepBlock 替换了 YOLOv5 中使用的 CSP-Block,同时对整体 Neck 中的算子进行了调整,目的是在硬件上达到高效推理的同时,保持较好的多尺度特征融合能力。

Rep-PAN结构
浅读一下美团提出的YOLOV6_第10张图片
对比yolox中的Neck:
浅读一下美团提出的YOLOV6_第11张图片

2.3 Simplified Decoupled Head

在 YOLOv6 中,采用了解耦检测头(Decoupled Head)结构,并对其进行了精简设计。
原始 YOLOv5 的检测头是通过分类和回归分支融合共享的方式来实现的,而 YOLOX 的检测头则是将分类和回归分支进行解耦,同时新增了两个额外的 3x3 的卷积层,虽然提升了检测精度,但一定程度上增加了网络延时。

因此,对解耦头进行了精简设计,同时综合考虑到相关算子表征能力和硬件上计算开销这两者的平衡,采用 Hybrid Channels 策略重新设计了一个更高效的解耦头结构,在维持精度的同时降低了延时,缓解了解耦头中 3x3 卷积带来的额外延时开销。通过在 nano 尺寸模型上进行消融实验,对比相同通道数的解耦头结构,精度提升 0.2% AP 的同时,速度提升6.8%。

浅读一下美团提出的YOLOV6_第12张图片

2.4 训练策略

2.4.1 Anchor-free无锚范式

由于 Anchor-based检测器需要在训练之前进行聚类分析以确定最佳 Anchor 集合,这会一定程度提高检测器的复杂度;同时,在一些边缘端的应用中,需要在硬件之间搬运大量检测结果的步骤,也会带来额外的延时。而 Anchor-free 无锚范式因其泛化能力强,解码逻辑更简单,在近几年中应用比较广泛。经过对 Anchor-free 的实验调研,我们发现,相较于Anchor-based 检测器的复杂度而带来的额外延时,Anchor-free 检测器在速度上有51%的提升。

2.4.2 SimOTA 标签分配策略

YOLOv5 的标签分配策略是基于 Shape 匹配,并通过跨网格匹配策略增加正样本数量,从而使得网络快速收敛,但是该方法属于静态分配方法,并不会随着网络训练的过程而调整。

为了获得更多高质量的正样本,YOLOv6 同样沿用了 YOLOX的SimOTA算法动态分配正样本,进一步提高检测精度。

2.4.3 SIoU 边界框回归损失

SIoU 边界框回归损失函数是2022年5月份提出的:SIoU Loss: More Powerful Learning for Bounding Box Regression

YOLOv6 采用了 SIoU 边界框回归损失函数来监督网络的学习。

目标检测网络的训练一般需要至少定义两个损失函数:分类损失和边界框回归损失,而损失函数的定义往往对检测精度以及训练速度产生较大的影响。

近年来,常用的边界框回归损失包括IoU、GIoU、CIoU、DIoU loss等等,这些损失函数通过考虑预测框与目标框之前的重叠程度、中心点距离、纵横比等因素来衡量两者之间的差距,从而指导网络最小化损失以提升回归精度,但是这些方法都没有考虑到预测框与目标框之间方向的匹配性。SIoU 损失函数通过引入了所需回归之间的向量角度,重新定义了距离损失,有效降低了回归的自由度,加快网络收敛,进一步提升了回归精度。
通过在 YOLOv6s 上采用 SIoU loss 进行实验,对比 CIoU loss,平均检测精度提升 0.3% AP。

三、实验结果

3.1 YOLOv6-nano 消融实验

浅读一下美团提出的YOLOV6_第13张图片

3.2 YOLOv6与主流的YOLO系列模型对比

浅读一下美团提出的YOLOV6_第14张图片

  1. YOLOv6-nano 在 COCO val 上 取得了 35.0% AP 的精度,同时在 T4 上使用 TRT FP16 batchsize=32 进行推理,可达到 1242FPS 的性能,相较于 YOLOv5-nano 精度提升 7% AP,速度提升 85%。
  2. YOLOv6-tiny 在 COCO val 上 取得了 41.3% AP 的精度, 同时在 T4 上使用 TRT FP16 batchsize=32 进行推理,可达到 602FPS 的性能,相较于 YOLOv5-s 精度提升 3.9% AP,速度提升 29.4%。
  3. YOLOv6-s 在 COCO val 上 取得了 43.1% AP 的精度, 同时在 T4 上使用 TRT FP16 batchsize=32 进行推理,可达到 520FPS 的性能,相较于 YOLOX-s 精度提升 2.6% AP,速度提升 38.6%;相较于 PP-YOLOE-s 精度提升 0.4% AP的条件下,在T4上使用 TRT FP16 进行单 batch 推理,速度提升 71.3%。

3.3 实验测试

浅读一下美团提出的YOLOV6_第15张图片
浅读一下美团提出的YOLOV6_第16张图片

浅读一下美团提出的YOLOV6_第17张图片

你可能感兴趣的:(论文阅读笔记,深度学习,python,人工智能)