主干网络
VoVNet:实时目标检测的新backbone网络_vovnet pytorch-CSDN博客
DenseNet:
arxiv.org/pdf/1608.06993
-
密集连接:
- DenseNet 的核心思想是将网络中的每一层与其前面的所有层直接连接。对于一个 L 层的网络,DenseNet 具有 L(L+1)/2 个直接连接,而传统卷积网络只有 L 个连接。
- 这种密集连接模式可以缓解梯度消失问题,增强特征传播,鼓励特征重用,并显著减少参数数量46。
-
复合函数:
- 每一层实现一个非线性变换 𝐻𝑙(⋅)Hl(⋅),通常由批量归一化(BN)、ReLU 激活函数和 3x3 卷积组成46。
-
过渡层:
- DenseNet 通过多个密集块(Dense Block)组成,每个密集块之间通过过渡层(Transition Layer)连接。过渡层通常包括 1x1 卷积和 2x2 平均池化46。
-
增长率:
- 增长率(Growth Rate)是指每一层输出的特征图数量。DenseNet 可以具有非常窄的层,例如 k=12。增长率控制每一层向全局状态贡献的新信息的数量46。
-
瓶颈层和压缩:
- 为了提高计算效率,DenseNet 在每个 3x3 卷积之前引入了 1x1 卷积作为瓶颈层(Bottleneck Layer)。此外,DenseNet 通过在过渡层减少特征图数量来进一步提高模型的紧凑性46。
VoVNetv1:
arxiv.org/pdf/1904.09730
oVNet(Variationally Connected Network)是一种高效的卷积神经网络架构,旨在解决 DenseNet 中密集连接导致的高内存访问成本和能耗问题。VoVNet 通过引入 OSA(One-Shot Aggregation)模块来优化特征提取过程,提高了网络的效率和性能。
主要特点
-
OSA 模块:
- OSA 模块是 VoVNet 的核心组件。与 DenseNet 的逐层密集连接不同,OSA 模块在最后一次性聚合所有前面层的特征。这种设计减少了中间特征的冗余,提高了计算效率5455。
- 每个 OSA 模块内部包含多个 3x3 卷积层,最后通过拼接操作将特征聚合。
-
网络结构:
- VoVNet 由多个 OSA 模块组成,通常分为多个阶段(stages)。每个阶段的最后会采用一个 stride 为 2 的 3x3 最大池化层进行降采样,模型最终的输出步长为 3254。
- VoVNet 的初始部分是一个由 3 个 3x3 卷积层构成的 stem block,然后是 4 个阶段的 OSA 模块54。
-
优化和改进:
- VoVNetV2 在 VoVNet 的基础上进行了改进,引入了残差连接(Residual Connection)和有效的 Squeeze-Excitation(eSE)模块5556。
- 残差连接帮助缓解了深层网络的优化问题,使得 VoVNet 可以训练更深的网络55。
- eSE 模块通过避免通道维度的减少,保持了通道信息,提高了模型性能55。
VoVNetv2:1911.06667 (arxiv.org)
OSA 模块全称为 "One-Shot Aggregation" 模块
PP-HGNet:
HGNet 作者针对 GPU 设备,对目前 GPU 友好的网络做了分析和归纳,尽可能多的使用 3x3 标准卷积(计算密度最高)。在此将 VOVNet 作为基准模型,将主要的有利于 GPU 推理的改进点进行融合。从而得到一个有利于 GPU 推理的骨干网络,同样速度下,精度大幅超越其他 CNN 或者 VisionTransformer 模型。
PP-HGNet 骨干网络的整体结构如下:
其中,PP-HGNet是由多个HG-Block组成,HG-Block的细节如下:
PP-HGNet 和 VoVNet 之间:
-
基础模型:
- PP-HGNet 是在 VoVNet 的基础上开发的模型。VoVNet 是一种卷积神经网络架构,旨在通过引入多尺度特征融合来提高模型的性能和效率。
- PP-HGNet 继承了 VoVNet 的基本结构,并在此基础上进行了优化和改进2627。
-
优化和改进:
- PP-HGNet 使用了可学习的下采样层(LDS Layer),这是一种新的下采样方法,可以在减少计算负载的同时增加感受野。
- PP-HGNet 还融合了 ResNet_vd 等模型的优点,进一步提高了模型的性能26。
- 在 GPU 平台上,PP-HGNet 通过使用 3x3 标准卷积(计算密度最高)和其他有利于 GPU 推理的改进点,显著提高了推理速度和精度
PP-HGHetv2
PP-HGNetV2 是 PP-HGNetV1 的改进版本,在多个方面进行了优化和增强,以提高模型的性能和效率。以下是 PP-HGNetV2 和 PP-HGNetV1 的主要区别:
1. 改进的 Stem 部分
- PP-HGNetV1:使用标准的卷积层进行初始特征提取。
- PP-HGNetV2:堆叠更多的 2x2 卷积核以学习更丰富的局部特征,并使用更小的通道数以提升大分辨率任务如目标检测、语义分割等的推理速度。
2. 优化的卷积层
- PP-HGNetV1:使用标准的卷积层进行特征提取。
- PP-HGNetV2:替换了靠后 stage 的较冗余的标准卷积层该为 Pointwise Convolution (PW) + Depthwise Convolution (DW)5x5 组合,在获得更大感受野的同时减少了网络的参数量,并进一步提升了精度。
3. LearnableAffineBlock 模块
- PP-HGNetV1:没有此模块。
- PP-HGNetV2:增加了 LearnableAffineBlock 模块,可以在增加极少参数量的同时大幅提升较小模型的精度,对推理时间无损。
4. 重构的 Stage 分布
- PP-HGNetV1:原有的 stage 分布。
- PP-HGNetV2:重构了网络的 stage 分布,使其涵盖了从 B0-B6 不同量级的模型,从而满足不同任务的需求。
5. SSLD 预训练权重
- PP-HGNetV1:使用标准的预训练权重。
- PP-HGNetV2:提供了精度更高、泛化能力更强的 SSLD 预训练权重,在下游任务中表现更佳。
6. 性能和效率
- PP-HGNetV1:在相同速度下,精度高于 ResNet34-D 模型 3.8 个百分点,高于 ResNet50-D 模型 2.4 个百分点。
- PP-HGNetV2:在相同速度下,精度进一步提升,并且在使用百度自研 SSLD 蒸馏策略后,超越 ResNet50-D 模型 4.7 个百分点。
MobileNets
图图1 标准卷积和深度可分离卷积
MobileNetV1将普通卷积替换为深度卷积和逐点卷积。普通卷积的卷积核是直接用在所有的输入通道上,而深度卷积分为两部分进行计算,首先按照通道分别对特征图分别进行卷积,并将输出特征图进行拼接,随后使用逐点卷积进行通道卷积得到特征图,逐点卷积是卷积核为1x1的卷积,通道数和输入特征图一致。理论上如果MobileNetV1采用3x3卷积核,那么深度可分离卷积相较普通卷积可以降低大约9倍的计算量。
MobileNetV2
普通的残差结构先用1x1的卷积降维,再升维的操作。在MobileNetV2却是相反的操作,原因是将残差块替换为了深度可分离卷积之后,参数减少,提取的特征也相对减少,如果再进行压缩的话,能提取的特征就更少了,MobileNetV2为了避免特征减少需要先扩张高维,再经过深度可分离卷积提取特征,随后将卷积提取的特征降到低维。因此残差结构是先升维,再降维的操作。由于ReLU6激活函数对于低维的信息可能会造成比较大的瞬损失,对于高维的特征信息造成的损失很小。所以使用一个线性的激活函数避免特征损失。
通过下图可以看出,左侧为ResNet中的残差结构,其结构为1x1卷积降维->3x3卷积->1x1卷积升维;右侧为MobileNetV2中的倒残差结构,其结构为1x1卷积升维->3x3DW卷积->1x1卷积降维。V2先使用1x1进行升维的原因也是前面所说的高维信息通过ReLU激活函数后丢失的信息更少。
需要注意的是只有当s=1,即步长为1时,才有shortcut连接,步长为2是没有的
在使用 MobileNetV1时,DW 部分的卷积核容易失效,即卷积核内数值大部分为零。作者认为这是 ReLU 引起的,在变换过程中,需要将低维信息映射到高维空间,再经 ReLU 重新映射回低维空间。若输出的维度相对较高,则变换过程中信息损失较小;若输出的维度相对较低,则变换过程中信息损失很大,如下图所示深度学习基础--Bottleneck(瓶颈) Architectures_a bottleneck architecture-CSDN博客:
需要注意的是步距s,当有多个bottleneck,s只针对第一个bottleneck,后面s都为1。
MobileNetV3
MobileNetV3进一步使用AutoML技术用更少的FLOPs获得了更好的性能。在残差中加入了 SE 模块,即注意力机制;更新了激活函数。该函数具有无上界、有下界、平滑、非单调的特点,在深层模型上优于ReLU。但是,由于sigmoid函数计算复杂(sigmoid(x) = (1 + exp(-x))^(-1)),所以V3改用近似函数来逼近swish,这使其变得更硬(hard)。作者选择了ReLU6作为这个近似函数,有两个原因:1、在几乎所有的软件和硬件框架上都可以使用ReLU6的优化实现;2、ReLU6能在特定模式下消除由于近似sigmoid的不同实现而带来的潜在的数值精度损失。
高层网络使用5x5卷积是为了捕获更大范围的空间信息,这有助于提高网络的感知能力和特征提取效果3。此外,5x5卷积还可以帮助网络更好地理解图像中的全局结构和上下文信息,从而提升网络的性能和准确性
详细且通俗讲解轻量级神经网络——MobileNets【V1、V2、V3】-云社区-华为云 (huaweicloud.com)
PP-LCNet
PP-LCNet是Mobilenetv1的变体,同时吸收Mobilenetv3中高层使用5X5卷积,卷积中使用SEnet和激活函数使用h-swish
neck
1. FPN(Feature Pyramid Network)
FPN是一种常用的neck架构,广泛应用于目标检测和分割任务中。其主要思想是通过自顶向下的路径和横向连接,融合来自不同尺度的特征图,从而生成多尺度的特征表示。
主要特点:
多尺度特征融合:通过在不同尺度上融合特征图,使得网络能够更好地检测不同大小的目标。.
自顶向下路径:从高层次特征向低层次特征传播,增强了低层次特征的表达能力。
横向连接:在自顶向下路径中添加横向连接,以保证不同尺度特征的有效融合。.
2.PANet (Path Aggregation Network)
PANet是对FPN的改进,进一步增强了特征融合的能力,特别是在细粒度特征上的表现。
主要特点:
增强的特征融合路径:增加了自底向上的路径,使得信息不仅从高层次特征传递到低层次特征也能从低层次特征传递到高层次特征。
自适应特征池化:通过自适应的特征池化操作,进一步提升了特征融合的效果
Head
DBNet:Real-time Scene Text Detection with Differentiable BinarizationReal-time Scene Text Detection with Differentiable Binarization
DBNet(Differentiable Binarization Network)是一种用于实时场景文本检测的高效算法,通过引入可微分二值化模块来优化分割预测结果。以下是对 DBNet 的详细介绍:
主要特点
-
可微分二值化(Differentiable Binarization, DB):
- DBNet 的核心思想是将二值化过程引入到网络中,使其成为可微分的部分,从而在训练过程中自适应地学习二值化阈值。这种设计不仅简化了后处理过程,还提高了文本检测的性能。
-
高效的文本检测:
- DBNet 在多个场景文本检测数据集上表现出色,包括水平文本、多方向文本和曲形文本。其检测效果和速度均优于其他算法。
-
轻量级网络:
- 即使使用轻量级的 ResNet-18 作为主干网络,DBNet 也能取得很好的检测效果,这使得它在检测精度和效率之间找到了理想的折衷方案。
DBNet++:Real-Time Scene Text Detection with Differentiable Binarization and Adaptive Scale Fusion
-
自适应多尺度融合(Adaptive Scale Fusion, ASF)模块:
- ASF 模块用于动态聚合多尺度特征图,通过引入空间注意力机制,使得融合后的特征更加鲁棒。
- ASF 是一个逐层注意力模块,能够在空间维度学习不同尺度和不同空间位置的权重,达到尺度鲁棒的特征融合。
PFhead:多分支融合Head结构
PFhead结构如下图所示,PFHead在经过第一个转置卷积后,分别进行上采样和转置卷积,上采样的输出通过3x3卷积得到输出结果,然后和转置卷积的分支的结果级联并经过1x1卷积层,最后1x1卷积的结果和转置卷积的结果相加得到最后输出的概率图。PP-OCRv4学生检测模型使用PFhead,hmean从76.22%增加到76.97%。
PaddleOCR/ppocr/modeling/heads/det_db_head.py at main · PaddlePaddle/PaddleOCR · GitHub
class DBHead(nn.Layer):
"""
Differentiable Binarization (DB) for text detection:
see https://arxiv.org/abs/1911.08947
args:
params(dict): super parameters for build DB network
"""
def __init__(self, in_channels, k=50, **kwargs):
super(DBHead, self).__init__()
self.k = k
self.binarize = Head(in_channels, **kwargs)
self.thresh = Head(in_channels, **kwargs)
def step_function(self, x, y):
return paddle.reciprocal(1 + paddle.exp(-self.k * (x - y)))
def forward(self, x, targets=None):
shrink_maps = self.binarize(x)
if not self.training:
return {"maps": shrink_maps}
threshold_maps = self.thresh(x)
binary_maps = self.step_function(shrink_maps, threshold_maps)
y = paddle.concat([shrink_maps, threshold_maps, binary_maps], axis=1)
return {"maps": y}
class LocalModule(nn.Layer):
def __init__(self, in_c, mid_c, use_distance=True):
super(self.__class__, self).__init__()
self.last_3 = ConvBNLayer(in_c + 1, mid_c, 3, 1, 1, act="relu")
self.last_1 = nn.Conv2D(mid_c, 1, 1, 1, 0)
def forward(self, x, init_map, distance_map):
outf = paddle.concat([init_map, x], axis=1)
# last Conv
out = self.last_1(self.last_3(outf))
return out
class PFHeadLocal(DBHead):
def __init__(self, in_channels, k=50, mode="small", **kwargs):
super(PFHeadLocal, self).__init__(in_channels, k, **kwargs)
self.mode = mode
self.up_conv = nn.Upsample(scale_factor=2, mode="nearest", align_mode=1)
if self.mode == "large":
self.cbn_layer = LocalModule(in_channels // 4, in_channels // 4)
elif self.mode == "small":
self.cbn_layer = LocalModule(in_channels // 4, in_channels // 8)
def forward(self, x, targets=None):
shrink_maps, f = self.binarize(x, return_f=True)
base_maps = shrink_maps
cbn_maps = self.cbn_layer(self.up_conv(f), shrink_maps, None)
cbn_maps = F.sigmoid(cbn_maps)
if not self.training:
return {"maps": 0.5 * (base_maps + cbn_maps), "cbn_maps": cbn_maps}
threshold_maps = self.thresh(x)
binary_maps = self.step_function(shrink_maps, threshold_maps)
y = paddle.concat([cbn_maps, threshold_maps, binary_maps], axis=1)
return {"maps": y, "distance_maps": cbn_maps, "cbn_maps": binary_maps}