VAN:Visual Attention Network

Visual Attention Network

[Submitted on 20 Feb 2022 (v1), last revised 11 Jul 2022 (this version, v5)]

Computer Vision and Pattern Recognition

https://github.com/Visual-Attention-Network

关键词:Attention, Vision Backbone, Deep Learning, ConvNets

0摘要:

虽然最初是为自然语言处理任务而设计的,但自注意机制最近已经席卷了各种计算机视觉领域。然而,图像的2D特性给在计算机视觉中应用自注意机制带来了三个挑战。

(1) 将图像处理为1D序列忽略了它们的2D结构。

(2) 二次复杂度对于高分辨率图像来说太昂贵了。

(3) 它只捕捉空间适应性,而忽略了通道适应性。

【视觉的注意力可以被分为四个类别: 通道注意力、空间注意力、时间注意力和分支注意力。】

在本文中,提出了一种新的线性注意力,称为大核注意力(LKA)模块,以在自注意力中实现自适应和长程相关性(long-range correlations,所以长程依赖可以理解为:当你想使用语言模型,并有效利用较早时间步的信息,最终产生预测的时候,那么你就要和较长路程前的信息建立一种依赖关系,这就是长程依赖。),同时避免其缺点。此外,还提出了一种基于LKA的神经网络,即视觉注意网络(VAN)。尽管极为简单,但VAN在各种任务(包括图像分类、对象检测、语义分割、全景分割、姿态估计等)中都超过了类似尺寸的视觉transformer(ViT)和卷积神经网络(CNN)。

1简介

本文的贡献总结如下:

  • 为计算机视觉设计了一种新的线性注意力机制LKA,它考虑了卷积和自注意力的优点,同时避免了它们的缺点。基于LKA, 进一步介绍了一种简单的 vision backbone,称为VAN。

  • 本文表明,在各种任务(包括图像分类、对象检测、语义分割、实例分割、姿势估计等)的广泛实验中,VANs优于相似级别的ViT和CNN。

2相关工作

2.1CNN

2.2Visual Attention Methods

2.3Vision MLPs

3方法

3.1 LKA

注意机制可以看作是一种自适应选择过程,它可以根据输入特征选择有区别的特征并自动忽略噪声响应。注意机制的关键步骤是生成注意图(attention map),它指示不同部分的重要性。为此,我们应该学习不同特征之间的关系。

在不同部分之间建立关系有两种众所周知的方法。

  • 第一种是采用自注意力机制来捕获长程依赖。在计算机视觉中应用自注意力有三个明显的缺点(摘要部分的三个)。

  • 第二种是使用大核卷积来构建相关性并生成注意图。这种方式仍有明显的缺点。大的核卷积带来了大量的计算开销和参数。

【作者的工作与MobileNet有相似之处,MobileNet将标准卷积解耦为两部分,即深度卷积和逐点卷积】

为了克服上面列出的缺点,并利用自注意和大核卷积的优点,本文建议分解大核卷积操作以捕获长距离关系。如图2所示,大核卷积可以分为三个部分:局部空间卷积(depthwise conv)、空间长程卷积(depthwise dilation conv)和通道卷积(1×1 conv)。

图2.大核卷积的分解图。标准卷积可以分解为三个部分:深度卷积(DW-Conv)、深度扩展卷积(DW-D-Conv)和点卷积(1×1 Conv)。彩色网格表示卷积核的位置,黄色网格表示中心点。13*13卷积分解为5*5深度卷积,5*5深度空洞卷积(膨胀速率为3),和1*1卷积;注:上图中省略了零填充。

通过上面的分解,可以用少量的计算成本和参数来捕获长程关系。在获得长程关系后,可以估计一个点的重要性并生成注意力图。如图3(a)所示,LKA模块可以写为

F ∈ R C × H × W F ∈R^{C×H×W} FRC×H×W:input features;

