news 2026/1/24 4:41:06

YOLO26改进 - 卷积Conv | RefConv重新参数化重聚焦卷积:突破传统卷积瓶颈,有效减少通道冗余

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLO26改进 - 卷积Conv | RefConv重新参数化重聚焦卷积:突破传统卷积瓶颈,有效减少通道冗余

前言

本文介绍了重新参数化再聚焦卷积(RefConv)在YOLO26中的结合应用。RefConv通过对预训练模型的基础卷积核应用可训练的再聚焦转换,建立参数间连接,利用预训练参数作为先验学习新表示,增强模型表示能力。它能减少通道冗余、平滑损失景观,提升多种基于CNN模型在图像分类、目标检测和语义分割上的性能,且不增加推理成本或改变模型结构。我们将RefConv集成到YOLO26的主干网络中,并进行相关注册和配置。实验结果验证了其有效性。

文章目录: YOLO26改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总

专栏链接: YOLO26改进专栏

文章目录

  • 前言
  • 介绍
    • 摘要
  • 文章链接
  • 基本原理
  • 核心代码
  • YOLO26引入代码
  • 注册
    • 步骤1:
    • 步骤2
  • 配置yolo26-RefConv.yaml
  • 实验
    • 脚本
    • 结果

介绍

摘要

我们提出了重新参数化再聚焦卷积(Re - parameterized Refocusing Convolution, RefConv)作为常规卷积层的替代方案,这是一个即插即用的模块,能够在不增加推理成本的前提下提升性能。具体而言,针对预训练模型,RefConv会对从预训练模型继承而来的基础卷积核实施可训练的再聚焦转换,以此在参数之间构建联系。例如,深度卷积的RefConv能够将特定通道的卷积核参数与其他卷积核的参数相关联,即便这些参数重新聚焦于模型的其他部分,而非仅仅关注输入特征。从另一视角来看,RefConv借助将预训练参数中编码的表示作为先验信息,并对这些先验进行重新聚焦以学习新的表示,进而增强预训练模型的表示能力。实验结果证实,RefConv能够显著提高多种基于卷积神经网络(CNN)的模型在图像分类(在ImageNet上最高可使top - 1准确率提升1.47%)、目标检测和语义分割等任务上的性能,且不会引入任何额外的推理成本,也不会改变原始模型结构。进一步研究显示,RefConv能够减少通道冗余并使损失景观更加平滑,这为其有效性提供了解释。

文章链接

论文地址:论文地址

代码地址:代码地址

基本原理

RefConv是一种重新参数化的重聚焦卷积模块,旨在提高卷积神经网络的性能,而无需额外的推断成本。它通过应用可训练的重聚焦变换到预训练模型的基础核来建立参数之间的连接。RefConv可以取代原始的卷积层,使特定通道的卷积核参数与其他卷积核的参数相关联,从而使它们重新聚焦到模型的其他部分,而不仅仅关注输入特征。这样做可以利用预训练参数中编码的表示作为先验,并重新聚焦到这些表示上,从而学习新颖的表示,进一步增强预训练模型的表示能力。

  1. 重聚焦变换:给定一个预训练模型,RefConv应用可训练的重聚焦变换到继承自预训练模型的基础核上,以建立参数之间的连接。例如,一个深度卷积的RefConv可以将特定通道的卷积核参数与其他卷积核的参数相关联,使它们重新聚焦到模型的其他部分,而不仅仅关注输入特征。

  2. 增强模型结构的先验:RefConv通过利用预训练参数中编码的表示作为先验,并重新聚焦到这些表示上,学习新颖的表示,从而增强预训练模型的表示能力。这种方法不改变模型结构,而是通过改变卷积核参数之间的关系来提高模型性能。

  3. 通道冗余减少和损失曲面平滑:RefConv可以减少通道冗余,使损失曲面更加平滑。通过扩大核通道之间的KL散度,减少通道相似性和冗余,RefConv能够学习更多样化的表示,增强模型的表示能力。

