首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >YOLO11优化: 引入了一种新颖的大核局部-全局-局部(LGL)模块,有效平衡图像信息低与高层语义差异大的问题 | ACM MM‘25

YOLO11优化: 引入了一种新颖的大核局部-全局-局部(LGL)模块,有效平衡图像信息低与高层语义差异大的问题 | ACM MM‘25

原创
作者头像
AI小怪兽
发布2025-09-04 15:25:50
发布2025-09-04 15:25:50
6170
举报
文章被收录于专栏:毕业设计毕业设计YOLO大作战

💡💡💡为了实现高效的局部-全局信息交换,有效平衡图像信息低与高层语义差异大的问题,

引入了一种新颖的大核局部-全局-局部(LGL)模块。

💡💡💡如何与YOLO11结合:C3k2与LGL结合;

💡💡💡多个数据集上实现暴力涨点;

《YOLOv11魔术师专栏》将从以下各个方向进行创新:

原创自研模块】【多组合点优化】【注意力机制】【卷积魔改】【block&多尺度融合结合】【损失&IOU优化】【上下采样优化 【小目标性能提升】前沿论文分享】【训练实战篇】

订阅者通过添加WX: AI_CV_0624,入群沟通,提供改进结构图等一系列定制化服务。

定期向订阅者提供源码工程,配合博客使用。

订阅者可以申请发票,便于报销

💡💡💡为本专栏订阅者提供创新点改进代码,改进网络结构图,方便paper写作!!!

💡💡💡适用场景:红外、小目标检测、工业缺陷检测、医学影像、遥感目标检测、低对比度场景

💡💡💡适用任务:所有改进点适用【检测】、【分割】、【pose】、【分类】等

💡💡💡全网独家首发创新,【自研多个自研模块】,【多创新点组合适合paper 】!!!

☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️ ☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️

包含注意力机制魔改、卷积魔改、检测头创新、损失&IOU优化、block优化&多层特征融合、 轻量级网络设计、24年最新顶会改进思路、原创自研paper级创新等

🚀🚀🚀 本项目持续更新 | 更新完结保底≥80+ ,冲刺100+ 🚀🚀🚀

🍉🍉🍉 联系WX: AI_CV_0624 欢迎交流!🍉🍉🍉

⭐⭐⭐专栏涨价趋势 159 ->199->259->299,越早订阅越划算⭐⭐⭐

💡💡💡 2024年计算机视觉顶会创新点适用于Yolov5、Yolov7、Yolov8、Yolov9等各个Yolo系列,专栏文章提供每一步步骤和源码,轻松带你上手魔改网络 !!!

💡💡💡重点:通过本专栏的阅读,后续你也可以设计魔改网络,在网络不同位置(Backbone、head、detect、loss等)进行魔改,实现创新!!!

☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️ ☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️☁️

1.YOLO11介绍

Ultralytics YOLO11是一款尖端的、最先进的模型,它在之前YOLO版本成功的基础上进行了构建,并引入了新功能和改进,以进一步提升性能和灵活性。YOLO11设计快速、准确且易于使用,使其成为各种物体检测和跟踪、实例分割、图像分类以及姿态估计任务的绝佳选择。

结构图如下:

1.1 C3k2

C3k2,结构图如下

C3k2,继承自类C2f,其中通过c3k设置False或者Ture来决定选择使用C3k还是Bottleneck

实现代码ultralytics/nn/modules/block.py

1.2 C2PSA介绍

借鉴V10 PSA结构,实现了C2PSA和C2fPSA,最终选择了基于C2的C2PSA(可能涨点更好?)

实现代码ultralytics/nn/modules/block.py

1.3 11 Detect介绍

分类检测头引入了DWConv(更加轻量级,为后续二次创新提供了改进点),结构图如下(和V8的区别):

实现代码ultralytics/nn/modules/head.py

2.原理介绍

论文:https://arxiv.org/pdf/2508.01064

