Boundary Aware PoolNet(1):PoolNet模型与代码介绍

Boundary Aware PoolNet = PoolNet + BASNet,即使用BASNet中的Deep Supervision策略和Hybrid Loss改进PoolNet。

为理解Boundary Aware PoolNet还是需要全面理解PoolNet的,因此本文将对PoolNet的模型结构及其代码实现进行介绍。

相关文章汇总:

PoolNet

PoolNet的论文名称为:A Simple Pooling-Based Design for Real-Time Salient Object Detection,该论文来自南开程明明老师的实验室。

传送门

用一句话概括PoolNet

PoolNet基于FPN(Feature Pyramid Network,特征金字塔网络)构造了GGM(Global Guidance Module,全局指导模块)和FAM(Feature Aggregation Module,特征聚合模块)2个模块,实现了显著性目标检测。

PoolNet结构

PoolNet模型结构如下图所示,其包括:

  1. GGM(下图中,“P”指PPM,橙色箭头指GGF)

  2. FAM(即下图中的“A”)

  3. FPN(即下图中的U型结构)

    因此下图中GGM、FAM之外的部分就是FPN。

img

GGM和FAM

img

如上图所示,GGM包括PPM(Pyramid pooling module,金字塔池化模块)和GGF(Global Guiding Flows,全局指导流),其作用是在FPN自底向上路径的顶部提取显著目标的位置信息并将其提供给FPN自顶向下路径中的不同金字塔层;FAM位于FPN自顶向下路径中FUSE操作之前,其作用是使来自GGM的特征与FPN自顶向下路径中不同金字塔层的特征更好地融合。

代码

PoolNet的代码在文件./networks/poolnet.py中的类PoolNet中,其调用了Backbone(比如ResNet50)、GGM、FAM等各个模块。