核心代码

importtorchimporttorch.nnasnnimporttorch.nn.functionalasFclassRepConv(nn.Module):def__init__(self,in_channels,out_channels,kernel_size,stride,padding=None,groups=1,map_k=3):super(RepConv,self).__init__()assertmap_k<=kernel_size# 记录原始卷积核形状self.origin_kernel_shape=(out_channels,in_channels//groups,kernel_size,kernel_size)self.register_buffer('weight',torch.zeros(*self.origin_kernel_shape))G=in_channels*out_channels//(groups**2)self.num_2d_kernels=out_channels*in_channels//groups self.kernel_size=kernel_size# 使用 2D 卷积生成映射self.convmap=nn.Conv2d(in_channels=self.num_2d_kernels,out_channels=self.num_2d_kernels,kernel_size=map_k,stride=1,padding=map_k//2,groups=G,bias=False)self.bias=Noneself.stride=stride self.groups=groupsifpaddingisNone:padding=kernel_size//2self.padding=paddingdefforward(self,inputs):# 生成权重矩阵origin_weight=self.weight.view(1,self.num_2d_kernels,self.kernel_size,self.kernel_size)# 使用卷积映射更新权重kernel=self.weight+self.convmap(origin_weight).view(*self.origin_kernel_shape)returnF.conv2d(inputs,kernel,stride=self.stride,padding=self.padding,dilation=1,groups=self.groups,bias=self.bias)classRepConvBlock(nn.Module):def__init__(self,in_channels,out_channels,stride=1):super(RepConvBlock,self).__init__()# 定义 RepConv 模块self.conv=RepConv(in_channels,out_channels,kernel_size=3,stride=stride,padding=None,groups=1,map_k=3)# 批量归一化层self.bn=nn.BatchNorm2d(out_channels)# 激活函数self.act=Hswish()defforward(self,x):x=self.conv(x)x=self.bn(x)x=self.act(x)returnxclassHswish(nn.Module):def__init__(self,inplace=True):super(Hswish,self).__init__()self.inplace=inplacedefforward(self,x):# H-swish 激活函数returnx*F.relu6(x+3.,inplace=self.inplace)/6.# 测试模块if__name__=="__main__":# 创建 RepConvBlock 实例并进行前向传播测试block=RepConvBlock(in_channels=3,out_channels=64,stride=1)x=torch.randn(1,3,224,224)output=block(x)print("Output shape:",output.shape)

YOLO26引入代码

在根目录下的ultralytics/nn/目录,新建一个conv目录,然后新建一个以RefConv.py为文件名的py文件, 把代码拷贝进去。