摘要:在临床实践中,医学影像分析往往需要在资源受限的移动设备上高效执行。然而,现有的移动模型——主要针对自然图像优化——由于自然领域与医学领域之间存在显著的信息密度差距,在医学任务上表现通常较差。在开发轻量、通用且高性能网络时,将计算效率与医学影像特有的架构优势结合起来仍然是一个挑战。为此,我们提出了一种专为医学影像分割设计的移动模型,称为移动U形视觉Transformer(Mobile U-ViT)。具体而言,我们采用新提出的ConvUtr作为分层块嵌入,其特点是参数高效的大核CNN与反向瓶颈融合。该设计在更轻、更快的同时,展现出类似Transformer的表征学习能力。为了实现高效的局部-全局信息交换,我们引入了一种新颖的大核局部-全局-局部(LGL)模块,有效平衡了医学图像信息密度低与高层语义差异大的问题。最后,我们引入了一个浅层轻量的Transformer瓶颈用于长程建模,并采用级联解码器与下采样跳跃连接实现密集预测。尽管计算需求大幅降低,我们这一面向医学优化的架构在涵盖多种成像模态的八个公共2D与3D数据集上均达到了最先进性能,并在四个未见数据集上实现了零样本测试。这些结果确立了它作为一种高效、强大且具有泛化能力的移动医学影像分析解决方案。

图1:Mobile U-ViT 的创新与卓越性能。(a) 医学图像与自然图像之间的信息密度差距。与自然图像不同,医学图像通常只包含稀疏的局部特征,且由于分布噪声和外部伪影,相关信息往往难以提取。由于二维病灶分割和三维体积分割都依赖全局上下文进行推理与定位,因此需要更大的感受野来捕获足够的信息。(b) 不同方法在三维多器官分割数据集上的性能。结果展示了 Mobile U-ViT 在不同大小器官上的优越性。(c) Mobile U-ViT 在二维数据集上的精度提升。结果验证了我们方法的鲁棒性。(d) Mobile U-ViT 编码器由两个核心组件构成:ConvUtr 和大核局部-全局-局部(LKLGL)模块。ConvUtr 基于 CNN,但具备 Transformer 的学习模式;LKLGL 则在保持高计算效率的同时,进一步提升全局与局部的理解能力。

本文旨在通过设计一种更高效、专为医学影像分割定制的移动端网络来弥合这一差距:

  • 针对问题 (i),为了在扩大感受野的同时保持计算效率,我们提出了一种采用“Transformer 模式”的大核卷积模块 ConvUir 作为补丁嵌入层。ConvUtr 基于深度可分离卷积(DSConv)构建:先利用大核深度卷积提取全局特征,再通过两级逐点卷积(倒置瓶颈)促进通道间交互。该设计呼应了 Transformer 的建模范式(见图 1(d))。相比原始 ViT,ConvUtr 显著削减参数量,为移动端提供了更轻、更快的选择。
  • 针对问题 (ii),我们引入 Large-Kernel Local-Global-Local(LKLGL)模块,以降低语义歧义并强化局部-全局特征融合。其信息流分为三步:先局部聚合(红色),再高效完成全局上下文交换(蓝色),最后将精炼信息重新局部分配(绿色),如图 1(d) 所示。模块内置的 token 聚合操作减少了 token 数量,使长程计算更加高效。
  • 此外,我们构建了带下采样跳跃连接的级联轻量解码器,在保证快速解码的同时,对齐细粒度局部细节与高层全局语义,实现精准密集预测。

大量实验表明,该医学专用架构在八个公开 2D/3D 多模态数据集上均取得 SOTA 性能,并在零样本场景下验证了其泛化能力。凭借显著降低的资源消耗与卓越性能,Mobile U-ViT 成为移动端医学影像分析的高效而强大的解决方案。

总结而言,我们提出了一种新颖的混合轻量网络 Mobile U-ViT,以应对移动端医学影像的挑战。其核心贡献包括:

  • ConvUtr:受 Transformer 启发的轻量 CNN 骨干,可将稀疏像素空间的医学图像高效压缩为紧凑潜表征;
  • LKLGL 模块:通过结构化局部-全局-局部信息流,实现鲁棒特征精炼;
  • 带下采样跳跃连接的级联解码器:有效对齐局部与全局特征,支撑精准高效的密集预测。

图2:Mobile U-ViT 的整体架构。编码器分为 5 个阶段:前 3 个阶段采用具有 CNN 结构的 ConvUtr 模块;第 4 阶段为 Large-kernel LGL 模块堆叠。每个解码器块由“上采样模块 + 卷积模块”组成,并通过下采样跳跃连接实现特征融合。

3.如何加入YOLOv11

3.1 新建ultralytics/nn/block/MobileUViT.py

完整源码:

代码语言:javascript
复制
https://blog.csdn.net/m0_63774211/article/details/151176498
代码语言:javascript
复制
class Residual(nn.Module):
    def __init__(self, fn):
        super().__init__()
        self.fn = fn

    def forward(self, x):
        return self.fn(x) + x


