SKNet学习和使用-pytorch

2023-10-29 19:40
文章标签 学习 使用 pytorch sknet

本文主要是介绍SKNet学习和使用-pytorch,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Selective Kernel Networks

论文:https://arxiv.org/abs/1903.06586?context=cs

代码:https://github.com/pppLang/SKNet

其灵感来源是,我们在看不同尺寸不同远近的物体时,视觉皮层神经元接受域大小是会根据刺激来进行调节的。那么对应于CNN网络,一般来说对于特定任务特定模型,卷积核大小是确定的,那么是否可以构建一种模型,使网络可以根据输入信息的多个尺度自适应的调节接受域大小呢?

SK单元用不同卷积核提取特征,然后通过每个分支引导的不同信息构成的softmax进行融合。

SK单元包括三个方面:Split, Fuse, Select

  • Split:阶段使用不同的卷积核对原图进行卷积;
  • Fuse:组合并聚合来自多个路径的信息,以获得选择权重的全局和综合表示;
  • Select:根据选择权重聚合不同大小的内核的特征映射。

Split:

✔️ 对于任意输入的feature map,首先进行两个变化,得到 ,使用的kernel size分别为 3x3 和 5x5,其中 5x5 的卷积核替换为一个dilation为2的3x3的卷积核。

Fuse:

✔️ 该步骤主要通过门控机制将上一层的输出进行有选择的筛选,使每一个分支都携带不同的信息流进入下一个神经元。

  1. 对不同分支的输出进行融合,即逐元素进行相加(输出的尺寸和通道数必须是一样的);

2. 对两个输出进行全局平均池化(global average pooling )操作,获得每一个通道上的全局信息;

3. 对输出 s 做全连接找到每一个通道占的比重大小;

δ 是relu函數,B表示批正则化处理.

4. 为了验证W中d的作用,引入了一个衰减率r,如下,其中C代表通道数。

Select:

✔️ 通道间的soft attention可以选择不同尺寸的信息,其被紧凑的特征信息z引导,在channel-wise应用softmax操作。

网络结构

✔️ 每个SK单元由一个1x1的卷积,SK卷积,及1x1卷积组成,原网络中所有具有较大尺寸的卷积核都替换为SK卷积从而可以使网络选择合适的感受野大小。

✔️ 在SK单元中,存在三个重要参数:

  • M 用于决定路径的数量,即选择不同卷积核尺寸进行融合的数量;
  • G 用于控制每个路径的基数;
  • r 用于控制fuse操作中的参数数量。

实验结果

SKNet代码

