Conv2Former:一种transformer风格的卷积特征提取方式

一、前言

昨天读到了一篇有意思的文章,文章提出通过利用卷积调制操作来简化self-attention。还证明了这种简单的方法可以更好地利用卷积层中嵌套的大核(≥7 × 7)。我们都知道ViTs推动了设计识别模型的发展,近几年使用的也相当的多,通常就是CNN网络引入注意力机制,往往可以获得不错的性能,因为相比较与卷积cnn,self-attention能够模拟全局成对依赖关系,这是一种更有效的空间信息编码方式。

自注意机制与所提出的卷积调制运算的比较 

作者注意到有研究者通过对标准ResNet进行现代化改进,采用与Transformers相似的设计和训练方法,ConvNets的性能在某些情况下甚至能够超越一些热门的ViTs。由此,引入了一种名为Conv2Former的新型网络结构,旨在更有效地利用空间卷积。与以往工作不同,Conv2Former采用了一种称为卷积调制的操作,通过将大内核卷积的输出与值表示进行Hadamard乘积,模拟了自注意力的输出计算过程。与传统的ViTs使用自注意力不同,Conv2Former完全是一个卷积网络,其计算复杂度随分辨率线性增加,而不是像Transformers那样呈二次增加。

二、Conv2Former的网络架构

在每两个阶段间,引入了一个Patch Embed来降低分辨率,通常是一个2 × 2的卷积,步幅为2。不同的阶段有不同数量的卷积块。

构建了五个Conv2Former变体,分别是Conv2Former- n、Conv2Former- t、Conv2Former- s、Conv2Former- b、Conv2Former- l。参数由下图所示:

残差块、自注意块和所提出的调制块之间的对比图

与自注意相比,(d)方法利用卷积来建立关系,这比自注意更节省内存,特别是在处理高分辨率图像时。与经典的残差块方法(a)相比,(d)还可以通过调制操作来适应输入内容。

在VGG,Resnet等网络提出后,3x3卷积几乎就是构建卷积网络的标准选择,但深度可分离卷积的出现改变了这一格局。ConvNeXt的研究显示,将卷积核从3扩大到7可以提升性能,然而,进一步增大卷积核几乎不再带来性能提升,反而增加了计算负担。

作者认为ConvNeXt未能从大于7×7的更大卷积核中获得更大性能提升的原因在于对空间卷积的使用方式。相比之下,Conv2Former通过观察发现,在卷积核大小从5×5增加到21×21的范围内,性能持续提升。这一现象在不同规模的Conv2Former模型中均得到验证,为更好地利用空间卷积提供了重要的设计指导。

考虑到模型的效率,作者选择将卷积核大小默认设置为11×11。这一研究发现对于ConvNet设计,更大的卷积核可以通过正确的使用方式获得持续的性能提升,为未来的视觉识别模型提供了有益的启示。

在Conv2Former的标准化和激活层方面,标准化层使用Layer Normalization,而不是常用的批标准化,激活层采用GELU。作者发现这种Layer Normalization和GELU的组合能够带来0.1%-0.2%的性能提升。

三、卷积调制操作

卷积核大小影响性能

实验证明,在Conv2Former中,增加深度卷积核大小(从5×5到21×21)可以显著提升模型性能,与传统结论不同,这表明使用卷积特征作为权重能更有效地利用大核,相较于传统方法无法带来明显性能提升。

Hadamard乘积优于求和

对比Hadamard乘积和元素求和两种融合策略,实验证明在Conv2Former中,使用深度卷积特征通过Hadamard乘积调制权重表现更好,尤其对于小型模型。这突显了卷积调制在编码空间信息方面的高效性。

权重策略分析

通过尝试不同的特征图融合方式,包括添加Sigmoid函数、应用L1标准化以及线性归一化等,结果显示Hadamard乘积依然是最优选择。有趣的是,将A的值调整为正值反而导致性能下降,与传统注意机制的做法有所不同,为未来研究提供了新的问题。

四、论文复现

作者也是给出了代码地址:HVision-NKU/Conv2Former

但我看了一下,里面只是给出了一些核心的代码,所以复现还是要靠咱自己。

