supervision Legacy 评估 API 详解:ConfusionMatrix 与 MeanAveragePrecision 的原理、用法与迁移指南
本篇聚焦 supervision 文档中的 Legacy Metrics(遗留评估 API),即 src/supervision/metrics/detection.py 中实现的 ConfusionMatrix 与 MeanAveragePrecision 两个对象检测评估类。文章覆盖二者的完整属性、构建方式、贪心匹配与 COCO 101 点插值等底层实现细节,以及自 0.23.0 起引入的新 metrics 模块与遗留 API 的关系和迁移路径。读完后可独立完成:安装 metrics 依赖、用 from_detections / from_tensors / benchmark 三种入口计算混淆矩阵与 mAP,理解 TP/FP/FN 归属逻辑,并判断何时应改用新版指标模块。
Legacy Metrics 的定位与安装
自 supervision 0.23.0 起,项目引入了全新的 metrics 模块(src/supervision/metrics/init.py 导出的 MeanAveragePrecision、F1Score、Precision、Recall、MeanAverageRecall 等)。sv.ConfusionMatrix 和顶层 sv.MeanAveragePrecision(来自 supervision.metrics.detection)则属于遗留评估 API,文档明确说明其"will be deprecated in the future"(见 docs/detection/metrics.md)。
使用本页 API 前,需要安装 metrics 可选依赖:
pip install "supervision[metrics]"
从 pyproject.toml 可以看到,该 extra 目前只额外安装了 pandas>=2。这两个类通过 src/supervision/init.py 暴露在顶层命名空间,因此可直接以 sv.ConfusionMatrix、sv.MeanAveragePrecision 的方式引用。
需要注意两者的废弃状态并不相同(以当前仓库源码为准,当前开发版本为 0.31.0.dev0):
| 类 | 废弃标记(源码事实) |
|---|---|
sv.ConfusionMatrix |
未加 @deprecated_class 装饰器,但被文档归为 legacy API |
sv.MeanAveragePrecision |
有 @deprecated_class(deprecated_in="0.27.0", remove_in="0.31.0"),且 docstring 明确提示其结果与 pycocotools 不一致,推荐使用 supervision.metrics.mean_average_precision.MeanAveragePrecision |
ConfusionMatrix:按类统计 TP / FP / FN
ConfusionMatrix 是一个 dataclass,定义于 src/supervision/metrics/detection.py,用于对象检测任务的混淆矩阵统计。其核心属性如下:
| 属性 | 类型 | 说明 |
|---|---|---|
matrix |
np.ndarray[np.int32] |
形状为 (len(classes) + 1, len(classes) + 1) 的二维矩阵,最后多出的行列用于汇总 FP / FN |
classes |
list[str] |
模型类别名列表 |
conf_threshold |
float |
置信度阈值(0~1),低于该值的预测不计入矩阵 |
iou_threshold |
float |
IoU 阈值(0~1),低于该值的预测-真值对不会被匹配,预测记为 FP |
metric_target |
MetricTarget |
IoU 计算所用坐标类型:BOXES(默认)或 ORIENTED_BOUNDING_BOXES;MASKS 不受支持 |
MetricTarget 枚举定义在 src/supervision/metrics/core.py,取值 BOXES(xyxy 框)、MASKS(掩码)、ORIENTED_BOUNDING_BOXES(OBB 旋转框)。ConfusionMatrix 仅支持前两者之外的 BOXES 与 OBB 两种——传入 MetricTarget.MASKS 会抛出 ValueError(见 detection.py 中的 _assert_supported_target)。
三种构建方式
1. from_detections:从 sv.Detections 列表构建
import numpy as np
import supervision as sv
targets = [
sv.Detections(
xyxy=np.array([[0, 0, 10, 10], [50, 50, 60, 60]]),
class_id=np.array([0, 0]),
)
]
predictions = [
sv.Detections(
xyxy=np.array([[0, 0, 10, 10], [100, 100, 110, 110]]),
class_id=np.array([0, 0]),
confidence=np.array([0.9, 0.8]),
)
]
confusion_matrix = sv.ConfusionMatrix.from_detections(
predictions=predictions,
targets=targets,
classes=["person"],
conf_threshold=0.3, # 默认值 0.3
iou_threshold=0.5, # 默认值 0.5
)
print(confusion_matrix.matrix)
# array([[1, 1],
# [1, 0]], dtype=int32)
from_detections 内部先把每组 Detections 转换为张量再调用 from_tensors。转换规则由 detections_to_tensor 实现(src/supervision/metrics/detection.py):
MetricTarget.BOXES:预测张量行格式(x_min, y_min, x_max, y_max, class_id, confidence),即(M, 6);真值无 confidence,为(N, 5)。MetricTarget.ORIENTED_BOUNDING_BOXES:要求detections.data[ORIENTED_BOX_COORDINATES]中存有 float32 的 OBB 坐标,形状(N, 8)(扁平)或(N, 4, 2)(sv.Detections.from_ultralytics的存储形式),内部统一规整为(N, 8);对应张量行为(x1, y1, x2, y2, x3, y3, x4, y4, class_id [, confidence]),即预测(M, 10)、真值(N, 9)。class_id为None会报错;with_confidence=True但confidence为None也会报错。
2. from_tensors:直接从 numpy 张量列表构建
import numpy as np
import supervision as sv
targets = [
np.array([
[0.0, 0.0, 3.0, 3.0, 0],
[2.0, 2.0, 5.0, 5.0, 0],
[6.0, 1.0, 8.0, 3.0, 1],
])
]
predictions = [
np.array([
[0.0, 0.0, 3.0, 3.0, 0, 0.9],
[0.1, 0.1, 3.0, 3.0, 0, 0.9],
[6.0, 1.0, 8.0, 3.0, 1, 0.8],
])
]
confusion_matrix = sv.ConfusionMatrix.from_tensors(
predictions=predictions,
targets=targets,
classes=["person", "dog"],
)
print(confusion_matrix.matrix)
# array([[1, 0, 1],
# [0, 1, 0],
# [1, 0, 0]], dtype=int32)
_validate_input_tensors 会校验:预测与真值列表长度一致、元素必须是 numpy 数组、列数符合 metric_target 的期望(BOXES 为 6/5 列,OBB 为 10/9 列)。
3. benchmark:数据集 + 回调函数一步到位
import supervision as sv
dataset = sv.DetectionDataset.from_yolo(
images_directory_path=".../test/images",
annotations_directory_path=".../test/labels",
data_yaml_path=".../data.yaml",
)
def callback(image: np.ndarray) -> sv.Detections:
return model.predict(image[:, :, ::-1])
confusion_matrix = sv.ConfusionMatrix.benchmark(
dataset=dataset,
callback=callback,
conf_threshold=0.3,
iou_threshold=0.5,
save_directory_path="./results", # 可选
)
print(confusion_matrix.matrix)
benchmark 遍历 DetectionDataset(每轮产出 image_name, image, annotation),调用 callback 得到预测后汇总。可选参数 save_directory_path(关键参数,仅 benchmark 支持)会在该目录中为每张图写出一张 2x2 结果拼图,按原图文件名直接落盘:四个面板分别为 Ground Truth、True Positives、False Positives、False Negatives。从源码看(_save_detection_validation_visualization,src/supervision/metrics/detection.py),该拼图通过 _split_detections_by_outcome 复用与 evaluate_detection_batch 相同的匹配逻辑划分 TP/FP/FN,并用 BoxAnnotator / LabelAnnotator 按类别着色绘制;若目录中已存在同名文件会发出 UserWarning 后覆盖。完整的基准测试工作流可参考 docs/how_to/benchmark_a_model.md。
匹配算法:TP / FP / FN 如何归属
单张图的矩阵累加由静态方法 evaluate_detection_batch 完成,流程可从源码逐段印证:
- 形状校验:预测
(M, 6)(或 OBB 下(M, 10)),真值(N, 5)(或(N, 9))。 - 置信度过滤:
predictions[confidence >= conf_threshold]留下参与匹配的预测。 - 边界短路:无有效预测时,所有真值计入
matrix[gt_class, num_classes](FN 汇总列);真值为空时,所有有效预测计入matrix[num_classes, det_class](FP 汇总行)。 - IoU 矩阵:BOXES 用
box_iou_batch,OBB 用oriented_box_iou_batch(均来自 src/supervision/detection/utils/iou_and_nms.py)。 - 贪心匹配:取所有
iou > iou_threshold的候选对,用np.lexsort按"同类优先、IoU 降序"排序后逐一贪心分配,每个真值与每个预测最多匹配一次。 - 跨类空间匹配的特殊处理:两个框空间重叠但类别不同时,
matrix[gt_class, det_class] += 1——即该预测对目标类别是 FP(错检),对预测类别是 FN(漏检),同一笔错检同时体现在两个位置。 - 汇总:未匹配真值累加到 FN 列,未匹配预测累加到 FP 行。
矩阵语义因此是:matrix[i, j](i != j 且均在类索引范围内)= 真值为类 i 但被预测成类 j 的数量;对角线 = TP;最后一列 = 各类 FN;最后一行 = 各类 FP。
plot:热力图可视化
fig = confusion_matrix.plot(
save_path=None, # 给路径则保存为 250 dpi 透明背景 PNG
title="Corgi benchmark", # 可选标题
classes=None, # 自定义显示类别,None 则显示全部
normalize=False, # True 时按列归一化
fig_size=(12, 10), # 画布尺寸
)
实现细节(plot 方法):矩阵先转 float64;normalize=True 时按列求和归一化;小于 0.005 的单元格置为 NaN 以隐藏噪点;坐标轴刻度默认显示类名并追加 FN / FP 两个汇总刻度;格子数少于 30 个时会在每个单元格内标注数值,颜色随数值大小在黑/白之间切换。
MeanAveragePrecision(遗留版):mAP@50:95 的计算
sv.MeanAveragePrecision(frozen dataclass,定义于 src/supervision/metrics/detection.py)的四个属性为:
| 属性 | 含义 |
|---|---|
map50_95 |
IoU 阈值 0.50~0.95(步长 0.05)十个档位上的 mAP 均值 |
map50 |
仅 IoU = 0.50 时的 mAP |
map75 |
仅 IoU = 0.75 时的 mAP |
per_class_ap50_95 |
每个类在 10 个 IoU 档位上的 AP 数组,形状 (num_classes, 10) |
再次强调(源码 docstring 中的废弃提示):该实现自 0.27.0 起被标记 deprecated,计划于 0.31.0 移除;官方理由是"deprecated implementation provides results that are inconsistent with pycocotools",建议改用新版 supervision.metrics.mean_average_precision.MeanAveragePrecision(该新实现与 pycocotools 结果一致)。如果你的目标是与 COCO 评测对齐,请优先走新模块;下述内容用于理解遗留实现本身及已有代码。
计算入口
import supervision as sv
# 方式一:从 Detections 列表
mAP = sv.MeanAveragePrecision.from_detections(
predictions=predictions_list, # list[sv.Detections]
targets=targets_list, # list[sv.Detections]
)
# 方式二:从张量列表(每图 (M,6) / (N,5))
mAP = sv.MeanAveragePrecision.from_tensors(
predictions=prediction_tensors,
targets=target_tensors,
)
# 方式三:数据集 + 回调
mAP = sv.MeanAveragePrecision.benchmark(
dataset=dataset,
callback=callback,
)
print(mAP.map50_95, mAP.map50, mAP.map75)
一个最小示例:单图单框完全重合且类别一致时,map50 为 1.0;若真值为空的背景图上存在预测,这些预测全部计为 FP,会压低 AP(背景图语义在 from_tensors 的 docstring 中有明确说明)。
实现原理:IoU 档位、贪心匹配与 101 点插值
from_tensors 的核心计算链可以从源码拆解为三步:
- 多档 IoU 匹配(
_match_detection_batch):IoU 档位为np.linspace(0.5, 0.95, 10),即[0.50, 0.55, ..., 0.95]共 10 档。对每一档,用box_iou_batch算整图 IoU 矩阵,要求iou >= 档位值且类别一致,再经_greedy_match(来自 src/supervision/metrics/utils/matching.py)保证每个真值与预测各只匹配一次。最终得到每图每档的 TP 布尔矩阵。 - 按置信度排序累计 P/R(
_average_precisions_per_class):所有图的匹配结果、预测置信度与类别被拼接后,按预测置信度全局降序排列;对每个类分别累加true_positives/false_positives,得到 recall 与 precision 曲线。注意此处只统计至少在一个真值图中出现的类——从未出现在 GT 中的类会被跳过。 - COCO 101 点插值(
compute_average_precision):将 precision 做从尾部起的最大值累积(单调包络),再在 recall = 0, 0.01, ..., 1.0 的 101 个取整点采样求均值,即标准 COCO AP 定义。
边界情况同样有源码背书:若所有图都没有真值,函数返回 0.0 而非 NaN;map50 / map75 / map50_95 分别取平均精度数组的第 1 列、第 6 列(0.75 档)与全体均值。
与新版指标的差异提示:新版 supervision.metrics 中的指标采用 update(...).compute() 的两段式 API(基类 Metric 定义于 src/supervision/metrics/core.py),支持 MetricTarget.BOXES / MASKS / ORIENTED_BOUNDING_BOXES 与 AveragingMethod.MACRO / MICRO / WEIGHTED 三种平均方式,并额外提供按对象尺寸(small / medium / large)的细分结果;而遗留版 MeanAveragePrecision 仅支持 xyxy 框、固定按类宏平均。
从 Legacy 迁移到新指标模块的对照
结合 src/supervision/metrics/init.py 的导出与 docs/metrics/ 下的文档,迁移对照关系如下:
| Legacy(本页) | 新模块推荐替代 | 关键差异 |
|---|---|---|
sv.MeanAveragePrecision(supervision.metrics.detection) |
supervision.metrics.mean_average_precision.MeanAveragePrecision |
新版结果与 pycocotools 一致,支持 MASKS / OBB、尺寸细分 |
sv.ConfusionMatrix.from_detections(...) |
新模块未提供同名类,可保留使用 | 目前 ConfusionMatrix 源码中无废弃装饰器,但仍属 legacy 页面范畴,建议关注后续版本 |
一次性 from_tensors |
metric.update(predictions, targets).compute() |
新版支持流式累积,便于大图集分批评估 |
新模块各指标的详细说明可查阅仓库内文档:mAP、F1 Score、Precision、Recall、MAR、常用数值。
小结与适用前提
- 本仓库当前开发版本为
0.31.0.dev0(见 pyproject.toml),sv.MeanAveragePrecision携带"0.31.0 移除"的废弃标记,新增代码不应再依赖它;sv.ConfusionMatrix则暂无源码级废弃标记,但仍位于 legacy 文档页,使用时应留意版本演进。 - 使用任一 API 前先执行
pip install "supervision[metrics]";ConfusionMatrix要求预测携带confidence(benchmark/from_detections路径)、两者都要求class_id非空。 conf_threshold与iou_threshold默认值分别为0.3与0.5,直接决定 TP 判定口径,跨配置比较指标时必须保持一致。- 若需要逐图定位错检/漏检原因,
sv.ConfusionMatrix.benchmark(..., save_directory_path=...)会产出 GT/TP/FP/FN 四宫格拼图,是与数值指标配合的最快排障手段。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0626
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00