yolov26改进 | 融合改进篇 | ASFYOLO配合RepViT助力yolov26有效涨点(教你如何融合改进机制创新点)

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

开始正文前,先向大家推荐我的YOLO专栏系列。本人持续更新 YOLOv8、YOLO11、YOLO26 等热门模型,内容覆盖图像分类、目标检测、实例分割、多目标跟踪、姿态估计与关键点检测,重点讲解 小目标检测、注意力机制、特征融合、损失函数改进、自定义数据集训练、消融实验及论文代码复现。同时分享如何使用 OpenAI Codex辅助撰写论文、配置实验环境、调试项目、改进模型和分析实验结果。 专栏目前正在进行限时优惠,每周更新 5–7篇最新论文机制、YOLO改进方法和实战教程。订阅后可获得包含本人全部改进方案的代码与配置文件,并加入专属技术交流群。我也会定期在群内分享 YOLO论文选题、创新点设计、实验方案、论文写作与投稿发表经验,欢迎大家订阅交流!


一、本文介绍

本文给大家带来的最新改进机制是ASF-YOLO与RepViT的融合改进方案,并将其应用到YOLOv26中。最近有多位读者反馈,部分改进模块单独使用时能够取得不错的涨点效果,但将多个模块直接组合后,模型精度反而下降。其主要原因并不是模块本身无效,而是不同结构可能存在功能重复、特征分布不一致、通道与尺度不匹配以及优化方向冲突等问题。因此,模型融合不能简单地堆叠涨点模块,而应先理解每个模块的作用位置和改进原理,再选择功能互补的结构进行组合。本文采用RepViT优化Backbone,利用其轻量、高效且硬件友好的卷积结构增强基础特征提取能力;同时结合ASF-YOLO的多尺度特征融合结构,进一步强化不同层级特征之间的信息交互,使浅层细节和深层语义得到更加充分的整合。两者分别作用于特征提取与特征融合阶段,结构职责相对清晰,能够在控制参数量和计算量的同时,提高模型对复杂背景及大、中、小目标的检测能力。本文还会重点讲解融合过程中的输出层选择、通道对齐、特征尺寸匹配和配置方法,避免组合后出现报错或掉点。RepViT也可以替换为专栏内其他主干网络,方便大家开展组合实验、消融分析和二次创新。文中将提供完整代码、配置文件、模块注册方法以及Codex辅助修改思路。

专栏链接:YOLOv26有效涨点专栏包含:Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制


目录

一、本文介绍

二、RepViT基本原理

三、ASFYOLO原理

2.1 尺度序列特征融合(SSFF)模块

2.2 三重特征编码器(TFE)模块

2.3 通道和位置注意力机制(CPAM)

四、手把手教你修改ASFYOLO

4.1 修改一

4.2 修改二 

4.3 修改三 

4.4 修改四 

五、手把手教你添加RepViT 

5.1 RepViT核心代码

5.2 修改一

5.3 修改二 

5.4 修改三 

5.5 修改四 

5.6 修改五

5.7 修改六 

5.8 修改七

5.9 修改八

5.10 修改九

六、融合改进yaml文件 

6.1 ASFYOLO-RepViT-1的yaml文件 

6.2 ASFYOLO-RepViT-2的yaml文件 

七、本文总结


二、RepViT基本原理

官方论文地址: 官方论文地址点击即可跳转

官方代码地址: 官方代码地址点击即可跳转

​​ 


RepViT: Revisiting Mobile CNN From ViT Perspective 这篇论文探讨了如何改进轻量级卷积神经网络(CNN)以提高其在移动设备上的性能和效率。作者们发现,虽然轻量级视觉变换器(ViT)因其能够学习全局表示而表现出色,但轻量级CNN和轻量级ViT之间的架构差异尚未得到充分研究。因此,他们通过整合轻量级ViT的高效架构设计,逐步改进标准轻量级CNN(特别是MobileNetV3),从而创造了一系列全新的纯CNN模型,称为RepViT。这些模型在各种视觉任务上表现出色,比现有的轻量级ViT更高效。

其主要的改进机制包括:

  1. 结构性重组:通过结构性重组(Structural Re-parameterization, SR),引入多分支拓扑结构,以提高训练时的性能。

  2. 扩展比率调整:调整卷积层中的扩展比率,以减少参数冗余和延迟,同时提高网络宽度以增强模型性能。

  3. 宏观设计优化:对网络的宏观架构进行优化,包括早期卷积层的设计、更深的下采样层、简化的分类器,以及整体阶段比例的调整。

  4. 微观设计调整:在微观架构层面进行优化,包括卷积核大小的选择和压缩激励(SE)层的最佳放置。