"""
Copyright (c) 2023, Auorui.
All rights reserved.reference <https://arxiv.org/pdf/2211.11943.pdf> (Conv2Former: A Simple Transformer-Style ConvNet for Visual Recognition)
Time:2023.12.31, Complete before the end of 2023.
"""
import torch
import torch.nn as nnfrom pyzjr.Models import DropPathC = {'n': [64, 128, 256, 512],'t': [72, 144, 288, 576],'s': [72, 144, 288, 576],'b': [96, 192, 384, 768],'l': [128, 256, 512, 1024],} #  reference <https://arxiv.org/pdf/2211.11943.pdf> Table 1
L = {'n': [2, 2, 8, 2],'t': [3, 3, 12, 3],'s': [4, 4, 32, 4],'b': [4, 4, 34, 4],'l': [4, 4, 48, 4],} #  reference <https://arxiv.org/pdf/2211.11943.pdf> Table 1class MLP(nn.Module):def __init__(self, dim, mlp_ratio=4.):super().__init__()self.norm = nn.LayerNorm(dim, eps=1e-6)self.fc1 = nn.Conv2d(dim, dim * mlp_ratio, 1)self.pos = nn.Conv2d(dim * mlp_ratio, dim * mlp_ratio, 3, padding=1, groups=dim * mlp_ratio)self.fc2 = nn.Conv2d(dim * mlp_ratio, dim, 1)self.act = nn.GELU()def forward(self, x):x = self.norm(x.permute(0, 2, 3, 1)).permute(0, 3, 1, 2)x = self.fc1(x)x = self.act(x)x = x + self.act(self.pos(x))x = self.fc2(x)return xclass ConvMod(nn.Module):def __init__(self, dim):super().__init__()self.norm = nn.LayerNorm(dim, eps=1e-6)self.a = nn.Sequential(nn.Conv2d(dim, dim, 1),nn.GELU(),nn.Conv2d(dim, dim, 11, padding=5, groups=dim))self.v = nn.Conv2d(dim, dim, 1)self.proj = nn.Conv2d(dim, dim, 1)def forward(self, x):x = self.norm(x.permute(0, 2, 3, 1)).permute(0, 3, 1, 2)a = self.a(x)x = a * self.v(x)x = self.proj(x)return xclass Block(nn.Module):def __init__(self, dim, mlp_ratio=4.0, drop_path=0.):super().__init__()self.attn = ConvMod(dim)self.mlp = MLP(dim, mlp_ratio)layer_scale_init_value = 1e-6self.layer_scale_1 = nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True)self.layer_scale_2 = nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True)self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()def forward(self, x):x = x + self.drop_path(self.layer_scale_1.unsqueeze(-1).unsqueeze(-1) * self.attn(x))x = x + self.drop_path(self.layer_scale_2.unsqueeze(-1).unsqueeze(-1) * self.mlp(x))return xclass BaseLayer(nn.Module):def __init__(self, dim, depth, mlp_ratio=4., drop_path=None, downsample=True):super().__init__()self.dim = dimself.drop_path = drop_pathself.blocks = nn.ModuleList([Block(dim=self.dim,mlp_ratio=mlp_ratio,drop_path=drop_path[i],)for i in range(depth)])# patch merging layerif downsample:self.downsample = nn.Sequential(nn.GroupNorm(num_groups=1, num_channels=dim),nn.Conv2d(dim, dim * 2, kernel_size=2, stride=2,bias=False))else:self.downsample = Nonedef forward(self, x):for blk in self.blocks:x = blk(x)if self.downsample is not None:x = self.downsample(x)return xclass Conv2Former(nn.Module):def __init__(self, num_classes=10, depths=(2,2,8,2), dim=(64,128,256,512), mlp_ratio=2.,drop_rate=0.,drop_path_rate=0.15, **kwargs):super().__init__()norm_layer = nn.LayerNormself.num_classes = num_classesself.num_layers = len(depths)self.dim = dimself.mlp_ratio = mlp_ratioself.pos_drop = nn.Dropout(p=drop_rate)# stochastic depth decay ruledpr = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))]# build layersself.layers = nn.ModuleList()for i_layer in range(self.num_layers):layer = BaseLayer(dim[i_layer],depth=depths[i_layer],mlp_ratio=self.mlp_ratio,drop_path=dpr[sum(depths[:i_layer]):sum(depths[:i_layer + 1])],downsample=(i_layer < self.num_layers - 1),)self.layers.append(layer)self.fc1 = nn.Conv2d(3, dim[0], 1)self.norm = norm_layer(dim[-1], eps=1e-6,)self.avgpool = nn.AdaptiveAvgPool2d(1)self.head = nn.Linear(dim[-1], num_classes) \if num_classes > 0 else nn.Identity()self.apply(self._init_weights)def _init_weights(self, m):if isinstance(m, nn.Linear):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias, 0.)elif isinstance(m, (nn.Conv1d, nn.Conv2d)):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias, 0.)elif isinstance(m, (nn.LayerNorm, nn.GroupNorm)):nn.init.constant_(m.bias, 0.)nn.init.constant_(m.weight, 1.)def forward_features(self, x):x = self.fc1(x)x = self.pos_drop(x)for layer in self.layers:x = layer(x)x = self.norm(x.permute(0, 2, 3, 1)).permute(0, 3, 1, 2)x = self.avgpool(x)x = torch.flatten(x, 1)return xdef forward(self, x):x = self.forward_features(x)x = self.head(x)return xif __name__ == '__main__':model = Conv2Former(num_classes=10, depths=L["b"], dim=C["b"], mlp_ratio=2, drop_path_rate=0.1)input_tensor = torch.randn(1, 3, 224, 224)output = model(input_tensor)print("Output shape:", output.shape)