importtorchimporttorch.nnasnnfromtorch.nnimportfunctionalasFclassRefConv(nn.Module):def__init__(self,in_channels,out_channels,kernel_size,stride,padding=None,groups=1,map_k=3):super(RefConv,self).__init__()assertmap_k<=kernel_size self.origin_kernel_shape=(out_channels,in_channels//groups,kernel_size,kernel_size)self.register_buffer('weight',torch.zeros(*self.origin_kernel_shape))G=in_channels*out_channels//(groups**2)self.num_2d_kernels=out_channels*in_channels//groups self.kernel_size=kernel_size self.convmap=nn.Conv2d(in_channels=self.num_2d_kernels,out_channels=self.num_2d_kernels,kernel_size=map_k,stride=1,padding=map_k//2,groups=G,bias=False)# nn.init.zeros_(self.convmap.weight)self.bias=None# nn.Parameter(torch.zeros(out_channels), requires_grad=True) # must have a bias for identical initializationself.stride=stride self.groups=groupsifpaddingisNone:padding=kernel_size//2self.padding=paddingdefforward(self,inputs):origin_weight=self.weight.view(1,self.num_2d_kernels,self.kernel_size,self.kernel_size)kernel=self.weight+self.convmap(origin_weight).view(*self.origin_kernel_shape)returnF.conv2d(inputs,kernel,stride=self.stride,padding=self.padding,dilation=1,groups=self.groups,bias=self.bias)defconv_bn(inp,oup,stride,conv_layer=nn.Conv2d,norm_layer=nn.BatchNorm2d,nlin_layer=nn.ReLU):returnnn.Sequential(RefConv(inp,oup,kernel_size=3,stride=stride,padding=None,groups=1,map_k=3),# conv_layer(inp, oup, 3, stride, 1, bias=False),norm_layer(oup),nlin_layer(inplace=True))defconv_1x1_bn(inp,oup,conv_layer=nn.Conv2d,norm_layer=nn.BatchNorm2d,nlin_layer=nn.ReLU):returnnn.Sequential(conv_layer(inp,oup,1,1,0,bias=False),norm_layer(oup),nlin_layer(inplace=True))classHswish(nn.Module):def__init__(self,inplace=True):super(Hswish,self).__init__()self.inplace=inplacedefforward(self,x):returnx*F.relu6(x+3.,inplace=self.inplace)/6.classHsigmoid(nn.Module):def__init__(self,inplace=True):super(Hsigmoid,self).__init__()self.inplace=inplacedefforward(self,x):returnF.relu6(x+3.,inplace=self.inplace)/6.classSEModule(nn.Module):def__init__(self,channel,reduction=4):super(SEModule,self).__init__()self.avg_pool=nn.AdaptiveAvgPool2d(1)self.fc=nn.Sequential(nn.Linear(channel,channel//reduction,bias=False),nn.ReLU(inplace=True),nn.Linear(channel//reduction,channel,bias=False),Hsigmoid()# nn.Sigmoid())defforward(self,x):b,c,_,_=x.size()y=self.avg_pool(x).view(b,c)y=self.fc(y).view(b,c,1,1)returnx*y.expand_as(x)classIdentity(nn.Module):def__init__(self,channel):super(Identity,self).__init__()defforward(self,x):returnxdefmake_divisible(x,divisible_by=8):importnumpyasnpreturnint(np.ceil(x*1./divisible_by)*divisible_by)

注册

ultralytics/nn/tasks.py中进行如下操作:

步骤1:

fromultralytics.nn.conv.RefConvimportRefConv

步骤2

修改def parse_model(d, ch, verbose=True):

RefConv

配置yolo26-RefConv.yaml

ultralytics/cfg/models/26/yolo26-RefConv.yaml

# 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# Parametersnc:80# number of classesend2end:True# whether to use end-to-end modereg_max:1# DFL binsscales:# 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 GFLOPss:[0.50,0.50,1024]# summary: 260 layers, 10,009,784 parameters, 10,009,784 gradients, 22.8 GFLOPsm:[0.50,1.00,512]# summary: 280 layers, 21,896,248 parameters, 21,896,248 gradients, 75.4 GFLOPsl:[1.00,1.00,512]# summary: 392 layers, 26,299,704 parameters, 26,299,704 gradients, 93.8 GFLOPsx:[1.00,1.50,512]# summary: 392 layers, 58,993,368 parameters, 58,993,368 gradients, 209.5 GFLOPs# YOLO26n backbonebackbone:# [from, repeats, module, args]-[-1,1,Conv,[64,3,2]]# 0-P1/2-[-1,1,RefConv,[128,3,2]]# 1-P2/4-[-1,2,C3k2,[256,False,0.25]]-[-1,1,RefConv,[256,3,2]]# 3-P3/8-[-1,2,C3k2,[512,False,0.25]]-[-1,1,RefConv,[512,3,2]]# 5-P4/16-[-1,2,C3k2,[512,True]]-[-1,1,RefConv,[1024,3,2]]# 7-P5/32-[-1,2,C3k2,[1024,True]]-[-1,1,SPPF,[1024,5,3,True]]# 9-[-1,2,C2PSA,[1024]]# 10# YOLO26n headhead:-[-1,1,nn.Upsample,[None,2,"nearest"]]-[[-1,6],1,Concat,[1]]# cat backbone P4-[-1,2,C3k2,[512,True]]# 13-[-1,1,nn.Upsample,[None,2,"nearest"]]-[[-1,4],1,Concat,[1]]# cat backbone P3-[-1,2,C3k2,[256,True]]# 16 (P3/8-small)-[-1,1,Conv,[256,3,2]]-[[-1,13],1,Concat,[1]]# cat head P4-[-1,2,C3k2,[512,True]]# 19 (P4/16-medium)-[-1,1,Conv,[512,3,2]]-[[-1,10],1,Concat,[1]]# cat head P5-[-1,1,C3k2,[1024,True,0.5,True]]# 22 (P5/32-large)-[[16,19,22],1,Detect,[nc]]# Detect(P3, P4, P5)

实验

脚本

importwarnings warnings.filterwarnings('ignore')fromultralyticsimportYOLOif__name__=='__main__':# 修改为自己的配置文件地址model=YOLO('./ultralytics/cfg/models/26/yolo26-RefConv.yaml')# 修改为自己的数据集地址model.train(data='./ultralytics/cfg/datasets/coco8.yaml',cache=False,imgsz=640,epochs=10,single_cls=False,# 是否是单类别检测batch=8,close_mosaic=10,workers=0,optimizer='MuSGD',amp=True,project='runs/train',name='yolo26-RefConv',)

结果

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/23 18:38:43

YOLO26 接入实时视频

1. 创建环境conda create --name yolo_new python3.102. 安装 yolopip install -U ultralytics3. 编写获取视频代码1. 环境&#xff1a;MacOS iphone 摄像头2. 导入相应的头文件import cv2 from ultralytics import solutions2. 获取摄像头def open_iphone_camera_with_cv():&…

作者头像 李华
网站建设 2026/1/23 15:26:53

毕业论文答辩PPT的终极解决方案:ChatPPT如何让我从焦虑到从容应对

毕业论文答辩PPT的终极解决方案&#xff1a;ChatPPT如何让我从焦虑到从容应对 凌晨两点&#xff0c;宿舍灯光下&#xff0c;我盯着电脑屏幕上三万字的论文&#xff0c;手指在键盘上悬停了十分钟——如何把这篇密密麻麻的文字浓缩成20页PPT&#xff1f;这曾是每个毕业生的噩梦。…

作者头像 李华
网站建设 2026/1/21 16:00:45

从混沌到秩序:Lisp家族的演化与ANSI标准化的必然

从混沌到秩序&#xff1a;Lisp家族的演化与ANSI标准化的必然 1.1.1 Lisp的基因溯源&#xff1a;从λ演算到符号计算革命 Lisp的诞生可以追溯到1958年&#xff0c;由John McCarthy在MIT发明。其核心灵感来源于Alonzo Church的λ演算&#xff0c;这一数学模型构成了现代函数式编程…

作者头像 李华
网站建设 2026/1/23 11:18:04

基于STM32单片机共享无线充电锂电池充电宝系统设计DIY21-640

本系统由STM32F103C8T6单片机核心板、继电器控制、蓝牙控制及电源组成。1、手机连接蓝牙设备。2、设备上贴有二维码&#xff0c;通过手机可以扫描&#xff0c;如果二维码解析正确&#xff0c;可以控制打开共享设备的继电器。3、如果使用完需要关闭设备开关&#xff08;即继电器…

作者头像 李华
网站建设 2026/1/20 3:26:28

深度测评8个AI论文软件,专科生轻松搞定毕业论文!

深度测评8个AI论文软件&#xff0c;专科生轻松搞定毕业论文&#xff01; 从焦虑到从容&#xff0c;你只需迈出第一步 千笔AI(官网直达) 对于专科生来说&#xff0c;写论文从来不是一件轻松的事。时间紧、任务重、资料难找、思路混乱&#xff0c;这些痛点在每一个毕业季都会反复…

作者头像 李华