这些创新机制共同推动了轻量级CNN的性能和效率,使其更适合在移动设备上使用,下面的是官方论文中的结构图,我们对其进行简单的分析。

​​

这张图片是论文中的图3,展示了RepViT架构的总览。RepViT有四个阶段,输入图像的分辨率依次为

​​

每个阶段的通道维度用 Ci​ 表示,批处理大小用 B 表示。 

  • Stem:用于预处理输入图像的模块。
  • Stage1-4:每个阶段由多个RepViTBlock组成,以及一个可选的RepViTSEBlock,包含深度可分离卷积(3x3DW),1x1卷积,压缩激励模块(SE)和前馈网络(FFN)。每个阶段通过下采样减少空间维度。
  • Pooling:全局平均池化层,用于减少特征图的空间维度。
  • FC:全连接层,用于最终的类别预测。

 总结:大家可以将RepViT看成是MobileNet系列的改进版本


三、ASFYOLO原理

 官方论文地址:官方论文地址

官方代码地址:官方代码地址


ASF-YOLO是一个基于YOLO的新型模型,专为细胞实例分割设计。它将注意力尺度序列融合(ASF)集成到YOLO框架中,提高了对细胞图像的检测和分割性能。ASF-YOLO包括尺度序列特征融合(SSFF)模块、三重特征编码器(TFE)模块和通道及位置注意力机制(CPAM),这些特性共同提升了模型的准确性。在细胞数据集上的评估表明,ASF-YOLO在分割精度和速度方面表现出色。论文详细介绍了模型架构、方法论和在细胞图像数据集上的评估,证明了其相较于现有方法的有效性。

ASF-YOLO的主要创新点包括:

1. 尺度序列特征融合(SSFF)模块:用于增强网络在多尺度信息提取上的能力。
2. 三重特征编码器(TFE)模块:融合不同尺度的特征图以增加详细信息。
3. 通道和位置注意力机制(CPAM):集成SSFF和TFE模块,专注于信息通道和与空间位置相关的小对象,从而提高检测和分割性能。
4. 优异的细胞实例分割性能:在细胞数据集上显示出高度的分割准确性和速度。

这个图片来源于论文,文章中这个图片就特别模糊,不知道为什么,怎么发出来的文章。 

这张图展示了ASF-YOLO模型的概览。模型主要包括尺度序列特征融合(SSFF)模块、三重特征编码(TFE)模块,以及基于CSPDarkNet主干网络和YOLO头部的通道和位置注意力模型(CPAM)。CSP和Concat模块来自于YOLOv5。在这个框架中,输入图像通过主干网络的不同层(P1到P5)进行特征提取,然后通过SSFF和CPAM模块进行特征融合和注意力加权,最终实现分割掩模的生成和不同尺度的边界框(P3,P4,P5 Box)的预测。 


2.1 尺度序列特征融合(SSFF)模块

尺度序列特征融合(SSFF)模块是设计用于处理多尺度信息的关键组件。它的主要功能是增强神经网络在提取不同尺度特征时的能力。通过聚合来自网络不同层的特征,SSFF模块能够提供更为丰富和细致的特征表示,有助于改善模型在处理不同大小对象时的表现。这种融合策略特别适用于那些需要精确定位和识别图像中多尺度对象的任务,如细胞分割或面部识别等。通过SSFF,模型可以更有效地识别和理解图像中的细节,从而提高整体的检测和识别性能。


2.2 三重特征编码器(TFE)模块

在ASF-YOLO中的三重特征编码器(TFE)模块是一个创新的特征融合机制,它设计来处理不同尺寸的输入特征图。这个模块通过特定的操作,如卷积、批量标准化和激活函数,对来自网络不同层的特征图进行处理。然后,它使用上采样和下采样技术来对特征图进行空间尺寸的调整,以确保特征图的尺寸一致。最后,通过一个融合操作(通常是拼接),将这些不同尺度的特征图结合在一起,形成一个综合特征表示,以捕获更多的上下文信息和细节。这样的设计使得网络能够更有效地处理多尺度信息,对于诸如细胞分割这样的细粒度任务尤为重要。

​图4展示了三重特征编码器(TFE)模块的结构。C代表通道数,S代表特征图大小。每个三重特征编码器模块使用三种不同大小的特征图作为输入。该模块通过卷积、批归一化和SiLU激活函数对特征进行处理,并使用最大池化和平均池化进行下采样,以及最近邻上采样方法进行上采样,最后通过Concat操作合并特征,生成综合的特征表示。 


2.3 通道和位置注意力机制(CPAM)