注意:学习代码时不只可以看PoolNet官方代码,还可以看我的Boundary Aware PoolNet的代码(包含详细中文注释,链接:https://github.com/chouxianyu/Boundary-Aware-PoolNet)。

接下来将分别介绍PoolNet模型中各个模块的理论和代码。

FPN

传送门

FPN结构

FPN即Feature Pyramid Network(特征金字塔网络),其结构如下图所示。FPN包含1条自底向上路径(从此输入)和1条自顶向下路径(得到输出),形成1种U型结构。

FPN网络图解

自底向上路径

图片从该路径输入,经过卷积等一系列操作,特征的尺寸越来越小、通道数越来越多。上图所示的自底向上路径中有5个长方体,这并不代表该路径中只有5层,而是表明在一系列操作中选出5层特征图以进一步利用。当然了,也可以选择数量更多或更少的层。

自顶向下路径

自顶向下路径由多个FUSE操作组成,上图所示的自顶向下路径中包含4个FUSE操作(数量与自底向上路径中选取的层的数量对应),将最后1个FUSE操作的输出作为整个模型的输出。

FUSE

一般FPN的FUSE操作有2个输入,其一是自底向上路径中的特征(对其进行1×1卷积),其二是自顶向下路径中上1个FUSE操作的输出(对其进行上采样),分别对这2个输入进行1×1卷积和上采样再将两者相加,最后进行3×3卷积得到该FUSE操作的输出。

注意:因为PoolNet引入了GGM,所以PoolNet中的FUSE操作有3个输入(除了上述的2个输入还有1个输入是GGF的输出),因此PoolNet中FPN的FUSE操作如下图所示(绿色箭头代表GGF,可以将上采样理解为GGF的一部分)。

img

Backbone

FPN更多是一种结构而非一种网络,基于FPN这种U型结构,我们可以更换Backbone(骨干网络)。什么是Backbone呢?暂时你可以将Backbone理解为自底向上路径中的网络。常见的Backbone有VGG16、ResNet系列网络等。PoolNet作者使用了VGG16和RestNet50。

代码

由上可知,FPN结构可以分为自底向上路径和自顶向下路径。

自底向上路径即Backbone,ResNet50的代码在文件./networks/deeplab_resnet.py中的类ResNet中,VGG16的代码在文件./networks/vgg.py中的类vgg16中。

自顶向下路径由多个FUSE操作形成,PoolNet作者将FUSE操作的代码与FAM的代码一起放在了文件./networks/poolnet.py中的类DeepPoolLayer中。

FPN自底向上路径和自顶向下路径中间还有一个1×1卷积,PoolNet作者将该1×1卷积的代码和GGM的代码放在了一起。

注意:学习代码时不只可以看PoolNet官方代码,还可以看我的Boundary Aware PoolNet的代码(包含详细中文注释,链接:https://github.com/chouxianyu/Boundary-Aware-PoolNet)。

GGM

由前文可知,GGM包括PPM(Pyramid pooling module,金字塔池化模块)和GGF(Global Guiding Flows,全局指导流),其作用是在FPN自底向上路径的顶部提取显著目标的位置信息并将其提供给FPN自顶向下路径中的不同金字塔层。

传送门

PPM

PPM由PSPNet一文提出。PoolNet中使用的是修改过的PPM,其位置在自底向上路径的顶部。

PoolNet中使用的PPM包括4个子分支,PoolNet中PPM的实现如下(可结合代码理解):

  1. 用4个分支对Backbone的输出进行处理

    第1个分支为恒等映射层(即不进行处理);后3个分支分别为输出尺寸为1×1的平均池化层(即全局平均池化层)、输出尺寸为3×3的平均池化层、输出尺寸为5×5的平均池化层,并且这3个平均池化层后面都有一个1×1卷积(不改变通道数)、ReLU、上采样层(使尺寸与Backbone输出的尺寸一致)。

  2. 将4个分支的输出拼接

    首先在通道维度上将4个子分支的输出拼接,然后用3×3卷积使通道数与Backbone输出的通道数一致,再加上1个ReLU。

由上可知,PPM输出特征的尺寸、通道数与输入相同。

注意:FPN自底向上路径和自顶向下路径中间还有一个1×1卷积,PoolNet作者将这个1×1卷积放在了PPM之前。

GGF

当Backbone为ResNet50时,则需要4个GGF。

每个GGF的输入都是PPM的输出,不同GGF之间的区别是输出特征的尺寸、通道数不相同同。

每个GGF的组成为:上采样(使尺寸与对应金字塔层的尺寸一致)、3×3卷积、ReLU。

代码

FPN自底向上路径和自顶向下路径中间的1×1卷积、PPM、GGF的代码都位于类Backbone_locate中。如果Backbone是ResNet50则代码位于文件./networks/deeplab_resnet.py的类ResNet_locate中,如果Backbone是VGG16则代码位于文件./networks/vgg.py的类vgg16_locate中。

注意:学习代码时不只可以看PoolNet官方代码,还可以看我的Boundary Aware PoolNet的代码(包含详细中文注释,链接:https://github.com/chouxianyu/Boundary-Aware-PoolNet)。

FAM

由上可知,PoolNet作者在FPN自顶向下路径中每个FUSE操作前引入了FAM,其可以使来自GGM的特征与FPN自顶向下路径中不同金字塔层的特征更好地融合。

img

每个FAM包含4个子分支,如上图所示,其实现如下:

  1. 用4个分支对输入进行处理

    第1个分支为恒等映射层(即不进行处理);后3个分支分别为下采样比例为2/4/8的平均池化层,每个平均池化层后为一个3×3卷积(不改变特征的通道数和尺寸)和上采样层(使尺寸与输入特征的尺寸一致)

  2. 将4个分支的输出相加,再送入一个3×3卷积(根据设置改变或不改变通道数)

FAM和FPN的FUSE操作的代码在文件./networks/poolnet.py中的类DeepPoolLayer中。

注意:学习代码时不只可以看PoolNet官方代码,还可以看我的Boundary Aware PoolNet的代码(包含详细中文注释,链接:https://github.com/chouxianyu/Boundary-Aware-PoolNet)。


Github(github.com):@chouxianyu

Github Pages(github.io):@臭咸鱼

知乎(zhihu.com):@臭咸鱼

博客园(cnblogs.com):@臭咸鱼

B站(bilibili.com):@绝版臭咸鱼

微信公众号:@臭咸鱼

转载请注明出处,欢迎讨论和交流!