VAN:Visual Attention Network

2023-11-02

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)
)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VAN:Visual Attention Network 的相关文章

随机推荐

  • 你是如何看待“孔乙己的长衫”?

    学历是一个十分有争议的话题 观点不一 这使得这个话题讨论起来令人热血沸腾 就人生而言 学历是否会成为敲门砖或枷锁 可以说是个纯粹的看法和态度问题 首先 我们要看到学历本身 学历是告诉人们你有哪些学科的专业知识和能力 但是这并不代表你一定能够
  • java连接rocksdb_rocksdb编译步骤——Java、Golang、mac

    如果不是必要不建议自己编译rocksdb 编译的过程比较耗时费力 现在已经有很多编译好的文件可供使用 Java org rocksdb rocksdbjni 5 10 3 Go版本 https github com leeyazhou go
  • 使用vcpkg编译、管理C++类库

    为什么使用vcpkg 1 vcpkg提供了一种类似linux编译 安装第三方类库的方式 不需要手动下载源码 编译源码 2 vcpkg自动管理已经安装的类库 使用集成开发环境如visual studio时直接引用对应的头文件就可以的 不需要配
  • React +TS实现拖拽列表

    使用React TS编写逻辑代码 less编写样式代码 不依赖第三方库 开箱即用 最近写的拖拽组件 分享给大家 直接上代码 首先看看如何使用 自己定义的组件需要包裹在DragList Item组件中 import DragList from
  • 遍历磁盘根目录

    for char i A i lt Z i 遍历所有磁盘 char dir 20 i 组成磁盘名称 char path 100 定义文件路径 UINT type GetDriveType dir 获取磁盘类型 if type DRIVE F
  • 网络与信息安全基础知识--网络安全

    说在前面 本系列文章专注于软考备考复习内容梳理 文章内容是对教材中知识点和考点的提炼 备考过程中可以有针对的进行复习 减少阅读量 有的放矢 导航目录 一 网络安全概述 二 网络的信息安全 1 信息的存储安全 2 信息的传输安全 三 防火墙技
  • Mac安装Netcat教程

    Netcat可以用于测试通信连接 Mac安装Netcat方式 打开终端输入 brew install netcat 安装好以后测试 输入 nc 可以看到是这样的 itzhuzhu itzhuzhudeMacBook Pro brew ins
  • 五、【服务器】基本概念-1

    服务器标准 ATCA AdvancedTelecom Computing Architecture 国际标准 ATCA脱胎于在电信 航天 工业控制 医疗器械 智能交通 军事装备等领域应用广泛的新一代主流工业计算技术 CompactPCI标准
  • 网络系统实现技术之IPX与SPX

    IPX SPX Novell NetWare网络 Novell公司为适应网络发展 将主机网络转换为PC网络 开发了Novell NetWare网络系统 该系统中基于客户机 服务器模式 以普通PC机做为客户机 以性能强大的服务器做为服务器 为
  • 什么是算法?

    什么是算法 当人们提到 算法 一词 往往就会把它们当成专属于 人工智能 的范畴 很多专业的计算机人士也是 提起算法就头疼 不知道如何学习算法 慢慢的对算法就会失去兴趣 算法不仅仅是计算机行业特有的 在我们的生活中也处处存在着算法 算法是专注
  • 【积跬步以至千里】Windows无法访问指定设备,路径或文件,您可能没有合适的权限访问

    一 问题描述 今天在使用电脑时突然出现如下状况 然后我打开用户权限发现了原来是权限的问题 我点击编辑 依然不管事 那怎么处理呢 二 解决办法 1 方法一 单独设置 1 在无法打开的文件 文件夹上单击鼠标右键 选择 属性 2 切换到 安全 选
  • __int64、ULONGLONG格式化输出

    Tips 打印日志信息的时候出现的问题 虽然很小 也算提个醒 Code 不考虑溢出的情况 ULONGLONG n1 100 printf d n n1 int64 n2 100 printf d n n2 此处是个坑 printf d d
  • 华为推出手机系统云翻新服务:什么是云翻新?如何使用?

    华为手机系统云翻新是华为推出的一项功能 旨在通过云服务提供系统翻新的服务 它可以帮助用户对手机的系统进行优化和更新 以提高手机的性能和流畅度 具体而言 华为手机系统云翻新功能提供了免费的云空间 用户可以将手机中的系统数据备份到云端 并进行系
  • 一位程序员使用M1 Mac的感受

    作为一个window的java开发者 虽然现在window高配置不卡 但是身边的高级开发者都是使用苹果开发 并且给予高度评价 这里也抱着学习的态度去尝试安利一台MAC作为开发 所以去苹果官网看了一下 但是这次苹果出了一个全新的M1芯片 我在
  • STM32网络通信Web Server中SSI和CGI的应用

    介绍 最近由于项目功能需要 开始研究STM32 WebServer通信以及SSI和CGI应用方法 项目结束后 主要总结浏览器与STM32之间进行通行 STM32作为服务器而浏览器做为客户端进行通行 文件介绍 此部分的代码是根据ST官方的We
  • 免费分享一套 SpringBoot + Vue的排课/选课管理系统,挺漂亮的

    大家好 我是锋哥 看到一个不错的SpringBoot Vue 的排课 选课管理系统 分享下哈 项目介绍 近年来 随着网络学校规模的逐渐增大 人工书写数据已经不能够处理如此庞大的数据 为了更好的适应信息时代的高效性 一个利用计算机来实现学生信
  • Python——requests

    requests是python实现的简单易用的HTTP库 使用起来比urllib简洁很多 因为是第三方库 所以使用前需要cmd安装 pip install requests 安装完成后import一下 正常则说明可以开始使用了 基本用法 r
  • c/c++ 计算字符数组/字符串长度

    1 自定义函数求长度 2 使用strlen 函数 3 使用sizeof 操作符 4 使用length 函数 利用自定义函数的方法 int cont str char s int i 0 while str i 0 return i 利用st
  • 已解决【partially initialized module ‘cv2‘ has no attribute ‘gapi_wip_gst_GStreamerPipeline‘】

    已解决 partially initialized module cv2 has no attribute gapi wip gst GStreamerPipeline 在尝试了几乎所有网上能找到的办法之后 本来已经放弃了 但是过了几天抱着
  • VAN:Visual Attention Network

    Visual Attention Network Submitted on 20 Feb 2022 v1 last revised 11 Jul 2022 this version v5 Computer Vision and Patter