class ConvUtr(nn.Module):
    def __init__(self, ch_in, ch_out, depth=1, kernel=3):
        super(ConvUtr, self).__init__()
        self.block = nn.Sequential(
            *[nn.Sequential(
                Residual(nn.Sequential(
                    nn.Conv2d(ch_in, ch_in, kernel_size=(kernel, kernel), groups=ch_in, padding=(kernel // 2, kernel // 2)),
                    nn.GELU(),
                    nn.BatchNorm2d(ch_in)
                )),
                Residual(nn.Sequential(
                    nn.Conv2d(ch_in, ch_in * 4, kernel_size=(1, 1)),
                    nn.GELU(),
                    nn.BatchNorm2d(ch_in * 4),
                    nn.Conv2d(ch_in * 4, ch_in, kernel_size=(1, 1)),
                    nn.GELU(),
                    nn.BatchNorm2d(ch_in)
                )),
            ) for i in range(depth)]
        )
        self.up = nn.Sequential(
            nn.Conv2d(ch_in, ch_out, kernel_size=3, stride=1, padding=1, bias=True),
            nn.BatchNorm2d(ch_out),
            nn.ReLU(inplace=True)
        )

    def forward(self, x):
        x = self.block(x)
        x = self.up(x)
        return x


class Embeddings(nn.Module):
    def __init__(self, inch=3, dims=[8, 16, 32], depths=[1, 1, 3], kernels=[3, 3, 7]):
        super(Embeddings, self).__init__()
        self.stem = nn.Sequential(
            nn.Conv2d(inch, dims[0], kernel_size=3, stride=1, padding=1, bias=True),
            nn.BatchNorm2d(dims[0]),
            nn.ReLU(inplace=True)
        )
        self.layer1 = ConvUtr(dims[0], dims[0], depth=depths[0], kernel=kernels[0])
        self.layer2 = ConvUtr(dims[0], dims[1], depth=depths[1], kernel=kernels[1])
        self.layer3 = ConvUtr(dims[1], dims[2], depth=depths[2], kernel=kernels[2])
        self.down = nn.MaxPool2d(kernel_size=2, stride=2)

    def forward(self, x):
        x0 = self.stem(x)
        x0 = self.layer1(x0)

        x1 = self.down(x0)
        x1 = self.layer2(x1)

        x2 = self.down(x1)
        x2 = self.layer3(x2)

        return x2, (x0, x1, x2)


class Mlp(nn.Module):
    def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
        super().__init__()
        out_features = out_features or in_features
        hidden_features = hidden_features or in_features
        self.fc1 = nn.Linear(in_features, hidden_features)
        self.act = act_layer()
        self.fc2 = nn.Linear(hidden_features, out_features)
        self.drop = nn.Dropout(drop)

    def forward(self, x):
        x = self.fc1(x)
        x = self.act(x)
        x = self.drop(x)
        x = self.fc2(x)
        x = self.drop(x)
        return x


class CMlp(nn.Module):
    def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
        super().__init__()
        out_features = out_features or in_features
        hidden_features = hidden_features or in_features
        self.fc1 = nn.Conv2d(in_features, hidden_features, 3, padding=1, groups=in_features)
        self.act = act_layer()
        self.fc2 = nn.Conv2d(hidden_features, out_features, 3, padding=1, groups=in_features)
        self.drop = nn.Dropout(drop)

    def forward(self, x):
        x = self.fc1(x)
        x = self.act(x)
        x = self.drop(x)
        x = self.fc2(x)
        x = self.drop(x)
        return x


class GlobalSparseAttn(nn.Module):
    def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0., sr_ratio=1.):
        super().__init__()
        self.num_heads = num_heads
        head_dim = dim // num_heads

        self.scale = qk_scale or head_dim ** -0.5
        self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
        self.attn_drop = nn.Dropout(attn_drop)
        self.proj = nn.Linear(dim, dim)
        self.proj_drop = nn.Dropout(proj_drop)

        self.sr = sr_ratio
        if self.sr > 1:
            self.sampler = nn.AvgPool2d(1, sr_ratio)
            kernel_size = sr_ratio
            self.LocalProp = nn.ConvTranspose2d(dim, dim, kernel_size, stride=sr_ratio, groups=dim)
            self.norm = nn.LayerNorm(dim)
        else:
            self.sampler = nn.Identity()
            self.upsample = nn.Identity()
            self.norm = nn.Identity()

    def forward(self, x, H: int, W: int):
        B, N, C = x.shape
        if self.sr > 1.:
            x = x.transpose(1, 2).reshape(B, C, H, W)
            x = self.sampler(x)
            x = x.flatten(2).transpose(1, 2)

        qkv = self.qkv(x).reshape(B, -1, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
        q, k, v = qkv[0], qkv[1], qkv[2]
        attn = (q @ k.transpose(-2, -1)) * self.scale
        attn = attn.softmax(dim=-1)
        attn = self.attn_drop(attn)
        x = (attn @ v).transpose(1, 2).reshape(B, -1, C)

        if self.sr > 1:
            x = x.permute(0, 2, 1).reshape(B, C, int(H / self.sr), int(W / self.sr))
            x = self.LocalProp(x)
            x = x.reshape(B, C, -1).permute(0, 2, 1)
            x = self.norm(x)
        x = self.proj(x)
        x = self.proj_drop(x)
        return x


class LocalAgg(nn.Module):
    def __init__(self, dim, mlp_ratio=4., drop=0., drop_path=0., act_layer=nn.GELU):
        super().__init__()
        self.pos_embed = nn.Conv2d(dim, dim, 9, padding=4, groups=dim)
        self.norm1 = nn.BatchNorm2d(dim)
        self.conv1 = nn.Conv2d(dim, dim, 1)
        self.conv2 = nn.Conv2d(dim, dim, 1)
        self.attn = nn.Conv2d(dim, dim, 9, padding=4, groups=dim)
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.norm2 = nn.BatchNorm2d(dim)
        mlp_hidden_dim = int(dim * mlp_ratio)
        self.mlp = CMlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
        self.sg = nn.Sigmoid()

    def forward(self, x):
        x = x + x * (self.sg(self.pos_embed(x)) - 0.5)
        x = x + x * (self.sg(self.drop_path(self.conv2(self.attn(self.conv1(self.norm1(x)))))) - 0.5)
        x = x + x * (self.sg(self.drop_path(self.mlp(self.norm2(x)))) - 0.5)
        return x


class SelfAttn(nn.Module):
    def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
                 drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm, sr_ratio=1.):
        super().__init__()
        self.pos_embed = nn.Conv2d(dim, dim, 3, padding=1, groups=dim)
        self.norm1 = norm_layer(dim)
        self.attn = GlobalSparseAttn(
            dim,
            num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale,
            attn_drop=attn_drop, proj_drop=drop, sr_ratio=sr_ratio)
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.norm2 = norm_layer(dim)
        mlp_hidden_dim = int(dim * mlp_ratio)
        self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)

    def forward(self, x):
        x = x + self.pos_embed(x)
        B, N, H, W = x.shape
        x = x.flatten(2).transpose(1, 2)
        x = x + self.drop_path(self.attn(self.norm1(x), H, W))
        x = x + self.drop_path(self.mlp(self.norm2(x)))
        x = x.transpose(1, 2).reshape(B, N, H, W)
        return x