通道和位置注意力机制(CPAM)旨在通过集成尺度序列特征融合(SSFF)和三重特征编码器(TFE)模块,提高对细节丰富的小对象的检测和分割能力。CPAM通过专注于信息丰富的通道以及与空间位置相关的小对象特征,能够为模型提供一种有效的注意力指导。这样的机制允许模型更加精准地识别和定位图像中的细小目标,从而提高检测和分割任务的性能

​这张图展示了通道和位置注意力机制(CPAM)模块的结构。该模块包括通道注意力网络和位置注意力网络两部分。通道注意力部分通过平均池化和1D卷积来生成每个通道的权重,然后使用Sigmoid函数进行归一化。位置注意力网络分别对宽度和高度进行平均池化,再通过一个卷积层和Sigmoid函数生成空间权重。最后,这两个权重通过哈达玛积(元素间相乘)合并,以产生最终的加权输出,增强模型对特定通道和位置的聚焦能力。 


四、手把手教你修改ASFYOLO

4.1 修改一

第一还是建立文件,我们找到如下ultralytics/nn文件夹下建立一个目录名字呢就是'Addmodules'文件夹(用群内的文件的话已经有了无需新建)!然后在其内部建立一个新的py文件将核心代码复制粘贴进去即可。


4.2 修改二 

第二步我们在该目录下创建一个新的py文件名字为'__init__.py'(用群内的文件的话已经有了无需新建),然后在其内部导入我们的检测头如下图所示。

​​


4.3 修改三 

第三步我门中到如下文件'ultralytics/nn/tasks.py'进行导入和注册我们的模块(用群内的文件的话已经有了无需重新导入直接开始第四步即可)

​​


4.4 修改四 

按照我的添加在parse_model里添加即可。

# ------------------------------ASF-YOLO--------------------------------
        elif m is Zoom_cat:
            c2 = sum(ch[x] for x in f)
        elif m is Add:
            c2 = ch[f[-1]]
        elif m is ScalSeq:
            c1 = [ch[x] for x in f]
            c2 = make_divisible(args[0] * width, 8)
            args = [c1, c2]
        elif m is attention_model:
            args = [ch[f[-1]]]
# ------------------------------ASF-YOLO--------------------------------

​​


五、手把手教你添加RepViT 

5.1 RepViT核心代码

from symbol import factor

import torch.nn as nn
from timm.models.layers import SqueezeExcite
import torch

__all__ = ['repvit_m0_6','repvit_m0_9', 'repvit_m1_0', 'repvit_m1_1', 'repvit_m1_5', 'repvit_m2_3']

def _make_divisible(v, divisor, min_value=None):
    """
    This function is taken from the original tf repo.
    It ensures that all layers have a channel number that is divisible by 8
    It can be seen here:
    https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
    :param v:
    :param divisor:
    :param min_value:
    :return:
    """
    if min_value is None:
        min_value = divisor
    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
    # Make sure that round down does not go down by more than 10%.
    if new_v < 0.9 * v:
        new_v += divisor
    return new_v


class Conv2d_BN(torch.nn.Sequential):
    def __init__(self, a, b, ks=1, stride=1, pad=0, dilation=1,
                 groups=1, bn_weight_init=1, resolution=-10000):
        super().__init__()
        self.add_module('c', torch.nn.Conv2d(
            a, b, ks, stride, pad, dilation, groups, bias=False))
        self.add_module('bn', torch.nn.BatchNorm2d(b))
        torch.nn.init.constant_(self.bn.weight, bn_weight_init)
        torch.nn.init.constant_(self.bn.bias, 0)

    @torch.no_grad()
    def fuse_self(self):
        c, bn = self._modules.values()
        w = bn.weight / (bn.running_var + bn.eps) ** 0.5
        w = c.weight * w[:, None, None, None]
        b = bn.bias - bn.running_mean * bn.weight / \
            (bn.running_var + bn.eps) ** 0.5
        m = torch.nn.Conv2d(w.size(1) * self.c.groups, w.size(
            0), w.shape[2:], stride=self.c.stride, padding=self.c.padding, dilation=self.c.dilation,
                            groups=self.c.groups,
                            device=c.weight.device)
        m.weight.data.copy_(w)
        m.bias.data.copy_(b)
        return m


