YOLOv5改进系列(十六) 引入FasterNet中的PConv,backbone

文章目录

  • 原理
    • 1、简介
    • 2、PConv和FasterNet的设计
      • 2.1、原理
      • 2.2、PConv作为一个基本的算子
      • 2.3、PConv之后是PWConv
      • 2.4、FasterNet作为Backbone
      • 2.5、代码实现
    • 3、实验
      • 3.1、PConv的快速性与高Flops
      • 3.2、PConv与PWConv一起有效
      • 3.3、FasterNet on ImageNet-1k
      • 3.4、FasterNet在下游任务的表现
        • 1、目标检测
      • 3.5、消融实验
  • PConv接入YOLOv5
    • YOLO算法添加方式
    • YOLOv5s-PConv.yaml
  • 引入FasterNet之backbone
    • `common.py`中添加如下代码:
    • YOLOv5-FasterNet.yaml


为了设计快速神经网络,许多工作都集中在减少浮点运算(FLOPs)的数量上。然而,作者观察到FLOPs的这种减少不一定会带来延迟的类似程度的减少。这主要源于每秒低浮点运算(FLOPS)效率低下。

为了实现更快的网络,作者重新回顾了FLOPs的运算符,并证明了如此低的FLOPS主要是由于运算符的频繁内存访问,尤其是深度卷积。因此,本文提出了一种新的partial convolution(PConv),通过同时减少冗余计算和内存访问可以更有效地提取空间特征。

基于PConv进一步提出FasterNet,这是一个新的神经网络家族,它在广泛的设备上实现了比其他网络高得多的运行速度,而不影响各种视觉任务的准确性。例如,在ImageNet-1k上小型FasterNet-T0在GPU、CPU和ARM处理器上分别比MobileVitXXS快3.1倍、3.1倍和2.5倍,同时准确度提高2.9%。

大模型FasterNet-L实现了令人印象深刻的83.5%的TOP-1精度,与Swin-B不相上下,同时GPU上的推理吞吐量提高了49%,CPU上的计算时间也节省了42%。

原理

1、简介

神经网络在图像分类、检测和分割等各种计算机视觉任务中经历了快速发展。尽管其令人印象深刻的性能为许多应用程序提供了动力,但一个巨大的趋势是追求具有低延迟和高吞吐量的快速神经网络,以获得良好的用户体验、即时响应和安全原因等。

如何快速?研究人员和从业者不需要更昂贵的计算设备,而是倾向于设计具有成本效益的快速神经网络,降低计算复杂度,主要以浮点运算(FLOPs)的数量来衡量。

MobileNet、ShuffleNet和GhostNet等利用深度卷积(DWConv)和/或组卷积(GConv)来提取空间特征。然而,在减少FLOPs的过程中,算子经常会受到内存访问增加的副作用的影响。MicroNet进一步分解和稀疏网络,将其FLOPs推至极低水平。尽管这种方法在FLOPs方面有所改进,但其碎片计算效率很低。此外,上述网络通常伴随着额外的数据操作,如级联、Shuffle和池化,这些操作的运行时间对于小型模型来说往往很重要。

除了上述纯卷积神经网络(CNNs)之外,人们对使视觉Transformer(ViTs)和多层感知器(MLP)架构更小更快也越来越感兴趣。例如,MobileViT和MobileFormer通过将DWConv与改进的注意力机制相结合,降低了计算复杂性。然而,它们仍然受到DWConv的上述问题的困扰,并且还需要修改的注意力机制的专用硬件支持。使用先进但耗时的标准化和激活层也可能限制其在设备上的速度。

所有这些问题一起导致了以下问题:这些“快速”的神经网络真的很快吗?为了回答这个问题,作者检查了延迟和FLOPs之间的关系,这由

220af10b3dad8811db903fd47203c1de.png

其中FLOPS是每秒浮点运算的缩写,作为有效计算速度的度量。虽然有许多减少FLOPs的尝试,但都很少考虑同时优化FLOPs以实现真正的低延迟。为了更好地理解这种情况,作者比较了Intel CPU上典型神经网络的FLOPS。

521b01dd4db339e6f6d40d13f9ed9858.png

