视觉指标:mAP 之外
检测 mAP 高不代表 latency、误报率和 worst-case 能上线;要报 tail latency、固定 FP 预算下的 recall 和场景切片。

1. 榜单分数到不了产线
检测模型在验证集上平均精度涨了三个点,集成进导航栈后客户仍报雨夜误停。查下来不是模型坏了,是评测工作点与车上阈值不一致:离线用极低置信度扫整条精确率召回曲线,产线固定零点四五且要求每天误报少于五次。单一数字掩盖了尾部延迟、校准质量和最坏场景切片,这三项才是今晚能不能开的答案。评测设计不是科研附属品,而是产品约束的编码——阈值、算力预算、安全误报上限都该写进报告,而不是附在论文表格后面。
2. 平均精度回答什么、不回答什么
平均精度是对全精确率召回曲线的积分,适合研究排名,不是产线决策点。它不关心实际用的阈值,也不关心百分之九十九延迟是否超预算。两个模型平均精度差零点五,在固定阈值零点五下召回可能差十个百分点。安全相关任务还要单独报高置信度误报桶:置信度大于零点八的误检比整体平均精度更要命,客户看到的是高置信度误停,不是榜单表格。置信度能否用于决策,看可靠性图:预测置信度与经验准确率的对应关系。期望校准误差量化偏差;验证集上拟合温度缩放,测试集只报告,别把校准泄漏进测试。未校准的置信度不能直接驱动高置信就刹车这类策略。
3. 延迟要剖到阶段
端到端延迟不是一个前向推理数字。用计时拆预处理、推理、后处理,报中位数和百分之九十九分位:
freq = cv2.getTickFrequency()
t0 = cv2.getTickCount()
blob = cv2.dnn.blobFromImage(frame, 1/255.0, (640, 640), swapRB=True)
t1 = cv2.getTickCount()
net.setInput(blob)
out = net.forward()
t2 = cv2.getTickCount()
idxs = cv2.dnn.NMSBoxes(boxes, scores, score_th, nms_th)
t3 = cv2.getTickCount()含缩放、色彩转换、主机与设备间拷贝。嵌入式上推理后端没开加速时,隐藏开销常在内存拷贝而非推理本身。最坏情况输入也要测:最大分辨率、最多检测框,不只测平均图像。机器人闭环里百分之九十九延迟比平均延迟更接近真实体验——平均二十毫秒、尾部八十毫秒,控制环照样振荡。
4. 场景切片,不是 aggregate 一张表
逆光、雨夜、粉尘、小目标分开报固定阈值下的召回和误报。聚合平均精度会掩盖尾部风险:某一切片召回掉两成,在聚合里可能只剩一个百分点。安全任务对最坏切片要人工签字确认,不能只看均值。检测额外报每天误报数;分割报边界误差毫米或像素;跟踪报身份切换;深度报各距离区间的绝对相对误差。切片维度要和部署场景对齐:室内工厂、户外物流、夜间安防的失败模式不同,不能用一个验证集代表全部。我会把切片表和 operating point 曲线绑在一起评审,缺一切片就不给上线签字。
5. 在线对比与回滚
小流量影子模式对比旧流水线,预演回滚路径。离线涨点不到两个百分点且百分之九十九延迟增五毫秒,在三十赫兹闭环里常不值得换。端到端任务成功率——抓取成功、导航通过率、工位节拍——比孤立平均精度更接近真相。代理指标涨而任务不涨,说明评测与产线脱节。持续集成应固化:工作点精确率召回曲线、延迟直方图、切片表、校准图四件套。换模型合并请求必须附带这四项差异,否则评审只看平均精度数字是在赌博。
6. 案例:高平均精度、高置信误停
某次换模型后平均精度涨二点一,但固定阈值零点五下高置信度误报在雨夜切片翻倍。根因是新模型置信度整体偏高且未校准,零点五阈值实际等价于旧模型零点三五。验证集上拟合温度缩放后,工作点对齐,每天误报回到预算内。平均精度涨了,产线差点关——这是典型的评测与部署脱节。教训是:任何模型替换必须重跑校准和工作点表,不能只看验证集平均精度 diff。
7. 与录包复盘
事故袋若没有推理阈值、非极大值抑制参数和输入分辨率快照,只能猜当时配置。状态层录包应包含关键参数 dump 或安全参数白名单。证据链完整,才分得清是算法责任还是配置责任。我会把评测四件套导出路径写进录包元数据,复盘时直接拉切片表对照当时场景标签。
8. 验收
- 工作点精确率召回曲线加实际阈值标注
- 延迟直方图(中位数与百分之九十九)加阶段分解表
- 场景切片表加最坏误报片段人工签字
- 校准图(期望校准误差或可靠性图)
- 影子对比有回滚记录
- 端到端任务成功率与代理指标对照
平均精度回答研究问题;产线问的是这阈值、这延迟、这雨夜切片今晚能不能开。把问题问对,指标才有用。
相关
也可以看看
johan's blog