☰
YOLO26改进-Neck | LPRMAlignUpModule:局部像素关系建模对齐上采样,缓解跨尺度融合中的细节损失 | TPAMI2025
2026/10/14 1:44:12 网站建设 项目流程

前言

本文介绍了局部像素关系对齐上采样模块(LPRMAlignUpModule)在YOLO26中的结合应用。该模块通过压缩特征预测局部像素关系,并利用不同膨胀率的动态关系对跨尺度特征进行对齐与细化,增强上采样过程中的局部结构表达能力。我们将LPRMAlignUpModule集成到YOLO26的Neck多尺度特征融合路径中,以替换对应的Concat融合位置,并进行相关注册和配置,用于改善上采样特征与侧向特征之间的空间对齐和细节融合。

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

文章目录

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

介绍

高空间频率信息(包括纹理等细节)对语义分割的准确性有重要贡献。然而,根据奈奎斯特—香农采样定理,在步幅卷积等下采样层传播时,高频成分容易受到混叠或失真的影响。为此,我们提出了一种新的空间频率调制(SFM)方法,在下采样前将高频特征调制到较低频率,并在上采样过程中将其重新解调回来。具体而言,我们通过自适应重采样(ARS)实现调制,并设计了一种轻量级附加模块,对高频区域进行密集采样以放大信号,从而依据频率缩放特性降低其频率。我们还提出了多尺度自适应上采样(MSAU),通过非均匀上采样对调制后的特征进行解调并恢复高频信息。该模块进一步通过显式利用不同尺度下密集重采样区域与稀疏重采样区域之间的信息交互来改善分割效果。上述两个模块都能够无缝集成到不同架构中,适用范围从卷积神经网络扩展到Transformer。特征可视化与分析表明,我们的方法能够有效缓解混叠,同时在解调后成功保留细节。最后,我们将SFM的适用性和有效性扩展验证到图像分类、对抗鲁棒性、实例分割和全景分割等任务中。代码已公开在https://github.com/Linwei-Chen/SFM。

文章链接

论文地址:https://arxiv.org/pdf/2507.11893

代码地址:https://github.com/search?q=repo%3ALinwei-Chen%2FSFM+LPRMAlignUpModule&type=code

基本原理

1. 解决的关键问题

YOLO26的Neck通常通过上采样与Concat完成不同尺度特征的融合。普通双线性或最近邻上采样使用固定空间采样规则,难以针对局部纹理、边缘和目标轮廓进行自适应细化;当高层语义特征与低层细节特征进行跨尺度融合时,还可能出现空间错位、细节稀释和局部结构恢复不足的问题。LPRMAlignUpModule针对这一过程,引入由压缩特征动态预测的局部像素关系,使输出不再只是固定插值或直接拼接,而是根据当前特征内容重新聚合邻域信息。

2. 整体架构

模块接收两路Neck特征:低分辨率路径特征和高分辨率侧向引导特征。首先使用1×1卷积将两路输入投影到目标输出通道,并把空间尺寸对齐到高分辨率特征;随后分别压缩两路特征并相加,形成用于预测局部像素关系的条件特征。条件特征经过关系建模后,先后送入两个不同膨胀率的局部像素关系细化单元,对低分辨率路径进行动态邻域重采样,最后与高分辨率引导特征进行残差式融合并通过输出投影得到YOLO26后续C3k2所需的特征。

在YOLO26中,模块放置在Neck的四个跨尺度融合位置:P5到P4、P4到P3、P3回流到P4以及P4回流到P5。这样既保留了YOLO26的自顶向下和自底向上路径,又把原来的Concat替换为带局部关系建模的对齐融合操作。

3. 技术原理