图2中的结果表明,许多现有神经网络的FLOPS较低,其FLOPS通常低于流行的ResNet50。由于FLOPS如此之低,这些“快速”的神经网络实际上不够快。它们的FLOPs减少不能转化为延迟的确切减少量。在某些情况下,没有任何改善,甚至会导致更糟的延迟。例如,CycleMLP-B1具有ResNet50的一半FLOPs,但运行速度较慢(即CycleMLPB1与ResNet50:111.9ms与69.4ms)。

请注意,FLOPs与延迟之间的差异在之前的工作中也已被注意到,但由于它们采用了DWConv/GConv和具有低FLOPs的各种数据处理,因此部分问题仍未解决。人们认为没有更好的选择。

本文旨在通过开发一种简单、快速、有效的运算符来消除这种差异,该运算符可以在减少FLOPs的情况下保持高FLOPS。

具体来说,作者重新审视了现有的操作符,特别是DWConv的计算速度——FLOPS。作者发现导致低FLOPS问题的主要原因是频繁的内存访问。然后,作者提出了PConv作为一种竞争性替代方案,它减少了计算冗余以及内存访问的数量。

图1说明了PConv的设计。它利用了特征图中的冗余,并系统地仅在一部分输入通道上应用规则卷积(Conv),而不影响其余通道。本质上,PConv的FLOPs低于常规Conv,而FLOPs高于DWConv/GConv。换句话说,PConv更好地利用了设备上的计算能力。PConv在提取空间特征方面也很有效,这在本文后面的实验中得到了验证。

作者进一步引入PConv设计了FasterNet作为一个在各种设备上运行速度非常快的新网络家族。特别是,FasterNet在分类、检测和分割任务方面实现了最先进的性能,同时具有更低的延迟和更高的吞吐量。例如,在GPU、CPU和ARM处理器上,小模型FasterNet-T0分别比MobileVitXXS快3.1倍、3.1倍和2.5倍,而在ImageNet-1k上的准确率高2.9%。大模型FasterNet-L实现了83.5%的Top-1精度,与Swin-B不相上下,同时在GPU上提供了49%的高吞吐量,在CPU上节省了42%的计算时间。

总之,贡献如下:

  • 指出了实现更高FLOPS的重要性,而不仅仅是为了更快的神经网络而减少FLOPs。
  • 引入了一种简单但快速且有效的卷积PConv,它很有可能取代现有的选择DWConv。
  • 推出FasterNet,它在GPU、CPU和ARM处理器等多种设备上运行良好且普遍快速。
  • 对各种任务进行了广泛的实验,并验证了PConv和FasterNet的高速性和有效性。

2、PConv和FasterNet的设计

2.1、原理

ff4fabcc7c694cbad655abab99753308.png

DWConv是Conv的一种流行变体,已被广泛用作许多神经网络的关键构建块。对于输入,DWConv应用个滤波器来计算输出。如图1(b)所示,每个滤波器在一个输入通道上进行空间滑动,并对一个输出通道做出贡献。

与具有的FLOPs常规Conv相比,这种深度计算使得DWConv仅仅具有的FLOPs。虽然在减少FLOPs方面有效,但DWConv(通常后跟逐点卷积或PWConv)不能简单地用于替换常规Conv,因为它会导致严重的精度下降。因此,在实践中,DWConv的通道数(或网络宽度)增加到>以补偿精度下降,例如,倒置残差块中的DWConv宽度扩展了6倍。然而,这会导致更高的内存访问,这会造成不可忽略的延迟,并降低总体计算速度,尤其是对于I/O绑定设备。特别是,内存访问的数量现在上升到

f6778ee0d5b996986d5580aff6157374.png

它比一个常规的Conv的值要高,即,

57a227f50af53f9a1ff5167643c7deef.png

注意,内存访问花费在I/O操作上,这被认为已经是最小的成本,很难进一步优化。

2.2、PConv作为一个基本的算子

7fb8f8759aafd34237838e74b6ebda6d.png

在下面演示了通过利用特征图的冗余度可以进一步优化成本。如图3所示,特征图在不同通道之间具有高度相似性。许多其他著作也涵盖了这种冗余,但很少有人以简单而有效的方式充分利用它。