class Residual(torch.nn.Module):
    def __init__(self, m, drop=0.):
        super().__init__()
        self.m = m
        self.drop = drop

    def forward(self, x):
        if self.training and self.drop > 0:
            return x + self.m(x) * torch.rand(x.size(0), 1, 1, 1,
                                              device=x.device).ge_(self.drop).div(1 - self.drop).detach()
        else:
            return x + self.m(x)

    @torch.no_grad()
    def fuse_self(self):
        if isinstance(self.m, Conv2d_BN):
            m = self.m.fuse_self()
            assert (m.groups == m.in_channels)
            identity = torch.ones(m.weight.shape[0], m.weight.shape[1], 1, 1)
            identity = torch.nn.functional.pad(identity, [1, 1, 1, 1])
            m.weight += identity.to(m.weight.device)
            return m
        elif isinstance(self.m, torch.nn.Conv2d):
            m = self.m
            assert (m.groups != m.in_channels)
            identity = torch.ones(m.weight.shape[0], m.weight.shape[1], 1, 1)
            identity = torch.nn.functional.pad(identity, [1, 1, 1, 1])
            m.weight += identity.to(m.weight.device)
            return m
        else:
            return self


class RepVGGDW(torch.nn.Module):
    def __init__(self, ed) -> None:
        super().__init__()
        self.conv = Conv2d_BN(ed, ed, 3, 1, 1, groups=ed)
        self.conv1 = torch.nn.Conv2d(ed, ed, 1, 1, 0, groups=ed)
        self.dim = ed
        self.bn = torch.nn.BatchNorm2d(ed)

    def forward(self, x):
        return self.bn((self.conv(x) + self.conv1(x)) + x)

    @torch.no_grad()
    def fuse_self(self):
        conv = self.conv.fuse_self()
        conv1 = self.conv1

        conv_w = conv.weight
        conv_b = conv.bias
        conv1_w = conv1.weight
        conv1_b = conv1.bias

        conv1_w = torch.nn.functional.pad(conv1_w, [1, 1, 1, 1])

        identity = torch.nn.functional.pad(torch.ones(conv1_w.shape[0], conv1_w.shape[1], 1, 1, device=conv1_w.device),
                                           [1, 1, 1, 1])

        final_conv_w = conv_w + conv1_w + identity
        final_conv_b = conv_b + conv1_b

        conv.weight.data.copy_(final_conv_w)
        conv.bias.data.copy_(final_conv_b)

        bn = self.bn
        w = bn.weight / (bn.running_var + bn.eps) ** 0.5
        w = conv.weight * w[:, None, None, None]
        b = bn.bias + (conv.bias - bn.running_mean) * bn.weight / \
            (bn.running_var + bn.eps) ** 0.5
        conv.weight.data.copy_(w)
        conv.bias.data.copy_(b)
        return conv


