资讯动态

目标检测 - 从FPN到PAN:双向路径聚合如何提升特征融合效率

发布时间:2026/8/20 12:41:56 来源:尧图企业网站定制
1. 目标检测中的特征金字塔从FPN到PAN的进化之路在目标检测任务中处理多尺度目标一直是个棘手的问题。想象一下你要在一张图片中同时识别出近处的行人、远处的车辆和更远处的交通标志这些目标的尺寸差异可能达到数十倍。传统方法就像用同一把尺子测量大象和蚂蚁效果自然不理想。特征金字塔网络FPN的提出改变了这一局面。它通过构建自顶向下Top-down的特征金字塔将高层语义信息传递给低层特征。这就像给检测系统装上了望远镜和显微镜让模型既能看清大目标也能捕捉小细节。但FPN有个明显缺陷信息流动是单向的低层的精确定位信息无法有效传递给高层。我在实际项目中就遇到过这种情况当处理密集小目标时FPN的表现总是不尽如人意。直到尝试了路径聚合网络PAN检测精度才有了显著提升。这让我意识到双向信息流动对目标检测有多重要。2. FPN的工作原理与局限性2.1 FPN的基本结构FPN的核心思想很简单通过横向连接lateral connection和上采样upsampling构建从深层到浅层的特征金字塔。具体实现通常包含三个关键步骤自底向上的特征提取Backbone网络如ResNet会自然生成不同尺度的特征图我们记作C1到C5其中C5的感受野最大自顶向下的特征传播从C5开始通过上采样将高层特征与低层特征融合横向连接使用1×1卷积对齐通道数后将Backbone的特征与上采样特征相加# 简化版FPN实现示例 class FPN(nn.Module): def __init__(self, backbone_channels[256, 512, 1024, 2048], fpn_channels256): super().__init__() # 横向连接的1×1卷积 self.lateral_convs nn.ModuleList([ nn.Conv2d(channels, fpn_channels, 1) for channels in backbone_channels ]) # 上采样使用的3×3卷积 self.fpn_convs nn.ModuleList([ nn.Conv2d(fpn_channels, fpn_channels, 3, padding1) for _ in backbone_channels ]) def forward(self, features): laterals [conv(feat) for conv, feat in zip(self.lateral_convs, features)] # 自顶向下路径 for i in range(len(laterals)-1, 0, -1): laterals[i-1] F.interpolate(laterals[i], scale_factor2) return [conv(feat) for conv, feat in zip(self.fpn_convs, laterals)]2.2 FPN的三大痛点虽然FPN在很多场景表现不错但在实际部署中我发现几个明显问题信息衰减问题低层的精确位置信息在向上传递过程中会逐渐丢失。就像传话游戏经过多层传递后原始信息已经失真小目标检测不稳定对小目标的检测结果波动较大特别是当目标密集出现时特征融合不充分简单的相加操作可能无法有效融合不同层次的特征有次我在处理卫星图像时FPN对小建筑物的召回率比大建筑物低了近15个百分点。这促使我开始寻找更好的特征融合方案。3. PAN的创新设计双向信息高速公路3.1 双向路径聚合的核心理念PAN的核心创新在于增加了自底向上Bottom-up的路径增强。如果说FPN是单行道那么PAN就是双向八车道的高速公路。这种设计带来了三个关键优势位置信息保留低层的精确位置信息可以向上传递改善定位精度多级特征复用每个层次的特征都能被多次利用提高特征利用率自适应特征选择网络可以自主决定哪些信息需要向上或向下传递在实际项目中改用PAN后小目标的检测AP提升了约8%而计算量仅增加了不到5%。这个性价比让我印象深刻。3.2 PAN的代码级实现细节不同框架对PAN的实现各有特色。以mmdetection和nanodet为例我们看看实际工程中的处理方式# mmdetection风格的PAN实现 class PAN(nn.Module): def __init__(self, in_channels[256, 512, 1024, 2048], out_channels256): super().__init__() # 自顶向下路径同FPN self.top_down_layers nn.ModuleList([ nn.Conv2d(ch, out_channels, 1) for ch in in_channels ]) # 自底向上路径新增的卷积层 self.bottom_up_convs nn.ModuleList() for i in range(len(in_channels)-1): self.bottom_up_convs.append(nn.Sequential( nn.Conv2d(out_channels, out_channels, 3, stride2, padding1), nn.BatchNorm2d(out_channels), nn.ReLU() )) def forward(self, features): # 自顶向下路径 top_down [] for i in range(len(features)-1, -1, -1): if i len(features)-1: top_down.append(self.top_down_layers[i](features[i])) else: top_down.append(self.top_down_layers[i](features[i]) F.interpolate(top_down[-1], scale_factor2)) # 自底向上路径 bottom_up [top_down[-1]] for i in range(len(top_down)-1): bottom_up.append(self.bottom_up_convs[i](bottom_up[-1]) top_down[-i-2]) return bottom_up[::-1] # 按从浅到深的顺序返回nanodet的实现更加轻量直接使用插值进行特征融合# nanodet风格的轻量级PAN class LightPAN(nn.Module): def forward(self, features): # 自顶向下 for i in range(len(features)-1, 0, -1): features[i-1] F.interpolate(features[i], scale_factor2) # 自底向上 for i in range(len(features)-1): features[i1] F.interpolate(features[i], scale_factor0.5) return features4. PAN在YOLO系列中的应用实践4.1 YOLOv4中的PAN改进YOLOv4对原始PAN做了几处重要改进跨阶段连接借鉴CSPNet思想减少计算冗余SPP模块集成在PAN路径中加入空间金字塔池化增强感受野Mish激活函数替代ReLU获得更好的梯度流动这些改进使得YOLOv4在保持速度优势的同时精度大幅提升。我在工业质检项目中测试发现相比YOLOv3v4对小缺陷的检测率提升了12%。4.2 轻量化PAN设计技巧对于资源受限的场景可以考虑以下优化策略通道裁剪减少PAN中特征图的通道数如从256减至128深度可分离卷积替换标准3×3卷积降低计算量部分连接只对关键层级进行双向连接# 轻量级PAN实现示例 class LitePAN(nn.Module): def __init__(self, channels128): super().__init__() # 使用深度可分离卷积 self.dw_conv nn.Sequential( nn.Conv2d(channels, channels, 3, padding1, groupschannels), nn.BatchNorm2d(channels), nn.ReLU(), nn.Conv2d(channels, channels, 1), nn.BatchNorm2d(channels), nn.ReLU() ) def forward(self, features): # 只对P3-P5进行双向连接 p3, p4, p5 features[-3:] # 自顶向下 p4 F.interpolate(p5, scale_factor2) p3 F.interpolate(p4, scale_factor2) # 自底向上 p4 self.dw_conv(F.avg_pool2d(p3, 2)) p5 self.dw_conv(F.avg_pool2d(p4, 2)) return [p3, p4, p5]5. 特征融合的进阶思考5.1 加法 vs 拼接哪种融合方式更好在实现PAN时特征融合有两种主要方式融合方式优点缺点适用场景特征相加计算量小参数少可能丢失部分信息计算资源受限特征拼接保留完整信息增加通道数提升计算量精度优先场景我的经验是对于轻量级模型加法更合适而对于追求精度的场景拼接效果更好。可以像这样灵活选择def merge_features(feat1, feat2, methodadd): if method add: return feat1 feat2 elif method concat: return torch.cat([feat1, feat2], dim1) else: raise ValueError(fUnknown merge method: {method})5.2 特征金字塔的层级选择不是所有层级都适合加入PAN。通过实验发现对于输入尺寸为640×640的图像P3-P5stride 8/16/32通常足够更高分辨率的P2stride 4会显著增加计算量但对小目标提升有限更深的P6-P7stride 64/128对大目标检测有帮助在无人机图像检测项目中我最终选择了P3-P5的配置在精度和速度间取得了最佳平衡。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价