模块使用一个小通道压缩分支生成关系条件图,再由3×3卷积预测每个空间位置的k²个邻域权重,并在邻域维度进行Softmax归一化。对于输入特征的每个位置,使用这些权重对膨胀邻域展开结果进行加权求和,从而完成动态局部像素关系聚合。第一阶段使用膨胀率1建模近邻关系,第二阶段使用膨胀率2扩大局部感受野,使模块能够同时利用细粒度边缘信息和稍大范围的上下文信息。与固定插值相比,这种方式能够根据局部内容改变采样邻域的贡献;与直接Concat相比,它先完成通道投影、空间对齐和关系细化,再输出统一通道数的融合特征。当前YOLO26适配版保留了LPRM的动态局部关系核心,并将原论文面向非均匀坐标的上采样过程改造成适合YOLO26多尺度Neck输入输出契约的可运行模块。

核心代码

classLPRMAlignUpModule(nn.Module):def__init__(self,low_res_channels,high_res_channels,kernel_size=3,align_corners=False,compress_ratio=4):super().__init__()self.align_corners=align_corners predictor_in_channels=low_res_channels+high_res_channels compressed_channels=predictor_in_channels//compress_ratio self.compress_conv_low=nn.Sequential(nn.Conv2d(low_res_channels,compressed_channels,1,bias=True))self.compress_conv_high=nn.Sequential(nn.Conv2d(high_res_channels,compressed_channels,1,bias=True))self.lprm=LPRM_efficient(channels=compressed_channels,kernel_size=kernel_size,upscale=2)self.lpr_conv=nn.Conv2d(compressed_channels,kernel_size**2,3,padding=1)defforward(self,x_low,guidance_high_aligned):_,_,target_h,target_w=guidance_high_aligned.shape compressed_low=self.compress_conv_low(x_low)compressed_high=self.compress_conv_high(guidance_high_aligned)lpr_feat=F.interpolate(self.lpr_conv(compressed_low),scale_factor=2,mode='bilinear',align_corners=self.align_corners)+F.interpolate(self.lpr_conv(compressed_high),size=(x_low.size(-2)*2,x_low.size(-1)*2),mode='bilinear',align_corners=self.align_corners)x_low=self.lprm(lpr_feat,x_low)returnF.interpolate(x_low,size=(target_h,target_w),mode='bilinear',align_corners=self.align_corners)

YOLO26引入代码

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