f17b7a11d0da0951dac414fcb5512b5d.png

具体而言,作者提出了一种简单的PConv,以同时减少计算冗余和内存访问。图4中的左下角说明了PConv的工作原理。它只需在输入通道的一部分上应用常规Conv进行空间特征提取,并保持其余通道不变。对于连续或规则的内存访问,将第一个或最后一个连续的通道视为整个特征图的代表进行计算。在不丧失一般性的情况下认为输入和输出特征图具有相同数量的通道。因此,PConv的FLOPs仅

4d1b7a54e4863a2f919688db52235a92.png

对于典型的r=1/4 ,PConv的FLOPs只有常规Conv的1/16。此外,PConv的内存访问量较小,即:

36e1a3e512a9423bbe5d0df3802cfcfd.png

对于r=1/4,其仅为常规Conv的1/4。

由于只有通道用于空间特征提取,人们可能会问是否可以简单地移除剩余的(c−)通道?如果是这样,PConv将退化为具有较少通道的常规Conv,这偏离了减少冗余的目标。

请注意,保持其余通道不变,而不是从特征图中删除它们。这是因为它们对后续PWConv层有用,PWConv允许特征信息流经所有通道。

2.3、PConv之后是PWConv

2b08187a321d871be0e9ff3cfa358f42.png

为了充分有效地利用来自所有通道的信息,进一步将逐点卷积(PWConv)附加到PConv。它们在输入特征图上的有效感受野看起来像一个T形Conv,与均匀处理补丁的常规Conv相比,它更专注于中心位置,如图5所示。为了证明这个T形感受野的合理性,首先通过计算位置的Frobenius范数来评估每个位置的重要性。

假设,如果一个职位比其他职位具有更大的Frobenius范数,则该职位往往更重要。对于正则Conv滤波器,位置处的Frobenius范数由计算,其中。

751a29f6303e6747692bf06eb0cab15a.png

作者认为一个显著位置是具有最大Frobenius范数的位置。然后,在预训练的ResNet18中集体检查每个过滤器,找出它们的显著位置,并绘制显著位置的直方图。图6中的结果表明,中心位置是过滤器中最常见的突出位置。换句话说,中心位置的权重比周围的更重。这与集中于中心位置的T形计算一致。

虽然T形卷积可以直接用于高效计算,但作者表明,将T形卷积分解为PConv和PWConv更好,因为该分解利用了滤波器间冗余并进一步节省了FLOPs。对于相同的输入和输出,T形Conv的FLOPs可以计算为:

dba14a089eb779564b00bbce7ec512fc.png

它高于PConv和PWConv的流量,即:

d7fc5b7c2498004ef230b20670fa20b3.png

其中和(例如,当时)。此外,可以很容易地利用常规Conv进行两步实现。

2.4、FasterNet作为Backbone

鉴于新型PConv和现成的PWConv作为主要的算子,进一步提出FasterNet,这是一个新的神经网络家族,运行速度非常快,对许多视觉任务非常有效。作者的目标是使体系结构尽可能简单,使其总体上对硬件友好。

95e151768389b91b721e71f0231d3193.png

在图4中展示了整体架构。它有4个层次级,每个层次级前面都有一个嵌入层(步长为4的常规4×4卷积)或一个合并层(步长为2的常规2×2卷积),用于空间下采样和通道数量扩展。每个阶段都有一堆FasterNet块。作者观察到,最后两个阶段中的块消耗更少的内存访问,并且倾向于具有更高的FLOPS,如表1中的经验验证。因此,放置了更多FasterNet块,并相应地将更多计算分配给最后两个阶段。每个FasterNet块有一个PConv层,后跟2个PWConv(或Conv 1×1)层。它们一起显示为倒置残差块,其中中间层具有扩展的通道数量,并且放置了Shorcut以重用输入特征。

除了上述算子,标准化和激活层对于高性能神经网络也是不可或缺的。然而,许多先前的工作在整个网络中过度使用这些层,这可能会限制特征多样性,从而损害性能。它还可以降低整体计算速度。相比之下,只将它们放在每个中间PWConv之后,以保持特征多样性并实现较低的延迟。

