CSwin Transformer 学习笔记

news2024/11/20 11:27:43

        Cswin提出了上图中使用交叉形状局部attention,为了解决VIT模型中局部自注意力感受野进一步增长受限的问题,同时提出了局部增强位置编码模块,超越了Swin等模型,在多个任务上效果SOTA(当时的SOTA,已经被SG Former超越,感兴趣的可以看看SG Former)。

论文地址:https://arxiv.org/abs/2107.00652 

代码地址:https://github.com/microsoft/CSWin-Transformer

        模型整体结构如上所示,由token embeeding layer4stageblock所堆叠而成,每个stage block后面都会接入一个conv层,用来对featuremap进行下采样。和典型的R50设计类似,每次下采样后,会增加dim的数量,一是为了提升感受野,二是为了增加特征性。

研究动机:

  • 基于global attentiontransformer效果虽然好但是计算复杂度与特征图大小平方(H==W的情况)成正比
  • 基于local attentiontransformer的会限制每个token的感受野的交互,减缓感受野的增长,需要堆叠大量的block来实现全局自注意力。

解决办法:

  • 提出了Cross-Shaped Window self-attention机制,对注意力头进行分组,并行计算水平和竖直方向的self-attention,可以在更小的计算量条件下获得更好的效果。
  • 提出了Locally-enhanced Positional Encoding(LePE), 可以更好的处理局部位置信息,并且支持任意形状的输入。

1.1 Convolutional Token Embedding

        用convolution来做embedding,为了减少计算量,本文直接采用了7x7的卷积核,stride为4的卷积来直接对输入进行embedding,之后再对最后一维进行layernorm。