class LGLBlock(nn.Module):
    def __init__(self, dim, num_heads=8, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
                 drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm, sr_ratio=2):
        super().__init__()

        if sr_ratio > 1:
            self.LocalAgg = LocalAgg(dim, mlp_ratio, drop, drop_path, act_layer)
        else:
            self.LocalAgg = nn.Identity()

        self.SelfAttn = SelfAttn(dim, num_heads, mlp_ratio, qkv_bias, qk_scale, drop, attn_drop, drop_path, act_layer,
                                 norm_layer, sr_ratio)

    def forward(self, x):
        x = self.LocalAgg(x)
        x = self.SelfAttn(x)
        return x

3.2 yolo11-C3k2_LGLB.yaml

代码语言:javascript
复制
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
 
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs
 
# YOLO11n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  - [-1, 2, C3k2_LGLB, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  - [-1, 2, C3k2_LGLB, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 2, C2PSA, [1024]] # 10
 
# YOLO11n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2, [512, False]] # 13
 
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)
 
  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)
 
  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)
 
  - [[16, 19, 22], 1, Detect, [nc]] # Detect(P3, P4, P5)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 1.YOLO11介绍
  • 1.1 C3k2
  • 1.2 C2PSA介绍
  • 1.3 11 Detect介绍
  • 2.原理介绍
  • 3.如何加入YOLOv11
  • 3.1 新建ultralytics/nn/block/MobileUViT.py
  • 3.2 yolo11-C3k2_LGLB.yaml
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档