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

相关文章

使用Dify访问mysql数据库详细代码示例

《使用Dify访问mysql数据库详细代码示例》:本文主要介绍使用Dify访问mysql数据库的相关资料,并详细讲解了如何在本地搭建数据库访问服务,使用ngrok暴露到公网,并创建知识库、数据库访... 1、在本地搭建数据库访问的服务,并使用ngrok暴露到公网。#sql_tools.pyfrom

使用mvn deploy命令上传jar包的实现

《使用mvndeploy命令上传jar包的实现》本文介绍了使用mvndeploy:deploy-file命令将本地仓库中的JAR包重新发布到Maven私服,文中通过示例代码介绍的非常详细,对大家的学... 目录一、背景二、环境三、配置nexus上传账号四、执行deploy命令上传包1. 首先需要把本地仓中要

pytorch+torchvision+python版本对应及环境安装

《pytorch+torchvision+python版本对应及环境安装》本文主要介绍了pytorch+torchvision+python版本对应及环境安装,安装过程中需要注意Numpy版本的降级,... 目录一、版本对应二、安装命令(pip)1. 版本2. 安装全过程3. 命令相关解释参考文章一、版本对

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Spring Cloud之注册中心Nacos的使用详解

《SpringCloud之注册中心Nacos的使用详解》本文介绍SpringCloudAlibaba中的Nacos组件,对比了Nacos与Eureka的区别,展示了如何在项目中引入SpringClo... 目录Naacos服务注册/服务发现引⼊Spring Cloud Alibaba依赖引入Naco编程s依

Java springBoot初步使用websocket的代码示例

《JavaspringBoot初步使用websocket的代码示例》:本文主要介绍JavaspringBoot初步使用websocket的相关资料,WebSocket是一种实现实时双向通信的协... 目录一、什么是websocket二、依赖坐标地址1.springBoot父级依赖2.springBoot依赖

Java使用Mail构建邮件功能的完整指南

《Java使用Mail构建邮件功能的完整指南》JavaMailAPI是一个功能强大的工具,它可以帮助开发者轻松实现邮件的发送与接收功能,本文将介绍如何使用JavaMail发送和接收邮件,希望对大家有所... 目录1、简述2、主要特点3、发送样例3.1 发送纯文本邮件3.2 发送 html 邮件3.3 发送带

使用DeepSeek搭建个人知识库(在笔记本电脑上)

《使用DeepSeek搭建个人知识库(在笔记本电脑上)》本文介绍了如何在笔记本电脑上使用DeepSeek和开源工具搭建个人知识库,通过安装DeepSeek和RAGFlow,并使用CherryStudi... 目录部署环境软件清单安装DeepSeek安装Cherry Studio安装RAGFlow设置知识库总

Python FastAPI入门安装使用

《PythonFastAPI入门安装使用》FastAPI是一个现代、快速的PythonWeb框架,用于构建API,它基于Python3.6+的类型提示特性,使得代码更加简洁且易于绶护,这篇文章主要介... 目录第一节:FastAPI入门一、FastAPI框架介绍什么是ASGI服务(WSGI)二、FastAP

Spring-AOP-ProceedingJoinPoint的使用详解

《Spring-AOP-ProceedingJoinPoint的使用详解》:本文主要介绍Spring-AOP-ProceedingJoinPoint的使用方式,具有很好的参考价值,希望对大家有所帮... 目录ProceedingJoinPoijsnt简介获取环绕通知方法的相关信息1.proceed()2.g