from__future__importannotationsfromcollections.abcimportSequenceimporttorchimporttorch.nnasnnimporttorch.nn.functionalasFfromultralytics.nn.modules.convimportConvclass_LocalPixelRelation(nn.Module):"""Apply dynamic k-by-k local relations to a BCHW feature map."""def__init__(self,channels:int,kernel_size:int=3)->None:super().__init__()ifkernel_size<1orkernel_size%2==0:raiseValueError("kernel_size must be a positive odd integer")self.channels=int(channels)self.kernel_size=int(kernel_size)self.padding=self.kernel_size//2defforward(self,relation_logits:torch.Tensor,value:torch.Tensor)->torch.Tensor:ifrelation_logits.ndim!=4orvalue.ndim!=4:raiseValueError("relation_logits and value must be 4D BCHW tensors")b,_,h,w=value.shape k2=self.kernel_size*self.kernel_sizeifrelation_logits.shape[1]!=k2:raiseValueError(f"expected{k2}relation channels, got{relation_logits.shape[1]}")ifrelation_logits.shape[-2:]!=(h,w):relation_logits=F.interpolate(relation_logits,size=(h,w),mode="bilinear",align_corners=False)weights=relation_logits.reshape(b,1,k2,h,w).softmax(dim=2)padded=F.pad(value,(self.padding,)*4,mode="replicate")patches=F.unfold(padded,kernel_size=self.kernel_size,padding=0,stride=1,)patches=patches.reshape(b,self.channels,k2,h,w)return(patches*weights).sum(dim=2)classLPRMAlignUpModule(nn.Module):def__init__(self,in_channels:Sequence[int],out_channels:int,kernel_size:int=3,align_corners:bool=False,compress_ratio:int=4,)->None:super().__init__()low_res_channels,high_res_channels=(int(c)forcinin_channels)self.low_res_channels=low_res_channels self.high_res_channels=high_res_channels self.out_channels=int(out_channels)self.align_corners=bool(align_corners)predictor_in_channels=low_res_channels+high_res_channels compressed_channels=max(8,predictor_in_channels//int(compress_ratio))self.compressed_channels=compressed_channels self.compress_conv_low=nn.Conv2d(low_res_channels,compressed_channels,kernel_size=1,bias=True)self.compress_conv_high=nn.Conv2d(high_res_channels,compressed_channels,kernel_size=1,bias=True)self.lpr_conv=nn.Conv2d(compressed_channels,kernel_size*kernel_size,kernel_size=3,padding=1)self.lprm=_LocalPixelRelation(low_res_channels,kernel_size=kernel_size)self.guidance_to_low=(nn.Identity()ifhigh_res_channels==low_res_channelselsenn.Conv2d(high_res_channels,low_res_channels,kernel_size=1,bias=False))self.conv_final=Conv(low_res_channels,self.out_channels,1)defforward(self,inputs:Sequence[torch.Tensor])->torch.Tensor:x_low,x_high=inputs target_size=x_high.shape[-2:]relation_low=self.lpr_conv(self.compress_conv_low(x_low))relation_high=self.lpr_conv(self.compress_conv_high(x_high))ifrelation_low.shape[-2:]!=target_size:relation_low=F.interpolate(relation_low,size=target_size,mode="bilinear",align_corners=self.align_corners)relation_logits=relation_low+relation_highifx_low.shape[-2:]!=target_size:x_low=F.interpolate(x_low,size=target_size,mode="bilinear",align_corners=self.align_corners)aligned_low=self.lprm(relation_logits,x_low)guidance=self.guidance_to_low(x_high)fused=aligned_low+guidancereturnself.conv_final(fused)

注册

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

步骤1:

fromultralytics.nn.neck.LPRMAlignUpModuleimportLPRMAlignUpModule

步骤2

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

elifmisLPRMAlignUpModule:c2=make_divisible(min(args[0],max_channels)*width,8)ifargselsech[f[0]]args=[[ch[index]forindexinf],c2,*args[1:]]

配置yolo26-LPRMAlignUpModule.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:-[-1,1,Conv,[64,3,2]]-[-1,1,Conv,[128,3,2]]-[-1,2,C3k2,[256,False,0.25]]-[-1,1,Conv,[256,3,2]]-[-1,2,C3k2,[512,False,0.25]]-[-1,1,Conv,[512,3,2]]-[-1,2,C3k2,[512,True]]-[-1,1,Conv,[1024,3,2]]-[-1,2,C3k2,[1024,True]]-[-1,1,SPPF,[1024,5,3,True]]-[-1,2,C2PSA,[1024]]head:-[-1,1,nn.Upsample,[None,2,nearest]]-[[-1,6],1,LPRMAlignUpModule,[512]]-[-1,2,C3k2,[512,True]]-[-1,1,nn.Upsample,[None,2,nearest]]-[[-1,4],1,LPRMAlignUpModule,[256]]-[-1,2,C3k2,[256,True]]-[-1,1,Conv,[256,3,2]]-[[-1,13],1,LPRMAlignUpModule,[512]]-[-1,2,C3k2,[512,True]]-[-1,1,Conv,[512,3,2]]-[[-1,10],1,LPRMAlignUpModule,[1024]]-[-1,1,C3k2,[1024,True,0.5,True]]-[[16,19,22],1,Detect,[nc]]

实验

脚本

importwarnings warnings.filterwarnings('ignore')fromultralyticsimportYOLOif__name__=='__main__':# 修改为自己的配置文件地址model=YOLO('./ultralytics/cfg/models/26/yolo26-LPRMAlignUpModule.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',# optimizer='SGD',amp=False,project='runs/train',name='LPRMAlignUpModule',)

结果

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询