从滑动窗口到RPN:目标检测候选区域生成技术的演进与核心
1. 目标检测的起点滑动窗口时代我第一次接触目标检测是在2013年那时候最流行的方法还是滑动窗口Sliding Window。这个方法简单粗暴得可爱——就像拿着放大镜在图片上一点点移动检查。具体来说就是在图像上设置一个固定大小的矩形窗口从左到右、从上到下依次滑动对每个窗口内的图像块进行分类判断。但这个方法有个致命问题计算量爆炸。假设我们要检测一张1000x1000像素的图片使用100x100的窗口步长为50像素那么需要滑动(1000/50)x(1000/50)400次。这还只是单一尺度的检测实际中我们需要检测不同大小的物体就得用不同尺寸的窗口重复这个过程。我做过实验在当时的硬件条件下处理一张图片可能要几分钟。更糟的是大部分窗口都是无效的。记得有次我用滑动窗口检测行人结果90%以上的窗口都在检测背景。这种大海捞针的方式实在太低效了。不过滑动窗口有个优点实现简单。下面是个简化版的伪代码for scale in scales: for (x, y, window) in sliding_window(image, scale): if classifier.predict(window) target: detections.append((x, y, scale))2. 选择性搜索传统方法的巅峰2014年左右选择性搜索Selective Search开始流行。这个方法聪明多了——它不再盲目扫描整张图片而是先用图像分割算法把图片分成多个区域然后合并相似区域生成候选框。我特别喜欢选择性搜索的一点是它考虑了多种视觉特征。比如颜色相似度计算区域间的颜色直方图距离纹理相似度用SIFT-like特征描述纹理大小相似度优先合并小区域形状相似度考虑区域的吻合度在实际项目中我发现选择性搜索的召回率确实比滑动窗口高很多。有次测试COCO数据集选择性搜索只用2000个候选框就能覆盖90%以上的目标而滑动窗口需要上百万次计算。不过它也有硬伤不可学习合并策略基于启发式规则无法通过数据优化速度瓶颈CPU实现处理一张图要2-3秒与检测网络割裂候选框生成和分类是两个独立步骤3. 深度学习的革命RPN的诞生当Faster R-CNN在2015年提出RPNRegion Proposal Network时我立刻意识到这是game changer。RPN的精妙之处在于端到端学习候选框生成和分类统一在一个网络里Anchor机制预设多种尺度和长宽比的参考框特征共享与检测网络共用基础特征提取器我记得第一次实现RPN时的震撼——原来候选框可以这样生成RPN的核心是在特征图的每个位置上设置k个anchor通常k9。对于W×H的特征图总共会有W×H×k个anchor。每个anchor会预测2个分类分数前景/背景4个坐标偏移量中心点x,y和宽高w,h# 简化版RPN前向计算 feature_map backbone(image) # 获取特征图 cls_logits conv1x1_cls(feature_map) # 分类分支 bbox_pred conv1x1_bbox(feature_map) # 回归分支4. RPN的技术细节与实现技巧在实际项目中我总结了几个RPN的关键实现要点4.1 Anchor设计策略尺度选择通常采用[8,16,32]等指数增长的尺度长宽比常用1:1,1:2,2:1三种比例特征步长根据backbone的下采样率确定比如ResNet通常是16有次我调整anchor设置时发现针对特定数据集如行人检测优化anchor比例能显著提升性能。把默认的[1:1,1:2,2:1]改为[1:1.5,1:2,1:3]后AP提升了3个点。4.2 训练样本选择RPN训练最大的挑战是样本不平衡。我的经验法则是每张图采样256个anchor约128正128负正样本与任一GT的IoU0.7或最高IoU的anchor负样本与所有GT的IoU0.3有个容易踩的坑是忽略边界anchor。有次训练时发现模型对边缘目标检测很差后来发现是没处理好跨图像边界的anchor。解决方法很简单过滤掉完全越界的anchor即可。4.3 损失函数设计RPN的损失函数由两部分组成L L_cls λL_reg分类损失L_cls通常用交叉熵回归损失L_reg用smooth L1。λ一般设为10以平衡两个loss的量级。我在实验中发现适当调整λ可以改善框的定位精度但会影响分类稳定性。5. RPN的演进与变种这些年我跟踪过不少RPN的改进版本有几个特别有意思5.1 Cascade RPN这个改进版通过级联多个RPN逐步细化候选框。就像画画时先打草稿再描细节。具体实现是第一级RPN生成粗糙候选框将候选框映射回特征图第二级RPN在这些区域上进一步优化实测下来这种级联结构对小目标检测特别有效。在VisDrone数据集上AP-small提升了5.6%。5.2 Guided Anchoring传统RPN的anchor是固定的而Guided Anchoring会预测哪些位置该放置anchor位置预测每个位置该用多大尺度的anchor形状预测这就像让网络自己决定在哪里画框和画多大的框。实现时需要特别注意特征对齐我通常会在预测分支后加个可变形卷积来缓解对齐问题。5.3 RPN与单阶段检测器的融合有趣的是像RetinaNet这样的单阶段检测器其实也吸收了RPN的思想。它们的anchor机制和RPN如出一辙只是把分类和回归直接做到了最后阶段。我在项目中经常把这两种思路混用比如用RPN生成高质量候选框再用单阶段网络做快速分类。6. 实战中的经验与教训在部署RPN时我踩过不少坑也总结了些实用技巧数据方面Anchor设置要与数据集统计匹配。有次做交通标志检测发现默认anchor太大调整后mAP提升了8%注意处理极端长宽比目标。有次检测旗杆时专门增加了1:8的anchor训练技巧预训练很重要。我习惯先用RPN单独训练再端到端finetune学习率要小心设置。RPN部分通常需要比检测头更大的学习率推理优化NMS阈值很关键。我一般设0.7但对密集目标会降到0.5可以动态调整输出的proposal数量。简单场景用100个就够复杂场景可能需要1000有次在嵌入式设备部署时发现RPN成了速度瓶颈。后来通过量化剪枝把推理时间从120ms降到了35ms。关键是把RPN的通道数从256减到128几乎不影响精度。7. RPN的局限与未来尽管RPN很强大但仍有改进空间。我在最近的项目中发现对小目标检测仍不够友好特征分辨率低Anchor的设计还是依赖经验与transformer架构的兼容性问题最近在试验一些无anchor的替代方案比如基于中心点的预测。不过就目前来看RPN依然是大多数检测系统的首选方案。它的设计思想——用神经网络学习生成候选区域——已经成为了目标检测的标准范式。