A t t e n t i o n ∈ R C × H × W Attention ∈R_{C×H×W} AttentionRC×H×W:attention map;

图3.不同模块的结构:(a)提出的大核注意力(LKA);(b) 非注意模块;(c) 用加法代替LKA中的乘法;(d) 自我关注。值得注意的是,(d)设计用于1D序列。

注意力图中的值表示每个特征的重要性。⊗指元素乘积。

源代码:

# LKA
class AttentionModule(nn.Module):
    def __init__(self, dim):
        super().__init__()
        # 深度卷积
        self.conv0 = nn.Conv2d(dim, dim, 5, padding=2, groups=dim)
        # 深度空洞卷积
        self.conv_spatial = nn.Conv2d(
            dim, dim, 7, stride=1, padding=9, groups=dim, dilation=3)
        # 逐点卷积
        self.conv1 = nn.Conv2d(dim, dim, 1)

    def forward(self, x):
        u = x.clone()
        attn = self.conv0(x)
        attn = self.conv_spatial(attn)
        attn = self.conv1(attn)

        # 注意力操作
        return u * attn

与常见的注意方法不同,LKA不需要额外的标准化函数,如sigmoid和softmax,如表3所示(VAN-B0 Acc最高)。

w/o:without

w/:with

本文还认为,注意力方法的关键特征是基于输入特征自适应调整输出,而不是归一化注意力图。如表1所示,本文提出的LKA结合了卷积和自注意力机制的优点。它考虑了局部上下文信息、大的感受野、线性复杂性和动态过程。此外,LKA不仅在空间维度上实现了适应性,而且在通道维度上也实现了适应性。值得注意的是,不同的通道通常代表深度神经网络中的不同对象,通道维度的适应性对于视觉任务也很重要。

LKA的优点总结:

3.2 VAN

VAN具有简单的分层结构,即输出空间分辨率降低的四个阶段序列,即分别为H/4×W/4、H/8×W/8、H/16×W/16和H/32×W/32。这里,H和W表示输入图像的高度和宽度。随着分辨率的降低,输出通道的数量也在增加。输出通道Ci的变化如表5所示。

对于图4所示的每个阶段,首先对输入进行下采样,并使用步幅数来控制下采样率。在下采样之后,阶段中的所有其他层保持相同的输出大小,即空间分辨率和通道数。然后,依次堆叠L组归一化,1×1 Conv、GELU激活、大核关注和前馈网络(FFN)以提取特征。

图4. VAN的一个阶段。d表示深度卷积。k×k表示k×k卷积。

根据参数和计算成本,本文设计了七种架构VAN-B0、VAN-B1、VAN-B2、VAN-B3、VAN-B4、VAN-B5、VAN-B6。整个网络的详细信息如表5所示。

源代码:

# attention
class SpatialAttention(nn.Module):
    def __init__(self, d_model):
        super().__init__()
        # 1*1
        self.proj_1 = nn.Conv2d(d_model, d_model, 1)
        # 激活函数
        self.activation = nn.GELU()
        # LKA
        self.spatial_gating_unit = AttentionModule(d_model)
        # 1*1
        self.proj_2 = nn.Conv2d(d_model, d_model, 1)

    def forward(self, x):
        # res
        shorcut = x.clone()
        x = self.proj_1(x)
        x = self.activation(x)
        x = self.spatial_gating_unit(x)
        x = self.proj_2(x)
        x = x + shorcut
        return x