class RepViTBlock(nn.Module):
    def __init__(self, inp, hidden_dim, oup, kernel_size, stride, use_se, use_hs):
        super(RepViTBlock, self).__init__()
        assert stride in [1, 2]

        self.identity = stride == 1 and inp == oup
        assert (hidden_dim == 2 * inp)

        if stride == 2:
            self.token_mixer = nn.Sequential(
                Conv2d_BN(inp, inp, kernel_size, stride, (kernel_size - 1) // 2, groups=inp),
                SqueezeExcite(inp, 0.25) if use_se else nn.Identity(),
                Conv2d_BN(inp, oup, ks=1, stride=1, pad=0)
            )
            self.channel_mixer = Residual(nn.Sequential(
                # pw
                Conv2d_BN(oup, 2 * oup, 1, 1, 0),
                nn.GELU() if use_hs else nn.GELU(),
                # pw-linear
                Conv2d_BN(2 * oup, oup, 1, 1, 0, bn_weight_init=0),
            ))
        else:
            self.token_mixer = nn.Sequential(
                RepVGGDW(inp),
                SqueezeExcite(inp, 0.25) if use_se else nn.Identity(),
            )
            self.channel_mixer = Residual(nn.Sequential(
                # pw
                Conv2d_BN(inp, hidden_dim, 1, 1, 0),
                nn.GELU() if use_hs else nn.GELU(),
                # pw-linear
                Conv2d_BN(hidden_dim, oup, 1, 1, 0, bn_weight_init=0),
            ))

    def forward(self, x):
        return self.channel_mixer(self.token_mixer(x))


class RepViT(nn.Module):
    def __init__(self, cfgs, factor):
        super(RepViT, self).__init__()
        # setting of inverted residual blocks
        cfgs = [sublist[:2] + [_make_divisible(int(sublist[2] * factor) , 8)] + sublist[3:] for sublist in cfgs]
        self.cfgs = cfgs
        # building first layer
        input_channel = self.cfgs[0][2]
        patch_embed = torch.nn.Sequential(Conv2d_BN(3, input_channel // 2, 3, 2, 1), torch.nn.GELU(),
                                          Conv2d_BN(input_channel // 2, input_channel, 3, 2, 1))
        layers = [patch_embed]
        # building inverted residual blocks
        block = RepViTBlock
        for k, t, c, use_se, use_hs, s in self.cfgs:
            output_channel = _make_divisible(c , 8)
            exp_size = _make_divisible(input_channel * t, 8)
            layers.append(block(input_channel, exp_size, output_channel, k, s, use_se, use_hs))
            input_channel = output_channel
        self.features = nn.ModuleList(layers)
        self.width_list = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]

    def forward(self, x):
        # x = self.features(x
        results = [None, None, None, None]
        temp = None
        i = None
        for index, f in enumerate(self.features):
            x = f(x)
            if index == 0:
                temp = x.size(1)
                i = 0
            elif x.size(1) == temp:
                results[i] = x
            else:
                temp = x.size(1)
                i = i + 1
        return results



def repvit_m0_6(factor):
    """
    Constructs a MobileNetV3-Large model
    """
    cfgs = [
        [3,   2,  40, 1, 0, 1],
        [3,   2,  40, 0, 0, 1],
        [3,   2,  80, 0, 0, 2],
        [3,   2,  80, 1, 0, 1],
        [3,   2,  80, 0, 0, 1],
        [3,   2,  160, 0, 1, 2],
        [3,   2, 160, 1, 1, 1],
        [3,   2, 160, 0, 1, 1],
        [3,   2, 160, 1, 1, 1],
        [3,   2, 160, 0, 1, 1],
        [3,   2, 160, 1, 1, 1],
        [3,   2, 160, 0, 1, 1],
        [3,   2, 160, 1, 1, 1],
        [3,   2, 160, 0, 1, 1],
        [3,   2, 160, 0, 1, 1],
        [3,   2, 320, 0, 1, 2],
        [3,   2, 320, 1, 1, 1],
    ]
    model = RepViT(cfgs, factor)
    return model


def repvit_m0_9(factor):
    """
    Constructs a MobileNetV3-Large model
    """
    cfgs = [
        # k, t, c, SE, HS, s
        [3, 2, 48, 1, 0, 1],
        [3, 2, 48, 0, 0, 1],
        [3, 2, 48, 0, 0, 1],
        [3, 2, 96, 0, 0, 2],
        [3, 2, 96, 1, 0, 1],
        [3, 2, 96, 0, 0, 1],
        [3, 2, 96, 0, 0, 1],
        [3, 2, 192, 0, 1, 2],
        [3, 2, 192, 1, 1, 1],
        [3, 2, 192, 0, 1, 1],
        [3, 2, 192, 1, 1, 1],
        [3, 2, 192, 0, 1, 1],
        [3, 2, 192, 1, 1, 1],
        [3, 2, 192, 0, 1, 1],
        [3, 2, 192, 1, 1, 1],
        [3, 2, 192, 0, 1, 1],
        [3, 2, 192, 1, 1, 1],
        [3, 2, 192, 0, 1, 1],
        [3, 2, 192, 1, 1, 1],
        [3, 2, 192, 0, 1, 1],
        [3, 2, 192, 1, 1, 1],
        [3, 2, 192, 0, 1, 1],
        [3, 2, 192, 0, 1, 1],
        [3, 2, 384, 0, 1, 2],
        [3, 2, 384, 1, 1, 1],
        [3, 2, 384, 0, 1, 1]
    ]
    model = RepViT(cfgs, factor)
    return model


def repvit_m1_0(factor):
    """
    Constructs a MobileNetV3-Large model
    """
    cfgs = [
        # k, t, c, SE, HS, s
        [3, 2, 56, 1, 0, 1],
        [3, 2, 56, 0, 0, 1],
        [3, 2, 56, 0, 0, 1],
        [3, 2, 112, 0, 0, 2],
        [3, 2, 112, 1, 0, 1],
        [3, 2, 112, 0, 0, 1],
        [3, 2, 112, 0, 0, 1],
        [3, 2, 224, 0, 1, 2],
        [3, 2, 224, 1, 1, 1],
        [3, 2, 224, 0, 1, 1],
        [3, 2, 224, 1, 1, 1],
        [3, 2, 224, 0, 1, 1],
        [3, 2, 224, 1, 1, 1],
        [3, 2, 224, 0, 1, 1],
        [3, 2, 224, 1, 1, 1],
        [3, 2, 224, 0, 1, 1],
        [3, 2, 224, 1, 1, 1],
        [3, 2, 224, 0, 1, 1],
        [3, 2, 224, 1, 1, 1],
        [3, 2, 224, 0, 1, 1],
        [3, 2, 224, 1, 1, 1],
        [3, 2, 224, 0, 1, 1],
        [3, 2, 224, 0, 1, 1],
        [3, 2, 448, 0, 1, 2],
        [3, 2, 448, 1, 1, 1],
        [3, 2, 448, 0, 1, 1]
    ]
    model = RepViT(cfgs,factor=factor)
    return model


def repvit_m1_1(factor):
    """
    Constructs a MobileNetV3-Large model
    """
    cfgs = [
        # k, t, c, SE, HS, s
        [3, 2, 64, 1, 0, 1],
        [3, 2, 64, 0, 0, 1],
        [3, 2, 64, 0, 0, 1],
        [3, 2, 128, 0, 0, 2],
        [3, 2, 128, 1, 0, 1],
        [3, 2, 128, 0, 0, 1],
        [3, 2, 128, 0, 0, 1],
        [3, 2, 256, 0, 1, 2],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 512, 0, 1, 2],
        [3, 2, 512, 1, 1, 1],
        [3, 2, 512, 0, 1, 1]
    ]
    model = RepViT(cfgs,factor=factor)
    return model


def repvit_m1_5(factor):
    """
    Constructs a MobileNetV3-Large model
    """
    cfgs = [
        # k, t, c, SE, HS, s
        [3, 2, 64, 1, 0, 1],
        [3, 2, 64, 0, 0, 1],
        [3, 2, 64, 1, 0, 1],
        [3, 2, 64, 0, 0, 1],
        [3, 2, 64, 0, 0, 1],
        [3, 2, 128, 0, 0, 2],
        [3, 2, 128, 1, 0, 1],
        [3, 2, 128, 0, 0, 1],
        [3, 2, 128, 1, 0, 1],
        [3, 2, 128, 0, 0, 1],
        [3, 2, 128, 0, 0, 1],
        [3, 2, 256, 0, 1, 2],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 1, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 256, 0, 1, 1],
        [3, 2, 512, 0, 1, 2],
        [3, 2, 512, 1, 1, 1],
        [3, 2, 512, 0, 1, 1],
        [3, 2, 512, 1, 1, 1],
        [3, 2, 512, 0, 1, 1]
    ]
    model = RepViT(cfgs,factor=factor)
    return model


def repvit_m2_3(factor):
    """
    Constructs a MobileNetV3-Large model
    """
    cfgs = [
        # k, t, c, SE, HS, s
        [3, 2, 80, 1, 0, 1],
        [3, 2, 80, 0, 0, 1],
        [3, 2, 80, 1, 0, 1],
        [3, 2, 80, 0, 0, 1],
        [3, 2, 80, 1, 0, 1],
        [3, 2, 80, 0, 0, 1],
        [3, 2, 80, 0, 0, 1],
        [3, 2, 160, 0, 0, 2],
        [3, 2, 160, 1, 0, 1],
        [3, 2, 160, 0, 0, 1],
        [3, 2, 160, 1, 0, 1],
        [3, 2, 160, 0, 0, 1],
        [3, 2, 160, 1, 0, 1],
        [3, 2, 160, 0, 0, 1],
        [3, 2, 160, 0, 0, 1],
        [3, 2, 320, 0, 1, 2],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 320, 1, 1, 1],
        [3, 2, 320, 0, 1, 1],
        # [3,   2, 320, 1, 1, 1],
        # [3,   2, 320, 0, 1, 1],
        [3, 2, 320, 0, 1, 1],
        [3, 2, 640, 0, 1, 2],
        [3, 2, 640, 1, 1, 1],
        [3, 2, 640, 0, 1, 1],
        # [3,   2, 640, 1, 1, 1],
        # [3,   2, 640, 0, 1, 1]
    ]
    model = RepViT(cfgs,factor=factor)
    return model


