Supervision 换模型对照手册:16 家模型分别怎么接
同一个业务需求,换 YOLO、RF-DETR、SAM、Transformers、VLM 代码分别怎么写。附一览速查表,和换模型时最容易踩的四个坑
上一篇讲了 Supervision 是什么。这篇是配套的对照手册:同一件事,换不同厂商的模型,代码分别长什么样。
对应版本 supervision 0.30.1。选型的问题在 这些框架该选哪个 里单独讲。
先说清楚一件事:到底哪部分不变
教学文档里写”只改这一行”,严格讲不够准确,容易误导。真实情况是:
价值不在”少写几行”,而在于:你的业务代码永远不知道底下用的是谁家的模型。
代码量上:① + ② 通常 5~10 行,③ 往往是几百行。换模型只动那 5~10 行。
③ 段:所有例子共用的”不变部分”
下面每个厂商的例子,结尾都接这一段,一字不改。为节省篇幅后面不再重复。
# ===== 以下代码与模型无关,换任何厂商都不用改 =====
# 过滤
detections = detections[detections.confidence > 0.5]
detections = detections[detections.class_id == 0]
# 标注
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated = box_annotator.annotate(scene=image.copy(), detections=detections)
annotated = label_annotator.annotate(scene=annotated, detections=detections)
cv2.imwrite("output.jpg", annotated)
# 视频里还会接:追踪、越线计数、区域统计……同样都不用改
# tracker.update_with_detections(detections)
# line_zone.trigger(detections)
一、Ultralytics YOLO ★ 推荐入门
pip install ultralytics supervision
import cv2
import supervision as sv
from ultralytics import YOLO
image = cv2.imread("input.jpg")
model = YOLO("yolov8s.pt") # ①
results = model(image)[0] # ①
detections = sv.Detections.from_ultralytics(results) # ②
# ↓ 接 ③ 段
| 项 | 说明 |
|---|---|
| 首次运行 | 自动下载权重文件(几十 MB) |
| 模型选择 | yolov8n/s/m/l/x.pt,n 最快 x 最准;也可用 yolo11n.pt |
| 分割模型 | 换成 yolov8s-seg.pt,detections.mask 就有值了 |
| 注意 | model(image) 返回列表,必须加 [0] 取第一张图的结果 |
| 许可证 | ⚠️ AGPL-3.0,商用需开源或购买授权 |
二、RF-DETR ★ 推荐商用
唯一一家不需要 from_* —— 它直接返回 sv.Detections。
pip install rfdetr supervision
import supervision as sv
from rfdetr import RFDETRMedium
from rfdetr.assets.coco_classes import COCO_CLASSES
model = RFDETRMedium() # ①
detections = model.predict("input.jpg", threshold=0.5) # ① + ② 合二为一
# ↓ 直接接 ③ 段
| 项 | 说明 |
|---|---|
| 型号 | RFDETRNano / Small / Medium / Large / XLarge / 2XLarge |
| 分割版 | RFDETRSegMedium,配 sv.MaskAnnotator() |
| 取类别名 | 预训练模型用 COCO_CLASSES[class_id];自己微调的用 detections.data["class_name"] |
| 取原图 | detections.metadata["source_image"](它支持直接传 URL) |
| 许可证 | ✅ Apache 2.0,商用无限制 |
三、Roboflow Inference
Roboflow 的推理服务,可以跑自己在平台上训练的模型。
pip install inference supervision
import cv2
import supervision as sv
from inference import get_model
image = cv2.imread("input.jpg")
model = get_model(model_id="yolov8s-640") # ①
result = model.infer(image)[0] # ①
detections = sv.Detections.from_inference(result) # ②
| 项 | 说明 |
|---|---|
model_id | 换成自己项目的 ID(如 "my-project/3")即可跑私有模型 |
| 适用 | 已经在 Roboflow 平台标注/训练的团队 |
| 额外 | 0.30 起也能解析 SAM3 的检测与视频分割输出 |
四、HuggingFace Transformers(DETR 等)
注意:这家必须多传一个 id2label 参数,否则没有类别名。
pip install transformers torch pillow supervision
import torch
import supervision as sv
from PIL import Image
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50") # ①
model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
image = Image.open("input.jpg")
inputs = processor(images=image, return_tensors="pt") # ①
with torch.no_grad():
outputs = model(**inputs) # ①
width, height = image.size
target_size = torch.tensor([[height, width]])
results = processor.post_process_object_detection( # ①
outputs=outputs, target_sizes=target_size)[0]
detections = sv.Detections.from_transformers( # ②
transformers_results=results,
id2label=model.config.id2label) # ← 例外:必须传这个
| 项 | 说明 |
|---|---|
| 图像库 | 用 PIL(Image.open),不是 cv2 |
| 例外点 | 必须传 id2label=model.config.id2label |
target_sizes | 顺序是 (高, 宽),写反了框会全部错位 |
| 适用 | 想用 HuggingFace 上任意开源检测模型 |
五、SAM(分割一切)
注意:SAM 没有类别概念,class_id 为空,只有 mask。
pip install segment-anything supervision
import cv2
import supervision as sv
from segment_anything import sam_model_registry, SamAutomaticMaskGenerator
MODEL_TYPE = "vit_h"
CHECKPOINT_PATH = "sam_vit_h_4b8939.pth"
DEVICE = "cuda"
image = cv2.imread("input.jpg")
sam = sam_model_registry[MODEL_TYPE](checkpoint=CHECKPOINT_PATH).to(device=DEVICE) # ①
mask_generator = SamAutomaticMaskGenerator(sam)
sam_result = mask_generator.generate(image) # ①
detections = sv.Detections.from_sam(sam_result=sam_result) # ②
# ③ 段要微调:SAM 只有掩码,用 MaskAnnotator,且没有类别可过滤
annotated = sv.MaskAnnotator().annotate(scene=image.copy(), detections=detections)
| 项 | 说明 |
|---|---|
| ⚠️ 例外 | 没有 class_id / confidence 的类别语义,detections.class_id 为 None |
| 权重 | 需手动下载 .pth 文件(vit_h 约 2.4 GB) |
| 性能 | 慢且吃显存,不适合实时 |
| 常见搭配 | YOLO 定位 → SAM 精修轮廓 |
| SAM3 | 新版走 from_sam3() 或 Roboflow Inference 的 from_inference() |
六、Detectron2(Meta)
import cv2
import supervision as sv
from detectron2.engine import DefaultPredictor
from detectron2.config import get_cfg
image = cv2.imread("input.jpg")
cfg = get_cfg() # ①
cfg.merge_from_file("<CONFIG_PATH>")
cfg.MODEL.WEIGHTS = "<WEIGHTS_PATH>"
predictor = DefaultPredictor(cfg)
result = predictor(image) # ①
detections = sv.Detections.from_detectron2(result) # ②
| 项 | 说明 |
|---|---|
| 安装 | 需从源码编译,Windows 上较麻烦 |
| 配置 | 必须准备 config 文件 + 权重文件两样 |
| 适用 | 需要改模型结构的研究场景 |
七、MMDetection(上海 AI Lab)
import cv2
import supervision as sv
from mmdet.apis import init_detector, inference_detector
image = cv2.imread("input.jpg")
model = init_detector("<CONFIG_PATH>", "<WEIGHTS_PATH>", device="cuda:0") # ①
result = inference_detector(model, image) # ①
detections = sv.Detections.from_mmdetection(result) # ②
| 项 | 说明 |
|---|---|
| 安装 | 依赖 mmcv、mmengine,版本必须严格匹配,最容易装崩的一家 |
| 配置 | 同样需要 config + 权重 |
| 优势 | 模型库最全(100+ 种算法) |
八、YOLOv5(旧版,仍有存量项目)
import cv2
import torch
import supervision as sv
image = cv2.imread("input.jpg")
model = torch.hub.load('ultralytics/yolov5', 'yolov5s') # ①
result = model(image) # ① 注意:这里不加 [0]
detections = sv.Detections.from_yolov5(result) # ②
新项目不要用 v5,直接上 v8/v11。这段只为接手老项目时用。
九、YOLO-NAS(Deci / super-gradients)
import cv2
import supervision as sv
from super_gradients.training import models
image = cv2.imread("input.jpg")
model = models.get('yolo_nas_l', pretrained_weights="coco") # ①
result = list(model.predict(image, conf=0.35))[0] # ①
detections = sv.Detections.from_yolo_nas(result) # ②
十、PaddleDetection(百度飞桨)
import supervision as sv
import paddle
from ppdet.engine import Trainer
from ppdet.core.workspace import load_config
cfg = load_config("<CONFIG_PATH>") # ①
trainer = Trainer(cfg, mode='test')
trainer.load_weights("<WEIGHTS_PATH>")
paddledet_result = trainer.predict(["input.jpg"])[0] # ①
detections = sv.Detections.from_paddledet(paddledet_result) # ②
国产化 / 信创环境要求用飞桨时选它。
十一、EasyOCR(文字识别)
OCR 的框也能塞进同一套结构 —— 文字内容存在 class_name 字段里。
pip install easyocr supervision
import supervision as sv
import easyocr
reader = easyocr.Reader(['ch_sim', 'en']) # ① 中文简体 + 英文
results = reader.readtext("input.jpg") # ①
detections = sv.Detections.from_easyocr(results) # ②
detected_text = detections["class_name"] # ← 识别出的文字在这里
print(detected_text)
| 项 | 说明 |
|---|---|
| 中文 | Reader(['ch_sim', 'en']),首次运行自动下载中文模型 |
| 取文字 | detections["class_name"] 或 detections.data["class_name"] |
| 妙用 | OCR 结果也能用 PolygonZone 过滤 —— 比如”只要发票右上角区域的文字” |
十二、Azure AI Vision(云 API)
import requests
import supervision as sv
image = open("input.jpg", "rb").read()
endpoint = "https://<你的资源名>.cognitiveservices.azure.com/..."
subscription_key = "<你的KEY>"
headers = {
"Content-Type": "application/octet-stream",
"Ocp-Apim-Subscription-Key": subscription_key,
}
response = requests.post(endpoint, headers=headers, data=image).json() # ①
detections = sv.Detections.from_azure_analyze_image(response) # ②
云 API 按次收费,且图片要上传到微软服务器 —— 涉密/隐私场景禁用。
十三、DeepSparse(CPU 加速)
没有 GPU、只能用 CPU 跑的场景,Neural Magic 的稀疏化推理能快好几倍。
import supervision as sv
from deepsparse import Pipeline
yolo_pipeline = Pipeline.create( # ①
task="yolo",
model_path="zoo:cv/detection/yolov5-l/pytorch/ultralytics/coco/pruned80_quant-none",
)
result = yolo_pipeline("input.jpg") # ①
detections = sv.Detections.from_deepsparse(result) # ②
十四、NCNN(手机 / 嵌入式)
腾讯出品,专为手机、树莓派等端侧设备优化。
import cv2
from ncnn.model_zoo import get_model
import supervision as sv
image = cv2.imread("input.jpg")
model = get_model( # ①
"yolov8s",
target_size=640,
prob_threshold=0.5,
nms_threshold=0.45,
num_threads=4,
use_gpu=True,
)
result = model(image) # ①
detections = sv.Detections.from_ncnn(result) # ②
十五、TensorFlow Hub
注意:这家必须多传 resolution_wh。
import cv2
import numpy as np
import tensorflow_hub as hub
import supervision as sv
module_handle = "https://tfhub.dev/tensorflow/centernet/hourglass_512x512_kpts/1"
model = hub.load(module_handle) # ①
img = np.array(cv2.imread("input.jpg"))
result = model(img) # ①
h, w = img.shape[:2]
detections = sv.Detections.from_tensorflow( # ②
tensorflow_results=result, resolution_wh=(w, h)) # ← 例外:必须传分辨率
TF 模型输出的是 0~1 归一化坐标,所以要告诉它原图尺寸才能还原成像素坐标。
十六、视觉大模型 VLM(用自然语言检测)
这一类和前面本质不同:Supervision 不负责调用大模型, 它只负责把大模型吐出的那段文字解析成 Detections。
流程
支持的 VLM
sv.VLM.PALIGEMMA、QWEN_2_5_VL、QWEN_3_VL、DEEPSEEK_VL_2、
FLORENCE_2、MOONDREAM、GOOGLE_GEMINI_2_0、GOOGLE_GEMINI_2_5
示例:Gemini
import supervision as sv
# ① 你自己调 Gemini API,拿回这样一段文本(此处直接写死演示)
gemini_response_text = """```json
[
{"box_2d": [543, 40, 728, 200], "label": "cat", "id": 1},
{"box_2d": [653, 352, 820, 522], "label": "dog", "id": 2}
]
```"""
# ② 解析
detections = sv.Detections.from_vlm(
sv.VLM.GOOGLE_GEMINI_2_0,
gemini_response_text,
resolution_wh=(1000, 1000), # 原图宽高,必传
classes=['cat', 'dog'], # 类别表,必传
)
# ↓ 之后接 ③ 段,和 YOLO 完全一样
示例:Qwen2.5-VL(通义千问)
qwen_result = """```json
[
{"bbox_2d": [139, 768, 315, 954], "label": "cat"},
{"bbox_2d": [366, 679, 536, 849], "label": "dog"}
]
```"""
detections = sv.Detections.from_vlm(
sv.VLM.QWEN_2_5_VL,
qwen_result,
input_wh=(1000, 1000), # Qwen 特有:模型输入尺寸
resolution_wh=(1000, 1000), # 原图尺寸
classes=['cat', 'dog'],
)
示例:Moondream(小型本地 VLM)
moondream_result = {
'objects': [
{'x_min': 0.570, 'y_min': 0.200, 'x_max': 0.704, 'y_max': 0.301},
{'x_min': 0.621, 'y_min': 0.330, 'x_max': 0.841, 'y_max': 0.496},
]
}
detections = sv.Detections.from_vlm(
sv.VLM.MOONDREAM,
moondream_result,
resolution_wh=(1000, 1000),
)
from_lmm()是from_vlm()的旧名字,两者等价。新代码统一用from_vlm()。
附一:一览速查表
| # | 厂商 / 模型 | 转换写法 | 额外必传参数 | 备注 |
|---|---|---|---|---|
| 1 | Ultralytics YOLO | from_ultralytics(results) | — | 推理要加 [0] |
| 2 | RF-DETR | 无需转换 | — | predict() 直接返回 Detections |
| 3 | Roboflow Inference | from_inference(result) | — | 推理要加 [0] |
| 4 | Transformers | from_transformers(...) | id2label= | 用 PIL 读图 |
| 5 | SAM | from_sam(sam_result=...) | — | 无类别,只有 mask |
| 6 | Detectron2 | from_detectron2(result) | — | 需 config + 权重 |
| 7 | MMDetection | from_mmdetection(result) | — | 需 config + 权重 |
| 8 | YOLOv5 | from_yolov5(result) | — | 推理不加 [0] |
| 9 | YOLO-NAS | from_yolo_nas(result) | — | 结果要 list(...)[0] |
| 10 | PaddleDetection | from_paddledet(result) | — | 信创环境 |
| 11 | EasyOCR | from_easyocr(results) | — | 文字在 class_name |
| 12 | Azure Vision | from_azure_analyze_image(resp) | — | 云 API,涉密勿用 |
| 13 | DeepSparse | from_deepsparse(result) | — | CPU 加速 |
| 14 | NCNN | from_ncnn(result) | — | 端侧 / 手机 |
| 15 | TensorFlow | from_tensorflow(...) | resolution_wh= | 坐标是归一化的 |
| 16 | VLM 大模型 | from_vlm(sv.VLM.X, text, ...) | resolution_wh= classes= | 解析文本,不做推理 |
附二:换模型时最容易踩的四个坑
| # | 坑 | 症状 | 原因 |
|---|---|---|---|
| 1 | 推理结果忘了取 [0] | 报类型错误 / 转换失败 | Ultralytics、Inference 返回的是列表(支持批量),YOLOv5 不是 |
| 2 | Transformers 漏传 id2label | 标签全变成数字 0 1 2 | 它的原始输出里只有数字 ID,没有类别名 |
| 3 | 换 SAM 后过滤代码报错 | class_id is None | SAM 没有类别概念,detections[detections.class_id == 0] 会崩 |
| 4 | 框全部错位 | 框跑到图外或缩在角落 | 分辨率参数写反了 —— Transformers 是 (高,宽),from_tensorflow 是 (宽,高) |
写一个”可切换模型”的工程做法
真要在项目里做到随时切换,把 ① + ② 封装成一个函数就行:
def detect(image, backend="yolo"):
"""统一入口:返回 sv.Detections,上层业务不关心用的是谁"""
if backend == "yolo":
return sv.Detections.from_ultralytics(_yolo(image)[0])
elif backend == "rfdetr":
return _rfdetr.predict(image, threshold=0.5)
elif backend == "detr":
...
raise ValueError(backend)
# 业务代码永远只写这一句,改配置就换了模型
detections = detect(image, backend=CONFIG["backend"])
这就是 Supervision 真正的用法 —— 它让”换模型”从架构级改动降级成一个配置项。