目标检测后处理与部署细节笔记
· 更新于 2025/1/20
目标检测项目里,模型结构只是一部分。真正落到工程系统时,前处理、后处理、类别规则、坐标还原、可视化和硬件推理框架都会影响最终效果。这篇文章把几篇早期笔记合并起来,作为我对目标检测工程细节的一次整理。
这些内容看起来偏碎,但在真实项目里很常见:模型训练指标不错,接入系统后却因为坐标缩放、NMS 策略、类别冲突或显示性能问题造成误判。
LetterBox:保持比例的输入预处理
YOLO 系列模型通常要求固定输入尺寸。直接 resize 会改变目标宽高比,对细长目标、小目标和旋转目标尤其不友好。LetterBox 的思路是保持原图比例缩放,再用 padding 补齐到目标尺寸。
这个步骤的关键不是“把图变成固定大小”,而是要保留从原图到模型输入之间的映射关系。后处理时,检测框需要从模型输入坐标还原回原图坐标。如果缩放比例和 padding 偏移没有处理一致,就会出现框偏移、框大小不准或边缘目标定位异常。
我后来做检测部署时,会把前处理输出写得更明确:不仅返回处理后的图像,还返回缩放比例、上下左右 padding 和原图尺寸。这样后处理函数不需要猜测坐标关系,部署到不同框架时也更容易排查。
NMS 与分组 NMS
NMS 是检测后处理中最基础的一步:对同一目标产生的多个候选框,根据置信度和重叠程度保留最合适的结果。常规 NMS 在大多数任务里够用,但在类别关系复杂的场景中会遇到问题。
比如某些类别外观接近,模型可能同时输出多个相邻类别的框。完全按类别独立做 NMS,可能保留多个互相重叠的结果;完全不区分类别做 NMS,又可能错误压掉本该并存的目标。
分组 NMS 的思路是把容易冲突的类别放到同一组内做抑制,不相关类别仍然分开处理。它不是替代模型训练,而是在业务类别体系比较细、误报成本较高时,用后处理规则补充模型输出。
我认为这类后处理策略的好处在于可解释、可控、容易回滚。相比为了少量误报重新训练模型,先从类别规则和后处理策略入手,往往能更快定位问题。
中文标签绘制的性能问题
视频流或实时监控系统里,检测结果通常需要绘制到画面上。如果每一帧都动态加载字体、计算文字布局,再绘制中文标签,会带来不必要的性能开销。
我当时采用过一种简单优化:把常用中文标签提前渲染成纹理并缓存,视频流处理时直接贴图。这样可以减少重复字体渲染,尤其适合类别固定、帧率较高的场景。
这个问题说到底不是算法问题,而是实时系统里的细节优化。单帧看不明显,但在多路视频、长时间运行的服务里,类似的小开销会累积成稳定性问题。
Ascend 平台 YOLOv5 推理
在 Ascend 平台上部署 YOLOv5,需要把训练框架里的模型推理流程拆成更明确的几个部分:图像预处理、模型输入构造、ACL 推理调用、输出解析、NMS 后处理和坐标还原。
和常规 Python 推理相比,硬件推理框架更强调输入输出内存、数据类型、模型转换和算子兼容性。很多问题不在模型本身,而在部署链路里:输入尺寸不一致、数据格式不匹配、后处理坐标没还原,都会导致看起来像“模型效果变差”。
因此我在做这类部署时更关注两件事:
- 训练侧和推理侧前后处理必须保持一致。
- 每个中间结果都要能单独验证,不能把模型、前处理和后处理混在一起排查。
相关实现
这部分经验中有一个小工具被单独整理成仓库:class-group-aware-nms。它提供了一个纯 Python 的类分组感知 NMS 实现,用 class_groups 把语义相近的类别映射到同一抑制分组,同时保留最终输出里的原始预测类别。
这个工具不追求复杂框架封装,主要是把一个真实检测系统里常见的后处理问题抽象成可运行、可测试、可解释的小模块。
复盘
目标检测工程化的难点经常藏在模型之外。一个检测系统要稳定工作,数据预处理、模型推理、后处理规则和结果可视化都得串起来,每一步都要能解释和验证。
这些笔记对应的小工具和代码片段不一定适合单独展示,但它们代表了我在视觉算法落地中比较看重的一面:不只是能训练模型,也能把模型接入真实系统,处理部署之后冒出来的各种细节问题。