共计 2349 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点:小目标检测的挑战与 FPN 的局限
在目标检测任务中,小目标(小于 32×32 像素)的检测一直是一个技术难点。传统 FPN(Feature Pyramid Network)结构通过自上而下的路径将高层语义信息传递到低层,但在实际应用中存在以下问题:

- 特征融合时,低层细节信息容易被高层语义信息淹没,导致小目标的特征丢失
- 单向的特征传播路径限制了不同层级间的信息交互
- 对特征层的权重分配采用固定方式,无法自适应调整不同层级的重要性
技术对比:FPN、PANet 与 BiFPN
- FPN:采用单一的自顶向下路径,高层特征通过上采样与低层特征相加融合
- PANet:在 FPN 基础上增加自底向上路径,形成双向特征金字塔
- BiFPN:在 PANet 基础上引入三个关键改进:
- 移除只有单一输入边的节点(简化结构)
- 添加从原始输入到输出节点的快捷连接(同层特征复用)
- 引入可学习的权重系数(自适应特征重要性)
核心实现:BiFPN 加权双向特征融合
加权特征融合机制
BiFPN 的核心创新在于提出加权双向特征金字塔,其数学表达为:
O = ∑(w_i · I_i) / (∑w_j + ε)
其中 w_i 是通过 ReLU 约束的可学习权重(w_i ≥ 0),ε=0.0001 防止数值不稳定。这种设计使得网络可以自适应地学习不同特征层的重要性。
P2 层的关键作用
在标准 FPN 中,特征金字塔通常从 P3(1/ 8 分辨率)开始。BiFPN 通过保留 P2 层(1/ 4 分辨率)带来以下优势:
- 更精细的空间粒度(4×4 感受野对应原图 16×16 区域)
- 直接保留原始图像的高频细节
- 特别适合检测 10-20 像素级别的微小目标
结构示意图描述
典型 BiFPN-P2 结构包含:
- 骨干网络输出 P2-P7 六级特征(1/ 4 到 1 /128 分辨率)
- 第一轮自顶向下融合:P7→P6→P5→P4→P3→P2
- 第二轮自底向上融合:P2→P3→P4→P5→P6→P7
- 每个融合节点包含 3 - 4 个输入边(同级、上级、下级、原始输入)
代码实现:PyTorch 关键模块
import torch
import torch.nn as nn
import torch.nn.functional as F
class WeightedFeatureFusion(nn.Module):
"""可学习权重的特征融合层"""
def __init__(self, in_channels: int, epsilon: float = 1e-4):
super().__init__()
self.epsilon = epsilon
self.weights = nn.Parameter(torch.ones(3, dtype=torch.float32)) # 假设每个节点有 3 个输入
self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1)
def forward(self, features: list[torch.Tensor]) -> torch.Tensor:
"""
Args:
features: 待融合的特征图列表
Returns:
融合后的特征图
"""
# 归一化权重(使用 ReLU 保证非负)norm_weights = F.relu(self.weights) / (torch.sum(F.relu(self.weights)) + self.epsilon)
# 加权求和
out = torch.zeros_like(features[0])
for i, feat in enumerate(features):
out += norm_weights[i] * feat
return self.conv(out)
class P2_FeatureExtractor(nn.Module):
"""P2 层特征提取模块"""
def __init__(self, in_channels: int):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, in_channels//2, kernel_size=1)
self.conv2 = nn.Conv2d(in_channels//2, in_channels, kernel_size=3, padding=1)
self.act = nn.SiLU(inplace=True)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.act(self.conv2(self.act(self.conv1(x))))
性能优化实践
计算复杂度平衡
- 分辨率最高的 P2 层会占用约 40% 的计算量
- 优化策略:
- 对 P2 层使用深度可分离卷积
- 在训练后期才启用 P2 层(warmup 策略)
- 对 P6/P7 层适当减少通道数
COCO 数据集对比数据
| 模型 | AP | APs(小目标) | 参数量 |
|---|---|---|---|
| FPN | 36.2 | 18.7 | 32M |
| PANet | 38.1 | 21.3 | 35M |
| BiFPN-P2 | 41.5 | 26.8 | 37M |
避坑指南
训练技巧
- 初始学习率降低为 FPN 的 1 /3(建议 1e-4)
- 使用渐进式分辨率训练:
- 前 5 个 epoch 只训练 P3-P7
- 6-10epoch 加入 P2 但冻结其参数
- 10epoch 后解冻全部参数
显存优化
- 采用梯度检查点技术(checkpointing)
- 对 P2 层使用混合精度训练
- 多卡训练时采用 sharded 数据并行
部署量化
- P2 层对量化敏感,建议:
- 对 P2 层使用 16 位量化
- 其他层可用 8 位量化
- 部署时保持 P2 层的浮点计算
延伸思考
- 如何设计动态权重机制,使 P2 层在检测大目标时自动降低参与度?
- 能否将注意力机制与 BiFPN 结合,进一步优化特征选择?
- 对于视频小目标检测,如何利用时序信息增强 P2 层特征?
通过上述分析和实践,BiFPN+P2 的组合在保持合理计算开销的同时,显著提升了小目标检测性能。实际部署时需要特别注意显存管理和量化策略,以平衡精度与效率。
正文完