if __name__ == '__main__':
    model = repvit_m0_6(factor=0.25)
    inputs = torch.randn((1, 3, 640, 640))
    for i in model(inputs):
        print(i.size())


5.2 修改一

我们复制网络结构代码到“ultralytics/nn”目录下创建一个py文件复制粘贴进去 (我的名字是Addmodules)。


5.3 修改二 

第二步我们在该目录下创建一个新的py文件名字为'__init__.py'(用群内的文件的话已经有了无需新建),然后在其内部导入我们的检测头如下图所示。


5.4 修改三 

第三步我门中到如下文件'ultralytics/nn/tasks.py'进行导入和注册我们的模块(用群内的文件的话已经有了无需重新导入直接开始第四步即可)

从今天开始以后的教程就都统一成这个样子了,因为我默认大家用了我群内的文件来进行修改!!


5.5 修改四 

添加如下两行代码!!!


5.6 修改五

找到1600多行大概把具体看图片,按照图片来修改就行,添加红框内的部分,注意没有()只是函数名,我这里只添加了部分的版本,这个还有更多的版本可以添加可以看后面章节五,看我给的代码函数头即可。

        elif m in {自行添加对应的模型即可,下面都是一样的}:
            m = m(*args)
            c2 = m.width_list  # 返回通道列表
            backbone = True