class Block(nn.Module):
    def __init__(self, dim, mlp_ratio=4., drop=0., drop_path=0., act_layer=nn.GELU):
        super().__init__()
        # BN
        self.norm1 = nn.BatchNorm2d(dim)
        # attention
        self.attn = SpatialAttention(dim)
        # 正则化 随机删除分支
        # identity模块不改变输入,直接return input
        # 一种编码技巧吧,比如我们要加深网络,有些层是不改变输入数据的维度的,
        # 在增减网络的过程中我们就可以用identity占个位置,这样网络整体层数永远不变
        # van_small drop_path=0.1
        # 结合drop_path的调用,若x为输入的张量,其通道为[B,C,H,W]
        # 那么drop_path的含义为在一个Batch_size中
        # 随机有drop_prob的样本,不经过主干,而直接由分支进行恒等映射。
        self.drop_path = DropPath(
            drop_path) if drop_path > 0. else nn.Identity()
        # BN2
        self.norm2 = nn.BatchNorm2d(dim)
        mlp_hidden_dim = int(dim * mlp_ratio)
        # FFN
        self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim,
                       act_layer=act_layer, drop=drop)
        layer_scale_init_value = 1e-2
        self.layer_scale_1 = nn.Parameter(
            layer_scale_init_value * torch.ones((dim)), requires_grad=True)
        self.layer_scale_2 = nn.Parameter(
            layer_scale_init_value * torch.ones((dim)), requires_grad=True)

        self.apply(self._init_weights)

    def _init_weights(self, m):
        if isinstance(m, nn.Linear):
            # trunc_normal_函数:截断正太分布
            # 截断分布是指,限制变量xx 取值范围(scope)的一种分布
            trunc_normal_(m.weight, std=.02)
            if isinstance(m, nn.Linear) and m.bias is not None:
                # 使用val的值来填充输入的Tensor
                nn.init.constant_(m.bias, 0)
        elif isinstance(m, nn.LayerNorm):
            nn.init.constant_(m.bias, 0)
            nn.init.constant_(m.weight, 1.0)
        elif isinstance(m, nn.Conv2d):
            fan_out = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
            # groups = 1 时就是标准的卷积运算
            # groups = input_channels的情况是这样的
            # 当输入通道数等于输出通道数时,就是深度可分离卷积的depthwise conv
            # 可查看mobilenet的论文理解该卷积
            fan_out //= m.groups
            m.weight.data.normal_(0, math.sqrt(2.0 / fan_out))
            if m.bias is not None:
                # bias初始化为0
                m.bias.data.zero_()

    def forward(self, x):
        x = x + self.drop_path(self.layer_scale_1.unsqueeze(-1).unsqueeze(-1)
                               * self.attn(self.norm1(x)))
        x = x + \
            self.drop_path(
                self.layer_scale_2.unsqueeze(-1).unsqueeze(-1) * self.mlp(self.norm2(x)))
        return x

复杂度分析

假设输入和输出的特征都具有相同的大小 HxWxC,则参数和FLOPs可以被写成如下

参数P和FLOPs的数量可以表示为:

d表示膨胀率,K表示核大小。根据FLOP和参数的公式,FLOP与参数的预算节省率相同。

实现细节

默认采用K=21。对于K=21。公式(3)当d=3时取最小值,这对应于5×5深度卷积和7×7深度卷积与扩张3。

4实验

4.1图像分类

4.1.1 ImageNet-1K Experiments

设置

消融实验

本文进行了消融研究,以证明LKA的每个组成部分都至关重要。为了快速获得实验结果, 选择VAN-B0作为 的基线模型。表3中的实验结果表明,LKA中的所有组件对于提高性能是必不可少的。

  • DW-Conv. 可以利用图像的局部上下文信息。没有它,分类性能将下降0.5%(74.9%对75.4%),这表明了局部结构信息在图像处理中的重要性。

  • DW-D-Conv. 表示深度空洞卷积,其在捕获LKA中的长程依赖性中起作用。没有它,分类性能将下降1.3%(74.1%对75.4%),这证实了本文的观点,即长程依赖对视觉任务至关重要。

  • Attention Mechanism. 注意力机制的引入可以被视为使网络具有自适应特性。受益于此,VAN-B0实现了约1.1%(74.3%对75.4%)的改进。

  • 1 × 1 Conv. 这里,1×1 Conv捕获了通道维度中的关系。结合注意力机制,引入了通道维度的适应性。它带来了0.8%(74.6%对75.4%)的改善,这证明了通道维度适应性的必要性。

  • Sigmoid function. Sigmoid函数是将注意力图从0归一化为1的常用归一化函数。然而, 发现LKA模块在 的实验中没有必要。没有sigmoid的VAN-B0实现了0.2%(75.4%对75.2%)的改善和更少的计算。

