做CV项目的人应该都有同感:标注数据这件事,比训练模型还磨人。尤其是接触分割、检测这类任务的时候,几千张图起步,一张张框框点点,标注完再质检补漏,小一周就搭进去了。所以最近一年我一直在研究自动标注这条线,试过不少组合之后,目前最常用的一套是X-AnyLabeling + autodistill + Grounded-SAM的流程,实测下来能把标注初稿的人工工作量压到五分之一左右,后期只需要做检查和微调。
这套组合解决的核心问题非常明确:用预训练大模型先把图片里能识别的目标全部标出来,人只负责检查、修正、补漏,而不是从零开始画框。X-AnyLabeling 负责可视化标注和交互式编辑,autodistill 负责把零样本模型的输出转成标准标注格式并组织成可训练的数据集,Grounded-SAM 提供开放词汇的检测与分割能力。三者分工不同但能无缝串联,下一篇我会逐层拆解。
这篇内容适合三类读者:一是刚入门 CV 标注、想找替代 LabelImg 方案的标注负责人;二是需要快速清洗私有数据集、生成初稿标注的算法工程师;三是对自动标注感兴趣但不知道从哪里下手的个人开发者。我会按照“方案选型 — 环境部署 — 流水线搭建 — 联合实战 — 问题排查”的顺序来讲,每一步都说明为什么这么做,以及我实际踩过的坑。
1. 方案选型:为什么把这三个工具拼在一起
1.1 三个工具的定位差异
先澄清一个很多人容易混的点:X-AnyLabeling、autodistill、Grounded-SAM 不是三个并列的竞品,而是处在不同层级的三类工具,组合起来才构成完整的自动标注链路。
Grounded-SAM 是底层模型能力。它是 Grounding DINO 和 SAM 的组合体:Grounding DINO 负责“看图猜词”,你给它一句“a person”,它能在图里找出所有符合描述的人并给出检测框;SAM 是 Meta 的 Segment Anything,负责在检测框内生成精细的像素级分割掩码。合在一起的效果就是,输入一段文本提示,输出干净的检测框和分割 mask。
autodistill 是流程编排层。它本身不是一个标注软件,更像是一个自动化流水线框架,由 Roboflow 团队开源。核心概念是一句话:用基础模型(base model)自动标注未训练的数据,然后把这些标注拿去训练一个轻量的目标模型(target model)。autodistill 负责把 Grounded-SAM 这类大模型“接到”数据上,批量推理,并把推理结果统一成 YOLO、COCO 等训练格式。
X-AnyLabeling 是人工交互层。它是 AnyLabeling 的升级版,一个带图形界面的标注工具,底层支持加载多种 AI 模型辅助标注。它的定位是让人在自动标注结果上做最终的检查和修正——AI 标完了,人用这个工具快速浏览、微调、删除误检、补漏标。相当于产出标注初稿后的人工质检台。
这三个工具单独拿出来都有人用,但真正高效的用法是串起来:Grounded-SAM 提供模型能力,autodistill 负责自动化批量推理和格式转换,X-AnyLabeling 负责最终的人工审核修正。少了任何一环,要么标得慢,要么标完没法直接用。
1.2 全流程自动标注的链路设计
我在实际项目里跑通的标准链路是这样设计的:
- 准备一批未标注的图片,放在一个文件夹里,同时写一份类别清单,比如“person”“car”“dog”。
- 用 autodistill 调用 Grounded-SAM 作为基础模型,对整个文件夹批量标注,生成检测框和分割 mask,输出为训练格式(比如 YOLO 格式的 txt 和图片一一对应)。
- 把标注结果用 X-AnyLabeling 打开,人工过一遍。Grounded-SAM 的准确率一般能在七八成以上,但会有漏检、误检、框不准的问题,人工只需要处理这些边角情况。
- 修正后的数据集拿去训练正式的检测或分割模型(比如 YOLOv8),训练好的模型如果效果达标,还可以反过来继续参与下一批数据的预标注,形成飞轮。
这个设计的关键在于:自动标注不是没有人,而是让人从“画框”变成“审框”。画一千个框要几个小时,但审一千个已经画好的框只需要几十分钟。工人的时间成本降下来,标注一致性和质量反而更容易控制,因为人的注意力集中在了异常样本上,而不是机械重复操作上。
为什么用 Grounded-SAM 而不是直接用某个闭源标注平台的 API?两个原因:一是私有数据不出本地的合规考虑,二是批量数据的成本。自有 GPU 跑 Grounded-SAM 虽然要花点时间,但数据量上来之后,单位成本远比按张数计费的方式低,而且模型版本可控,想换提示词就换提示词。
2. X-AnyLabeling 环境部署与基础操作
2.1 PyCharm 运行源码环境部署
先讲环境部署,因为在后面的联合实战里,X-AnyLabeling 是最后一个人工审核环节,装不好后面全是坑。
X-AnyLabeling 官方提供了打包好的 release 版本,直接下安装包就能用,但对经常要改代码、调试模型的人来说,还是建议从源码跑。我用的是 PyCharm + conda 的组合,整个部署流程并不复杂,但有几个细节需要注意。
第一步,克隆源码并创建虚拟环境。建议用 Python 3.8 或者 3.9,太新的 Python 版本容易踩 PyQt5 和部分算子库的兼容性坑:
git clone https://github.com/CVHub520/X-AnyLabeling.git cd X-AnyLabeling conda create -n anylabeling python=3.9 -y conda activate anylabeling第二步,安装依赖。项目根目录下一般有requirements.txt,直接装基础依赖:
pip install -r requirements.txt但这里有个坑:requirements.txt里默认装的 PyTorch 是 CPU 版本或通用版本。如果你想用 GPU 跑内置的 SAM 模型做分割辅助,一定要先装 CUDA 版的 PyTorch,再装其他依赖,否则模型推理慢到怀疑人生。我一般是这样装:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118第三步,在 PyCharm 里配置解释器,选中刚才创建的 conda 环境,然后把项目根目录下main.py设为启动脚本。直接右键运行main.py就行。
首次启动会下载一些模型权重,比如 SAM 的 checkpoint。如果网络状况不好,建议提前把权重文件准备好放到models目录下。这里分享一个我实测过的经验:与其让程序自动下载,不如先把需要的模型权重清单列出来,手动下载好后放进对应目录,这样能省掉不少部署时间,后面跑大模型辅助标注时也不至于卡在“加载权重”这一步。
部署完成后,界面里能看到左侧是标签列表,中间是画面,顶部和右侧是工具栏。如果界面能打开,说明源码部署就成功了。
2.2 界面操作与快捷键实战
X-AnyLabeling 的界面风格和 LabelImg 类似,但功能强很多。它支持检测框、多边形、掩码、关键点等多种标注类型,这对不同类型的任务很重要——比如做姿态估计,你需要关键点标注;做实例分割,你需要多边形或掩码。
我用这套流程时主要用到它的两个能力:一是打开 autodistill 生成的标注结果进行微调,二是直接用内置的 AI 模型对难例做补充标注。这两个场景下,快捷键能明显提升效率。
几个我每天都会用到的快捷键操作:
| 操作 | 快捷键 | 说明 |
|---|---|---|
| 保存当前标注 | Ctrl + S | 常用操作,建议养成随时保存的习惯 |
| 撤销上一步 | Ctrl + Z | AI 标错了框,一键撤销 |
| 删除选中的标注 | Delete | 删除误检框 |
| 缩放画布 | Ctrl + 滚轮 | 放大看小目标,检查边缘 |
| 拖动画布 | 按住空格 + 左键拖动 | 查看大图其他区域 |
| 复制上一个标签 | Ctrl + C / Ctrl + V | 连续标注同类型目标时很方便 |
关于快捷键,我的建议是不要贪多。标注团队协作时,真正高频的就是保存、撤销、删除、缩放这四五个,先把这些练熟,效率就能上去。X-AnyLabeling 的快捷键可以在菜单里查看,也可以自己配置,具体以你安装的版本为准。
还有一个细节:X-AnyLabeling 支持标签列表里给不同类别配颜色,建议在开始标注前就把类别颜色配好,比如“person”配红色、“car”配蓝色。这样审核时一眼扫过去就能看出类别分配是否合理,颜色一致的同类目标如果在视觉上明显不对,大概率就是 AI 标错了。
2.3 内置 AI 模型的辅助标注配置
X-AnyLabeling 另一个核心卖点是内置了一批 AI 模型。在界面右上角可以看到模型列表,比如 SAM、YOLOv8、RT-DETR 等。选择模型后,可以用交互方式辅助标注——比如用 SAM 的时候,你只需要在目标上点一下,模型就会自动生成分割掩码;用 YOLOv8 的时候,点一下“运行”,模型就会对所有图片做一次预标注。
我平时的工作流里,X-AnyLabeling 的人工审核环节会接一个 YOLOv8 模型(用之前的标注数据训练好的),用来在新一批图片上做全自动预标注,然后我再基于这个预标注结果去微调。注意,这里用的模型是自己训练的领域模型,不是通用模型,所以在特定场景下准确率会明显好于 Grounded-SAM 这种零样本模型。
这点很重要:自动标注不是只能靠大模型。当你积累了第一批人工标注数据后,训练一个小模型做预标注,往往比继续调大模型提示词更高效,速度更快,成本更低。这就是自动标注飞轮的第二圈。
3. autodistill 自动标注工作流搭建
3.1 核心原理解读
autodistill 的设计思路非常直白:你定义一个本体(ontology),把类别名称和对应的提示词写清楚;指定一个基础模型(base model)来做自动标注;指定一个目标模型(target model)来消费这些标注数据并训练出最终的小模型。
它把整个流程抽象成了统一的 API。无论你用的是 Grounded-SAM 还是 DETIC 还是 YOLO-World,在 autodistill 看来都是“基础模型对象”,它们都有一个label()方法,输入是图片文件夹,输出是标准标注数据集;无论你最终想训练 YOLOv8 还是 DETR,也都是“目标模型对象”,它们都有一个train()方法。
这种抽象的价值在于:方案切换成本极低。今天我可以用 Grounded-SAM 做标注,明天如果发现 DETIC 的效果更好,只需要改一行代码换掉基础模型的实例化方式,后面所有流程不用动。
autodistill 的名字也起得很形象——它做的是“知识蒸馏”的概念延伸:大模型具备很强的开放世界感知能力,但它太重了,不适合部署到实际业务中。自动标注就是把大模型的能力“蒸馏”到小模型的训练数据中,让小模型用很小的体积学会大模型在特定场景下的识别能力。
3.2 实操:搭建基础模型 + 目标模型的标注流水线
我以“从一批街景图中自动标注人和车,然后训练 YOLOv8”为例,完整跑一遍 autodistill 的关键代码。
先装依赖。autodistill 本身是框架,每个基础模型和目标模型都有独立的安装包:
pip install autodistill pip install autodistill-grounded-sam pip install autodistill-yolov8接着定义本体(ontology)。注意这里每个类别可以配置一个或多个提示词,提示词的质量直接决定标注质量:
from autodistill.detection import Ontology, OntologyObject ontology = Ontology( [ OntologyObject(name="person", prompt="a person"), OntologyObject(name="car", prompt="a car"), OntologyObject(name="traffic light", prompt="a traffic light"), ] )定义本体之后,实例化基础模型和目标模型:
from autodistill_grounded_sam import GroundedSAM from autodistill_yolov8 import YOLOv8 base_model = GroundedSAM(ontology=ontology) target_model = YOLOv8("yolov8n.pt")然后这行代码是核心,它会遍历input_folder里的所有图片,用 Grounded-SAM 自动标注,并把结果输出到output_folder:
dataset = base_model.label( input_folder="images/unannotated", output_folder="images/annotated" )运行完你会发现images/annotated目录下生成了对应的 txt 或 json 标注文件,同时还自动生成了数据集配置文件data.yaml。
最后训练目标模型:
target_model.train("images/annotated/data.yaml", epochs=50)这里面有几个我反复调过的参数细节:
第一,提示词越具体越好。“a car” 和 “a sedan used in urban street” 的效果完全不同。Grounded-SAM 用的是 Grounding DINO 的文本编码器,它会把提示词和图像特征做匹配。提示词太泛,容易把广告牌上的汽车图案、玩具车都框进去;提示词带上了场景限制,误检率会明显下降。
第二,label()方法支持批量处理但占用显存较大。默认情况下它会按批次推理,如果显存不够,报错显示 OOM(Out of Memory),可以适当降低 batch size,或者把图片预处理成统一尺寸。
第三,输出格式的兼容问题。autodistill 默认输出的标注格式是按你的目标模型走的,比如目标模型是检测模型,输出就是检测框的 YOLO 格式;目标模型如果是分割模型,输出则是分割掩码。所以在实际项目中,我一般先想清楚最终要训练什么模型,再决定 autodistill 的配置,不要先标注完了才想起来“我要的是分割不是检测”。
3.3 数据质检接口的思路
autodistill 本身不带可视化质检界面,它的输出就是一堆文件和标签,让人很难直观地判断标注质量。所以我有一个习惯:在跑完base_model.label()之后,马上用 OpenCV 或 X-AnyLabeling 抽查一批图,把检测框画在原图上,快速扫一遍。
写一个简单的抽查脚本非常实用:
import cv2 import os image_dir = "images/annotated" for img_name in os.listdir(image_dir): if not img_name.endswith(".jpg"): continue img = cv2.imread(os.path.join(image_dir, img_name)) txt_path = os.path.join(image_dir, img_name.replace(".jpg", ".txt")) with open(txt_path) as f: for line in f: cls_id, x_center, y_center, w, h = map(float, line.split()[:5]) img_h, img_w = img.shape[:2] x1 = int((x_center - w / 2) * img_w) y1 = int((y_center - h / 2) * img_h) x2 = int((x_center + w / 2) * img_w) y2 = int((y_center + h / 2) * img_h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imshow("check", img) if cv2.waitKey(0) & 0xFF == ord("q"): break这个脚本虽然简陋,但能把标注质量问题从“抽象的报告”变成“可见的画面”。我通常会用它在 autodistill 跑完后快速抽查三五十张图,确定 Grounded-SAM 在本批数据上的表现是否符合预期,决定是调整提示词重新跑,还是直接进入人工微调阶段。
4. Grounded-SAM 接入与联合标注实现
4.1 关键模块解析
如果把整个自动标注链路拆开看,Grounded-SAM 是其中技术含量最高、也最值得深入理解的部分。它由两个独立训练出来的模型拼接而成:
Grounding DINO负责文本到检测框的映射。它基于 Transformer 架构,输入是“图像 + 文本描述”,输出是一组物体检测框和置信度。它最大的特点是开放词汇——不像 YOLO 那样只能识别训练时见过的类别,你想让它找“黑色的运动鞋”,它就能去找“黑色的运动鞋”,不用重新训练。
SAM负责从框到掩码的映射。它接收图像和一组提示(可以是框、点或文本),输出的是精确的物体分割掩码。SAM 在分割领域的泛化能力很强,很多没有在训练集中出现过的物体类型,它也能给出不错的分割边界。
这两个模型各自都有 GitHub 开源仓库,但直接把它们拼起来用需要写不少胶水代码。Grounded-SAM 这个项目就是专门做这件事的,它封装好了调用链:输入文本提示词 → Grounding DINO 生成框 → 把框作为 SAM 的提示 → SAM 生成掩码 → 最后输出标注结果。
在自动标注场景里,Grounded-SAM 相当于那个“什么都能认的实习生”。它可能对每个类别都不是百分之百准确,但胜在覆盖面广,能快速把一份零基础的图片库标出一个像样的初稿。后续的 autodistill 只是负责把它的输出整理成标准格式,而 X-AnyLabeling 则是在初稿之上做人工修正。
4.2 串联实战与参数调优
我在自己的项目里,有时候不直接走 autodistill 的封装,而是先用 Grounded-SAM 的原始接口跑一批数据,因为这样可以更细致地控制中间过程的参数。
Grounded-SAM 的典型调用方式大致是这样的思路:
from groundingdino.util.inference import load_model, predict import groundingdino.datasets.transforms as T from segment_anything import sam_model_registry, SamPredictor import cv2 import torch # 加载 Grounding DINO 模型 grounding_model = load_model("groundingdino/config/GroundingDINO_SwinT_OGC.py", "weights/groundingdino_swint_ogc.pth") # 加载 SAM 模型 sam = sam_model_registry["vit_h"](checkpoint="weights/sam_vit_h_4b8939.pth").to("cuda") sam_predictor = SamPredictor(sam) image = cv2.imread("street.jpg") image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 第一步:文本检测,得到框 boxes, logits, phrases = predict( model=grounding_model, image=image_rgb, caption="a person . a car . a traffic light", box_threshold=0.35, text_threshold=0.25, ) # 第二步:框交给 SAM 生成掩码 sam_predictor.set_image(image_rgb) for box in boxes: x1, y1, x2, y2 = box * torch.tensor([image.shape[1], image.shape[0], image.shape[1], image.shape[0]]) masks, scores, _ = sam_predictor.predict( box=torch.tensor([x1, y1, x2, y2]).cuda(), multimask_output=False, ) # 这里拿到 masks,可以保存成 PNG 或转成标注格式这里有几个关键参数值得展开讲,它们是你实际调优时最需要反复试的旋钮:
box_threshold(检测框置信度阈值):控制 Grounding DINO 输出框的严格程度。设成 0.35 表示只要置信度超过 35% 的框都会被保留。阈值设低,召回率高但误检多,需要人工删;阈值设高,误检少但容易漏检,需要人工补。我一般先用默认值跑一批,看误检率决定往哪个方向调。
text_threshold(文本匹配阈值):控制“文本和图像特征是否匹配”的判定。这个和 box_threshold 联动,两个阈值都低,检测框数量激增;两个阈值都高,框大量减少。多类别联合检测时更要注意,有些类别之间文本特征相似度高,需要单独微调。
multimask_output 参数:SAM 的输出模式。设成 True 时,SAM 会给出多个候选掩码,适合不确定边界时挑最好的;设成 False 时,只给一个最自信的掩码。自动标注场景里我建议设成 False,因为批处理时我们依赖的是确定性输出,多个候选掩码反而增加后续处理的复杂度。
一个实战中非常有效的技巧是:在提示词里把类别的上下文写进去。比如检测“car”时,提示词可以写成“a car on the road, not a toy car, not a logo”,这样能明显减少品牌图标带来的误检。这个技巧在 Grounding DINO 上特别管用,因为它使用的是基于文本的匹配,提示词对结果的影响非常直接。
4.3 与 X-AnyLabeling 的数据对接方式
跑完 Grounded-SAM 或 autodistill 之后,标注数据怎么无缝接到 X-AnyLabeling 里,是很多新手搞不清的地方。这里我直接给一个最实用的对接方案。
X-AnyLabeling 原生支持的格式包括 LabelMe 的 JSON、YOLO 的 txt、COCO 的 JSON 等。如果 autodistill 输出的是 YOLO 格式(每张图一个同名 txt 文件,内容是类别ID和归一化坐标),那你只需要保证图片和 txt 在同一个目录,或者按 X-AnyLabeling 要求的目录结构放好,然后直接从界面打开图片文件夹即可,它会自动识别同名的标注文件。
如果 autodistill 输出的不是 YOLO 格式,而是 COCO JSON,那就需要先转换一下。我常用的一种方式是写一个简短的脚本,把 COCO 转成 YOLO 格式。这里给个核心思路:
import json import os # 读取 COCO JSON with open("annotations.json") as f: coco = json.load(f) # 建立图片ID到文件名的映射 img_map = {img["id"]: img["file_name"] for img in coco["images"]} # 建立类别映射 cat_map = {cat["id"]: idx for idx, cat in enumerate(coco["categories"])} # 遍历所有标注 for ann in coco["annotations"]: img_file = img_map[ann["image_id"]] cat_id = cat_map[ann["category_id"]] x, y, w, h = ann["bbox"] img_w = next(img["width"] for img in coco["images"] if img["id"] == ann["image_id"]) img_h = next(img["height"] for img in coco["images"] if img["id"] == ann["image_id"]) x_center = (x + w / 2) / img_w y_center = (y + h / 2) / img_h nw = w / img_w nh = h / img_h txt_name = img_file.replace(".jpg", ".txt") with open(os.path.join("yolo_labels", txt_name), "a") as f: f.write(f"{cat_id} {x_center:.6f} {y_center:.6f} {nw:.6f} {nh:.6f}\n")这个脚本虽然不是完整的可用代码,但核心逻辑是成立的,你只要把标注字段的对应关系确认清楚,就能在 COCO JSON 和 YOLO txt 之间自由转换。有了这个转换能力,X-AnyLabeling 就成了整个流程里的人工质检台,所有自动标注的产物最终都能在这里进行人工修正。
5. 常见问题与排查技巧实录
5.1 典型问题速查表
这几个工具组合用下来,我在实际部署和使用中遇到了不少问题,这里整理一个速查表,按“症状—原因—解决”的方式记录,方便你遇到同类问题时直接对照排查。
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| X-AnyLabeling 启动后界面很卡 | GPU 版 PyTorch 没装好,模型在 CPU 上跑 | 确认torch.cuda.is_available()返回 True,重装 CUDA 版 PyTorch |
autodistill 跑label()时提示 OOM | 输入图片尺寸过大或 batch size 太高 | 先把图片统一 resize 到 640 或 1024,再降低 batch size |
| Grounded-SAM 检测结果出现大量误检 | box_threshold 过低,或提示词太宽泛 | 调高 box_threshold 到 0.4 以上,把提示词写得更具体 |
| Grounded-SAM 几乎检测不到目标 | 文本提示词和实际目标差异太大 | 检查提示词是否准确描述目标,尝试多个同义表达 |
| autodistill 输出格式不是想要的 | 目标模型类型与预期不符 | 确认目标模型是检测模型还是分割模型,再决定输出格式 |
| X-AnyLabeling 打开标注文件后不显示框 | 标注文件格式或目录结构不对 | 确认图片和 txt 文件名一致,且放在同一目录下 |
| SAM 生成掩码边界粗糙 | SAM checkpoint 版本太旧 | 换用官方最新权重,或降低图片压缩比例 |
| PyCharm 里运行 main.py 报缺少模块 | 虚拟环境没激活,或依赖没装完整 | 确认 PyCharm 解释器选的是 conda 创建的虚拟环境 |
5.2 独家避坑经验
在这个流程里踩过不少坑,分享几个真正影响效率的细节,这些细节常规文档里基本不会写。
第一个是提示词的统一管理。我最早是在每个脚本里直接写提示词,后来发现不同批次项目的类别名和提示词很容易弄混。现在我会单独维护一个 YAML 或 JSON 文件,把每个项目的类别、提示词、阈值配置集中管理,脚本启动时读取同一个配置文件。这样做最大的好处是,当你发现某一类目标误检严重时,只需要改一处配置即可,不用翻代码。
第二个是在批量标注前先跑小样本验证。autodistill 的label()一旦跑起来,对着几千张图推理,中间发现问题再改配置成本很高。我的习惯是先复制出三五十张图作为极简测试集,把流程完整跑一遍,确认标注速度和准确率可接受后,再跑全量数据。这个习惯帮我省下了大量无效等待时间。
第三个是保留 Grounded-SAM 推理结果中的置信度信息。autodistill 在输出 YOLO 格式时会丢弃置信度字段,但置信度对你后续的人工审核非常有用。如果你是在 X-AnyLabeling 里人工审,建议在生成初步标注时,把置信度低的候选框用不同颜色标记出来,让人优先检查这些“疑似误检”的框,而置信度高的框可以快速跳过。我实践出来的比例是:90% 的精力放在 10% 的低置信度框上,审核效率能翻倍。
第四个是关于模型权重路径的坑。Grounded-SAM 的权重文件很大,动辄几个 GB,而且官方仓库下载偶尔会超时。如果公司网络不稳定,建议提前把权重文件下载好,并在代码里用绝对路径指定,而不是依靠下载脚本。我在内网环境部署时就吃过这个亏,最后是把权重手动拷贝到内网机器上,才把流程跑通。
5.3 遇到异常标注结果时的处理思路
自动标注工具再强,也一定会有异常结果。这里说的异常不是简单的误检,而是模型输出的结构性错误,处理思路和普通微调不一样。
举个例子,Grounded-SAM 在拥挤场景下很容易把“多个人黏在一起”标成一个框,而且 SAM 生成掩码时会把多个重叠目标合并成一个整体。这种情况出现时,靠调阈值解决不了问题,因为问题出在检测阶段的 NMS 策略上。这个时候最有效的处理方式是在 X-AnyLabeling 里手动把大框拆成多个小框,再用 SAM 的交互式点选功能重新生成掩码。
再比如,某些类别之间视觉差异很小(比如“轿车”和“SUV”),文本提示词几乎无法区分。这种情况不要硬调提示词,而是让 Grounded-SAM 只负责检测父类别“vehicle”,把“car”“SUV”这类细分留给人工在 X-AnyLabeling 里打标签。这种做法看起来多了一步人工操作,但实际成功率远高于想让模型一步到位。
还有个思路值得一试:用训练好的目标模型反向修正基础模型的输出。autodistill 训练完 YOLOv8 之后,如果效果比 Grounded-SAM 在特定类别上更准,就把 YOLOv8 变成新的基础模型,跑下一批数据时用它来预标注,Grounded-SAM 只负责补漏。这其实就是前面说的飞轮效应,也是这套组合最强的地方——它不是一次性工具,而是一条可以持续进化的标注产线。
6. 一些补充建议与延伸玩法
到这个程度,X-AnyLabeling + autodistill + Grounded-SAM 已经能应付绝大多数检测和分割任务的自动标注需求了。但如果你还想把它玩得更深,有几个方向值得尝试。
第一个方向是把 Grounded-SAM 换成 YOLO-World 或 DETIC 对比测试。autodistill 兼容多个基础模型,不同模型在不同场景下的表现差异很明显。比如 DETIC 在少样本类别上有时比 Grounding DINO 更稳,而 YOLO-World 推理速度更快。我在项目中会针对数据类型做一个基准对比,用同一批测试图分别跑两个基础模型,统计精确率和召回率,然后选择更合适的。
第二个方向是利用 X-AnyLabeling 的批量 AI 标注能力做增量标注。当你的初版模型已经在业务场景跑起来后,新收集到的图片可以直接通过 X-AnyLabeling 内置的模型做初标,然后人工只修正新出现的困难样本。这个流程下,标注团队的效率每秒都在提升,而且模型效果越滚越好。
第三个方向是结合主动学习策略优化标注预算。自动标注不是用来替代人工的,而是帮助你把有限的人工精力花在最有价值的样本上。你可以先让 autodistill 对一大批未标注数据打初标,然后用目标模型的置信度去重排数据——低置信度的样本优先让人工修正,高置信度的可以直接进训练集。这样一套下来,同样的标注人力能解决的样本量会大很多。
我个人在实际操作中的体会是,自动标注工具链的搭建门槛并没有想象中高,真正的门槛在于你是否理解每个环节的输入输出,以及是否能在模型出错时快速定位问题。最开始接触这套流程时,我也曾被各种环境问题、格式问题、语义提示问题折腾得够呛,但当你把整条链路跑顺之后,会发现它带给你的解放感是巨大的——省下的时间你能做更多有价值的事情。
如果再让我选一次,我还是会用这三个工具的组合作为自动标注产线的基座,但我会把精力更多地投入到数据质检和提示词迭代上去,因为那才是自动标注效果天花板的决定因素。希望这篇内容能帮你少走一些我走过的弯路。