5.7 修改六 

按图修改。 

        if isinstance(c2, list):
            m_ = m
            m_.backbone = True
        else:
            m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args)  # module
            t = str(m)[8:-2].replace('__main__.', '')  # module type


        m.np = sum(x.numel() for x in m_.parameters())  # number params
        m_.i, m_.f, m_.type = i + 4 if backbone else i, f, t  # attach index, 'from' index, type

5.8 修改七

如下的也需要修改,全部按照我的来。

代码如下把原先的代码替换了即可。 

        if verbose:
            LOGGER.info(f'{i:>3}{str(f):>20}{n_:>3}{m.np:10.0f}  {t:<45}{str(args):<30}')  # print

        save.extend(x % (i + 4 if backbone else i) for x in ([f] if isinstance(f, int) else f) if x != -1)  # append to savelist
        layers.append(m_)
        if i == 0:
            ch = []
        if isinstance(c2, list):
            ch.extend(c2)
            if len(c2) != 5:
                ch.insert(0, 0)
        else:
            ch.append(c2)

5.9 修改八

修改七和前面的都不太一样,需要修改前向传播中的一个部分, 已经离开了parse_model方法了。

可以在图片中看代码行数,没有离开task.py文件都是同一个文件。 同时这个部分有好几个前向传播都很相似,大家不要看错了,是160多行左右的(不同仓库版本可能有些差异)!!!,同时我后面提供了代码,大家直接复制粘贴即可,不会修改联系博主获取视频教程。

​​

代码如下->

    def _predict_once(self, x, profile=False, visualize=False, embed=None):
        """Perform a forward pass through the network.

        Args:
            x (torch.Tensor): The input tensor to the model.
            profile (bool): Print the computation time of each layer if True.
            visualize (bool): Save the feature maps of the model if True.
            embed (list, optional): A list of layer indices to return embeddings from.

        Returns:
            (torch.Tensor): The last output of the model.
        """
        y, dt, embeddings = [], [], []  # outputs
        embed = frozenset(embed) if embed is not None else {-1}
        max_idx = max(embed)
        for m in self.model:
            if m.f != -1:  # if not from previous layer
                x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f]  # from earlier layers
            if profile:
                self._profile_one_layer(m, x, dt)
            if hasattr(m, 'backbone'):
                x = m(x)
                if len(x) != 5:  # 0 - 5
                    x.insert(0, None)
                for index, i in enumerate(x):
                    if index in self.save:
                        y.append(i)
                    else:
                        y.append(None)
                x = x[-1]  # 最后一个输出传给下一层
            else:
                x = m(x)  # run
                y.append(x if m.i in self.save else None)  # save output
            if visualize:
                feature_visualization(x, m.type, m.i, save_dir=visualize)
            if embed and m.i in embed:
                embeddings.append(nn.functional.adaptive_avg_pool2d(x, (1, 1)).squeeze(-1).squeeze(-1))  # flatten
                if m.i == max_idx:
                    return torch.unbind(torch.cat(embeddings, 1), dim=0)
        return x

5.10 修改九

我们找到如下文件'ultralytics/utils/torch_utils.py'按照如下的图片进行修改,否则容易打印不出来计算量。


六、融合改进yaml文件 

6.1 ASFYOLO-RepViT-1的yaml文件 

训练信息:YOLO26-merge-ASFYOLO-RepViT-1 summary: 419 layers, 1,586,444 parameters, 1,586,444 gradients, 3.8 GFLOPs

# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license

# Ultralytics YOLO26 object detection model with P3/8 - P5/32 outputs
# Model docs: https://docs.ultralytics.com/models/yolo26
# Task docs: https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80 # number of classes
end2end: True # whether to use end-to-end mode
reg_max: 1 # DFL bins
scales: # model compound scaling constants, i.e. 'model=yolo26n.yaml' will call yolo26.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 260 layers, 2,572,280 parameters, 2,572,280 gradients, 6.1 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 260 layers, 10,009,784 parameters, 10,009,784 gradients, 22.8 GFLOPs
  m: [0.50, 1.00, 512] # summary: 280 layers, 21,896,248 parameters, 21,896,248 gradients, 75.4 GFLOPs
  l: [1.00, 1.00, 512] # summary: 392 layers, 26,299,704 parameters, 26,299,704 gradients, 93.8 GFLOPs
  x: [1.00, 1.50, 512] # summary: 392 layers, 58,993,368 parameters, 58,993,368 gradients, 209.5 GFLOPs