self.stage1_conv_embed = nn.Sequential(
    nn.Conv2d(in_chans, embed_dim, 7, 4, 2),
    Rearrange('b c h w -> b (h w) c', h=img_size // 4, w=img_size // 4),
    nn.LayerNorm(embed_dim)
)

1.2 Cross-Shaped Window Self-Attention

        具体来讲,假设原始的Feature Map为H\times W\times C,为了计算它在横向上的自注意力,它首先被拆分成M = \frac{H}{sw}个横条的数据(实际代码先进行竖列处理),其中sw是横条的宽度。在这4个不同的Stage中取不同的值,实验结果表明[1,2,7,7]这组值在速度和精度上取得了比较好的均衡。

        对于每个条状特征X^{i} ,i=1,2,...M,使用Transformer可以得到它的特征Y^{i},最后将这M个特征拼接到一起便得到了这个head的输入。假设它属于第k个head,那么横向自注意力H-Attention_{i}(X)的计算方式为:

纵向自注意力V-Attention 和H-Attention的计算方式类似,不同的是它是取的宽度为sw的竖条。

最终,这个block的输出表示为:

CSWin self-attention计算复杂度分析:

对于高分辨率输入,H,W早期大于C,后期小于C,因此早期sw小,后期大。即,调整sw可以有效地扩大后期每个token的attention区域。为了使224×224输入的中间特征图大小可被sw整除,默认将4个阶段的sw设置为1、2、7、7。 

def img2windows(img, H_sp, W_sp):
    """
    img: B C H W
    """
    B, C, H, W = img.shape
    img_reshape = img.view(B, C, H // H_sp, H_sp, W // W_sp, W_sp) # [N 32 1 56 56 1] [N 32 56 1 1 56] / [N 64 1 28 14 2] [N 64 14 2 1 28] / [N 128 1 14 2 7] [N 128 2 7 1 14] / [N 512 1 7 1 7]
    img_perm = img_reshape.permute(0, 2, 4, 3, 5, 1).contiguous().reshape(-1, H_sp* W_sp, C) # [N*56*1 56 32] [N*56*1 56 32] / [N*14*1 56 64] [N*14*1 56 64] / [N*2*1 98 128] [N*2*1 98 128] / [N*1*1 49 512]
    return img_perm

def windows2img(img_splits_hw, H_sp, W_sp, H, W):
    """
    img_splits_hw: B' H W C
    """
    B = int(img_splits_hw.shape[0] / (H * W / H_sp / W_sp))

    img = img_splits_hw.view(B, H // H_sp, W // W_sp, H_sp, W_sp, -1) # [N*56*1 56 32]->[N 1 56 56 1 32] [N*56*1 56 32]->[N 56 1 1 56 32] / [N*14*1 56 64]->[N 1 14 28 2 64] [N*14*1 56 64]->[N 14 1 2 28 64] / [N*2*1 98 128]->[N 1 2 14 7 128] [N*2*1 98 128]->[N 2 1 7 14 128] / [N*1*1 49 512]->[N 1 1 7 7 512]
    img = img.permute(0, 1, 3, 2, 4, 5).contiguous().view(B, H, W, -1) # [N 56 56 32] [N 28 28 64] [N 14 14 128] [N 7 7 512]
    return img

class LePEAttention(nn.Module):
    def __init__(self, dim, resolution, idx, split_size=7, dim_out=None, num_heads=8, attn_drop=0., proj_drop=0.,
                 qk_scale=None):
        super().__init__()
        self.dim = dim
        self.dim_out = dim_out or dim
        self.resolution = resolution
        self.split_size = split_size
        self.num_heads = num_heads
        head_dim = dim // num_heads
        # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
        self.scale = qk_scale or head_dim ** -0.5
        if idx == -1:
            H_sp, W_sp = self.resolution, self.resolution
        elif idx == 0:
            H_sp, W_sp = self.resolution, self.split_size
        elif idx == 1:
            W_sp, H_sp = self.resolution, self.split_size
        else:
            print("ERROR MODE", idx)
            exit(0)
        self.H_sp = H_sp
        self.W_sp = W_sp
        stride = 1
        self.get_v = nn.Conv2d(dim, dim, kernel_size=3, stride=1, padding=1, groups=dim)

        self.attn_drop = nn.Dropout(attn_drop)

    def im2cswin(self, x):
        B, N, C = x.shape
        H = W = int(np.sqrt(N))
        x = x.transpose(-2, -1).contiguous().view(B, C, H, W)  # [B, N, C] -> [B, C, N] -> [B, C, H, W]
        x = img2windows(x, self.H_sp, self.W_sp)  # [N*56*1 56 32] [N*14*1 56 64] [N*2*1 98 128] [N*1*1 49 512]
        x = x.reshape(-1, self.H_sp * self.W_sp, self.num_heads, C // self.num_heads).permute(0, 2, 1,
                                                                                              3).contiguous()  # [N*56*1 1 56 32] [N*14*1 2 56 32] [N*2*1 4 98 32] [N*1*1 16 49 32]
        return x

    def get_lepe(self, x, func):
        B, N, C = x.shape  # [N 3136 32] [N 784 64] [N 196 128] [N 49 512]
        H = W = int(np.sqrt(N))
        x = x.transpose(-2, -1).contiguous().view(B, C, H, W)  # [N 32 56 56] [N 64 28 28] [N 128 14 14] [N 512 7 7]

        H_sp, W_sp = self.H_sp, self.W_sp
        x = x.view(B, C, H // H_sp, H_sp, W // W_sp,
                   W_sp)  # [N 32 1 56 56 1] [N 32 56 1 1 56] / [N 64 1 28 14 2] [N 64 14 2 1 28] / [N 128 1 14 2 7] [N 128 2 7 1 14] / [N 512 1 7 1 7]
        x = x.permute(0, 2, 4, 1, 3, 5).contiguous().reshape(-1, C, H_sp,
                                                             W_sp)  ### B', C, H', W' # [N*56*1 32 56 1][N*56*1 32 1 56] / [N*14*1 64 28 2][N*14*1 64 2 28] / [N*2*1 128 14 7][N*2*1 128 7 14] / [N*1*1 512 7 7]

        lepe = func(
            x)  ### B', C, H', W' # [N*56*1 32 56 1] [N*56*1 32 1 56] / [N*14*1 64 28 2][N*14*1 64 2 28] / [N*2*1 128 14 7][N*2*1 128 7 14]  / [N*1*1 512 7 7]
        lepe = lepe.reshape(-1, self.num_heads, C // self.num_heads, H_sp * W_sp).permute(0, 1, 3,
                                                                                          2).contiguous()  # [N*56*1 1 56 32] [N*14*1 2 56 32] [N*2*1 4 98 32] [N*1*1 16 49 32]

        x = x.reshape(-1, self.num_heads, C // self.num_heads, self.H_sp * self.W_sp).permute(0, 1, 3,
                                                                                              2).contiguous()  # [N*56*1 1 56 32] [N*14*1 2 56 32] [N*2*1 4 98 32] [N*1*1 16 49 32]
        return x, lepe

    def forward(self, qkv):
        """
        x: B L C
        """
        q, k, v = qkv[0], qkv[1], qkv[2]  # [N 3136 32] [N 784 64] [N 196 128] [N 49 512]

        ### Img2Window
        H = W = self.resolution  # 56 28 14 7
        B, L, C = q.shape  # [N 3136 32] [N 784 64] [N 196 128] [N 49 512]
        assert L == H * W, "flatten img_tokens has wrong size"

        q = self.im2cswin(q)  # [N*56*1 1 56 32] [N*14*1 2 56 32] [N*2*1 4 98 32] [N*1*1 16 49 32]
        k = self.im2cswin(k)  # [N*56*1 1 56 32] [N*14*1 2 56 32] [N*2*1 4 98 32] [N*1*1 16 49 32]
        v, lepe = self.get_lepe(v, self.get_v)

        q = q * self.scale
        attn = (q @ k.transpose(-2, -1))  # B head N C @ B head C N --> B head N N
        attn = nn.functional.softmax(attn, dim=-1, dtype=attn.dtype)
        attn = self.attn_drop(attn)

        x = (attn @ v) + lepe
        x = x.transpose(1, 2).reshape(-1, self.H_sp * self.W_sp,
                                      C)  # B head N N @ B head N C # [N*56*1 56 32] [N*14*1 56 64] [N*2*1 98 128] [N*1*1 49 512]

        ### Window2Img
        x = windows2img(x, self.H_sp, self.W_sp, H, W).view(B, -1, C)  # B H' W' C

        return x  # [N 3136 32] [N 784 64] [N 196 128] [N 49 512]

代码部分其实和Swin类似,如果理解了swin的分窗机制,再加上head分组,基本上就能很快理解论文中思想。 

1.3 Locally-Enhanced Positional Encoding(LePE)

        因为Transformer是输入顺序无关的,因此需要向其中加入位置编码。上图左边为ViT模型的PE,使用的绝对位置编码或者是条件位置编码,只在embedding的时候与token一起进入transformer,中间的是Swin,CrossFormer等模型的PE,使用相对位置编码偏差,通过引入token图的权重来和attention一起计算,灵活度更好,相对APE效果更好。

        本文所提出的LePE,相比于RPE更加直接,将位置信息施加到线性投影中,同时注意到RPE以head方式引入偏差,而LepE是per-channel bias,这可能显示出更强大的潜力来充当位置嵌入。也就是直接将位置编码添加加到了Value向量上,假设位置编码为E,它的添加方式是通过将位置编码EV相乘完成的。然后通过一个short-cut将添加了位置编码的V和通过自注意力加权的V单位加到一起,公式如下:

        这里作者基于一个假设:对于一个输入元素,他附近的元素提供最重要的位置信息。所以对V做一个深度卷积V,加到softmax之后的结果上。公式为:

        这样,LePE可以友好地应用于将任意输入分辨率作为输入的下游任务。

    def get_lepe(self, x, func):
        # func -> self.get_v = nn.Conv2d(dim, dim, kernel_size=3, stride=1, padding=1,groups=dim)
        B, N, C = x.shape  # [N 3136 32] [N 784 64] [N 196 128] [N 49 512]
        H = W = int(np.sqrt(N))
        x = x.transpose(-2, -1).contiguous().view(B, C, H, W)  # [N 32 56 56] [N 64 28 28] [N 128 14 14] [N 512 7 7]

        H_sp, W_sp = self.H_sp, self.W_sp
        x = x.view(B, C, H // H_sp, H_sp, W // W_sp,
                   W_sp)  # [N 32 1 56 56 1] [N 32 56 1 1 56] / [N 64 1 28 14 2] [N 64 14 2 1 28] / [N 128 1 14 2 7] [N 128 2 7 1 14] / [N 512 1 7 1 7]
        x = x.permute(0, 2, 4, 1, 3, 5).contiguous().reshape(-1, C, H_sp,
                                                             W_sp)  ### B', C, H', W' # [N*56*1 32 56 1][N*56*1 32 1 56] / [N*14*1 64 28 2][N*14*1 64 2 28] / [N*2*1 128 14 7][N*2*1 128 7 14] / [N*1*1 512 7 7]

        lepe = func(
            x)  ### B', C, H', W' # [N*56*1 32 56 1] [N*56*1 32 1 56] / [N*14*1 64 28 2][N*14*1 64 2 28] / [N*2*1 128 14 7][N*2*1 128 7 14]  / [N*1*1 512 7 7]
        lepe = lepe.reshape(-1, self.num_heads, C // self.num_heads, H_sp * W_sp).permute(0, 1, 3,
                                                                                          2).contiguous()  # [N*56*1 1 56 32] [N*14*1 2 56 32] [N*2*1 4 98 32] [N*1*1 16 49 32]

        x = x.reshape(-1, self.num_heads, C // self.num_heads, self.H_sp * self.W_sp).permute(0, 1, 3,
                                                                                              2).contiguous()  # [N*56*1 1 56 32] [N*14*1 2 56 32] [N*2*1 4 98 32] [N*1*1 16 49 32]
        return x, lepe

1.4 CSWin Transformer Block

        CSWin Transformer Block的结构如图所示,它最显著的特点是添加了两个shortcut,并使用LN对特征做归一化.

网络结构配置:

        其中X^{l}为第 l 个Transformer block的输出或各stage的卷积层。 

        CSwin的block有两个部分,一个是做LayerNorm和Cross-shaped window self-attention并接一个shortcut,另一个则是做LayerNorm和MLP,相比于Swin和Twins来说,block的计算量大大的降低了(swin,twins则是有两个attention+两个MLP堆叠一个block)。

class CSWinBlock(nn.Module):

    def __init__(self, dim, reso, num_heads,
                 split_size=7, mlp_ratio=4., qkv_bias=False, qk_scale=None,
                 drop=0., attn_drop=0., drop_path=0.,
                 act_layer=nn.GELU, norm_layer=nn.LayerNorm,
                 last_stage=False):
        super().__init__()
        self.dim = dim
        self.num_heads = num_heads
        self.patches_resolution = reso
        self.split_size = split_size
        self.mlp_ratio = mlp_ratio
        self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
        self.norm1 = norm_layer(dim)

        if self.patches_resolution == split_size:
            last_stage = True
        if last_stage:
            self.branch_num = 1
        else:
            self.branch_num = 2
        self.proj = nn.Linear(dim, dim)
        self.proj_drop = nn.Dropout(drop)
        
        if last_stage:
            self.attns = nn.ModuleList([
                LePEAttention(
                    dim, resolution=self.patches_resolution, idx = -1,
                    split_size=split_size, num_heads=num_heads, dim_out=dim,
                    qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
                for i in range(self.branch_num)])
        else:
            self.attns = nn.ModuleList([
                LePEAttention(
                    dim//2, resolution=self.patches_resolution, idx = i,
                    split_size=split_size, num_heads=num_heads//2, dim_out=dim//2,
                    qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
                for i in range(self.branch_num)])
        

        mlp_hidden_dim = int(dim * mlp_ratio)

        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, out_features=dim, act_layer=act_layer, drop=drop)
        self.norm2 = norm_layer(dim)

    def forward(self, x):
        """
        x: B, H*W, C
        """

        H = W = self.patches_resolution # 56
        B, L, C = x.shape # [N 3136 64] [N 784 128] [N 196 256] [N 49 512]
        assert L == H * W, "flatten img_tokens has wrong size"
        img = self.norm1(x)
        qkv = self.qkv(img).reshape(B, -1, 3, C).permute(2, 0, 1, 3) # [3 N 3136 64] [3 N 784 128] [3 N 196 256] [3 N 49 512]
        
        if self.branch_num == 2:
            x1 = self.attns[0](qkv[:,:,:,:C//2]) # qkv[3 N 3136 32]->x1[N 3136 32] qkv[3 N 784 128]->x1[N 784 64] qkv[3 N 196 256]->x1[N 196 128]
            x2 = self.attns[1](qkv[:,:,:,C//2:]) # qkv[3 N 3136 32]->x2[N 3136 32] qkv[3 N 784 128]->x1[N 784 64] qkv[3 N 196 256]->x1[N 196 128]
            attened_x = torch.cat([x1,x2], dim=2)
        else:
            attened_x = self.attns[0](qkv) # [3 N 49 512]->[N 49 512]
        attened_x = self.proj(attened_x)
        x = x + self.drop_path(attened_x)
        x = x + self.drop_path(self.mlp(self.norm2(x)))

        return x # [N 3136 64] [N 784 128] [N 196 256] [N 49 512]

在相似网络参数和计算量的模型中,cswin在分类任务和各类下游任务中都做到了SOTA

 检测:

分割:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1088560.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

滑动窗口算法题

更新结果 1、判断条件成立后更新结果 2、入窗口后即可更新结果 判断: 出窗口后状态更新,循环回去再判断。 1、长度最小的子数组 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

【C++STL基础入门】排序和遍历容器

文章目录 前言使用前须知头文件 一、for_each算法1.1 for_each是什么1.2 函数原型1.3 示例代码1:将容器中的每个元素打印出来1.4 示例代码2:将容器中的每个字符串转换为大写形式 二、sort算法2.1 sort算法是什么?2.2 函数原型2.3 示例代码1:按…

Win10找不到hosts文件的解决方案

正常情况下,Windows10系统的C:\Windows\System32\drivers\etc目录下应该有hosts文件,但偏偏有些电脑没有,哪怕你打开了查看“隐藏的项目”也没见到hosts文件,如下: 解决方案 1、先点击查看,再点击选项&…

红队专题-工具Fscan

红队专题 招募六边形战士队员简介主要功能 ubuntu 安装windows 安装常用命令:项目框架源文件common目录Plugins目录Webscan目录爆破插件Webtitle函数webpoc扫描类型common.Scantype 免杀源码特征 参考链接 招募六边形战士队员 一起学习 代码审计、安全开发、web攻防…

有哪些免费的PPT模板网站,推荐这6个PPT模板免费下载网站!

混迹职场的打工人,或是还在校园的学生党,在日常的工作汇报或课程作业中,必然少不了PPT的影子,而每当提到做PPT,许多人首先会想到:有哪些免费的PPT模板下载网站? 本着辛苦自己,造福所…

(vue)el-select根据下拉框显示隐藏的visible-change的事件使用

(vue)el-select根据下拉框显示隐藏的visible-change的事件使用 <el-select v-model"value1"multiple:multiple-limit"2"placeholder"请选择" visible-change"visibleChange" ><el-option...></el-option> </el-s…

【C++STL基础入门】list基本使用

文章目录 前言一、list简介1.1 list是什么1.2 list的头文件 二、list2.1 定义对象2.2 list构造函数2.3 list的属性函数 总结 前言 STL&#xff08;Standard Template Library&#xff09;是C标准库的一个重要组成部分&#xff0c;提供了一套丰富的数据结构和算法&#xff0c;可…

【算法练习Day19】二叉搜索树的最近公共祖先二叉搜索树中的插入操作删除二叉搜索树中的节点

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 二叉搜索树的最近公共祖先叉…

MS5611的ZYNQ驱动试验之一 分析

0&#xff0c;MS5611框图 1&#xff0c;原理图 项目需要用到MS5611气压计模块&#xff0c;原理图很简单明了&#xff0c;如下&#xff1a; 这里PS接GND是SPI接口模式&#xff0c;PS接VDD是I2C接口模式。我在设计原理图时候直接设置成了SPI模式&#xff0c;当然这个SPI不是纯粹意…

ubuntu 22.04.3 live server图文安装流程

备注&#xff1a;以下操作全用键盘&#xff0c;tab切换&#xff0c;enter确认&#xff0c;方向键移动&#xff1b; 一、安装操作系统 1、 选择安装&#xff0c;第一个&#xff1b; 2、选择语言&#xff0c;这里只能选择英语&#xff0c;无中文&#xff1b; 3、继续而不更新 4、…

springcloud笔记(7)-限流降级Sentinel

官方文档&#xff1a;概述 | Spring Cloud Alibaba basic-api-resource-rule | Sentinel (sentinelguard.io) Sentinel是SpringCloudAlibaba的组件。 sentinel的功能 introduction | Sentinel 流量控制 熔断降级&#xff1a;降低调用链路中的不稳定资源 系统负载保护&am…

什么是接口自动化?为什么要做?和怎么做接口自动化?

服务端接口测试介绍 什么是服务端&#xff1f; 一般所说的服务端是指为用户在 APP 或 PC 使用的互联网功能提供数据服务的背后的一切。以天猫精灵智能音箱系列的产品链路为例&#xff0c;服务端便是网关&#xff08;包括网关在内&#xff09;之后的链路。 什么是接口&#xf…

数据结构—— AVL树

&#xff08;一&#xff09; 基础补充 二叉搜索树(BST) 定义&#xff1a; 二叉搜索树&#xff08;Binary Search Tree&#xff09;&#xff0c;简写BST&#xff0c;是满足某些条件的特殊二叉树。任何一个节点的左子树上的点&#xff0c;都必须小于当前节点。任何一个…

java split分割去掉空值

代码如下&#xff1a; public static void main(String[] args) {String dataString "#01#02#03#00#05#434";String[] infos Arrays.stream(dataString.split("#")).filter(s -> !s.isEmpty()).toArray(String[]::new);//投向领域IDString[] infos2 d…

深度学习-房价预测案例

1. 实现几个函数方便下载数据 import hashlib import os import tarfile import zipfile import requests#save DATA_HUB dict() DATA_URL http://d2l-data.s3-accelerate.amazonaws.com/def download(name, cache_diros.path.join(.., data)): #save"""下载…

独立站活动怎么复盘,做独立站需要掌握哪些?-站斧浏览器

独立站的活动形式多种多样&#xff0c;可以通过推出抽奖活动、举办线下活动或者利用社交媒体平台来增加用户互动和参与度。但是要做好一个独立站&#xff0c;除了活动形式&#xff0c;还需要掌握设计能力、编程技术、SEO知识和内容创作能力。 独立站活动怎么复盘&#xff1f; …

学习编程-先改变心态

编程失败的天才 林一和我很久以前就认识了——我从五年级就认识他了。他是班上最聪明的孩子。如果每个人在家庭作业或考试准备方面需要帮助&#xff0c;他们都会去那里。 有趣的是&#xff0c;林一不是那种连续学习几个小时的孩子。 他的聪明才智似乎与生俱来&#xff0c;几乎毫…

Selenium八大定位策略实战,你会了么?

Selenium是一款非常强大的自动化测试工具&#xff0c;支持多种编程语言&#xff0c;如Java、Python等。在使用Selenium进行自动化测试时&#xff0c;定位元素是非常重要的一步&#xff0c;只有正确定位到元素才能进行后续的操作&#xff0c;如输入数据、点击按钮等。在Selenium…

HarmonyOS/OpenHarmony原生应用-ArkTS万能卡片组件Radio

单选框&#xff0c;提供相应的用户交互选择项。该组件从API Version 8开始支持。无子组件。 一、接口 Radio(options: {value: string, group: string}) 从API version 9开始&#xff0c;该接口支持在ArkTS卡片中使用。 参数: 二、属性 除支持通用属性外&#xff0c;还支持以…

springBoot组件注册

springBoot组件注册 前言1、创建组件文件2、写属性3、生成get和set方法4、以前注册的方法5、现在注册的方法6、在启动文件查看7、多实例Scope("prototype")8、注册第三方包导入对应的场景启动器注册组件查看是否存在也可以通过Import(FastsqlException.class)导入但是…