import torch.nn as nn
import torch
from functools import reduce
class SKConv(nn.Module):def __init__(self,in_channels,out_channels,stride=1,M=2,r=16,L=32):''':param in_channels:  输入通道维度:param out_channels: 输出通道维度   原论文中 输入输出通道维度相同:param stride:  步长,默认为1:param M:  分支数:param r: 特征Z的长度,计算其维度d 时所需的比率(论文中 特征S->Z 是降维,故需要规定 降维的下界):param L:  论文中规定特征Z的下界,默认为32'''super(SKConv,self).__init__()d=max(in_channels//r,L)   # 计算向量Z 的长度dself.M=Mself.out_channels=out_channelsself.conv=nn.ModuleList()  # 根据分支数量 添加 不同核的卷积操作for i in range(M):# 为提高效率,原论文中 扩张卷积5x5为 (3X3,dilation=2)来代替。 且论文中建议组卷积G=32self.conv.append(nn.Sequential(nn.Conv2d(in_channels,out_channels,3,stride,padding=1+i,dilation=1+i,groups=32,bias=False),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True)))self.global_pool=nn.AdaptiveAvgPool2d(1) # 自适应pool到指定维度    这里指定为1,实现 GAPself.fc1=nn.Sequential(nn.Conv2d(out_channels,d,1,bias=False),nn.BatchNorm2d(d),nn.ReLU(inplace=True))   # 降维self.fc2=nn.Conv2d(d,out_channels*M,1,1,bias=False)  # 升维self.softmax=nn.Softmax(dim=1) # 指定dim=1  使得两个全连接层对应位置进行softmax,保证 对应位置a+b+..=1def forward(self, input):batch_size=input.size(0)output=[]#the part of splitfor i,conv in enumerate(self.conv):#print(i,conv(input).size())output.append(conv(input))#the part of fusionU=reduce(lambda x,y:x+y,output) # 逐元素相加生成 混合特征Us=self.global_pool(U)z=self.fc1(s)  # S->Z降维a_b=self.fc2(z) # Z->a,b 升维  论文使用conv 1x1表示全连接。结果中前一半通道值为a,后一半为ba_b=a_b.reshape(batch_size,self.M,self.out_channels,-1) #调整形状,变为 两个全连接层的值a_b=self.softmax(a_b) # 使得两个全连接层对应位置进行softmax#the part of selectiona_b=list(a_b.chunk(self.M,dim=1))#split to a and b   chunk为pytorch方法,将tensor按照指定维度切分成 几个tensor块a_b=list(map(lambda x:x.reshape(batch_size,self.out_channels,1,1),a_b)) # 将所有分块  调整形状,即扩展两维V=list(map(lambda x,y:x*y,output,a_b)) # 权重与对应  不同卷积核输出的U 逐元素相乘V=reduce(lambda x,y:x+y,V) # 两个加权后的特征 逐元素相加return V
class SKBlock(nn.Module):'''基于Res Block构造的SK BlockResNeXt有  1x1Conv(通道数:x) +  SKConv(通道数:x)  + 1x1Conv(通道数:2x) 构成'''expansion=2 #指 每个block中 通道数增大指定倍数def __init__(self,inplanes,planes,stride=1,downsample=None):super(SKBlock,self).__init__()self.conv1=nn.Sequential(nn.Conv2d(inplanes,planes,1,1,0,bias=False),nn.BatchNorm2d(planes),nn.ReLU(inplace=True))self.conv2=SKConv(planes,planes,stride)self.conv3=nn.Sequential(nn.Conv2d(planes,planes*self.expansion,1,1,0,bias=False),nn.BatchNorm2d(planes*self.expansion))self.relu=nn.ReLU(inplace=True)self.downsample=downsampledef forward(self, input):shortcut=inputoutput=self.conv1(input)output=self.conv2(output)output=self.conv3(output)if self.downsample is not None:shortcut=self.downsample(input)output+=shortcutreturn self.relu(output)
class SKNet(nn.Module):'''参考 论文Table.1 进行构造'''def __init__(self,nums_class=1000,block=SKBlock,nums_block_list=[3, 4, 6, 3]):super(SKNet,self).__init__()self.inplanes=64# in_channel=3  out_channel=64  kernel=7x7 stride=2 padding=3self.conv=nn.Sequential(nn.Conv2d(3,64,7,2,3,bias=False),nn.BatchNorm2d(64),nn.ReLU(inplace=True))self.maxpool=nn.MaxPool2d(3,2,1) # kernel=3x3 stride=2 padding=1self.layer1=self._make_layer(block,128,nums_block_list[0],stride=1) # 构建表中 每个[] 的部分self.layer2=self._make_layer(block,256,nums_block_list[1],stride=2)self.layer3=self._make_layer(block,512,nums_block_list[2],stride=2)self.layer4=self._make_layer(block,1024,nums_block_list[3],stride=2)self.avgpool=nn.AdaptiveAvgPool2d(1) # GAP全局平均池化self.fc=nn.Linear(1024*block.expansion,nums_class) # 通道 2048 -> 1000self.softmax=nn.Softmax(-1) # 对最后一维进行softmaxdef forward(self, input):output=self.conv(input)output=self.maxpool(output)output=self.layer1(output)output=self.layer2(output)output=self.layer3(output)output=self.layer4(output)output=self.avgpool(output)output=output.squeeze(-1).squeeze(-1)output=self.fc(output)output=self.softmax(output)return outputdef _make_layer(self,block,planes,nums_block,stride=1):downsample=Noneif stride!=1 or self.inplanes!=planes*block.expansion:downsample=nn.Sequential(nn.Conv2d(self.inplanes,planes*block.expansion,1,stride,bias=False),nn.BatchNorm2d(planes*block.expansion))layers=[]layers.append(block(self.inplanes,planes,stride,downsample))self.inplanes=planes*block.expansionfor _ in range(1,nums_block):layers.append(block(self.inplanes,planes))return nn.Sequential(*layers)
def SKNet50(nums_class=1000):return SKNet(nums_class,SKBlock,[3, 4, 6, 3]) # 论文通过[3, 4, 6, 3]搭配出SKNet50
def SKNet101(nums_class=1000):return SKNet(nums_class,SKBlock,[3, 4, 23, 3])
if __name__=='__main__':x = torch.rand(2, 3, 224, 224)model=SKNet50()y=model(x)print(y) # shape [2,1000]

参考文档:https://zhuanlan.zhihu.com/p/76033612

这篇关于SKNet学习和使用-pytorch的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/302928

相关文章

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

Jsoncpp的安装与使用方式

《Jsoncpp的安装与使用方式》JsonCpp是一个用于解析和生成JSON数据的C++库,它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式,安装JsonCpp可以通过... 目录安装jsoncppJsoncpp的使用Value类构造函数检测保存的数据类型提取数据对json数

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

springboot整合 xxl-job及使用步骤

《springboot整合xxl-job及使用步骤》XXL-JOB是一个分布式任务调度平台,用于解决分布式系统中的任务调度和管理问题,文章详细介绍了XXL-JOB的架构,包括调度中心、执行器和Web... 目录一、xxl-job是什么二、使用步骤1. 下载并运行管理端代码2. 访问管理页面,确认是否启动成功

使用Nginx来共享文件的详细教程

《使用Nginx来共享文件的详细教程》有时我们想共享电脑上的某些文件,一个比较方便的做法是,开一个HTTP服务,指向文件所在的目录,这次我们用nginx来实现这个需求,本文将通过代码示例一步步教你使用... 在本教程中,我们将向您展示如何使用开源 Web 服务器 Nginx 设置文件共享服务器步骤 0 —

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min

使用Python绘制可爱的招财猫

《使用Python绘制可爱的招财猫》招财猫,也被称为“幸运猫”,是一种象征财富和好运的吉祥物,经常出现在亚洲文化的商店、餐厅和家庭中,今天,我将带你用Python和matplotlib库从零开始绘制一... 目录1. 为什么选择用 python 绘制?2. 绘图的基本概念3. 实现代码解析3.1 设置绘图画