YOLOv5的Neck端设计

在上一篇《YOLOv5的Backbone设计》中,我们从yolov5的backbone配置文件出发,细致讲解了backbone的网络架构及各模块的源码和结构,对骨架网络有了较为全面的初步认知。接下来我们会循着之前的学习思路,继续深入到网络结构源码中去探寻YOLO的Neck端设计。

1 Neck结构总览

网络结构配置文件中并未将neck和head进行区分,而是直接以head命名,这也是方便在models/yolo.py中的加载。为了读者能够清晰明白地感知neck的设计,在本文中我们只讨论head中的neck部分:

neck:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 13

   [-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 14], 1, Concat, [1]],  # cat head P4
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium)

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)
  ]

可以看到,Neck部分的组件相较于Backbone较为单一,基本上就由CBS、Upsample、Concat和不带shortcut的CSP(C3)。
FPN与PAN

另外,Neck的网络结构设计也是沿用了FPN+PAN的结构。FPN就是使用一种 自顶向下的侧边连接在所有尺度上构建出高级语义特征图,构造了特征金字塔的经典结构,也就是上图中的a,具体细节可以参考我之前的文章:FPN网络结构+源码讲解;PAN的结构也不稀奇,FPN中间经过多层的网络后,底层的目标信息已经非常模糊了,因此PAN又加入了自底向上的路线,弥补并加强了定位信息,也就是上图中的b。贴一下FPN和PAN原文:
FPN:Feature Pyramid Networks for Object Detection
PAN:Path Aggregation Network for Instance Segmentation

2 Neck部件模块

2.1 CBS

在Backbone中,为了进一步提取图像中的信息,CBS在改变特征图通道的同时,也会控制卷积模块中的步长s下采样来改变特征图的尺寸。Neck中左侧采用FPN自顶向下设计的过程中,是特征图上采样的过程,因此这个时候再下采样就不合时宜了,所以在FPN中s=1;而到了右侧PAN再次自下而上提取位置信息时,就需要使用CBS继续下采样抽取高层次的语义信息,这也是CBS前后参数差异的原因。具体的CBS结构可以参考上篇文章:YOLOv5的Backbone详解,这里不再赘述。

2.2 nn.Upsample

[-1, 1, nn.Upsample, [None, 2, 'nearest']]

Pytroch内置的上采样模块,需要指定上采样的倍数和方式。


这里我们不指定size,上采样倍数为2,上采样方式为nearest,也就是最近填充。

2.3 Concat

[[-1, 6], 1, Concat, [1]],  # cat backbone P4

Concat即拼接,接对象通过from传入,拼接的维度由args参数指定,此处即按照维度1(channel)拼接,其他维度不变。至于from中的特征图到底是哪一个,我建议大家运行模型将各层特征图打印出来,如:

通过上图就很容易确定concat的两个对象了,当然,我在文章最开始的时候已经给大家画出来网络结构,大家按图索骥也可以找到。

class Concat(nn.Module):
    # Concatenate a list of tensors along dimension
    def __init__(self, dimension=1):
        super().__init__()
        self.d = dimension

    def forward(self, x):
        return torch.cat(x, self.d)

2.4 CSP/C3

Backbone需要更深层次的网络获取更多的信息,可以说backbone已经完成了主要特征信息的提取,所以在Neck阶段我们并不需要再一味地加深网络,采取不带残差的C3模块可能会更合适一些。

具体的模块结构及源码参考backbone中的介绍。

neck端的主要内容大体就是以上了。

OVER

来源:Marlowee

物联沃分享整理
物联沃-IOTWORD物联网 » YOLOv5的Neck端设计

发表评论