资讯动态

目标检测后处理进阶:WBF加权框融合原理与工程实战

发布时间:2026/10/14 1:33:50 来源:尧图企业网站定制
搞检测项目的人应该都有过这种经历模型训练完验证集分数卡在一个尴尬的位置调结构、调loss、换数据增强费半天劲上涨零点几个点。这时候其实还有一个性价比极高的操作——Weighted Boxes Fusion通常直接叫WBF。它不是模型改造而是把多个检测结果在推理阶段合并起来不是像NMS那样留下一个框干掉一堆重叠框而是把重复框的坐标和置信度做加权融合合成一个更稳的新框。这篇文章我把WBF从算法原理到工程落地完整讲一遍包括公式拆解、手算示例、调参经验以及在几个项目里实际踩过的坑。适合正在做目标检测、想让最终结果再升一档的工程师也适合刚入门检测、想搞清楚“融合框”到底是什么的读者。1. 先搞清楚 WBF 到底在解决什么问题1.1 从 NMS 说起为什么“丢掉”低分框这个动作很可惜目标检测的后处理通常承担两件事去重和定位微调。标准NMS的思路非常直白先按置信度排序取最高分的框把所有和它IoU大于阈值的框全抑制掉然后继续处理剩下的框。这个过程简洁高效几乎成了默认配置但它的代价是信息被过早丢弃。举个例子。同一个目标模型A预测的框稍微偏左模型B预测的框稍微偏右两个框的IoU是0.6看起来重叠不算太大。NMS最后只会留下置信度更高的框A把框B直接扔掉。但实际上呢两个框的平均位置很可能比其中任意一个都更接近真值框。因为单个模型对目标边界的判断本身就有不确定性这种不确定性有时是随机波动有时是不同感受野带来的系统性偏差。多个模型的误差方向往往不完全一致彼此之间能抵消一部分。WBF的思路是另一条路不丢弃那些重叠的低分框而是把它们留下按置信度做加权平均合成一个新的框。这个新框不一定对应任何模型直接输出的结果是计算出来的虚拟框但它的位置通常比单个原始框更稳定对定位类指标尤其友好。很多第一次接触WBF的人会困惑“这不就是变种NMS吗”其实关键差异就在这里NMS在做选择题WBF在做加权求和。1.2 WBF 与 NMS、Soft-NMS 的本质差异可以把三种常见后处理做一次对比方法对重叠框的处理输出框数量是否利用低分框对定位精度帮助计算复杂度NMS选最高分抑制其余较少否一般O(N²)Soft-NMS按重叠程度衰减分数较少部分一般O(N²)WBF加权融合坐标与置信度较少是较强O(N²) 量级Soft-NMS是NMS的改进它不直接删掉重叠框而是把分数按IoU函数衰减从而让密集目标有机会被保留下来。但注意Soft-NMS最后输出的仍然是某个模型的原始框它并没有在坐标层面利用低分框的信息。WBF则完全不同它真正把多个框合成一个新框这在定位精度要求高的场景里优势特别明显。理解了这个差异就会明白WBF更适合用在什么样的地方当你有多个来源的检测结果时比如多个模型、同一个模型的多折训练、多种推理尺度、TTA增强这些结果的置信度和坐标各有偏差合并它们就是WBF的主场。2. WBF 算法逐行拆解2.1 五个关键步骤WBF的原始流程可以拆成五步我按实现顺序说明收集全部检测结果。假设有若干个模型或若干次推理把所有框放到同一个列表里每个框包含坐标、置信度、类别ID最好还保留来源模型编号。按置信度从高到低排序。排序的目的是让高分框优先形成簇低分框只能加入已经存在的簇或者创建新簇。这样就能保证一个簇内置信度最高的框永远是这个簇的“代表框”。定义簇。每个簇是一个候选集合代表当前图像中可能存在的某个目标。遍历排序后的框与现有簇逐一计算IoU。找到与当前框IoU最大且超过阈值的簇就把框加入这个簇如果没有找到就新建一个簇。这里需要注意的是原始算法用簇内最高分的框作为IoU计算基准而不是簇内所有框的平均框。这个设计是为了稳定聚类过程避免簇里框多了之后代表性坐标来回抖动。完成聚类后对每个簇做加权融合得到最终框的坐标和置信度。这里面还有个容易被忽略的参数设计。原始实现里引入了融合阈值和跳过阈值用于控制置信度过低的框是否参与计算。实操中一般会先做一轮分数过滤把低于阈值的框直接排除避免噪声框把簇带偏。2.2 坐标和置信度的融合公式簇内融合的公式并不复杂。假设簇内有n个框每个框置信度为score_i坐标是左上角(x1, y1)和右下角(x2, y2)融合后的坐标计算公式是新x1 Σ(score_i × x1_i) / Σ(score_i)新y1 Σ(score_i × y1_i) / Σ(score_i)新x2 Σ(score_i × x2_i) / Σ(score_i)新y2 Σ(score_i × y2_i) / Σ(score_i)简单说就是按置信度加权平均。置信度越高的框对最终坐标的贡献越大。置信度的融合公式稍微有点特别新置信度 Σ(score_i) / n。这里的n是簇内框的数量不是参与融合的模型数量。为什么要除以簇内框数量打个比方两个模型都在某个位置以0.8的置信度检出目标说明它们“一致认可”除以2之后置信度是0.8非常合理。但如果是一个模型连出三个重叠框另一个模型在这个目标上只出了一个框这个模型实际赢三个框的投票权就会不公平地融进坐标。所以实现时经常强调要先对每个模型内部做去重就是为了保证每个模型在簇里的“发言权”接近对等。有些实现还支持外部权重也就是根据模型在验证集上的表现给它乘一个权重系数。这时融合公式里的score就变成score_i × model_weight。我建议在模型差距明显的时候使用这种方案比如一个验证集mAP 0.58另一个0.51前者在簇里权重更大一些是合理的。2.3 一个具体例子手算一遍纸上谈兵不如手算我们拿两组框举例。假设模型A和模型B对同一辆车各输出一个框框Ascore0.9坐标 (10, 10, 100, 100)框Bscore0.7坐标 (20, 15, 110, 105)先算IoU。两个框都是90×90大小重叠区域的宽度是100-2080高度是100-1585重叠面积是6800。两个框的并集面积是8100×2-68009400IoU6800/9400≈0.72明显大于阈值0.55所以它们会进同一个簇。融合坐标新x1 (0.9×10 0.7×20) / (0.90.7) (9 14) / 1.6 14.375新y1 (0.9×10 0.7×15) / 1.6 (9 10.5) / 1.6 12.1875新x2 (0.9×100 0.7×110) / 1.6 (90 77) / 1.6 104.375新y2 (0.9×100 0.7×105) / 1.6 (90 73.5) / 1.6 102.1875新置信度 (0.9 0.7) / 2 0.8。可以看到新框的位置落在两个原始框之间更偏向高分框A一侧但并没有完全倒向一边。如果两个模型的误差方向不同这个平均过程就是在做定位上的互相纠偏如果两个框本来就非常接近融合框只会更稳定几乎不会损伤原有的精度。但这里暴露了一个隐患如果两个框的IoU勉强刚过阈值而它们的边界差异很大融合出来的框可能落在两个框的中间位置这个中间位置反而可能离真值框更远。所以IoU阈值不宜设太低我惯用范围是0.5到0.6之间多数场景0.55比较稳。2.4 算法复杂度与适用规模WBF单次计算的复杂度在O(N²)量级因为每个新框都要和已有簇计算IoU。在实际检测任务中一张图单个模型通常输出几十到上百个框多个模型加一起也就两三百个框在CPU上完全可接受不需要特别优化。不过如果一张图输出几千个框比如某些密集小目标场景聚类的耗时就会明显上升那时需要先用低置信度阈值把候选框砍到合理范围。3. 实操流程全记录3.1 数据准备把多个来源的检测结果拼在一起WBF本身不产生检测结果它只负责融合。开始之前需要先把所有模型的预测结果收集齐输入格式统一是最重要的前置动作。我在项目里使用的做法是每个模型推理完成后保存一份记录字段固定为image_id、class_id、x1、y1、x2、y2、score、model_idx。其中model_idx是来源模型编号用于后面计算权重。不同模型输出的坐标体系必须完全一致如果模型X输出是0到1归一化坐标模型Y输出是像素坐标直接混在一起算IoU就是灾难。def merge_predictions(multi_model_results): merged [] for image_id, model_outputs in multi_model_results.items(): for model_idx, boxes in enumerate(model_outputs): for b in boxes: merged.append({ image_id: image_id, model_idx: model_idx, x1: b[0], y1: b[1], x2: b[2], y2: b[3], score: b[4], class_id: int(b[5]) if len(b) 5 else 0 }) return merged需要提醒的是WBF的分簇一定要按类进行。不同类别之间不能混成一个簇否则“人”和“电动车”这两个目标如果靠得太近各自高分框竞争同一个簇最后会融出一个毫无意义的混合框。多类别场景最简单的处理方式就是在外层循环里按class_id分组分别跑WBF。3.2 加权怎么算按模型权重融合默认的WBF权重来自每个框自己的置信度这在多数情况下已经很好用。但如果你想给更靠谱的模型更高的话语权可以引入外部模型权重。我在项目里是这样处理的model_weights {0: 1.15, 1: 1.0, 2: 1.05} # 来自验证集表现 for record in merged: record[weighted_score] record[score] * model_weights[record[model_idx]]进入聚类和融合环节后坐标加权公式里的score全部换成weighted_score。注意置信度融合公式里的分母仍然除以簇内框数不要顺手改成除以总权值否则单个模型内部权重过大的问题会被放大。实测下来外部权重系数一般设置在0.8到1.2之间就够了超出这个范围容易让弱模型完全失去发言权。3.3 阈值怎么调三组关键参数的实际经验WBF的调参主要集中在三处IoU阈值iou_thr决定两个框达到多大重叠才算同一个目标候选。设低了不同目标的框容易融到一个簇设高了同一个目标的重复框又合并不起来。对常规检测任务0.55是一个稳妥起点我会在这个基础上按数据集的密集程度上下浮动0.05。置信度阈值score_thr低于该值的框直接不参与融合。建议设在0.05到0.1之间只去掉极端噪声保留更多低分信息。WBF的价值恰恰来自那些中等置信度的框阈值砍太狠等于回到NMS的思路。置信度融合方式conf_type常见有avg和max两种。avg平均更保守max只保留簇内最高置信度。如果模型置信度校准做得一般我偏向用avg如果模型本身置信度很有区分度max可能更接近单人模型的判断习惯。还有一个容易踩到的坑同一个模型在同一个位置连续输出两个几乎一样的框这并不罕见。如果不先对这个模型自己的结果做NMS去重它就在簇里占了两次投票权坐标会明显偏向这个模型。所以我在进入WBF之前永远先对每个模型的输出分别做一轮普通NMS只保留每个位置的最高分框然后再合并、聚类。4. 实际遇到过的坑与排查经验4.1 同一模型的重复输出没有先去重我第一次正式跑WBF直接把两个模型的原始输出拼在一起看融合结果发现mAP不升反降大约掉了0.01。查了很久才定位到问题第一个模型在目标位置输出了两三个近乎重叠的框它们在簇里的权重占比太高导致融合框整体偏向那个模型。解决方式就是我上面说的单个模型先做内部NMS再去融合。这个步骤看起来多此一举但在模型推理时没有做严格去重的情况下几乎是必踩的坑。4.2 坐标体系不一致导致融合框漂移第二种坑比第一种更隐蔽。有一次我在一个切图推理的场景里做多模型融合每个模型分别对图像分块结果发现融合后的框坐标漂移严重。排查之后发现子图的坐标是相对各自patch的没有先映射回原图坐标就直接参与融合加了坐标偏移量之后问题立刻消失。统一坐标这件事最好在每个模型推理结束时就同步完成。包括归一化坐标转像素、裁剪区域坐标转全局坐标、缩放的Padding补偿都不要留到融合阶段再处理。因为到了融合阶段你已经很难追踪某个框到底来自哪条预处理链路调试成本会翻倍。4.3 置信度没有校准加权变成“错重”WBF有一个隐式假设高置信度框比低置信度框更准确。但不同模型置信度尺度的差异可能非常大。有的模型倾向于打高分平均置信度0.85有的模型很保守平均置信度0.55但两者在同目标上的实际准确率可能差不多。这种情况下WBF的置信度加权就等于在偏袒虚高的模型。我的经验是进入WBF之前先统计每个模型在验证集上的置信度分布。如果发现某一方的平均置信度系统性地高出其他模型0.2以上我会给这个模型的整体分数乘一个0.85左右的折扣让加权更公平。否则那些保守模型即使判断正确也很难在簇里发出声音。4.4 类别没有分开两个正确目标被融成错误框这个坑在多类别检测场景特别容易犯。直观场景是“骑摩托的人”里的“人”和“摩托车”两个真实目标高度重叠IoU可能大于阈值。如果所有类别放在一起做WBF这两个框就会被分到同一个簇融合出一个覆盖人和车的混合框既没有准确定位人也没有准确定位车。按类别分别做WBF之后这个误融合就完全消除了。这一条无论是用现成库还是自己写代码都要在流程设计时确认一遍。下面整理成一张速查表方便后续排查现象可能原因排查顺序融合后mAP下降单模型重复框未去重第一步检查每个模型输出是否重叠过多融合框漂移、位置不合理坐标体系不一致第二步确认所有输入框是同一坐标空间弱模型几乎没贡献置信度尺度失衡第三步统计各模型置信度分布边界混乱、贴合多个目标类别未分离第四步检查是否按class_id分组5. 一个值得记录的真实项目5.1 基础设置与方案我帮一个项目组处理过某个工业构件的小目标检测场景。数据特点是每张图目标不多平均3到7个框但质检标准很严宁可漏检不许错检。当时效果最好的三个派生模型各有擅长模型一单阶段检测模型验证集mAP约0.53模型二两阶段检测模型验证集mAP约0.55模型三在模型二基础上加了测试时横向翻转mAP约0.54。三个模型单独看都不算突出但我注意到它们的误差分布不同。模型一在细长构件上容易漏模型二对边界重叠的目标定位差一些模型三因为翻转TTA的引入在方向性较强的目标上有额外优势。这正好符合WBF起效的前提模型误差具备互补性。5.2 融合前后的数据对比我没有动三个模型的训练代码只统一收集推理结果先单模型NMS去重再按类别做WBFIoU阈值0.55置信度阈值0.05。方案精确率召回率mAP0.5模型一0.740.610.53模型二0.760.640.55模型三0.750.630.54三模型WBF融合0.820.670.59融合后mAP提升了约0.04这是相当大的收益因为模型部分完全没动。提升最明显的是精确率从不到0.77跳到0.82。背后逻辑是三个模型漏检的位置很少完全重叠某个模型的低分输出在另一个模型那里可能得到支持融合过程相当于把碎片化的信号汇拢成完整证据链。5.3 为什么有效不同模型误差的互补性融合有效的前提是误差不相关。如果两个模型结构高度相同、训练数据一模一样它们的错误模式高度重叠WBF就只是两次重复投票没有新增信息量。反过来单阶段和两阶段模型在特征提取层和感受野分布上差异较大天然存在互补视角。基于这段经历我给团队定的规则是做WBF之前先看模型组合不要选两个结构完全一样的兄弟模型如果条件允许优先选择不同主干、不同分辨率、不同训练策略的异构模型组合。6. 什么时候别用 WBF6.1 只有单一模型且没有多尺度推理如果只有一个模型、只推理一次手上只有一份输出WBF无从谈起。这种情况下还是把精力放在模型结构或NMS参数上更有效。唯一例外是单模型做了TTA或多尺度推理之后产生多份变异结果这时WBF可以接管合并工作。6.2 密集小目标的场景密集人群、细胞分割、货架上的密集商品这类场景目标数量多、框之间重叠程度高IoU很大可能超过聚类阈值导致簇错误地吞掉相邻目标出现漏检。我踩过一次密集人群的坑融合后召回率反而下降了。此类场景更建议使用严格的IoU阈值或者干脆放弃融合采用逐目标匹配的后处理策略。6.3 实时性要求极高的部署WBF比单次NMS多出来的计算开销虽然只有几十毫秒但边缘设备的延迟预算往往已经没有余量。如果模型推理已经占了80%以上的时间再强加融合逻辑容易拖垮整个流程。此时可以降低置信度阈值、减少参与融合的框数或者只在离线评测阶段使用WBF确认精度上限最终部署还是回到轻量后处理。我的个人习惯是任何融合方案都先在离线评测上确认收益再决定是否搬进推理链路。千万不要把“应该有效”当作“一定有效”WBF的有效性始终依赖数据、模型组合和阈值匹配只有实测数字能说服人。最后分享一个一直留着的小习惯做完WBF融合我会把融合前后的输出分别保存一份抽查20到30张图专门看那些融合框边界落在两个原始框之间的样本。因为指标表格只能告诉你平均涨了还是跌了真正的“框该在哪”只有可视化才看得清楚。融合不是无脑合并它是把多个模型的判断用更合理的方式汇总理解这一点比记住任何参数都重要。

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

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

免费获取报价 →
↑