此外, 还进行了消融研究,以分解表6中不同大小的卷积核。 可以发现,分解21×21卷积比分解7×7卷积效果更好,这表明大核对视觉任务至关重要。分解更大的28×28卷积, 发现与分解21×21卷积相比,增益并不明显。

因此, 默认选择分解21×21卷积。

4.1.2 Visualization

4.1.3 Pretraining on ImageNet-22K

4.2目标检测

4.3图像分割

4.4全景分割

4.5姿态评估

4.6细颗粒分类

4.7显著性检测

5讨论

最近,基于transformer的模型迅速征服了各种视觉排行榜。正如 所知,自注意力只是一种特殊的注意机制。然而,人们逐渐默认采用自注意,而忽略了潜在的关注方法。本文提出了一种新的注意力模块LKA和基于CNN的网络VAN。它超越了用于视觉任务的最先进的基于transformer的方法。希望这篇论文能促使人们重新思考自注意力是否不可替代,以及哪种注意力更适合视觉任务。

6 future work

未来,将在以下方面继续完善VAN:

  • 继续改进它的结构。在本文中,只展示了一个直观的结构,还存在很多潜在的改进点,例如:应用大核、引入多尺度结构和使用多分支结构。

  • 大规模的自监督学习和迁移学习。VAN 自然地结合了CNN和ViT的优点。一方面VAN利用了图像的2D结构。另一方面 VAN可以基于输入图片动态的调整输出,它很适合自监督学习和迁移学习。结合了这两点,作者认为VAN可以在这两个领域有更好的性能。

  • 更多的应用场景。由于资源有限,作者只展示了它在视觉任务中的优秀性能。作者期待VAN在各个领域都展示优秀性能并变成一个通用的模型。

7 conclusion

在本文中, 提出了一种新的视觉注意LKA,它结合了卷积和自我注意的优点。基于LKA, 构建了一个 vision backbone VAN,在一些视觉任务中实现了最先进的性能,包括图像分类、对象检测、语义分割等。未来,将从第6节中提到的方向继续改进该框架。

