ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入理解RPN:原理、训练细节与工程实践

深入理解RPN:原理、训练细节与工程实践 在目标检测领域RPN 这三个字母几乎和 Faster R-CNN 绑定在一起。很多人初学 RPNRegion Proposal Network区域建议网络时最直观的感受是好像懂了但又说不清它到底是怎么把候选框框出来的。这篇文我不打算复述论文里的公式而是把 RPN 的前因后果、内部机制、训练细节和工程落地时容易踩的坑一条条掰开讲清楚。无论你是刚入门的算法工程师、还在肝毕业论文的学生还是想优化检测性能的开发者都应该能从里面找到自己需要的那块拼图。1. 为什么要有 RPN先从候选区域从哪来说起1.1 传统方法解决候选区域问题的思路在 Faster R-CNN 之前普遍的做法是先做 Selective Search 或 EdgeBoxes 这种独立模块来生成候选区域。当时 R-CNN 和 Fast R-CNN 的流程都是输入图像 → 离线算法生成约 2000 个候选框 → 用卷积网络对每个候选框提取特征 → 分类和回归。这里有个很别扭的地方候选区域生成过程完全发生在 GPU 和深度学习网络之外无法享受梯度回传。这种割裂带来两个后果。第一Selective Search 基于颜色、纹理、尺寸、轮廓等底层特征做区域合并本质上是个启发式方法运行一次耗时几百毫秒而且提取出来的候选框质量上下浮动很大。第二因为候选框生成和特征提取是两套体系整个检测框架无法做到端到端的联调优化。我当时第一次跑 R-CNN 时有个很直观的感受预处理那一步经常比后边的卷积推理还慢这显然不合理。1.2 RPN 改变了什么2015 年 Faster R-CNN 论文给出的答案非常简洁让卷积网络自己来生成候选区域。RPN 并不是一个独立的网络结构而是接在共享卷积层后面的一个小型分支输入是图像特征图输出是一组带包含目标分数的候选框提议。这意味着 RPN 和检测器共享底层特征。要知道卷积网络底层提取的是通用的边缘、纹理信息这些信息既用于判断这个区域是什么也完全具备足够能力判断这个区域是否值得看。共享特征带来的好处不仅是节省计算量更重要的是 RPN 能在训练过程中通过反向传播不断调整自己提取的候选框和后续检测器的需求更加匹配。这也是 RPN 从精度到速度全面碾压 Selective Search 的根本原因。1.3 RPN 的输入输出与整体定位从工程视角看RPN 更像一个带注意力机制的滑动窗口扫描器输入共享卷积层输出的特征图尺寸通常是 H×W×C。输出两样东西分类分数每个锚框属于前景还是背景的概率。边界框偏移每个锚框相对于真实目标的 4 个参数化偏移值。整个 Faster R-CNN 的推理流程可以粗略理解成主干网络先把图浓缩成特征图RPN 在特征图上粗筛一遍提出大约 300 个候选框后续 RoI Align 或 RoI Pooling 再把这些候选框对应区域抠出来做精细分类和位置精修。最关键的认知是RPN 不负责最终分类更不负责精确定位它只负责告诉后续模块哪些地方值得看一眼。如果 RPN 把目标漏掉了后面做得再好也无济于事这也是为什么 RPN 的召回率Recall比精确率Precision更值得关注。2. RPN 内部机制拆解锚框是灵魂回归与分类各司其职2.1 锚框一次定义好所有可能的候选形态锚框机制是整个 RPN 最核心的设计。它做的事情很简单在特征图的每个位置预先放置若干固定大小的参考框。如果输入特征图是 40×60每个位置设置 9 个锚框那么总共就有 40×60×9 21600 个锚框。这 9 个锚框是怎么来的通常由 3 种尺度scale比如 128×128、256×256、512×512和 3 种宽高比ratio比如 1:1、1:2、2:1组合而成。这种设计的直觉很朴素现实中的物体长得多姿多样人通常是竖长的汽车通常是横向的猫狗几乎是方形的。如果只用一种比例的框去框它们召回率会非常惨。需要特别提醒一点锚框的尺度和比例并不是死的。很多开源实现默认沿用论文里的 3 尺度 3 比例但实际项目里完全应该根据你的目标尺寸分布去设计。比如做卫星遥感检测时船舶目标在图像里通常又细又长1:2 和 2:1 的锚框很可能比 1:1 更有效如果待检测小目标多新增 64×64 这种更小尺度通常会带来明显的召回提升。2.2 分类分支前景与背景的二分类有了数万个锚框RPN 要逐一对它们做前景/背景判断。具体做法是在特征图的每个位置施加一个 3×3 的卷积层把每个锚框对应的特征向量映射出来再接两个 1×1 卷积分支。分类分支输出的通道数是 2K其中 K 是每个位置的锚框数量2 对应前景和背景两个类。这里有一个常见的困惑为什么是前景/背景二分类而不是直接判断物体类别原因有两层。第一RPN 的定位决定了它不需要知道具体是什么只要判断像不像有东西即可这大幅简化了任务也让负样本的构造容易得多。第二二分类让 RPN 在训练时不需要大量精标注的类别信息一张图哪怕只有边框标注也能训练。如果让 RPN 直接分 80 个类不仅计算量大还会和后面的分类器功能重叠也是浪费。2.3 回归分支锚框到真实框的四参数修正分类只告诉我们哪值得看回归则负责把锚框调整为接近真实框。这通常用四个参数表示中心点偏移 (t_x, t_y) 和宽高缩放 (t_w, t_h)。公式如下[ t_x \frac{x - x_a}{w_a}, \quad t_y \frac{y - y_a}{h_a} ] [ t_w \log\frac{w}{w_a}, \quad t_h \log\frac{h}{h_a} ]其中 (x_a, y_a, w_a, h_a) 是锚框的中心和宽高(x, y, w, h) 是预测框的值。用对数来做宽高缩放的好处是让回归目标落在接近线性的范围内而且正负对称训练时更好收敛。这里我想强调一个容易被忽略的细节回归分支预测的是偏移量而不是绝对坐标。为什么要这样因为锚框分布在特征图的各个位置绝对坐标的数值范围跨度极大直接回归绝对坐标会让 Loss 被大坐标主导模型很难收敛。偏移量做了归一化把目标压缩到以锚框为中心的相对尺度里训练稳定很多。这个思路在全系列的检测模型中都反复出现理解它比背公式有价值得多。2.4 损失函数分类损失与回归损失的组合方式RPN 的损失函数由两部分组成[ L({p_i},{t_i}) \frac{1}{N_{cls}}\sum_i L_{cls}(p_i, p_i^) \lambda \frac{1}{N_{reg}}\sum_i p_i^L_{reg}(t_i, t_i^*) ]其中 (p_i) 是锚框预测为目标的概率(p_i^) 是标签0 或 1(t_i) 是预测的四个回归参数(t_i^) 是真实偏移。(L_{cls}) 一般是二分类交叉熵(L_{reg}) 通常是 Smooth L1 损失。值得注意的有两点。第一回归损失前面乘了 (p_i^*)意味着只有正样本锚框才参与回归训练负样本只贡献分类损失。这是合理的因为你不需要让一个没有物体的框去学习如何回归到某个位置。第二公式里的 (N_{cls}) 和 (N_{reg}) 分别是 mini-batch 中的前景样本数和锚框总数(\lambda) 默认取 10 左右用来平衡两种损失的尺度。实际调参时如果发现训练时总损失里分类损失占比过大可以适当调整 (\lambda)而不是盲目改学习率。3. 训练细节RPN 到底是怎么被训出来的3.1 正负样本匹配策略IOU 阈值驱动的分配逻辑RPN 训练的第一步是把数万个锚框划分成正样本、负样本和忽略样本。规则大致如下正样本与任意真实框的 IOU 最大的锚框或者与某个真实框 IOU 大于 0.7 的锚框。负样本与所有真实框的 IOU 都小于 0.3 的锚框。忽略样本IOU 在 0.3 和 0.7 之间不参与任何损失计算。第一句IOU 最大的一定是正样本保证每个真实框至少有一个锚框负责这非常重要。如果没有这条规则某个小目标可能和所有锚框的 IOU 都不超过 0.7导致它完全没有正样本负责。IOU 阈值定在 0.7 和 0.3 也有一些讲究0.7 足够严格确保正样本里基本没有大量背景0.3 相对宽松保证负样本数量充足从而让分类器学到约束。实际工程里如果你的目标和标注质量较差把正样本阈值调到 0.5 左右也能跑只是候选框质量会下降。3.2 样本采样一张图里如何挑出 256 个小批量每个真实框的匹配结果出来后正样本和负样本的数量通常极不平衡。负样本可能有大几千个正样本可能只有几十个。如果全部喂进去训练分类器会被负样本带偏输出概率永远偏向背景。Faster R-CNN 的做法是从一张图的锚框里采样 256 个样本正负样本比例控制在 1:1 附近。如果正样本不足 128 个就用负样本补齐。这个采样策略在今天的很多实现里仍然被沿用不过也有改进空间。印象比较深的是在一些小目标占比特别高的数据集上由于锚框匹配困难正样本经常连 32 个都凑不满导致训练信号太弱。这种情况下与其死守 1:1不如适当放宽 IOU 阈值或者干脆采用 OHEM在线困难样本挖掘来给分类器提供更有区分度的样本。3.3 四步交替训练与端到端训练的对比原论文采用的训练方式叫四步交替训练先在 ImageNet 预训练的网络基础上训练 RPN微调整个网络。用上一步训好的 RPN 生成候选框拿去训练 Fast R-CNN 检测器。用检测器初始化共享卷积层固定共享层微调 RPN。固定共享层在 RPN 输出的候选框上微调检测器。这种交替方案在当时是为了避免两个模块联合训练时的内存和梯度问题但步骤繁琐且有多次微调训练周期很长。后来很多框架默认采用近似联合训练RPN 和检测器同时训练RPN 输出的候选框直接当作检测器的输入反向传播时梯度不断回传到共享层。近似联合训练收敛更快实现更简单实际效果和交替训练相差无几。我个人现在基本只用近似联合训练除非是复现论文对比实验否则没必要折腾四步法。3.4 NMS 的作用与阈值选择RPN 训练和推理的最后一步都要对数百甚至数千个预测框做非极大值抑制NMS。如果不做 NMS同一个目标周围会堆着密密麻麻、彼此高度重叠的候选框后续 RoI 模块会重复提取特征浪费计算量不说还会让检测器输出大量重复检测。NMS 按分类分数从高到低排序把和当前最高分框 IOU 超过阈值的框抑制掉直到剩下 Top-N 个候选框。在 RPN 阶段NMS 的 IOU 阈值一般取 0.7输出保留 2000 个训练或 300 个推理框。你可能好奇为什么分类阶段 NMS 阈值通常取 0.45 或 0.5而 RPN 却取 0.7因为 RPN 作为一个粗筛模块要保证高召回两个相近物体不能被过早抑制掉一个所以阈值要放得很宽。0.45 那种严格阈值是给最终检测器做去重用的。这个区别我在早期调参时经常搞混后来才意识到不同阶段 NMS 的目的完全不同。4. RPN 只是起点衍生变体与跨任务扩展4.1 Cascade RPN解决你的锚框根本不够好的问题RPN 的锚框机制有一个天然局限预先定义的锚框质量和后续回归的效果上限是绑定的。如果目标尺度分布特别极端锚框初始化不合适哪怕网络很好回归也救不回来。Cascade RPN 的思路就是把这个过程做了多级化第一级先产生较粗糙的候选框第二级用自适应卷积在更高 IoU 的分布上继续调整。简单说就是让候选框质量本身成为一个递进优化的目标而不是一步到位。实际项目中Cascade RPN 对小目标和高密度场景的提升挺明显代价是计算量变大、训练变复杂。如果你的模型参数量没那么充裕我更建议先统计自己数据集中目标的高宽分布据此重新设计锚框这比引入一个复杂模块性价比高得多。4.2 RPN 在目标跟踪中的变体Siamese RPN 系列热词里提到的RPN 跟踪主要指 Siamese RPN 及其后续工作。它的思路很有趣把跟踪问题建模成在搜索区域里找候选框。孪生网络提取模板帧和搜索帧的特征然后在搜索特征图上做类似 RPN 的回归与分类从而一次性输出目标位置和大小。相比传统跟踪算法逐帧搜索或者相关滤波Siamese RPN 类方法速度快、精度高如早期 SiamRPN 在 VOT 数据集上表现惊艳。核心创新点就是把 RPN 的候选框提出能力移植到跟踪场景模板分支提供目标特征当成锚框搜索分支通过互相关操作生成响应图最终找出最匹配的框。可以说 RPN 因为本身生框 二分类 回归的通用性天然适合被改造到跟踪任务里。4.3 DETR 等端到端方法还要不要 RPN2020 年 DETR 出现后一个典型问题浮现出来基于 Transformer 集合预测的检测器完全丢掉了 RPN 和锚框直接输出固定数量的预测。它的监督方式是二分图匹配让预测框和真实框一对一配对然后再做分类和回归。从效果上来看DETR 把 RPN 这种锚框机制替代为learned object queries相当于让模型自己学一个全局的查询向量去找目标省去了大量调锚框的超参数。然而 DETR 在训练收敛速度和小目标检测方面早期确实不如 Faster R-CNN 系方法。后续 Deformable DETR 又借鉴了多尺度特征和稀疏空间采样在多尺度特征图上采样本质上是对 RPN 前身多尺度滑动窗口理念的一种回归。就我自己的感知来说RPN 在今天不是过时了而是它的功能被分化了有些架构显式保留它有些架构用注意力机制隐式扩散了它的思想。理解 RPN 最原初的提出候选 前景判断逻辑依然可以帮助理解大部分现代检测器。5. 工程落地中 RPN 相关的踩坑记录与优化心得5.1 特征图尺寸和感受野的匹配问题一个很容易踩坑的细节是锚框尺度必须和特征图的感受野匹配。如果主干网络是 ResNet-50 的 C4 特征图下采样 16 倍感受野大约 128~256 像素那么设计 512 甚至 1024 的大尺度锚框就会出问题。因为特征图上的每个点根本看不见那么大的范围分类分支和回归分支只能凭非常稀薄的信息去判断质量自然不高。我之前在做一个高分辨率航拍图检测项目时把输入做了切片到 1024 分辨率但锚框尺度还是沿用默认的 128、256、512小目标检测召回率惨不忍睹。后来把尺度列表里新增了 32 和 64 后召回率立刻涨了近 12 个百分点。多尺度特征融合比如 FPN能从某种程度上缓解这个问题但锚框尺度和感受野的基本匹配关系仍然是必须优先检查的。5.2 训练不收敛时优先怀疑 RPN 的正负样本分布很多人在检测模型训崩的时候习惯先调学习率、改优化器但我建议先看一眼 RPN 阶段的损失曲线。如果 RPN 的分类损失和回归损失都在剧烈震荡或者分类损失一直降不下去大概率是正负样本分配出了问题。一个排查思路是单独把当前模型的 RPN 输出可视化检查第一轮训练出来的候选框是不是全都堆在图像边缘或背景区域。如果是多半是锚框匹配率太低正样本太少如果候选框全是一个尺度说明锚框尺度和目标不符还有一种常见情况是跨边界锚框没有处理好大量锚框中心落在图像边界外这部分样本既没实际意义又容易干扰梯度。实现时需要把越界锚框直接忽略掉而不只是打个标签。5.3 RPN 应不应该共享主干特征以及冻结策略Faster R-CNN 和很多实现默认 RPN 与检测头共享主干网络的特征这确实能大幅降低计算量。但在一些特定任务里共享反而有害。比如你准备先在辅助任务上预训练一个主干然后单独训 RPN再解冻一起调优这种交替方案下可能会出现共享特征同时被两边的损失拉扯的情况RPN 想让特征更强调前景背景差异分类头又想让特征更有类别判别性。我遇到过一个具体问题检测器的分类分支收敛得很快RPN 的召回却一直上不去。我的处理方法是将主干的前几层冻结让 RPN 和检测头分别训练更久一点等两者都比较稳定后再解冻骨干微调几个 epoch。这种做法不是论文里钦定的标准流程但在迁移学习的场景下很实用。核心思路是共享不等于盲目一起优化如果出现了任务竞争考虑先分后合。5.4 候选框数量、Top-N 与速度的权衡RPN 在推理阶段要输出多少候选框也是一个值得花时间调的参数。默认是训练 2000、测试 300但 300 在很多场景下并不是最优解。目标密集、小目标多时300 个框很容易在高重叠区域耗尽配额有价值的框被 NMS 挤掉目标稀疏场景则没必要用 2000 个框太浪费后续模块的计算。提速思路之一是先把 RPN 的分数阈值调高一点。举个例子如果你测试集里目标是中型目标RPN 分类分数输出 0.99 的框比例很高那么把阈值从 0.5 提到 0.7 能过滤掉大量背景框NMS 计算量明显下降候选框的精度也不牺牲太多。还有一点把 Top-N 和 NMS IOU 阈值联动起来调整NMS 阈值低、数量少时速度更快但可能漏掉重叠目标想要高召回就加大数量、放宽阈值但会增加后续检测头的压力。这是一个根据业务需求做取舍的决策没有标准答案。5.5 实现时用的推理加速小技巧工程上如果觉得完整 RPN 前向过程太重常见做法是先在低分辨率特征图上做一次降采样再跑 RPN或者把锚框数量做稀疏化。比如特征图是 40×60每个位置 9 个锚框总共有 21600 个框NMS 排序的耗时和你保留的候选数直接相关。这时可以考虑先用一个轻量的先验筛选每个位置仅保留前景分数最高的两个锚框然后再送入 NMS这样能减少约 70% 的排序量精度损失往往在 0.2~0.5 个点以内。此外把 NMS 换成 Non-Maximum Suppression with Soft 或者用 batched NMS GPU 实现也能省下不少时间。6. 从 RPN 出发应该再补哪些知识如果把 RPN 作为进入目标检测领域的切口后续有几个方向值得继续深入。一是 IoU 和匹配策略。RPN 里的正负样本分配只是 IoU 阈值匹配的一个典型案例。后面流行的 ATSS、Faster R-CNN 新版本、或者 YOLO 系列中的 assigner 设计核心都是围绕着如何把 anchor 和目标配对这个基础问题在改进。掌握了 IOU 匹配的逻辑看这些方案会顺畅很多。二是 NMS 的进阶形态。RPN 用的传统 NMS 在密集场景下容易过度抑制所以后来有了 Soft-NMS分数衰减而非一刀切、DIoU-NMS把中心点距离考虑进抑制条件、以及 Adaptive NMS。本质都是对两个框到底算不算重复的更合理度量。这比翻开论文直接看公式要有意思得多理解也更快。三是损失函数的发展。RPN 里的 Smooth L1 到现在仍然是边界框回归中非常常用的损失函数不过后来也出现了 IoU Loss、GIoU Loss、CIoU Loss 这些更直接优化框质量的方案。它们某种程度上改变了回归分支的行为方式但仍然以经典 RPN 的回归设计为骨架。如果你现在正卡在某个检测项目的调参瓶颈上不妨先单独把 RPN 拎出来做可视化画出每一层的候选框、在训练前期看锚框的匹配情况、观察回归偏移的数值范围。RPN 虽然只是整个检测链路里的一环它的质量直接决定了上游天花板。宁可在这里多花一天时间也胜过盲目堆模型结构。
返回列表