SKNet讲解

news2024/11/24 7:19:47

SKNet讲解

  • 0. 引言
  • 1. 网络结构
    • 1.1 Split部分
    • 1.2 Fuse部分
    • 1.3 Select部分
    • 1.4 三分支的情况
  • 2. SKNet网络体系结构
  • 3. 分析与解释
  • 4. 代码
  • 总结

0. 引言

视皮层神经元的感受野大小受刺激的调节,即对不同刺激卷积核的大小应该不同,但在构建CNN时一般在同一层只采用一种卷积核,很少考虑因图片大小不同采用不同卷积核。
于是提出了SKNet。在SKNet中,不同大小的感受视野(卷积核)对于不同尺度的目标会有不同的效果。尽管在Inception中使用多个卷积核来适应不同尺度图像,但是卷积核权重相同,参数就是被计算好的了。而SKNet 对不同输入使用的卷积核感受野不同,参数权重也不同,可以根据输入大小自适应的进行处理。
SKNet中,提出了一种动态选择机制,允许每个神经元根据输入信息的多个尺度自适应调整其接受野的大小。设计了一种称为选择性内核(SK)单元的构建模块,在该模块中,由不同内核大小的多个分支的信息引导,使用softmax的注意力进行融合。对这些分支的不同关注导致融合层神经元有效感受野的大小不同。

论文地址:https://arxiv.org/pdf/1903.06586.pdf
代码地址:https://github.com/implus/SKNet

1. 网络结构

在这里插入图片描述
SKNet网络主要由三个部分组成:SplitFuseSelect。其中,Split部分将输入信息X分别输入不同的核大小(这里是2个卷积核,卷积核大小分别为:3*35*5);Fuse部分进行特征融合;Select部分根据计算得到的权重对对应的特征进行选择操作。

1.1 Split部分

对于输入信息X:[h,w,C],在Split中,分别输入两个卷积层(默认为2个,根据需要可以设计多个),两个卷积层分别为3*35*5。其中,每个卷积层都是由高效的分组/深度卷积批处理归一化ReLU函数依次组成的。另外,为了进一步提高效率,将具有5*5核的传统卷积替换为具有3×3核膨胀大小为2扩展卷积。最终得到的输出分别为 U ~ \widetilde{U} U U ^ \hat{U} U^

1.2 Fuse部分

基本思想是使用门来控制来自多个分支的信息流,这些分支携带不同尺度的信息到下一层的神经元中。为实现这一目标,门需要整合来自所有分支的信息。我们首先通过element-wise summation融合来自多个分支的结果:
U = U ~ + U ^ U=\widetilde{U}+\hat{U} U=U +U^

F g p F_{gp} Fgp全局平均池化操作 F f c F_{fc} Ffc先降维再升维的两层全连接层。需要注意的是输出的两个矩阵ab,其中矩阵b为冗余矩阵,在如图两个分支的情况下b=1-a

通过简单地使用全局平均池化以生成channel-wise统计信息 s ∈ R C s\in{R^C} sRC 来生成全局信息。具体来说,s的第C个元素是通过空间尺寸h×w收缩U来计算的:
s c = F g p ( U c ) = 1 h × w ∑ i = 1 h ∑ j = 1 w U c ( i , j ) s_c = F_{gp}(U_c) = \frac{1}{h\times{w}}\sum_{i=1}^{h}\sum_{j=1}^{w}{U_c(i,j)} sc=Fgp(Uc)=h×w1i=1hj=1wUc(i,j)

此外,还创建了一个紧凑的特征 z ∈ R d × 1 z\in{R^{d\times1}} zRd×1,以便为精确和自适应选择提供指导。这是通过一个简单的完全连接(fc)层实现的,降低了维度以提高效率:
z = F f c ( s ) = δ ( B ( W s ) ) z = F_{fc}(s)=\delta(B(Ws)) z=Ffc(s)=δ(B(Ws))
其中 δ \delta δReLU函数, B B B 表示批量标准化, W ∈ R d × C W\in{R^{d\times C}} WRd×C。为了研究d对模型效率的影响,我们使用reduction ratio (r)来控制其值:
d = m a x ( C / r , L ) d=max(C/r, L) d=max(C/r,L)

其中L表示d的最小值(L=32是我们实验中的典型设置)。

1.3 Select部分

Select操作使用ab两个权重矩阵对 U ~ \widetilde{U} U U ^ \hat{U} U^ 进行加权操作,然后求和得到最终的输出向量V