# 四阶段模型
class VAN(nn.Module):
    #
    def __init__(self, img_size=224, in_chans=3, num_classes=3, embed_dims=[64, 128, 256, 512],
                 mlp_ratios=[4, 4, 4, 4], drop_rate=0., drop_path_rate=0., norm_layer=nn.LayerNorm,
                 depths=[3, 4, 6, 3], num_stages=4, flag=False, pretrained_cfg=None):

        super().__init__()
        if flag == False:
            self.num_classes = num_classes
        self.depths = depths
        self.num_stages = num_stages
        # 返回一个一维的tensor(张量),这个张量包含了从start到end(包括端点)的等距的steps个数据点
        dpr = [x.item() for x in torch.linspace(0, drop_path_rate,
                                                sum(depths))]  # stochastic depth decay rule
        cur = 0

        for i in range(num_stages):
            # 这里还下采样了
            # 提取特征
            patch_embed = OverlapPatchEmbed(img_size=img_size if i == 0 else img_size // (2 ** (i + 1)),
                                            patch_size=7 if i == 0 else 3,
                                            stride=4 if i == 0 else 2,
                                            in_chans=in_chans if i == 0 else embed_dims[i - 1],
                                            embed_dim=embed_dims[i])

            block = nn.ModuleList([Block(
                dim=embed_dims[i], mlp_ratio=mlp_ratios[i], drop=drop_rate, drop_path=dpr[cur + j])
                for j in range(depths[i])])
            # LayerNorm也是归一化的一种方法
            norm = norm_layer(embed_dims[i])
            cur += depths[i]
            # setattr() 函数对应函数 getattr(),用于设置属性值,该属性不一定是存在的。
            setattr(self, f"patch_embed{i + 1}", patch_embed)
            setattr(self, f"block{i + 1}", block)
            setattr(self, f"norm{i + 1}", norm)

        # classification head
        self.head = nn.Linear(
            embed_dims[3], num_classes) if num_classes > 0 else nn.Identity()

        self.apply(self._init_weights)

    def _init_weights(self, m):
        if isinstance(m, nn.Linear):
            trunc_normal_(m.weight, std=.02)
            if isinstance(m, nn.Linear) and m.bias is not None:
                nn.init.constant_(m.bias, 0)
        elif isinstance(m, nn.LayerNorm):
            nn.init.constant_(m.bias, 0)
            nn.init.constant_(m.weight, 1.0)
        elif isinstance(m, nn.Conv2d):
            fan_out = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
            fan_out //= m.groups
            m.weight.data.normal_(0, math.sqrt(2.0 / fan_out))
            if m.bias is not None:
                m.bias.data.zero_()
    # 冻结
    def freeze_patch_emb(self):
        self.patch_embed1.requires_grad = False

    @torch.jit.ignore
    def no_weight_decay(self):
        # has pos_embed may be better
        return {'pos_embed1', 'pos_embed2', 'pos_embed3', 'pos_embed4', 'cls_token'}

    def get_classifier(self):
        return self.head

    def reset_classifier(self, num_classes, global_pool=''):
        self.num_classes = num_classes
        self.head = nn.Linear(
            self.embed_dim, num_classes) if num_classes > 0 else nn.Identity()

    def forward_features(self, x):
        B = x.shape[0]
        x, H, W = self.patch_embed1(x)
        for blk in self.block1:
            x = blk(x)
        x = x.flatten(2).transpose(1, 2)
        x = self.norm1(x)
        x = x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()

        x, H, W = self.patch_embed2(x)
        for blk in self.block2:
            x = blk(x)
        x = x.flatten(2).transpose(1, 2)
        x = self.norm2(x)
        x = x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()

        x, H, W = self.patch_embed3(x)
        for blk in self.block3:
            x = blk(x)
        x = x.flatten(2).transpose(1, 2)
        x = self.norm3(x)
        x = x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()

        x, H, W = self.patch_embed4(x)
        for blk in self.block4:
            x = blk(x)
        x = x.flatten(2).transpose(1, 2)
        x = self.norm4(x)

        return x.mean(dim=1)

    def forward(self, x):
        x = self.forward_features(x)
        x = self.head(x)

        return x

网络架构

