本文研究yolo系列的Neck模块。yolov1、yolov2没有使用Neck模块,yolov3开始使用。Neck模块的目的是融合不同层的特征检测大中小目标。

模块

yolov3

FPN

yolov4

spp+PANet

yolov5

spp+PANet,Concat层后的CBL模块改成了CSP_V5模块

yolox

spp+FPN

yolov7

sppscp+优化的PAN(Concat层前的CBL改成MPConv,Concat层后使用E-ELAN)

在进行yolo系列Neck模块研究前,先研究FPN、SPP和PAN模块。

1.FPN(feature pyramid networks)

目的:提高小目标的检出。

         原来很多目标检测算法都是只采用高层特征进行预测,高层的特征语义信息比较丰富,但是分辨率较低,目标位置比较粗略。假设在深层网络中,最后的高层特征图中一个像素可能对应着输出图像20*20的像素区域,那么小于20*20像素的小物体的特征大概率已经丢失。与此同时,低层的特征语义信息比较少,但是目标位置准确,这是对小目标检测有帮助的。FPN将高层特征与底层特征进行融合,从而同时利用低层特征的高分辨率和高层特征的丰富语义信息,并进行了多尺度特征的独立预测,对小物体的检测效果有明显的提升。

kitti2D目标检测 指标 目标检测neck_目标检测

2.SPP(Spatial Pyramid Pooling)

SPP,即空间金字塔池化。SPP的目的是解决了输入数据大小任意的问题。SPP网络用在YOLOv4中的目的是增加网络的感受野

kitti2D目标检测 指标 目标检测neck_计算机视觉_02

 SPP的使用方法:

  • 首先划分输入:将输入特征分别划分成不同份:最左边有16个蓝色小格子的图,它的意思是将从输入特征分成16份,16X256中的256表示的是channel,即SPP对每一层都分成16份(不一定是等比分)。中间的4个绿色小格子和右边1个紫色大格子也同理,即将输入特征分别分成4X2561X256份。(注意上面划分成多少份是可以自定义)
  • 对每份特征进行池化:一般选择MAX Pooling,即对每一份进行最大池化。看上图,通过SPP层,输入特征被转化成了16X256+4X256+1X256 = 21X256的矩阵。
  • 后面连接一个全连接层:连接一个1X10752的全连接层。这样就解决了输入数据大小任意的问题了。

SPP中卷积核的 尺寸、和步长大小计算方法:

kitti2D目标检测 指标 目标检测neck_目标检测_03

kitti2D目标检测 指标 目标检测neck_目标检测_04

kitti2D目标检测 指标 目标检测neck_计算机视觉_05

假设输入数据大小是 (7,11), 池化数量 (4,4):

那么核大小为 (2,3), 步长大小为 (2,3), padding 为 (1,1), 得到池化后的矩阵大小的确是 4∗4。 

SPP的pytorch实现:

#coding=utf-8

import math
import torch
import torch.nn.functional as F

# 构建SPP层(空间金字塔池化层)
class SPPLayer(torch.nn.Module):

    def __init__(self, num_levels, pool_type='max_pool'):
        super(SPPLayer, self).__init__()

        self.num_levels = num_levels
        self.pool_type = pool_type

    def forward(self, x):
        num, c, h, w = x.size() # num:样本数量 c:通道数 h:高 w:宽
        for i in range(self.num_levels):
            level = i+1
            kernel_size = (math.ceil(h / level), math.ceil(w / level))
            stride = (math.ceil(h / level), math.ceil(w / level))
            pooling = (math.floor((kernel_size[0]*level-h+1)/2), math.floor((kernel_size[1]*level-w+1)/2))

            # 选择池化方式 
            if self.pool_type == 'max_pool':
                tensor = F.max_pool2d(x, kernel_size=kernel_size, stride=stride, padding=pooling).view(num, -1)
            else:
                tensor = F.avg_pool2d(x, kernel_size=kernel_size, stride=stride, padding=pooling).view(num, -1)

            # 展开、拼接
            if (i == 0):
                x_flatten = tensor.view(num, -1)
            else:
                x_flatten = torch.cat((x_flatten, tensor.view(num, -1)), 1)
        return x_flatten

SPPCSP

SPP的优化,在SPP模块基础上在最后增加concat操作,与SPP模块之前的特征图进行融合,更加丰富了特征信息。

kitti2D目标检测 指标 目标检测neck_池化_06

kitti2D目标检测 指标 目标检测neck_目标检测_07

 

3.PANet

网络结构如下图所示,与FPN相比,PANet 在UpSample之后又加了DownSample的操作。PANet对不同层次的特征进行疯狂融合,其在FPN模块的基础上增加了自底向上的特征金字塔结构,保留了更多的浅层位置特征,将整体特征提取能力进一步提升。

kitti2D目标检测 指标 目标检测neck_计算机视觉_08

 PAN模块的优化:

 PAN模块在每个Concat层后面引入一个E-ELAN结构,使用expand、shuffle、merge cardinality等策略实现在不破坏原始梯度路径的情况下,提高网络的学习能力。

kitti2D目标检测 指标 目标检测neck_计算机视觉_09

4.yolov3

    yolov3的NECK模块引入了FPN的思想,并对原始FPN进行修改。

kitti2D目标检测 指标 目标检测neck_kitti2D目标检测 指标_10

 YOLOv3设置了三个不同的尺寸,分别是19*19,38*38,76*76

 YOLOv3采用全卷积的思路,在Neck侧也不例外(YOLOv1-v2中采用池化层做特征图的下采样, v3中采用卷积层来实现)。

5.yolov4

yolov4的Neck模块主要包含了SPP模块和PAN模块。

kitti2D目标检测 指标 目标检测neck_目标检测_11

YOLOv4引入PAN时,特征图最后的融合操作相比于原论文发生了变化,从add操作改为concat操作,增加了特征图的通道数:

kitti2D目标检测 指标 目标检测neck_计算机视觉_12

6. yolov5

YOLOv5的Neck侧也使用了SPP模块和PAN模块,但是在PAN模块进行融合后,将YOLOv4中使用的CBL模块替换成借鉴CSPnet设计的CSP_v5结构,加强网络特征融合的能力。

kitti2D目标检测 指标 目标检测neck_目标检测_13

7.yolovx

YOLOx的Neck侧依然使用了YOLOv3的结构,并且使用了SPP模块。

kitti2D目标检测 指标 目标检测neck_池化_14

 在Neck侧,yolox和yov3的差别在于:在高层特征支路上使用了SPP模块:

kitti2D目标检测 指标 目标检测neck_池化_15

kitti2D目标检测 指标 目标检测neck_计算机视觉_16

8.yolov7

 YOLOv7的Neck侧主要包含了SPPSCP模块和优化的PAN模块

kitti2D目标检测 指标 目标检测neck_深度学习_17

 SPPCSP模块在SPP模块基础上在最后增加concat操作,与SPP模块之前的特征图进行融合,更加丰富了特征信息。

PAN模块引入E-ELAN结构,使用expand、shuffle、merge cardinality等策略实现在不破坏原始梯度路径的情况下,提高网络的学习能力。