返回博客列表

Supervision 换模型对照手册:16 家模型分别怎么接

同一个业务需求,换 YOLO、RF-DETR、SAM、Transformers、VLM 代码分别怎么写。附一览速查表,和换模型时最容易踩的四个坑

上一篇讲了 Supervision 是什么。这篇是配套的对照手册:同一件事,换不同厂商的模型,代码分别长什么样。

对应版本 supervision 0.30.1。选型的问题在 这些框架该选哪个 里单独讲。


先说清楚一件事:到底哪部分不变

教学文档里写”只改这一行”,严格讲不够准确,容易误导。真实情况是:

换模型时哪一段代码要改、哪一段不用改 代码分三段:装库加载模型跑推理这段每家写法都不同必须改,中间一行 from_XXX 转换只换方法名,下面的过滤、追踪、计数、标注、评估、导出等业务逻辑一个字都不用改。 1 装库 + 加载模型 + 跑推理 各家 API 天生不同,谁也统一不了 必须改 2 sv.Detections.from_XXX(...) 只换方法名 3 过滤 / 追踪 / 计数 / 标注 / 评估 / 导出 你的全部业务逻辑都在这里 一个字都不用改 ① + ② 通常 5~10 行,③ 往往几百行 —— 换模型只动那 5~10 行

价值不在”少写几行”,而在于:你的业务代码永远不知道底下用的是谁家的模型。

代码量上:① + ② 通常 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。

流程

用视觉大模型检测时 Supervision 负责哪一步 写提示词、调用大模型 API、拿回文本或 JSON 这三步都由你自己完成,Supervision 只负责最后一步:把那段文本解析成 Detections。 写提示词 你 调大模型 你 · API 拿回文本 你 · JSON from_vlm() Supervision 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()。


附一:一览速查表

#厂商 / 模型转换写法额外必传参数备注
1Ultralytics YOLOfrom_ultralytics(results)—推理要加 [0]
2RF-DETR无需转换—predict() 直接返回 Detections
3Roboflow Inferencefrom_inference(result)—推理要加 [0]
4Transformersfrom_transformers(...)id2label=用 PIL 读图
5SAMfrom_sam(sam_result=...)—无类别,只有 mask
6Detectron2from_detectron2(result)—需 config + 权重
7MMDetectionfrom_mmdetection(result)—需 config + 权重
8YOLOv5from_yolov5(result)—推理不加 [0]
9YOLO-NASfrom_yolo_nas(result)—结果要 list(...)[0]
10PaddleDetectionfrom_paddledet(result)—信创环境
11EasyOCRfrom_easyocr(results)—文字在 class_name
12Azure Visionfrom_azure_analyze_image(resp)—云 API,涉密勿用
13DeepSparsefrom_deepsparse(result)—CPU 加速
14NCNNfrom_ncnn(result)—端侧 / 手机
15TensorFlowfrom_tensorflow(...)resolution_wh=坐标是归一化的
16VLM 大模型from_vlm(sv.VLM.X, text, ...)resolution_wh= classes=解析文本,不做推理

附二:换模型时最容易踩的四个坑

#坑症状原因
1推理结果忘了取 [0]报类型错误 / 转换失败Ultralytics、Inference 返回的是列表(支持批量),YOLOv5 不是
2Transformers 漏传 id2label标签全变成数字 0 1 2它的原始输出里只有数字 ID,没有类别名
3换 SAM 后过滤代码报错class_id is NoneSAM 没有类别概念,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 真正的用法 —— 它让”换模型”从架构级改动降级成一个配置项。