news 2026/1/30 4:03:03

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/28 9:39:30

学长亲荐2026TOP9AI论文软件:本科生毕业论文全场景测评

学长亲荐2026TOP9AI论文软件&#xff1a;本科生毕业论文全场景测评 推荐1&#xff1a;「千笔AI」—— 一站式学术支持“专家”&#xff0c;学术写作全场景王者&#xff08;推荐指数&#xff1a;★★★★★&#xff09; 在众多AI论文工具中&#xff0c;「千笔AI」凭借其强大的功…

作者头像 李华
网站建设 2026/1/29 7:22:29

面向 OpenHarmony 的 Flutter UI 实践:便签卡片组件从设计到落地

文章目录面向 OpenHarmony 的 Flutter UI 实践&#xff1a;便签卡片组件从设计到落地前言背景Flutter OpenHarmony 跨端开发介绍架构定位开发核心代码便签卡片组件实现代码结构解析1. 状态驱动的颜色设计2. Card InkWell 的交互组合3. 顶部信息区&#xff1a;标题 完成状态4…

作者头像 李华
网站建设 2026/1/29 6:30:19

linux 如何查看udp协议缓冲区的默认大小

在 Linux 系统中&#xff0c;UDP 协议的接收和发送缓冲区大小可以通过内核参数进行配置。要查看 UDP 缓冲区的默认大小&#xff08;即未显式设置时的初始值&#xff09;以及最大限制&#xff0c;可以使用以下方法&#xff1a;1. 查看系统级别的 UDP 缓冲区默认值和限制这些值由…

作者头像 李华
网站建设 2026/1/28 7:11:02

【AI大模型开发】-基于FAISS的语义搜索系统(实战)

向量数据库实战&#xff1a;基于FAISS的语义搜索系统 一、项目概述 1.1 什么是向量数据库&#xff1f; 向量数据库是一种专门用于存储、索引和检索高维向量数据的数据库系统。在AI领域&#xff0c;向量通常是指通过预训练模型&#xff08;如Transformer&#xff09;将文本、图像…

作者头像 李华
网站建设 2026/1/28 8:27:58

老张的AI助手,每天早上帮他念一遍:“你不是机器。”

第一章&#xff1a;晨间仪式的技术隐喻 当老张的智能音箱第七次用合成语音念出“你不是机器”时&#xff0c;他正在调试金融系统的模糊测试脚本。这个看似荒诞的晨间仪式&#xff0c;恰是软件测试从业者的生存宣言——在自动化测试覆盖率突破80%的2026年&#xff0c;人类测试工…

作者头像 李华
网站建设 2026/1/27 8:00:53

校园低碳出行路径推荐系统设计与实现

一&#xff0e;研究目的及意义 本报告紧密围绕校园低碳出行推广核心需求&#xff0c;以引导师生养成绿色出行习惯、助力校园绿色交通管理数字化升级为目标&#xff0c;设计实现适配校园场景的低碳出行路径推荐系统&#xff0c;覆盖需求分析、功能开发至测试验证全流程&#xff…

作者头像 李华