介绍
摘要
本论文旨在开发现代、高效、轻量的密集预测模型,并在参数、浮点运算次数与性能之间寻求平衡。虽然倒置残差块(IRB)是轻量级卷积神经网络(CNN)的重要基础,但在基于注意力的研究中尚缺类似的构件。本研究从统一视角出发,结合高效IRB和有效的Transformer组件,重新考虑轻量级基础架构。我们将基于CNN的IRB扩展到基于注意力的模型,并提出了一种单残差元移动块(MMB)用于轻量级模型设计。基于简单而有效的设计原则,我们推出了一种新型的倒置残差移动块(iRMB),并以此为基础构建了一个类似于ResNet的高效模型(EMO),适用于下游任务。在ImageNet-1K、COCO2017和ADE20K基准上的大量实验表明,我们的EMO在性能上超越了最先进的方法,例如,EMO-1M/2M/5M在Top-1准确率上分别达到了71.5、75.1和78.4,超过了同等级别的CNN-/基于注意力的模型,同时在参数、效率和准确度上取得了良好的权衡:在iPhone14上运行速度比EdgeNeXt快2.8-4.0倍。
YOLOv11目标检测创新改进与实战案例专栏
点击查看文章目录: YOLOv11创新改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例
点击查看专栏链接: YOLOv11目标检测创新改进与实战案例
文章链接
论文地址:论文地址
代码地址:代码地址
基本原理
本文作者重新审视了轻量化CNN的反向残差模块和Transformer中的自注意力模块以及前馈神经网络模块,并从中归纳抽象出一个新的元结构——Meta-Mobile Block。本文作者认为之前的模块都是此元结构的一个实例化,并表明具体的实例化对模型性能非常重要。Meta-Mobile Block的公式如下所:
iRMB吸收了CNN在建模短距离依赖方面的高效性,以及Transformer在动态建模长距离交互方面的能力。这种融合提供了一个均衡的解决方案,使得模型既能捕捉局部特征,也能理解全局上下文。
如图2所示,在左侧部分,首先通过一个卷积多层感知器(CMLP)生成查询(Q)和键(K)矩阵。随后,利用膨胀卷积生成值(V)矩阵。接着,通过对Q、K、V实施窗口级别的自注意力操作,以实现远程信息的交互。此过程之后,使用深度可分离卷积(DWConv)对局部特征进行建模。最终,通过一个压缩卷积步骤调整通道数至原始水平,并将此输出与输入执行元素级加法操作以融合信息。特别指出,由于膨胀卷积和自注意力机制主要涉及矩阵乘法运算,因此可在执行膨胀卷积前计算自注意力机制。此优化策略旨在降低浮点操作次数(FLOPs),同时保持操作的等效性,提高整体计算效率。
核心代码
class iRMB(nn.Module):
def __init__(self, dim_in, dim_out, norm_in=True, has_skip=True, exp_ratio=1.0, norm_layer='bn_2d',
act_layer='relu', v_proj=True, dw_ks=3, stride=1, dilation=1, se_ratio=0.0, dim_head=8, window_size=7,
attn_s=True, qkv_bias=False, attn_drop=0., drop=0., drop_path=0., v_group=False, attn_pre=False):
super().__init__()
self.norm = get_norm(norm_layer)(dim_in) if norm_in else nn.Identity()
dim_mid = int(dim_in * exp_ratio)
self.has_skip = (dim_in == dim_out and stride == 1) and has_skip
self.attn_s = attn_s
if self.attn_s:
assert dim_in % dim_head == 0, 'dim should be divisible by num_heads'
self.dim_head = dim_head
self.window_size = window_size
self.num_head = dim_in // dim_head
self.scale = self.dim_head ** -0.5
self.attn_pre = attn_pre
self.qk = ConvNormAct(dim_in, int(dim_in * 2), kernel_size=1, bias=qkv_bias, norm_layer='none',
act_layer='none')
self.v = ConvNormAct(dim_in, dim_mid, kernel_size=1, groups=self.num_head if v_group else 1, bias=qkv_bias,
norm_layer='none', act_layer=act_layer, inplace=inplace)
self.attn_drop = nn.Dropout(attn_drop)
else:
if v_proj:
self.v = ConvNormAct(dim_in, dim_mid, kernel_size=1, bias=qkv_bias, norm_layer='none',
act_layer=act_layer, inplace=inplace)
else:
self.v = nn.Identity()
self.conv_local = ConvNormAct(dim_mid, dim_mid, kernel_size=dw_ks, stride=stride, dilation=dilation,
groups=dim_mid, norm_layer='bn_2d', act_layer='silu', inplace=inplace)
self.se = SqueezeExcite(dim_mid, rd_ratio=se_ratio, act_layer=get_act(act_layer)) if se_ratio > 0.0 else nn.Identity()
self.proj_drop = nn.Dropout(drop)
self.proj = ConvNormAct(dim_mid, dim_out, kernel_size=1, norm_layer='none', act_layer='none', inplace=inplace)
self.drop_path = DropPath(drop_path) if drop_path else nn.Identity()
task与yaml配置
详见:https://blog.csdn.net/shangyanaf/article/details/143052993