此外,使用批次归一化(BN)代替其他替代方法。BN的优点是,它可以合并到其相邻的Conv层中,以便更快地进行推断,同时与其他层一样有效。对于激活层,根据经验选择了GELU用于较小的FasterNet变体,而ReLU用于较大的FasterNet变体,同时考虑了运行时间和有效性。最后三个层,即全局平均池化、卷积1×1和全连接层,一起用于特征转换和分类。

为了在不同的计算预算下提供广泛的应用,提供FasterNet的Tiny模型、Small模型、Medium模型和Big模型变体,分别称为FasterNetT0/1/2、FasterNet-S、FasterNet-M和FasterNet-L。它们具有相似的结构,但深度和宽度不同。

架构规范如下:

21721ed51d6034e1b280202839cbeca8.png

2.5、代码实现

9288354af8554be5b20d4e785d128b67.png

3、实验

3.1、PConv的快速性与高Flops

59cc630ab9ad3c661f91dfb442e014e9.png

3.2、PConv与PWConv一起有效

7301c597c91b83679120a3186d2502f7.png

3.3、FasterNet on ImageNet-1k

b836c5bd1d93d6333d7c26c93bfc9436.pngc87650c4692013a5e8cf36686b6ab339.png

3.4、FasterNet在下游任务的表现

1、目标检测

15a03d22fd4bdd813ddd0ba2b5f674a6.png

3.5、消融实验

28d9d74f061f9a7c65b0980443b0f21c.png

PConv接入YOLOv5


YOLO算法添加方式

值得注意的是,PConvFasterNet中提出的卷积算子,这篇文章介绍的是PConv的使用方式:

第一步

common.py中添加如下的代码:

"""
https://arxiv.org/abs/2303.03667
<<Run, Don't Walk: Chasing Higher FLOPS for Faster Neural Networks>>
"""
from collections import OrderedDict
from functools import partial
from typing import List
from torch import Tensor


class PConv2d(nn.Module):
    def __init__(self,
                 in_channels,
                 kernel_size=3,
                 n_div: int = 4,
                 forward: str = 'split_cat'):
        super(PConv2d, self).__init__()
        assert in_channels > 4, "in_channels should > 4, but got {} instead.".format(in_channels)
        self.dim_conv = in_channels // n_div  # 计算分割后的卷积通道数
        self.dim_untouched = in_channels - self.dim_conv  # 未分割的通道数

        self.conv = nn.Conv2d(in_channels=self.dim_conv,
                              out_channels=self.dim_conv,
                              kernel_size=kernel_size,
                              stride=1,
                              padding=(kernel_size - 1) // 2,
                              bias=False)

        if forward == 'slicing':
            self.forward = self.forward_slicing

        elif forward == 'split_cat':
            self.forward = self.forward_split_cat

        else:
            raise NotImplementedError("forward method: {} is not implemented.".format(forward))

    def forward_slicing(self, x: Tensor) -> Tensor:
        # 在这个forward方法中,通过切片的方式进行卷积操作,只对部分通道进行卷积
        x[:, :self.dim_conv, :, :] = self.conv(x[:, :self.dim_conv, :, :])

        return x

    def forward_split_cat(self, x: Tensor) -> Tensor:
        # 在这个forward方法中,将输入张量分割为两部分,对第一部分进行卷积,然后将两部分连接起来
        x1, x2 = torch.split(x, [self.dim_conv, self.dim_untouched], dim=1)
        x1 = self.conv(x1)  # 对第一部分进行卷积
        x = torch.cat((x1, x2), dim=1)  # 连接两部分

        return x

第二步

我们需要在yolo.py中添加如下的代码,v7v5是一致的:

        elif m is PConv2d: 
            c1 = ch[f]
            args = [c1, *args[0:]]

第三步

修改模型yaml文件,千万注意args参数的写法,不需要改变通道,直接保持写 [3, 4] 就行,后面可以选择'split_cat'或者'slicing'


YOLOv5s-PConv.yaml

YOLOv5s.yaml文件写法,我这里给一个参考,我是直接替换的C3,但是我加深了PConv2d模块的深度,大家可以灵活使用:

# Parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
   [-1, 1, Conv, [128, 3, 2]],    # 1-P2/4
   [-1, 6, PConv2d, [3, 4, 'split_cat']], # 'split_cat' or 'slicing'
   [-1, 1, Conv, [256, 3, 2]],    # 3-P3/8
   [-1, 9, PConv2d, [3, 4, 'split_cat']],
   [-1, 1, Conv, [512, 3, 2]],    # 5-P4/16
   [-1, 12,PConv2d, [3, 4, 'split_cat']],
   [-1, 1, Conv, [1024, 3, 2]],   # 7-P5/32
   [-1, 6, PConv2d, [3, 4, 'split_cat']],
   [-1, 1, SPPF, [1024,5]],       # 9
  ]

# YOLOv5 head
head:
  [[-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, SE, [16]],     # 18  ---> You can add your attention module name here

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 14], 1, Concat, [1]],  # cat head P4
   [-1, 3, C3, [512, False]],   # 21 (P4/16-medium)
   [-1, 1, SE, [16]],   # 22  ---> You can add your attention module name here

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # 24 cat head P5
   [-1, 3, C3, [1024, False]],  # 25 (P5/32-large)
   [-1, 1, SE, [16]], # 26   ---> You can add your attention module name here

   [[18, 22, 26], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

引入FasterNet之backbone

common.py中添加如下代码:

"""
https://arxiv.org/abs/2303.03667
<<Run, Don't Walk: Chasing Higher FLOPS for Faster Neural Networks>>
"""
# --------------------------FasterNet----------------------------
from timm.models.layers import DropPath


class Partial_conv3(nn.Module):
    def __init__(self, dim, n_div, forward):
        super().__init__()
        self.dim_conv3 = dim // n_div
        self.dim_untouched = dim - self.dim_conv3
        self.partial_conv3 = nn.Conv2d(self.dim_conv3, self.dim_conv3, 3, 1, 1, bias=False)

        if forward == 'slicing':
            self.forward = self.forward_slicing
        elif forward == 'split_cat':
            self.forward = self.forward_split_cat
        else:
            raise NotImplementedError

    def forward_slicing(self, x):
        # only for inference
        x = x.clone()  # !!! Keep the original input intact for the residual connection later
        x[:, :self.dim_conv3, :, :] = self.partial_conv3(x[:, :self.dim_conv3, :, :])

        return x

    def forward_split_cat(self, x):
        # for training/inference
        x1, x2 = torch.split(x, [self.dim_conv3, self.dim_untouched], dim=1)
        x1 = self.partial_conv3(x1)
        x = torch.cat((x1, x2), 1)
        return x


class MLPBlock(nn.Module):
    def __init__(self,
                 dim,
                 n_div,
                 mlp_ratio,
                 drop_path,
                 layer_scale_init_value,
                 act_layer,
                 norm_layer,
                 pconv_fw_type
                 ):

        super().__init__()
        self.dim = dim
        self.mlp_ratio = mlp_ratio
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.n_div = n_div

        mlp_hidden_dim = int(dim * mlp_ratio)
        mlp_layer = [
            nn.Conv2d(dim, mlp_hidden_dim, 1, bias=False),
            norm_layer(mlp_hidden_dim),
            act_layer(),
            nn.Conv2d(mlp_hidden_dim, dim, 1, bias=False)
        ]
        self.mlp = nn.Sequential(*mlp_layer)
        self.spatial_mixing = Partial_conv3(
            dim,
            n_div,
            pconv_fw_type
        )
        if layer_scale_init_value > 0:
            self.layer_scale = nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True)
            self.forward = self.forward_layer_scale
        else:
            self.forward = self.forward

    def forward(self, x):
        shortcut = x
        x = self.spatial_mixing(x)
        x = shortcut + self.drop_path(self.mlp(x))
        return x

    def forward_layer_scale(self, x):
        shortcut = x
        x = self.spatial_mixing(x)
        x = shortcut + self.drop_path(
            self.layer_scale.unsqueeze(-1).unsqueeze(-1) * self.mlp(x))
        return x