跨通道的软关注用于自适应地选择信息的不同空间尺度,空间尺度由紧凑特征描述符z引导。具体而言,softmax运算符应用于channel-wise数字:
a c = e A c z e A c z + e B c z , b c = e B c z e A c z + e B c z a_c = \frac{e^{A_cz}}{e^{A_cz}+e^{B_cz}},b_c = \frac{e^{B_cz}}{e^{A_cz}+e^{B_cz}} ac=eAcz+eBczeAcz,bc=eAcz+eBczeBcz
其中 A , B ∈ R C × d A,B\in{R^{C\times d}} A,BRC×d ,a、b表示 U ~ \widetilde{U} U U ^ \hat{U} U^soft attention A c A_c AcA的第c行,$a_c $ 是a的第c个元素。在两个分支的情况下,矩阵B是冗余的,因为 a c + b c = 1 a_c +b_c = 1 ac+bc=1。最终的特征映射V是通过各种卷积核的注意力权重获得的:
V c = a c ∗ U ~ + b c ∗ U ^ , a c + b c = 1 V_c = a_c * \widetilde{U} + b_c * \hat{U}, a_c +b_c = 1 Vc=acU +bcU^,ac+bc=1
其中 V = [ V 1 , V 2 , . . . , V C ] V=[V_1,V_2,...,V_C] V=[V1,V2,...,VC], V c ∈ R h × w V_c∈R^{h×w} VcRh×w,注意,这里我们提供了一个双分支情况的公式,并且可以通过扩展轻松推断出具有更多分支的情况。

1.4 三分支的情况

这里以三分支为例,绘制网络结构。后续多分支结构与此类似。
在这里插入图片描述

2. SKNet网络体系结构

在这里插入图片描述

  1. 与ResNeXt相似,SKNet主要由一堆重复的瓶颈(bottleneck)块组成,称为“ SK单元”。

  2. 每个SK单元由1×1卷积,SK卷积和1×1卷积的序列组成。

  3. 通常,ResNeXt中原始瓶颈块中的所有大内核卷积都将由SK卷积代替

  4. 与ResNeXt-50相比,SKNet-50仅会使参数数量增加10%,计算成本增加5%。

3. 分析与解释

为什么SKNet会取得这么好的效果?
为了理解自适应卷积核选择的工作原理,我们通过输入相同的目标对象但在不同的尺度上分析注意力。我们从ImageNet验证集中获取所有图像实例,并通过中心裁剪和随后的大小调整逐步将中心对象从1.0倍扩大到2.0倍。

图1 第一个例子
图2 第二个例子

由上述两个例子对比可知:在大多数通道中,当目标对象扩大时,大核(5×5)的注意力权重就会增加,这表明神经元的RF大小会自适应地变大,这与预期相符。
关于跨深度的自适应选择的作用,还有一个令人惊讶的特点:目标对象越大,通过低级和中级阶段(例如,SK 23,SK 34)的“选择性内核”机制,对更大内核的关注就越多。 但是,在更高的层上(例如,SK 5_3),所有比例尺信息都丢失了,这种模式消失了。

在这里插入图片描述
随着目标规模的增长5×5内核的重要性不断提高。在网络的底层部分(前部),可以根据对象大小的语义意识选择合适的内核大小,从而有效地调整这些神经元的RF大小。但是,这种模式在像SK 5_3这样的较高层中并不存在,因为对于高级表示,“比例”部分编码在特征向量中,并且与较低层的情况相比,内核大小的重要性较小

4. 代码

最后,附上SKNet的代码实现。

import torch
import torch.nn as nn


