YOLOv5、YOLOv8改进:BoTNet Transformer

 

目录

1.简介

2.YOLOv5改进

2.1增加以下yolov5s_botnet.yaml文件

2.2common.py配置

2.3 yolo.py配置修改


1.简介

论文地址

 Paper

 本文提出的BoTNet是一种简单高效的网络,有效的将SA应用到多种视觉任务,如图像识别、目标检测、实例分割任务。通过将ResNet50中最后三个bottleneck模块的空间卷积替换为全局的SA操作,有效提升了基线模型在签署任务上的性能。

Section I
常用的CNN大多采用3x3的卷积核,鉴于卷积操作可以有效的不糊哦局部信息,但是对于一些视觉任务如目标检测、实例分割、关键点检测还需要建立长程依赖关系。比如实例分割中需要收集场景相关的信息才能学习物体之间的关系;那么为了吧局部信息聚合就需要堆叠多个卷积层。但基于non-local操作可以更有效,也不需要堆叠那么多层。
而建模长程依赖对NLP任务也十分重要,Self-Attention可以有效学习每一对实体之间的关联,基于SA组成的Transformer已经成为NLP的主流,如GPT和BERT。


SA应用于视觉的一种简便方法及时将卷积层替换为MHSA层,参见Fig 1。按照这种思路有两种改进方向,一是将Resnet中的卷积层替换为各种SA操作,比如SASA,AACN,SANet;二是将图像切分成互补重叠的patch然后送入堆叠的Transformer模块。

虽然看起来是两种不同类型的体系结构,但是事实并非如此。本文提出ResNet 模块中使用MHSA层可以看做是一种带有瓶颈结构的Transformer模块,只不过有细微的变化比如残差连接、归一化层的选择上。因此本文将带有MHSA层的ResNet模块称之为BoT模块,具体结构参见Fig3.
将注意力应用到视觉领域有以下挑战:
(1)图像一般比用于分类的图像更大,分类一般(224,224)就够了,用于目标检测和实例分割的图像分辨率更高。

(2)SA的计算是输入分辨率的平方项,因此对内存和算力有要求

为了克服以上挑战本文进行以下设计:

(1)使用卷积来高效学习低分辨率、抽象的特征

(2)使用SA来处理、聚合卷积提取到的特征

这种混合设计可以有效利用卷积和SA的优点,同通过卷积进行下采样可以有效处理较高分辨率的输入图像。

因此本文的提出一种简单的设计方案:将ResNet最后三个block替换为BoT模块,其余不做任何改动。再说明白点,只将ResNet最后三个3x3卷积替换为MHSA层。


只做这一小小的改动,就将COCO上目标检测精度提升了1.2%;并且BoTNet在结构上并没什么新颖之处因此本文相信这种简洁性使其可以作为一个值得进一步研究的backbone。
使用BoTNet做实例分割,效果也有显著提升,尤其对小物体有显著提升。



最后本文还对BoTNet进行了放缩,发现BoTNet在更小数据集上没有什么实质性提升,但在ImageNet上达到了84.7%的top-1精度;在TPU-V3硬件测试上比目前流行的EfficientNet块1.64倍。基于BoTNet展现的结果本文希望SA未来可以在视觉任务中广泛使用。

 

Section II Related Work
Fig 2总结了计算机视觉任务中的注意力,本节主要关注:

(1)Transformer vs BoTNet


(2)DETR vs BoTNet

 
(3)Bon-Local vs BoTNet

Fig 3中左侧是Transformer ,中间是本文定义的BoT模块,右侧就是ResNet Block中将卷积层替换为MHSA后的结果


Connection to the Transformer


正如标题提到的本文的关键是将ResNet中的block替换为MHSA层,但BoT的架构设计并不是本文的贡献,本文只是指出MHSA ResNet Bottleneck与Transformer之间的关系,从而能够提升对计算机视觉中SA的理解和设计。



除了在Fig 3中恒看出的区别,如残差连接还有一些区别如:




(1)归一化 Transformer使用的是LN而ResNet使用的是BN

(2)非线性 Transforemr在FFN层引入非线性,ResNet则在BoT中使用了3个非线性变换

(3)输出映射 Transformer中的MHSA包含一个输出投影而BoT中没有

(4)一般视觉任务常使用SGD Optimizer而Transformer通常使用Adam Optimizer

Connection to DETR


DETR是基于Transformer的目标检测框架,DETR和BoTNet都尝试使用SA来提升目标检测和实例分割的性能,不同之处在于DETR是在主干之外使用了SA模块,主要目的是为了避免使用RP和非极大值抑制;