# YOLO26n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, repvit_m0_6, [0.25]] # 0-4 P1/2 这里是四层大家不要被yaml文件限制住了思维,不会画图进群看视频.
  - [-1, 1, SPPF, [1024, 5]] # 5
  - [-1, 2, C2PSA, [1024]] # 6

# YOLO11n head
head:
  - [-1, 1, Conv, [512, 1, 1]] # 7
  - [2, 1, Conv, [512, 1, 1]] # 8
  - [[-1, 3, -2], 1, Zoom_cat, []]  # 9 cat backbone P4
  - [-1, 2, C3k2, [512, True]]  # 10

  - [-1, 1, Conv, [256, 1, 1]] # 11
  - [1, 1, Conv, [256, 1, 1]] # 12
  - [[-1, 2, -2], 1, Zoom_cat, []]  # 13  cat backbone P3
  - [-1, 2, C3k2, [256, True]]  # 14 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]] # 15
  - [[-1, 11], 1, Concat, [1]]  # 16 cat head P4
  - [-1, 2, C3k2, [512, True]]  # 17(P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]] # 18
  - [[-1, 7], 1, Concat, [1]]  # 19 cat head P5
  - [-1, 2, C3k2, [1024, True, 0.5, True]]  # 20 (P5/32-large)

  - [[2, 3, 4], 1, ScalSeq, [256]] # 21 args[inchane]
  - [[14, -1], 1, Add, [64]] # 22

  - [[22, 17, 20], 1, Detect, [nc]]  # 23 (P3, P4, P5)


6.2 ASFYOLO-RepViT-2的yaml文件 

训练信息:YOLO26-merge-ASFYOLO-RepViT-2 summary: 428 layers, 1,587,223 parameters, 1,587,223 gradients, 3.8 GFLOPs

# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license

# Ultralytics YOLO26 object detection model with P3/8 - P5/32 outputs
# Model docs: https://docs.ultralytics.com/models/yolo26
# Task docs: https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80 # number of classes
end2end: True # whether to use end-to-end mode
reg_max: 1 # DFL bins
scales: # model compound scaling constants, i.e. 'model=yolo26n.yaml' will call yolo26.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 260 layers, 2,572,280 parameters, 2,572,280 gradients, 6.1 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 260 layers, 10,009,784 parameters, 10,009,784 gradients, 22.8 GFLOPs
  m: [0.50, 1.00, 512] # summary: 280 layers, 21,896,248 parameters, 21,896,248 gradients, 75.4 GFLOPs
  l: [1.00, 1.00, 512] # summary: 392 layers, 26,299,704 parameters, 26,299,704 gradients, 93.8 GFLOPs
  x: [1.00, 1.50, 512] # summary: 392 layers, 58,993,368 parameters, 58,993,368 gradients, 209.5 GFLOPs

# YOLO26n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, repvit_m0_6, [0.25]] # 0-4 P1/2 这里是四层大家不要被yaml文件限制住了思维,不会画图进群看视频.
  - [-1, 1, SPPF, [1024, 5]] # 5
  - [-1, 2, C2PSA, [1024]] # 6

# YOLO11n head
head:
  - [-1, 1, Conv, [512, 1, 1]] # 7
  - [2, 1, Conv, [512, 1, 1]] # 8
  - [[-1, 3, -2], 1, Zoom_cat, []]  # 9 cat backbone P4
  - [-1, 2, C3k2, [512, True]]  # 10

  - [-1, 1, Conv, [256, 1, 1]] # 11
  - [1, 1, Conv, [256, 1, 1]] # 12
  - [[-1, 2, -2], 1, Zoom_cat, []]  # 13  cat backbone P3
  - [-1, 2, C3k2, [256, True]]  # 14 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]] # 15
  - [[-1, 11], 1, Concat, [1]]  # 16 cat head P4
  - [-1, 2, C3k2, [512, True]]  # 17(P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]] # 18
  - [[-1, 7], 1, Concat, [1]]  # 19 cat head P5
  - [-1, 2, C3k2, [1024, True, 0.5, True]]  # 20 (P5/32-large)

  - [[2, 3, 4], 1, ScalSeq, [256]] # 21 args[inchane]
  - [[14, -1], 1, attention_model, [256]] # 22

  - [[22, 17, 20], 1, Detect, [nc]]  # 23 (P3, P4, P5)

七、本文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv26改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,目前本专栏免费阅读(暂时,大家尽早关注不迷路~),如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

专栏链接:YOLOv26有效涨点专栏包含:Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Snu77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值