class BasicStage(nn.Module):
    def __init__(self,
                 dim,
                 depth=1,
                 n_div=4,
                 mlp_ratio=2,
                 layer_scale_init_value=0,
                 norm_layer=nn.BatchNorm2d,
                 act_layer=nn.ReLU,
                 pconv_fw_type='split_cat'
                 ):
        super().__init__()
        dpr = [x.item()
               for x in torch.linspace(0, 0.0, sum([1, 2, 8, 2]))]
        blocks_list = [
            MLPBlock(
                dim=dim,
                n_div=n_div,
                mlp_ratio=mlp_ratio,
                drop_path=dpr[i],
                layer_scale_init_value=layer_scale_init_value,
                norm_layer=norm_layer,
                act_layer=act_layer,
                pconv_fw_type=pconv_fw_type
            )
            for i in range(depth)
        ]

        self.blocks = nn.Sequential(*blocks_list)

    def forward(self, x):
        x = self.blocks(x)
        return x


class PatchEmbed_FasterNet(nn.Module):

    def __init__(self, in_chans, embed_dim, patch_size, patch_stride, norm_layer=nn.BatchNorm2d):
        super().__init__()
        self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_stride, bias=False)
        if norm_layer is not None:
            self.norm = norm_layer(embed_dim)
        else:
            self.norm = nn.Identity()

    def forward(self, x):
        x = self.norm(self.proj(x))
        return x

    def fuseforward(self, x):
        x = self.proj(x)
        return x


class PatchMerging_FasterNet(nn.Module):

    def __init__(self, dim, out_dim, k, patch_stride2, norm_layer=nn.BatchNorm2d):
        super().__init__()
        self.reduction = nn.Conv2d(dim, out_dim, kernel_size=k, stride=patch_stride2, bias=False)
        if norm_layer is not None:
            self.norm = norm_layer(out_dim)
        else:
            self.norm = nn.Identity()

    def forward(self, x):
        x = self.norm(self.reduction(x))
        return x

    def fuseforward(self, x):
        x = self.reduction(x)
        return x

# -----------------------------------

第二步yolo.py中添加如下代码

[BasicStage, PatchEmbed_FasterNet, PatchMerging_FasterNet]

            elif m in [BasicStage]:
                args.pop(1)

在这里插入图片描述
请大家看好这个缩进的位置!!!很容易出错!!

在这里插入图片描述

随后依然在 yolo.pyctrl + F 搜索 for m in self.model.modules(): ,定位到如下位置,在如下位置继续添加代码:

在这里插入图片描述

            if type(m) is PatchEmbed_FasterNet:
                m.proj = fuse_conv_and_bn(m.proj, m.norm)
                delattr(m, 'norm')  # remove BN
                m.forward = m.fuseforward
            if type(m) is PatchMerging_FasterNet:
                m.reduction = fuse_conv_and_bn(m.reduction, m.norm)
                delattr(m, 'norm')  # remove BN
                m.forward = m.fuseforward

YOLOv5-FasterNet.yaml

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple

anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, PatchEmbed_FasterNet, [40, 4, 4]],  # 0-P1/4
   [-1, 1, BasicStage, [40, 1]],  # 1
   [-1, 1, PatchMerging_FasterNet, [80, 2, 2]],  # 2-P2/8
   [-1, 2, BasicStage, [80, 1]],  # 3-P3/16
   [-1, 1, PatchMerging_FasterNet, [160, 2, 2]],  # 4
   [-1, 8, BasicStage, [160, 1]],  # 5-P4/32
   [-1, 1, PatchMerging_FasterNet, [320, 2, 2]], # 6
   [-1, 2, BasicStage, [320, 1]], # 7
   [-1, 1, SPPF, [320, 5]],  # 8
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 5], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [256, False]],  # 12

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

   [-1, 1, Conv, [128, 3, 2]],
   [[-1, 13], 1, Concat, [1]],  # cat head P4
   [-1, 3, C3, [256, False]],  # 19 (P4/16-medium)

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 9], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [512, False]],  # 22 (P5/32-large)

   [[16, 19, 22], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]
  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小酒馆燃着灯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值