BoTNet目的是为了提出一个主干框架直接进行目标检测和实例分割。实验结果显示BoTNet对小物体的检测提升效果明显,相信在未来可以解决DETR对小物体检测不佳的问题。



Connection to Non-Local Neural Nets




Non-Local Nets主要是将Transformer与非局部算法结合,比如在ResNet最后的1-2个stage中引入非局部模块,来提升实例分割、视频分类的效果,BoT是一种混合设计,同时使用了卷积核SA。




Fig 4展示了Non-Local层和SA层的区别:





(1)MHSA中包含多个头来进行Q,K,V的映射





(2)NL Block中通常包含一个通道缩放因子对通道进行缩放,因子通常设置为2,而MHSA中设置为4





(3)NL Block是作为一个额外的模块插入到ResNet Block中 但是BoTNet是直接替换

Section III Method
BoTNet的设计很简单,将ResNet的最后三个3x3卷积替换为MHSA,这样就实现了featuremap的全局计算。通常ResNet包含4个stage[c2,c3,c4,c5],每一个stage中堆叠不同的block,并且使用残差连接。




 
本文的目标就是使用将SA用于高分辨率的实例分割,因此最简单的方法就是在主干网路低分辨率特征图中加入注意力,即c5阶段,c5一般包含3个残差快,因此将这3个残差快替换为MHSA模块就组成了BoTNet。

Table 1展示了BoTNet的网络结构,Fig 4展示了MHSA的结构。涉及到步长卷积的操作在本文都替换为了池化操作。




 
Relative Position Encodings




 
近期研究表明相对位置编码更有效,因为考虑了不同位置特征之间的相对距离,从而能够有效的将不同内容之间的相对距离考虑进来,因此BoTNet使用的是2D相对位置编码。

2.YOLOv5改进

2.1增加以下yolov5s_botnet.yaml文件

# parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multipleanchors:- [10,13, 16,30, 33,23]  # P3/8- [30,61, 62,45, 59,119]  # P4/16- [116,90, 156,198, 373,326]  # P5/32# YOLOv5 backbone
backbone:# [from, number, module, args]               # [c=channels,module,kernlsize,strides][[-1, 1, Conv, [64, 6, 2, 2]],   # 0-P1/2           [c=3,64*0.5=32,3][-1, 1, Conv, [128, 3, 2]],  # 1-P2/4    [-1, 3, C3, [128]],                                [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8            [-1, 6, C3, [256]],                         [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16       [-1, 9, C3, [512]],                     [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32[-1, 1, SPPF, [1024,5]],[-1, 3, BoT3, [1024]],  # 9]# YOLOv5 head
head:[[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 5], 1, Concat, [1]],  # cat backbone P4[-1, 3, C3, [512, False]],  # 13[-1, 1, Conv, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 3], 1, Concat, [1]],  # cat backbone P3[-1, 3, C3, [256, False]],  # 17 (P3/8-small)[-1, 1, Conv, [256, 3, 2]],[[-1, 14], 1, Concat, [1]],  # cat head P4[-1, 3, C3, [512, False]],  # 20 (P4/16-medium)       [256, 256, 1, False]  [-1, 1, Conv, [512, 3, 2]],                           #[256, 256, 3, 2] [[-1, 10], 1, Concat, [1]],  # cat head P5[-1, 3, C3, [1024, False]],  # 23 (P5/32-large)       [512, 512, 1, False][[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)]

2.2common.py配置