VAN(
  (patch_embed1): OverlapPatchEmbed(
    (proj): Conv2d(3, 32, kernel_size=(7, 7), stride=(4, 4), padding=(3, 3))
    (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
  (block1): ModuleList(
    (0): Block(
      (norm1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=32)
          (conv_spatial): Conv2d(32, 32, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=32)
          (conv1): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): Identity()
      (norm2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(32, 256, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=256)
        )
        (act): GELU()
        (fc2): Conv2d(256, 32, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (1): Block(
      (norm1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=32)
          (conv_spatial): Conv2d(32, 32, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=32)
          (conv1): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.008)
      (norm2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(32, 256, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=256)
        )
        (act): GELU()
        (fc2): Conv2d(256, 32, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (2): Block(
      (norm1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=32)
          (conv_spatial): Conv2d(32, 32, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=32)
          (conv1): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.017)
      (norm2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(32, 256, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=256)
        )
        (act): GELU()
        (fc2): Conv2d(256, 32, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
  )
  (norm1): LayerNorm((32,), eps=1e-06, elementwise_affine=True)
  (patch_embed2): OverlapPatchEmbed(
    (proj): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
    (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
  (block2): ModuleList(
    (0): Block(
      (norm1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(64, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=64)
          (conv_spatial): Conv2d(64, 64, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=64)
          (conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.025)
      (norm2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(64, 512, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=512)
        )
        (act): GELU()
        (fc2): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (1): Block(
      (norm1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(64, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=64)
          (conv_spatial): Conv2d(64, 64, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=64)
          (conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.033)
      (norm2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(64, 512, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=512)
        )
        (act): GELU()
        (fc2): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (2): Block(
      (norm1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(64, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=64)
          (conv_spatial): Conv2d(64, 64, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=64)
          (conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.042)
      (norm2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(64, 512, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=512)
        )
        (act): GELU()
        (fc2): Conv2d(512, 64, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
  )
  (norm2): LayerNorm((64,), eps=1e-06, elementwise_affine=True)
  (patch_embed3): OverlapPatchEmbed(
    (proj): Conv2d(64, 160, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
    (norm): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
  (block3): ModuleList(
    (0): Block(
      (norm1): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(160, 160, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=160)
          (conv_spatial): Conv2d(160, 160, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=160)
          (conv1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.050)
      (norm2): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(160, 640, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(640, 640, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=640)
        )
        (act): GELU()
        (fc2): Conv2d(640, 160, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (1): Block(
      (norm1): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(160, 160, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=160)
          (conv_spatial): Conv2d(160, 160, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=160)
          (conv1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.058)
      (norm2): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(160, 640, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(640, 640, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=640)
        )
        (act): GELU()
        (fc2): Conv2d(640, 160, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (2): Block(
      (norm1): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(160, 160, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=160)
          (conv_spatial): Conv2d(160, 160, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=160)
          (conv1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.067)
      (norm2): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(160, 640, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(640, 640, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=640)
        )
        (act): GELU()
        (fc2): Conv2d(640, 160, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (3): Block(
      (norm1): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(160, 160, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=160)
          (conv_spatial): Conv2d(160, 160, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=160)
          (conv1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.075)
      (norm2): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(160, 640, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(640, 640, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=640)
        )
        (act): GELU()
        (fc2): Conv2d(640, 160, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (4): Block(
      (norm1): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(160, 160, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=160)
          (conv_spatial): Conv2d(160, 160, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=160)
          (conv1): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(160, 160, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.083)
      (norm2): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(160, 640, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(640, 640, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=640)
        )
        (act): GELU()
        (fc2): Conv2d(640, 160, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
  )
  (norm3): LayerNorm((160,), eps=1e-06, elementwise_affine=True)
  (patch_embed4): OverlapPatchEmbed(
    (proj): Conv2d(160, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
    (norm): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
  (block4): ModuleList(
    (0): Block(
      (norm1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(256, 256, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=256)
          (conv_spatial): Conv2d(256, 256, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=256)
          (conv1): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.092)
      (norm2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=1024)
        )
        (act): GELU()
        (fc2): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
    (1): Block(
      (norm1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (attn): Attention(
        (proj_1): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))
        (activation): GELU()
        (spatial_gating_unit): LKA(
          (conv0): Conv2d(256, 256, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=256)
          (conv_spatial): Conv2d(256, 256, kernel_size=(7, 7), stride=(1, 1), padding=(9, 9), dilation=(3, 3), groups=256)
          (conv1): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))
        )
        (proj_2): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))
      )
      (drop_path): DropPath(drop_prob=0.100)
      (norm2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (mlp): Mlp(
        (fc1): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1))
        (dwconv): DWConv(
          (dwconv): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=1024)
        )
        (act): GELU()
        (fc2): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))
        (drop): Dropout(p=0.0, inplace=False)
      )
    )
  )
  (norm4): LayerNorm((256,), eps=1e-06, elementwise_affine=True)
  (head): Linear(in_features=256, out_features=3, bias=True)
)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值