class SKConv(nn.Module):
    def __init__(self, features, M: int = 2, G: int = 32, r: int = 16, stride: int = 1, L: int = 32):
        super().__init__()
        d = max(features / r, L)
        self.M = M
        self.features = features
        # 1.split
        self.convs = nn.ModuleList([])
        for i in range(M):
            self.convs.append(nn.Sequential(
                nn.Conv2d(features, features, kernel_size=3, stride=stride, padding=1+i, dilation=1+i, groups=G, bias=False),
                nn.BatchNorm2d(features),
                nn.ReLU(inplace=True)
            ))
        # 2.fuse
        self.gap = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(nn.Conv2d(features, d, kernel_size=1, stride=1, bias=False),
                                nn.BatchNorm2d(d),
                                nn.ReLU(inplace=True))
        # 3.select
        self.fcs = nn.ModuleList([])
        for i in range(M):
            self.fcs.append(
                 nn.Conv2d(d, features, kernel_size=1, stride=1)
            )
        self.softmax = nn.Softmax(dim=1)
        
    def forward(self, x):
        batch_size = x.shape[0]
        # 1.split
        feats = [conv(x) for conv in self.convs]
        feats = torch.cat(feats, dim=1)
        feats = feats.view(batch_size, self.M, self.features, feats.shape[2], feats.shape[3])
        print('feats.shape', feats.shape)
        # 2.fuse
        feats_U = torch.sum(feats, dim=1)
        feats_S = self.gap(feats_U)
        feats_Z = self.fc(feats_S)
        print('feats_U.shape', feats_U.shape)
        print('feats_S.shape', feats_S.shape)
        print('feats_Z.shape', feats_Z.shape)
        # 3.select
        attention_vectors = [fc(feats_Z) for fc in self.fcs]
        attention_vectors = torch.cat(attention_vectors, dim=1)
        print('attention_vectors.shape', attention_vectors.shape)
        attention_vectors = attention_vectors.view(batch_size, self.M, self.features, 1, 1)
        print('attention_vectors.shape', attention_vectors.shape)
        attention_vectors = self.softmax(attention_vectors)
        feats_V = torch.sum(feats * attention_vectors, dim=1)
        print('feats_V.shape', feats_V.shape)
        return feats_V
    
    
if __name__ == '__main__':
    inputs = torch.randn(4, 64, 512, 512)
    net = SKConv(64)
    outputs = net(inputs)

得到的输出如下所示:

feats.shape torch.Size([4, 2, 64, 512, 512])
feats_U.shape torch.Size([4, 64, 512, 512])
feats_S.shape torch.Size([4, 64, 1, 1])
feats_Z.shape torch.Size([4, 32, 1, 1])
attention_vectors.shape torch.Size([4, 128, 1, 1]) #a, b
attention_vectors.shape torch.Size([4, 2, 64, 1, 1]) #a, b
feats_V.shape torch.Size([4, 64, 512, 512])

总结

SKNet中使用了不同的卷积核,且卷积核权重是不同的,该创新点是突出的!相信一定能在某些情况下取得不错的效果。最后,如果有什么疑问欢迎在评论区提出,对于共性问题可能会后续添加到文章介绍中。

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

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

相关文章

<DB2>《DB2创建分区表及相关操作》(精华)

《DB2创建分区表及相关操作》 1 基本概念2 操作2.1 查看数据库中存在的分区表2.2 查看分区表详细2.3 断开对数据表的访问连接2.4 备份数据2.5 拆离分区2.6 添加分区2.7 导入数据2.8 校验前后数据2.9 删除临时表数据 1 基本概念 当表中的数据量不断增大,查询数据的速…

使用Kettle实现数据排序