class MHSA(nn.Module):def __init__(self, n_dims, width=14, height=14, heads=4,pos_emb=False):super(MHSA, self).__init__()self.heads = headsself.query = nn.Conv2d(n_dims, n_dims, kernel_size=1)self.key = nn.Conv2d(n_dims, n_dims, kernel_size=1)self.value = nn.Conv2d(n_dims, n_dims, kernel_size=1)self.pos=pos_embif self.pos :self.rel_h_weight = nn.Parameter(torch.randn([1, heads, (n_dims ) // heads, 1, int(height)]), requires_grad=True)self.rel_w_weight = nn.Parameter(torch.randn([1, heads, (n_dims )// heads, int(width), 1]), requires_grad=True)self.softmax = nn.Softmax(dim=-1)def forward(self, x):n_batch, C, width, height = x.size() q = self.query(x).view(n_batch, self.heads, C // self.heads, -1)k = self.key(x).view(n_batch, self.heads, C // self.heads, -1)v = self.value(x).view(n_batch, self.heads, C // self.heads, -1)#print('q shape:{},k shape:{},v shape:{}'.format(q.shape,k.shape,v.shape))  #1,4,64,256content_content = torch.matmul(q.permute(0,1,3,2), k) #1,C,h*w,h*w# print("qkT=",content_content.shape)c1,c2,c3,c4=content_content.size()if self.pos:# print("old content_content shape",content_content.shape) #1,4,256,256content_position = (self.rel_h_weight + self.rel_w_weight).view(1, self.heads, C // self.heads, -1).permute(0,1,3,2)   #1,4,1024,64content_position = torch.matmul(content_position, q)# ([1, 4, 1024, 256])content_position=content_position if(content_content.shape==content_position.shape)else content_position[:,: , :c3,]assert(content_content.shape==content_position.shape)#print('new pos222-> shape:',content_position.shape)# print('new content222-> shape:',content_content.shape)energy = content_content + content_positionelse:energy=content_contentattention = self.softmax(energy)out = torch.matmul(v, attention.permute(0,1,3,2)) #1,4,256,64out = out.view(n_batch, C, width, height)return out
class BottleneckTransformer(nn.Module):# Transformer bottleneck#expansion = 1def __init__(self, c1, c2, stride=1, heads=4, mhsa=True, resolution=None,expansion=1):super(BottleneckTransformer, self).__init__()c_=int(c2*expansion)self.cv1 = Conv(c1, c_, 1,1)#self.bn1 = nn.BatchNorm2d(c2)if not mhsa:self.cv2 = Conv(c_,c2, 3, 1)else:self.cv2 = nn.ModuleList()self.cv2.append(MHSA(c2, width=int(resolution[0]), height=int(resolution[1]), heads=heads))if stride == 2:self.cv2.append(nn.AvgPool2d(2, 2))self.cv2 = nn.Sequential(*self.cv2)self.shortcut = c1==c2 if stride != 1 or c1 != expansion*c2:self.shortcut = nn.Sequential(nn.Conv2d(c1, expansion*c2, kernel_size=1, stride=stride),nn.BatchNorm2d(expansion*c2))self.fc1 = nn.Linear(c2, c2)     def forward(self, x):out=x + self.cv2(self.cv1(x)) if self.shortcut else self.cv2(self.cv1(x))return outclass BoT3(nn.Module):# CSP Bottleneck with 3 convolutionsdef __init__(self, c1, c2, n=1,e=0.5,e2=1,w=20,h=20):  # ch_in, ch_out, number, , expansion,w,hsuper(BoT3, self).__init__()c_ = int(c2*e)  # hidden channelsself.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c1, c_, 1, 1)self.cv3 = Conv(2 * c_, c2, 1)  # act=FReLU(c2)self.m = nn.Sequential(*[BottleneckTransformer(c_ ,c_, stride=1, heads=4,mhsa=True,resolution=(w,h),expansion=e2) for _ in range(n)])# self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])def forward(self, x):return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1)) 

2.3 yolo.py配置修改

然后找到./models/yolo.py文件下里的parse_model函数,将加入的模块名BoT3加入进去
在 models/yolo.py文件夹下

 

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

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

相关文章

06-基础例程6

基础例程6 01、WIFI实验—WebServer 实验介绍 ​ 连接路由器上网是我们每天都做的事情,日常生活中只需要知道路由器的账号和密码,就可以使用手机或电脑连接到路由器,然后上网。 ​ 连接路由器,将ESP32的IP地址等信息通过shell…

自动化运维:Ansible脚本之playbook剧本

目录 一、理论 1.playbooks 2.YAML 3.使用ansible批量安装apache服务 4.定义、引用变量 5.指定远程主机sudo切换用户 6.when条件判断 7.迭代 8.Templates 模块 9.tags 模块 10.Roles 模块 二、实验 1.使用ansible批量安装apache服务 2.定义、引用变量…

【STM32】学习笔记-江科大

【STM32】学习笔记-江科大 1、STM32F103C8T6的GPIO口输出 2、GPIO口输出 GPIO(General Purpose Input Output)通用输入输出口可配置为8种输入输出模式引脚电平:0V~3.3V,部分引脚可容忍5V输出模式下可控制端口输出高低电平&#…

华为数通方向HCIP-DataCom H12-821题库(单选题:101-120)

第101题 可用于多种路由协议,由 ​​if-match​​​和 ​​apply​​子句组成的路由选择工具是 A、​​route-policy​​ B、​​IP-Prefix​​ C、​​commnityfilter​​ D、​​as-path-filter​​ 答案:A 解析: Route-policy(路由策…

Oracle数据传输加密方法

服务器端“dbhome_1\NETWORK\ADMIN\”sqlnet.ora文件中添加 SQLNET.ENCRYPTION_SERVER requested SQLNET.ENCRYPTION_TYPES_SERVER (RC4_256) 添加后新的链接即刻生效,服务器无需重新启动。 也可以通过Net manager管理工具添加 各个参数含义如下: 是…

excel功能区(ribbonx)编程笔记--2 button控件与checkbox控件

我们上一章简单先了解了ribbonx的基本内容,以及使用举例实现自己修改ribbox的内容,本章紧接上一章,先讲解一下ribbonx的button控件。 在功能区的按钮中,可以使用内置图像或提供自已的图像,可以指定大按钮或者更小的形式,添加少量的代码甚至可以同时提供标签。此外,可以利…

LoRA学习笔记

Background 全参微调 全量微调指的是,在下游任务的训练中,对预训练模型的每一个参数都做更新。例如图中,给出了Transformer的Q/K/V矩阵的全量微调示例,对每个矩阵来说,在微调时,其d*d个参数,都…

数据库CPU飙高问题定位及解决

在业务服务提供能力的时候,常常会遇到CPU飙高的问题,遇到这类问题,大多不是数据库自身问题,都是因为使用不当导致,这里记录下业务服务如何定位数据库CPU飙高问题并给出常见的解决方案。 CPU 使用率飙升根因分析 在分…

Centos7 安装Docker管理工具Portainer

0、前提条件 已安装Docker并且开启Docker,安装Docker可参见:Centos7 安装 Docker_瘦身小蚂蚁的博客-CSDN博客 1、 拉取portainer-ce镜像 docker pull portainer/portainer-ce:latest [rootlocalhost ~]# docker pull portainer/portainer-ce:latest la…

Doris架构中包含哪些技术?

Doris主要整合了Google Mesa(数据模型),Apache Impala(MPP Query Engine)和Apache ORCFile (存储格式,编码和压缩)的技术。 为什么要将这三种技术整合? Mesa可以满足我们许多存储需求的需求,但是Mesa本身不提供SQL查询引擎。 Impala是一个…

1 Hadoop入门

1.Hadoop是什么? (1)Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 (2)主要解决,海量数据的存储和海量数据的分析计算问题。 (3)广义上来说,Hadoop通常是指一个更广泛的概念——Hadoop生态圈 2.Hadoop的优势 3 Hadoop组成 4 HDF…

git 基础

1.下载安装Git(略) 2.打开git bash窗口 3.查看版本号、设置用户名和邮箱 用户名和邮箱可以随意起,与GitHub的账号邮箱没有关系 4.初始化git 在D盘中新建gitspace文件夹,并在该目录下打开git bash窗口 git init 初始化完成后会…

GO语言语法结构

GO语言结构 包声明引入包函数变量语句 && 表达式注释 package main import "fmt" func main() {fmt.Println("Hello,World!") } 如这段代码块根据上面的语法结构进行逐行解释 第一行的 package main 是定义一个包名,必须在源文件…

vector实现遇到的问题

前言:vector是表示可变大小数组的序列容器。就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它…

阿里云大数据实战记录8:拆开 json 的每一个元素,一行一个

目录 一、前言二、目标介绍三、使用 pgsql 实现3.1 拆分 content 字段3.2 拆分 level 字段3.3 拼接两个拆分结果 四、使用 ODPS SQL 实现4.1 拆分 content 字段4.2 拆分 level 字段4.3 合并拆分 五、使用 MySQL 实现六、总结 一、前言 商业场景中,经常会出现新的业…

docker network

docker network create <network>docker network connect <network> <container>docker network inspect <network>使用这个地址作为host即可 TODO&#xff1a;添加docker-compose

【CI/CD技术专题】「Docker实战系列」本地进行生成镜像以及标签Tag推送到DockerHub

背景介绍 Docker镜像构建成功后&#xff0c;只要有docker环境就可以使用&#xff0c;但必须将镜像推送到Docker Hub上去。创建的镜像最好要符合Docker Hub的tag要求&#xff0c;因为在Docker Hub注册的用户名是liboware&#xff0c;最后利用docker push命令推送镜像到公共仓库…

Redis发布订阅

Redis发布订阅 Redis 发布订阅(pub/sub)是一种 消息通信模式&#xff1a;发送者(pub)发送消息&#xff0c;订阅者(sub)接收消息。 Redis 客户端可以订阅任意数量的频道。 订阅/发布消息图&#xff1a; 下图展示了频道 channel1 &#xff0c; 以及订阅这个频道的三个客户端 —…

Linux中的工具:yum,vim,gcc/g++,make/makefile,gdb

目录 1、yum 1.1 查看软件包&#xff1a; 1.2 安装软件包 1.3 卸载软件 2、vim 2.1 vim的三种模式 2.2 vim的基本操作 2.3. vim正常模式命令集 2.3.1 插入模式 2.3.2 移动光标 2.3.3 删除文字 2.3.4 复制 2.3.5 替换 2.3.6撤销上一次操作 2.3.7 更改 2.3.8 跳至…