暂时还未进行测试,如果有空再进行实验, 你可以从这里找到我的源码:pyzjr/pyzjr/Models/backbone/Conv2Former_2.py at main · Auorui/pyzjr (github.com)

总结

Conv2Former,这是一种新型的卷积神经网络架构,其核心是卷积调制操作,通过卷积和Hadamard乘积简化了自注意力机制。在ImageNet分类、目标检测和语义分割任务中,Conv2Former相对于先前的CNN和Transformer模型表现更优。作者强调了对大内核卷积的更有效利用,如何将提出的卷积调制块与Transformer结合起来,这是将来的研究方向。

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

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

相关文章

《ORANGE’S:一个操作系统的实现》读书笔记(十九)输入输出系统(一)

我们刚刚实现了简单的进程&#xff0c;你现在可能很想把它做得更加完善&#xff0c;比如进一步改进调度算法、增加通信机制等。但是这些工作不但做起来没有尽头&#xff0c;而且有些也是难以实现的&#xff0c;因为进程必须与I/O、内存管理等其它模块一起工作。而且&#xff0c…

Linux系统---进程程序替换

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、进程程序替换 一、替换原理 用fork 创建子进程后执行的是和父进程相同的程序 ( 但有可能执行不同的代码分支 ), 子进程往往要…

02 HAL库驱动按键响应外部中断

引言&#xff1a;这里我采用的实验平台可能跟大家的不太一样&#xff0c;文章的图像是一块资源拓展板&#xff0c; 主控板式fs_mp1a, 该板子的SOC是stm32mp157a&#xff0c; 有两个内核一个A7&#xff0c; 一个M4.但是实验的流程肯定都是一样的&#xff0c; 因为都是裸机程序嘛…

【PTA-C语言】实验七-函数与指针I

如果代码存在问题&#xff0c;麻烦大家指正 ~ ~有帮助麻烦点个赞 ~ ~ 目录——实验七-函数与指针I 6-1 弹球距离&#xff08;分数 10&#xff09;6-2 使用函数输出一个整数的逆序数&#xff08;分数 10&#xff09;6-3 使用函数求最大公约数&#xff08;分数 10&#xff09;6-4…

Visual Studio 2015 中 SDL2 开发环境的搭建

Visual Studio 2015 中 SDL2 开发环境的搭建 Visual Studio 2015 中 SDL2 开发环境的搭建新建控制台工程拷贝并配置 SDL2 开发文件拷贝 SDL2 开发文件配置 SDL2 开发文件 测试SDL2 开发文件的下载链接 Visual Studio 2015 中 SDL2 开发环境的搭建 新建控制台工程 新建 Win32 …

从2023看2024前端发展趋势

前言 流光溯影&#xff0c;纵观2023全年&#xff0c;整个前端业界呈现出百业凋零之状&#xff0c;更不乏有“前端已死”等论调甚嚣尘上。从全局视角看IT行业&#xff0c;除了AI领域的大语言模型爆发外&#xff0c;整体都鲜有特别亮眼及突出的技术展现。故而&#xff0c;作为IT…

【华为机试】2023年真题B卷(python)-猴子爬山

一、题目 题目描述&#xff1a; 一天一只顽猴想去从山脚爬到山顶&#xff0c;途中经过一个有个N个台阶的阶梯&#xff0c;但是这猴子有一个习惯&#xff1a; 每一次只能跳1步或跳3步&#xff0c;试问猴子通过这个阶梯有多少种不同的跳跃方式&#xff1f; 二、输入输出 输入描述…

深度学习核心技术与实践之计算机视觉篇

非书中全部内容&#xff0c;只是写了些自认为有收获的部分 计算机视觉背景 &#xff08;1&#xff09;视觉皮层的神经元是一列一列组织起来的&#xff0c;每一列神经元只喜欢某一种特定的形状或者某些简单的线条组合&#xff0c;而不是鱼、老鼠、鲜花 &#xff08;2&#xf…

记矩阵基础概念