一、Kettle的安装 1.下载Kettle的安装包文件 在Windows系统中打开浏览器,访问Kettle官网(https://sourceforge.net/projects/pentaho/),下载Kettle安装文件pdi-ce-9.1.0.0-324.zip。 或者在我的百度网盘分享里面下载 链接&…

【软件测试】软件测试总结笔记(2)

软件测试过程(内容) 1.单元测试基本概念定义⭐单元测试环境⭐单元测试内容单元测试用例的设计思路⭐单元测试的过程 2. 集成测试集成测试内容集成测试优点⭐集成测试层次集成测试方法Drivers and Stubs ⭐集成策略(基于分解的集成&#xff09…

crontab定时任务介绍

1 crontab概述 crontab是linux操作系统上用来设置定时任务的基础命令,是基于crond服务实现任务调度执行。 当安装完成操作系统后,默认会安装crond服务及其附属命令,并且会自动启动crond进程,crond进程每分钟会定期检查是否有要执…

Python量化交易:策略创建运行流程

学习目标 目标 知道策略的创建和运行知道策略的相关设置知道RQ的策略运行流程应用 无 1、体验创建策略、运行策略流程 1.1 创建策略 1.2 策略界面 2、 策略界面功能、运行介绍 2.1 一个完整的策略需要做的事情 选择策略的运行信息: 选择运行区间和初始资金选择回…

水库大坝安全问题有哪些?

我国现有水库大坝9.8万余座,80%水库大坝修建于上世纪50至70年代,受经济、技术等历史因素的影响,存在坝体结构破损、坝基渗漏、坝体渗漏、坝面变形等严重的安全隐患。 一、水库大坝的安全问题主要包括以下几个方面: 1.坝体结构破损…

“微商城”项目(3页面布局)

1.设置标题 设置页面头部标题,方便告诉用户当前显示的是哪一个页面。编辑src\router.js文件,示例代码如下。 routes: [{ path: /, redirect: /home, meta: { title: 首页 } },{ path: /home, component: Home, name: home, meta: { title: 首页 } } ] …

ConditionObject的await方法分析

ConditionObject的await方法分析 判断当前线程是否中断,中断直接抛出非法监视器状态异常要是没有中断则通过addConditionWaiter()方法将该节点加入到Condition的单向链表中通过fullyRelease(node)方法一次新释放掉锁资源初始化一个状态模式为0的标记执行while判断&…

Linux基础【Linux开发】

Linux基础【Linux开发】 1.Linux系统结构2.Linux内核下载流程3. 文本编辑器4. 软件包管理5. shell命令5.1 shell作为命令语言5.2 shell作为编程语言 6. makefile工程管理文件 1.Linux系统结构 2.Linux内核下载流程 Linux内核官方网站👇 3. 文本编辑器 vim 老…

TextCNN:用于文本分类的CNN网络

参考资料:文本分类之TextCNN与DPCNN TextCNN 是在2014年的论文 《Convolutional Neural Networks for Sentence Classification》中提出来的。 以下是TextCNN的网络结构: (1)TextCNN的第一层为 Embedding 层 Embedding 层的输入…

C++的右值引用和移动语义

1.左值和右值 在C中,每个表达式或者是左值,或者是右值。 左值(lvalue):可以出现在赋值表达式左侧的值,例如变量名a、数据成员a.m、解引用表达式*p等。左值可以被赋值和取地址。右值(rvalue):只能出现在赋值表达式右侧…

十七、多线程(下)

文章目录 一、线程互斥,它是对的,但是不合理(饥饿问题)——同步二、条件变量(一)概念(二)条件变量接口1. pthread_cond_init 创建条件变量2. pthread_cond_wait 等待条件满足3. pthr…

类的成员之:构造器(构造方法)

1.构造器的特征: 它具有与类相同的名称它不声明返回值类型。(与声明为void不同)不能被static、final、synchronized、abstract、native修饰,不能有return语句返回值 2.构造器的作用: 1.创建对象2.初始化对象的…

StackLLaMA: A hands-on guide to train LLaMA with RLHF

Paper name StackLLaMA: A hands-on guide to train LLaMA with RLHF Paper Reading Note Project URL: https://huggingface.co/blog/stackllama Code URL: https://huggingface.co/docs/trl/index TL;DR Huggingface 公司开发的 RLHF 训练代码,已集成到 hugg…

产品设计-产品设计五要素

概念介绍 产品设计五要素分别是:战略层、范围层、结构层、框架层、表现层。自上而下的分析可用来分析已有的产品,自下而上分析则可以用来创造新的产品。下面是各个层级所包括的内容: 战略层:产品目标和用户需求(做什…

【STL(2)】

STL(2) 知识点回顾函数对象函数对象理解系统的仿函数仿函数应用 容器适配器stackdeque queuepriority_queue mapmap使用插入访问下标访问的应用:计算文件中单词的个数 知识点回顾 在STL库中存在三个容器适配器,stack - queue - p…

西门子200系列PLC学习课程大纲(课程筹备中)

西门子200系列PLC学习课程大纲如下表所示,共106课,关注我,让你从菜鸟变大神。 第1课西门子200PLC概述S7-200 PLC新特性是什么第2课S7-200 PLC的CPU介绍第3课S7-200 PLC编程软件介绍第4课S7-200 PLC通信方式有哪些第5课S7-200 PLC显示面板介绍…

6.1——我在CSDN的创作纪念日

文章目录 ⭐前言⭐相遇CSDN⭐切换到编程赛道的契机💖 好好的美工为什么切换编程赛道💖 转换编程赛道的催化剂 ⭐写博客的目的——写给未来的自己💖 初衷——为学习铺路💖 博客是灯——照亮前行的路💖 博客是路——互联…

wenet-基于预训练模型进行增量训练

1867-154075-0014 重中之重 run.sh脚本分析 wenet aishell脚本解析_weixin_43870390的博客-CSDN博客 一、准备工作 第一步:准备训练数据,拷贝到远程服务器 将准备好的数据文件0529_0531_dataset,上传到恒源云上的/hy-tmp/wenet/example…

数据结构与算法10:递归树、Trie树、B+树

目录 【递归树】 【Trie 树】 【B树】 【每日一练:最长公共前缀】 【递归树】 递归的思想是将大问题分解为小问题,然后再将小问题分解为更小的问题,直到问题的数据规模被分解得足够小,不用继续递归分解为止。如果把这个一层…