PaddleOCR模型ch_PP-OCRv3文本检测模型研究(二)颈部网络
上节研究了PaddleOCR文本检测v3模型的骨干网,本文接着研究其颈部网络。
研究起点
摘取开源yml配置文件,摘取网络架构Architecture中颈部网络的配置如下
Neck:
name: RSEFPN
out_channels: 96
shortcut: True
可以看出颈部网络的名称为RSEFPN,这个名字可以拆开来做如下理解:
- R
代表残差(Residual),即输入特征与中间输出特征做加法,形成最终输出特征。 - SE
代表压发层(Squeeze&Excitation),即通道注意力机制,通过压制与发扬,减弱低效通道作用,强化高效通道效能,详情参考上一节分析。 - FPN
代表特征金字塔(FeaturePyramidNetwork),即在各个不同尺度上提取目标特征,形成一个原始图像从整体到细节的全方位理解。参照上节的分析,骨干网通过四个阶段,分别在1/4、1/8、1/16、1/32等四个层次上进行操作。
通过搜索,可以找到RSEFPN类的定义在db_fpn.py文件的246-304行,官方链接请参考gitee。
残注层
RSELayer的代码,在db_fpn.py文件的221-243行,包含一个卷积层和一个压发层,这里将RSELayer中文名称取为残注层,意思是既有残差的含义,也有注意力机制的含义。阅读源代码,可以将RSELayer的结构图示如下:
从上到下看残注层结构示意图,首先是传入了一个输入通道数c_in的张量,结构为c_in,h,w,经过一个卷积核为k_in步长为1的卷归层的处理,输出一个结构为c_out,h,w的张量,其中c_out代表设置的输出通道数。接着是一个压发层SEModule,不改变输入张量结构。最后根据shortcut参数是否为True,来决定是否将压发层的结果与压发层的输入做加法。
颈部网络
有了上节残注层的基础知识,RSEFPN类的源码就能看懂。但代码阅读,远没有图来得直观。通过总结理解RSEFPN的代码,可以形成如下颈部网络示意图:
通过上图,可以将颈部网络划分为如下几个部分:
- 对接
需要从骨干网四个阶段输出,依此承接,参照上图左侧虚线部分,详情见上节都骨干网的分析。 - 通道统一
通过四个残注层RSELayer,将骨干网四阶段输出,统一转为96通道,宽高不变,依此形成in5/in4/in3/in2四层输出。 - 上采样
通过三个scale为2的上采样操作,将细粒度下层特征放大,并与上层结果做加法,实现各层次视觉信息的融合,依此形成out4/out3/out2 - 通道压缩
通过四个卷积核大小为3的残注层RSELayer,将上采样结果进行通道压缩,将原通道数缩为1/4,依此形成p5/p4/p3/p2 - 聚合
将通道压缩结果,依此做scale=8/4/2的上采样,将所有四层金字塔视觉信息处理成果统一转为通道数、宽、高一致的信息,在通道维度上做拼接,最终将骨干网16/24/56/480通道的四阶段输出,结果颈部网络RSEFPN的处理,形成96通道的输出,宽高与骨干网stage0的输出一致。
代码实验
下面做python的代码实践。通过paddle.summary函数调用,得到以下输出:
--------------------------------------------------------------------------------
Layer (type) Input Shape Output Shape Param #
================================================================================
Conv2D-82 [[5, 480, 2, 10]] [5, 96, 2, 10] 46,080
AdaptiveAvgPool2D-15 [[5, 96, 2, 10]] [5, 96, 1, 1] 0
Conv2D-83 [[5, 96, 1, 1]] [5, 24, 1, 1] 2,328
Conv2D-84 [[5, 24, 1, 1]] [5, 96, 1, 1] 2,400
SEModule-15 [[5, 96, 2, 10]] [5, 96, 2, 10] 0
RSELayer-7 [[5, 480, 2, 10]] [5, 96, 2, 10] 0 stage3->in5
Conv2D-76 [[5, 56, 4, 20]] [5, 96, 4, 20] 5,376
AdaptiveAvgPool2D-13 [[5, 96, 4, 20]] [5, 96, 1, 1] 0
Conv2D-77 [[5, 96, 1, 1]] [5, 24, 1, 1] 2,328
Conv2D-78 [[5, 24, 1, 1]] [5, 96, 1, 1] 2,400
SEModule-13 [[5, 96, 4, 20]] [5, 96, 4, 20] 0
RSELayer-5 [[5, 56, 4, 20]] [5, 96, 4, 20] 0 stage2->in4
Conv2D-70 [[5, 24, 8, 40]] [5, 96, 8, 40] 2,304
AdaptiveAvgPool2D-11 [[5, 96, 8, 40]] [5, 96, 1, 1] 0
Conv2D-71 [[5, 96, 1, 1]] [5, 24, 1, 1] 2,328
Conv2D-72 [[5, 24, 1, 1]] [5, 96, 1, 1] 2,400
SEModule-11 [[5, 96, 8, 40]] [5, 96, 8, 40] 0
RSELayer-3 [[5, 24, 8, 40]] [5, 96, 8, 40] 0 stage1->in3
Conv2D-64 [[5, 16, 16, 80]] [5, 96, 16, 80] 1,536
AdaptiveAvgPool2D-9 [[5, 96, 16, 80]] [5, 96, 1, 1] 0
Conv2D-65 [[5, 96, 1, 1]] [5, 24, 1, 1] 2,328
Conv2D-66 [[5, 24, 1, 1]] [5, 96, 1, 1] 2,400
SEModule-9 [[5, 96, 16, 80]] [5, 96, 16, 80] 0
RSELayer-1 [[5, 16, 16, 80]] [5, 96, 16, 80] 0 stage0->in2
Conv2D-85 [[5, 96, 2, 10]] [5, 24, 2, 10] 20,736
AdaptiveAvgPool2D-16 [[5, 24, 2, 10]] [5, 24, 1, 1] 0
Conv2D-86 [[5, 24, 1, 1]] [5, 6, 1, 1] 150
Conv2D-87 [[5, 6, 1, 1]] [5, 24, 1, 1] 168
SEModule-16 [[5, 24, 2, 10]] [5, 24, 2, 10] 0
RSELayer-8 [[5, 96, 2, 10]] [5, 24, 2, 10] 0 in5->p5
Conv2D-79 [[5, 96, 4, 20]] [5, 24, 4, 20] 20,736
AdaptiveAvgPool2D-14 [[5, 24, 4, 20]] [5, 24, 1, 1] 0
Conv2D-80 [[5, 24, 1, 1]] [5, 6, 1, 1] 150
Conv2D-81 [[5, 6, 1, 1]] [5, 24, 1, 1] 168
SEModule-14 [[5, 24, 4, 20]] [5, 24, 4, 20] 0
RSELayer-6 [[5, 96, 4, 20]] [5, 24, 4, 20] 0 out4->p4
Conv2D-73 [[5, 96, 8, 40]] [5, 24, 8, 40] 20,736
AdaptiveAvgPool2D-12 [[5, 24, 8, 40]] [5, 24, 1, 1] 0
Conv2D-74 [[5, 24, 1, 1]] [5, 6, 1, 1] 150
Conv2D-75 [[5, 6, 1, 1]] [5, 24, 1, 1] 168
SEModule-12 [[5, 24, 8, 40]] [5, 24, 8, 40] 0
RSELayer-4 [[5, 96, 8, 40]] [5, 24, 8, 40] 0 out3->p3
Conv2D-67 [[5, 96, 16, 80]] [5, 24, 16, 80] 20,736
AdaptiveAvgPool2D-10 [[5, 24, 16, 80]] [5, 24, 1, 1] 0
Conv2D-68 [[5, 24, 1, 1]] [5, 6, 1, 1] 150
Conv2D-69 [[5, 6, 1, 1]] [5, 24, 1, 1] 168
SEModule-10 [[5, 24, 16, 80]] [5, 24, 16, 80] 0
RSELayer-2 [[5, 96, 16, 80]] [5, 24, 16, 80] 0 out2->p2
================================================================================
Total params: 158,424
Trainable params: 158,424
Non-trainable params: 0
--------------------------------------------------------------------------------
Input size (MB): 0.81
Forward/backward pass size (MB): 23.39
Params size (MB): 0.60
Estimated Total Size (MB): 24.80
--------------------------------------------------------------------------------
主要输出与上节图形残注层RSELayer的对应关系,备注在行尾。
小结
本文分析了残注层RSELayer的内部结构,了解到卷归层和压发层是其内核;分析了颈部网络RSEFPN的四层金字塔结构,以及颈部网络与骨干网络的对接关系;做了简单的代码实验,将实战输出与图形描述进行了对应标注。代码实验参见gitee。
原文地址:https://blog.csdn.net/Eric_Hxy/article/details/144392686
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!