转自up&#xff1a;Naruto_Qcsdn&#xff1a;三维空间几何变换矩阵 先贴个站里分享的基础概念。 learn form 肥猫同学VFX b站&#xff1a;会用transform就会用矩阵 移动 旋转 缩放 1.transofrm ——输出变化矩阵 可以移动transform查看变化去理解 位移 缩放 旋转 由此—…

一个有趣的MOSFET电路-触摸调光电路

来源 刷B站视频&#xff0c;看到一个很新奇的“触摸调光电路”&#xff0c;电路图如下&#xff1a; 视频在这里&#xff0c;只使用了3个元件。 刚好最近在学模拟电路的 MOSFET&#xff0c;我之前的理解是 MOSFET 的控制电压应该加在 Gate 和 Source 之间&#xff0c;也就是 栅…

【ES】es介绍,使用spring-boot-starter-data-elasticsearch整合的ES来进行操作Es

文章目录 倒排索引&#xff08;Inverted Index&#xff09;和正排索引&#xff08;Forward Index&#xff09;es和MySQL对比IK分词器的总结mapping映射使用springboot整合的ES来进行操作Es1. 实体类中添加注解2. 编写Repository层3. 通过Repository进行增删改查 倒排索引&#…

2023年年度总结,一个小白的CSDN涨粉历程

前言 滚滚长江东逝水&#xff0c;一去不复返。 转眼间已到2024年节点&#xff0c;时间如滚滚长江水向东奔流不息&#xff0c;在长江消失之前&#xff0c;都不会停歇&#xff0c;也不会回头。人亦如此&#xff0c;不管是生活还是学习&#xff0c;都是不断往前走的过程&#xff…

VMware虚拟机之文件夹共享jdk和tomcat安装防火墙设置

目录 一. 配置文件夹共享功能 1.1 为什么需要配置文件夹共享功能 1.2 配置文件共享功能 1.3 普通共享和高级共享的区别 1.3.1 普通共享 1.3.2 高级共享 1.3.3 总结 二. jdk的配置 2.1 安装jdk 2.2 配置jdk的环境配置jdk 2.3 配置成功 三. TomCat的配置 四. 防火墙设置 4.1…

java生产设备效率管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web生产设备效率管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为ac…

【SD】一致性角色 - 同一人物 不同姿势 - 2

首先生成4张不同姿势的图片 masterpiece,high quality,(white background:1.6),(simple background:1.4),1gril,solo,black footwear,black hair,brown eyes,closed mouth,full body,glasses,jacket,long hair,long sleeves,lookig at viewer,plaid,plaid skirt,pleated shirt,…

记录 Docker 中安装 ROS2

目录 1 安装 Docker 2 安装 ROS2 3 启动 Docker 4 测试 ROS2 环境 1 安装 Docker 1. 更新软件包sudo apt updatesudo apt upgrade2. 安装 docker 依赖sudo apt-get install ca-certificates curl gnupg lsb-release3. 添加 docker 官方 GPG 密钥curl -fsSL http://mirror…

VUE——IDEA 启动前端工程VS文件启动前端工程

IDEA 启动前端 目录 前言一、打开控制台二、输入npm install三、依赖下载完之后&#xff0c;输入npm run dev&#xff0c;运行前端项目1、IDEA启动前端工程2、文件目录启动前端工程 四、点击http://localhost:8080后续敬请期待 前言 启动已有的vue前端项目 一、打开控制台 选…

【解决复杂链式任务打造全能助手】大模型思维链 CoT 应用:langchain 大模型 结合 做 AutoGPT

大模型思维链 CoT 应用&#xff1a;langchain 大模型 结合 做 AutoGPT&#xff0c;解决复杂链式任务打造全能助手 思维链 CoTlangchainlangchain 大模型结合打造 AutoGPT 思维链 CoT 最初的语言模型都是基于经验的&#xff0c;只能根据词汇之间的相关性输出答案&#xff0c;根…

【分库分表篇】分区和分表的区别

分区和分表的区别 ✔️ 解析✔️拓展知识仓✔️分区的方式✔️MySQL 数据库支持的分区类型为水平分区 ✔️ 解析 数据库中数据量过多&#xff0c;表太大的时候&#xff0c;不仅可以做分库分表&#xff0c;还可以做表分区&#xff0c;分区和分表类似&#xff0c;都是按照一定的规…

Vue-Setup

一、setup概述 小小提示&#xff1a;vue3中可以写多个根标签。 Person.vue中内容 <template><div class"person"><h2>姓名&#xff1a;{{name}}</h2><h2>年龄&#xff1a;{{age}}</h2><!--定义了一个事件&#xff0c;点击这…