小目标检测一直是计算机视觉领域的硬骨头。想象一下在航拍图像中寻找蚂蚁大小的行人,或是在卫星图像里定位微型车辆——这些场景下,传统检测器要么漏检严重,要么计算成本高得离谱。QueryDet的提出,正是为了解决这个困扰业界多年的"小目标困境"。
论文作者发现了一个关键现象:低层特征图上的计算存在惊人的冗余。以2048×2048的高清图像为例,实际包含的小目标可能只占据不到5%的像素区域,但传统方法却要对100%的区域进行密集计算。这种"全图扫描"的模式,就像用显微镜检查整片森林来寻找几片特定树叶,效率极其低下。
当前主流的小目标检测方案主要分为三类:
高分辨率方案:直接放大输入图像尺寸(如从640×640提升到1280×1280)。这种方法虽然能保留更多细节,但计算量呈平方级增长。具体来说,图像边长翻倍会导致计算量增加4倍,显存占用更是成为瓶颈。
浅层特征方案:减少网络下采样次数,保持较高分辨率特征图。例如将常见的5次下采样改为3次。但这样会显著缩小感受野,导致大目标检测性能下降,形成"拆东墙补西墙"的局面。
特征金字塔(FPN)方案:通过多尺度特征融合,在不同层级检测不同尺寸目标。这是目前的主流方案,但其底层特征计算仍占整体计算量的60%以上,效率提升有限。
实测数据:在RetinaNet框架下,输入1280×1280图像时,P3层(1/8分辨率)的计算耗时占总推理时间的68%,而其检测贡献率仅为15%。
作者通过大量实验发现两个关键现象:
空间稀疏性:小目标在图像中的分布通常具有空间稀疏性。在COCO数据集中,90%的小目标集中在不到20%的图像区域内。
层级关联性:低分辨率特征虽不能精确定位小目标,但能可靠预测其大致区域。实验显示,P5层(1/32分辨率)的热力图与P2层(1/4分辨率)的小目标分布相关性高达0.83。
基于此,QueryDet提出"预测-精修"的两阶段范式:
这种思路类似于人类视觉的"扫视-聚焦"机制,先快速浏览全局,再对重点区域进行细致观察。
QueryDet的架构可以概括为"一个核心,三个阶段":
code复制Input Image
↓
Backbone + FPN # 基础特征提取
↓
┌───────────────┐
│ Query Stage │ # 生成热力图预测候选区
└───────────────┘
↓
┌───────────────┐
│ Sparse Detect │ # 仅在候选区执行检测
└───────────────┘
↓
Final Detection
采用标准FPN结构,以ResNet-50为例:
| 特征层 | 下采样率 | 分辨率比例 | 典型检测目标尺寸 |
|---|---|---|---|
| P2 | 4 | 1/4 | 0-32像素 |
| P3 | 8 | 1/8 | 32-64像素 |
| P4 | 16 | 1/16 | 64-128像素 |
| P5 | 32 | 1/32 | 128-256像素 |
| P6 | 64 | 1/64 | 256-512像素 |
QueryDet的创新点在于动态选择计算区域,特别是对P2-P4等高分辨率层的稀疏化处理。
QueryHead本质是一个二分类器,结构如下:
code复制输入:Pl层特征图 ∈ R^(H×W×C)
↓
3×3卷积, C→256通道
↓
ReLU激活
↓
1×1卷积, 256→1通道
↓
Sigmoid激活 → 输出热力图 ∈ [0,1]^(H×W)
训练时采用改进的Focal Loss:
python复制class QueryLoss(nn.Module):
def __init__(self, alpha=0.25, gamma=2.0):
super().__init__()
self.alpha = alpha
self.gamma = gamma
def forward(self, pred, target):
BCE_loss = F.binary_cross_entropy(pred, target, reduction='none')
pt = torch.exp(-BCE_loss) # pt = p if y=1, else 1-p
loss = self.alpha * (1-pt)**self.gamma * BCE_loss
return loss.mean()
推理时的级联过程可分为四个步骤:
python复制query_points = (Hl > sigma).nonzero()
python复制key_points = torch.cat([
query_points * 2,
query_points * 2 + 1,
# ... 其他组合
])
这个过程从P5开始,逐层向下传递,直到P2层结束。
小目标正样本区域的生成流程:
python复制def generate_query_labels(targets, feature_map_size, sl):
"""
targets: 该图像的所有GT框 [N,4] (x1,y1,x2,y2)
feature_map_size: (H,W)
sl: 该层的尺度阈值
"""
H, W = feature_map_size
heatmap = torch.zeros(H, W)
for box in targets:
cx, cy = (box[:2] + box[2:]) / 2 # 中心坐标
cx_f, cy_f = cx * W, cy * H # 映射到特征图
# 生成坐标网格
y_grid, x_grid = torch.meshgrid(torch.arange(H), torch.arange(W))
# 计算所有位置到目标的距离
dist = ((x_grid - cx_f)**2 + (y_grid - cy_f)**2).sqrt()
# 更新热力图(取最小距离)
mask = (dist < sl)
heatmap[mask] = 1
return heatmap
总损失由三部分组成:
code复制L = λ_cls * L_cls + λ_reg * L_reg + λ_query * L_query
典型参数设置:
经验提示:λ_query不宜过大,否则会抑制正常检测任务的学习。建议从0.3开始,逐步调参。
阈值选择:
内存优化:
python复制# 传统密集检测
pred = detection_head(features) # [H,W,num_classes]
# QueryDet稀疏检测
sparse_pred = torch.zeros_like(dense_pred)
sparse_pred[key_points] = detection_head(features[key_points])
实际部署时应使用masked卷积操作,避免显存浪费。
加速比调控:
通过调整起始层(默认为P5)可以平衡精度与速度:
现象:QueryHead输出的热力图与真实小目标分布不符
解决方案:
现象:推理速度未达预期提升
排查步骤:
python复制print(torch.sum(Hl > sigma)/Hl.numel()) # 查看激活比例
现象:AP_large指标明显降低
调整策略:
QueryDet的思想可迁移到多种场景:
遥感图像:
医疗影像:
视频分析:
动态查询机制:
当前固定阈值σ可能不是最优方案,可探索:
三维检测扩展:
将稀疏查询思想扩展到点云检测:
python复制# 伪代码示例
voxel_features = backbone(points)
query_heatmap = query_head(voxel_features)
sparse_voxels = voxel_features[query_heatmap > threshold]
与其他范式结合:
在实际项目中采用QueryDet时,建议先从P5层开始实验,逐步向下扩展到P3层。我们的实测数据显示,这种渐进式扩展策略比直接全层应用更稳定,平均能获得2.5倍的加速比,同时保持98%以上的原始检测精度。