做深度学习和CV项目,最磨人的不是训练,是标注。我最早用LabelImg画框,几百张图就画到心态崩了,后来接触到X-AnyLabeling、autodistill和Grounded-SAM这三个工具,把它们串成一条自动标注流水线,才真正从“逐框手画”变成“程序出初稿,人来修错”。这篇内容就是我把这套流程跑通后的完整记录,包括每个工具各自负责什么、怎么部署、具体怎么跑、会踩哪些坑,全部按实操顺序写出来,给还在手工标注的朋友一个可以直接照做的参考。
1. 整体思路与工具选型
1.1 三个工具各干各的活
先说结论:这套组合里的分工非常明确。
Grounded-SAM,可以理解为“带文本理解能力的分割模型组合”。它先通过Grounding DINO根据自然语言描述(比如“person”“dog”)找到目标框,再交给SAM生成精细的像素级掩码。输入是一张图加一句提示词,输出是目标框和分割掩码,这就是自动标注的“初稿来源”。
autodistill是一个自动标注框架,它把“大模型当老师、小模型当学生”的思路落地成标准流程。我们用autodistill去调用Grounded-SAM批量处理一个文件夹里的所有图片,自动落盘检测结果,生成YOLO格式的标注txt。它在中间起到的作用是流程标准化和批量化的管理。
X-AnyLabeling则是面向人工的交互标注工具,也是一直被我放在“最后精修关卡”的软件。它支持读取已有的检测和分割标注,基于Qt开发,完全本地运行,有自己的模型辅助面板。你用它可以加载模型做预标注,也可以手工用矩形、多边形、橡皮擦工具把自动标注的结果修到能用的程度。
1.2 为什么选择这套组合而不是其他方案
市面上标注工具其实很多,LabelImg、labelme、CVAT、Roboflow都能用。但我实际对比下来,传统工具最大的问题是“人要从零开始画”。标注员面对一张图,没有任何辅助信息,每个框都要自己判断位置和边界,一张图三五分钟很正常。
这套组合解决的问题在于“从人工画框变成人工审框”。Grounded-SAM先跑一遍,即使初稿的边界有一点歪,框也能大致落在目标上,人只需要把误检删掉、把漏检补上、把边缘微调,效率是肉眼可见的提升。X-AnyLabeling做的不是帮你去画第一个框,而是帮你快速修正已有的框。
之所以不直接在Grounded-SAM的输出上训练,是因为初稿质量不稳定。个别图、个别类别的误检漏检还是比较明显,直接拿去训练会教坏模型。所以中间必须有X-AnyLabeling这一道人工审核。
还有一点,这三个工具全是开源且本地运行的,数据不用上传到任何第三方平台,数据隐私上安心很多,尤其适合做医疗、工业、安防这类对数据敏感的项目。
1.3 这套方案适合什么场景
我在实际项目中主要用它应对三类情况:
第一,冷启动数据集。手里有一堆原始图片,没有任何标注,类别还五花八门。用Grounded-SAM写几行代码、跑一两个小时,就能得到一批大概可用的初稿,人工再去修,比从零开始手工建库快得多。
第二,已有少量标注,但需要增加类别。比如项目里原本只标注了“人”,现在要把“安全帽”也加进来。传统做法是一个人一张图翻着找安全帽,累且容易漏。用Grounded-SAM基于文本提示直接找“helmet”,大批量初稿几分钟就有了。
第三,在模型迭代过程中扩展数据。你先用这套流程产出一批数据训练了一个小模型,之后可以把小模型加载到X-AnyLabeling里做辅助预标注,拿它跑完全部图片再人工修正。这样后续新增图片的成本会越来越低,形成“自动标注→训练→更好的自动标注”的正循环。
边界条件也提醒一下:如果目标特别细小、密集,或者类别相似度高,比如标一群蚂蚁、标几百根钢筋,这种场景自动标注还是会漏很多,人工补漏检的成本可能比纯手工还高。这类项目建议还是以人工为主,模型辅助只能锦上添花。
2. 环境部署与源码运行
2.1 X-AnyLabeling的安装方式
X-AnyLabeling的安装分两种方式。一种是直接pip安装现成包,命令很简单:
pip install x-anylabeling装完在终端敲x-anylabeling就能启动。这种方式胜在快,适合只是日常用一下精修标注的同学,但缺点也很明显:你没法改源码,看不到内部实现,想自己加模型或者修改快捷键逻辑就无从下手了。
另一种方式就是跑源码,也是我推荐的。因为X-AnyLabeling本身更新还是比较快的,用源码方式能随时拉最新代码,方便排查问题,也能自己在本地加一些模型配置。后面展开讲。
注意一下,X-AnyLabeling对Python版本有要求,实测Python 3.8到3.10之间最稳,3.11在某些机器上装PyQt5相关依赖时容易遇到编译问题。我自己的环境是Python 3.10 + PyCharm + conda,跑了很久没出大问题。
2.2 PyCharm运行x-anylabeling源码环境部署
这里把我在PyCharm里跑X-AnyLabeling源码的完整步骤写出来,每一步都踩过坑,照着来能少走弯路。
第一步,准备工作。需要先装好Git和Anaconda或Miniconda,PyCharm建议用专业版或社区版都行,社区版完全够用。
第二步,拉源码。
git clone https://github.com/CVHub520/X-AnyLabeling.git然后直接用PyCharm打开这个目录。PyCharm会自动识别这是一个Python项目,但解释器还没有配置。
第三步,创建虚拟环境。打开PyCharm右下角解释器设置,选“Add Interpreter”,选择“Conda Environment”,新建一个环境,Python版本选3.10。这一步的关键是:后续所有包都要装到这个环境里,别装进base环境,不然后面全是版本冲突。
第四步,安装依赖。在PyCharm底部打开Terminal,确认当前激活的是刚才创建的conda环境,然后执行:
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple这里用清华源是因为PyQt5、numpy这些大包从默认源下载会慢到怀疑人生。如果某些包提示需要编译,多半是Python版本太高或者缺少编译工具链,建议先检查Python版本,别硬刚编译问题。
第五步,启动源码。X-AnyLabeling的入口是main.py,在PyCharm右上角运行配置里新建一个Python配置,Script path指向main.py,然后点运行。
如果启动后出现窗口,说明环境部署成功。如果有报错,重点检查三个地方:虚拟环境是否激活、PyQt5是否装成功、当前目录是否在项目根目录下。我遇到过一次黑屏问题,重装PyQt5后解决,后面常见问题部分细说。
2.3 autodistill与Grounded-SAM环境部署
autodistill的部署核心依赖一个能跑深度学习模型的GPU环境。先装PyTorch,再装autodistill相关包:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install autodistill autodistill-grounded-sam装好之后,Grounded-SAM需要的权重文件会在第一次调用时自动下载,包括Grounding DINO的权重和SAM的权重。但如果你网络下载不稳定,也可以手动去对应release页面下载后放到指定目录。
硬件方面,跑autodistill里GroundedSAM的最小配置建议6GB以上显存。我在11GB的卡上跑得很舒服,用SwinT版本的Grounding DINO加SAM vit_b,单张图推理大概1到2秒。如果显存小于6GB,建议用CPU先跑小批量试试,或者改用更轻量的基础模型。
有个很重要的点是torch版本不能太新也不能太旧,实测和CUDA 11.8配套的PyTorch 2.0到2.1版本最稳。太新的torch版本有时会导致groundingdino的C扩展编译失败。
3. 自动标注全流程实操
3.1 冷启动:Grounded-SAM生成第一版初稿
先把Grounded-SAM单独跑通手动流程。这里用的是Grounded-SAM官方仓库的命令行方式:
python grounded_sam_demo.py \ --config GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py \ --grounded_checkpoint groundingdino_swint_ogc.pth \ --sam_checkpoint sam_vit_h_4b8939.pth \ --input_image demo.jpg \ --output_dir "outputs" \ --box_threshold 0.3 \ --text_threshold 0.25 \ --text_prompt "tree"这里最有讲究的是text_prompt和两个阈值。
提示词别写太口语化,尽量用标准的英文名词,比如 “person” “car” “dog”,并且官方demo习惯在末尾加上英文句号,变成"tree."。实测下来带句号的文本输入在Grounding DINO里匹配更稳定。多类别时直接在句子里用英文句点分隔,比如"person. dog. car.",不要用中文逗号或分号。
box_threshold控制检测框的置信度门槛,text_threshold控制文本匹配的门槛。这两个值设得太高会漏检,设得太低会大量误检。我的个人习惯是第一轮跑自动标注时把box_threshold设到0.25,宁多勿缺。理由很简单:多检出的框在X-AnyLabeling里就是多选中几个删除,几秒钟的事;漏检则要一张图一张图去肉眼找,成本高得多。
跑完一张测试图确认效果后,接下来要对整个文件夹批量处理。Grounded-SAM输出的是像素掩码(mask),要转成检测框格式才能给下游用。我写了一个简单的转换脚本,把mask转成YOLO格式的归一化框:
import json import cv2 import numpy as np def mask_to_yolo(mask_path, image_path, class_id, output_path): mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) image = cv2.imread(image_path) h, w = image.shape[:2] contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) lines = [] for contour in contours: x, y, box_w, box_h = cv2.boundingRect(contour) x_center = (x + box_w / 2) / w y_center = (y + box_h / 2) / h box_w_norm = box_w / w box_h_norm = box_h / h lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {box_w_norm:.6f} {box_h_norm:.6f}") with open(output_path, "w") as f: f.write("\n".join(lines))如果目标本身不是矩形,这个脚本生成的框会比较大,把多余的背景也框进去。后面在X-AnyLabeling里人工微调时顺手收一下就行。
3.2 批量跑:autodistill蒸馏标注
当图片量上了几百上千张,直接用Grounded-SAM自己写循环就不太高效了。这时候autodistill的价值就出来了,它把“模型加载、批量推理、结果落盘”标准化了。
autodistill的核心概念是Ontology,你可以理解为“类别提示词映射表”。用起来是这样的:
from autodistill_grounded_sam import GroundedSAM from autodistill.detection import CaptionOntology ontology = CaptionOntology({ "person": "person", "dog": "dog", "car": "vehicle", }) base_model = GroundedSAM( ontology=ontology, box_threshold=0.25, text_threshold=0.25 ) base_model.label( input_folder="raw_images", output_folder="auto_labels" )这里的ontology字典,左边是给Grounded-SAM的文本提示词,右边是对应输出类别名。注意autodistill输出的类别编号是按照这个字典的遍历顺序从0递增的,所以字典顺序就是类别编号顺序,写的时候尽量固定,不然后面检查标注会一脸懵。
跑完后auto_labels目录下会自动生成图片对应的txt文件,同时还会生成一张可视化标注图,方便你快速浏览一下自动标注的质量。
从这开始,你的角色就从“标注员”变成了“质检员”。打开可视化图,整体看一遍哪类漏得多、哪类误检多,心里有数之后再去X-AnyLabeling里修。
3.3 精修:X-AnyLabeling加载与手工修正
到这一步,自动标注的结果已经在auto_labels/images里了。打开X-AnyLabeling,通过“打开文件夹”加载原图目录,正常情况下同名txt标签会被自动读进来。
注意一个细节,X-AnyLabeling的标签读取依赖它当前选择的保存格式。在软件设置里把输出格式切到YOLO格式,同时确保类别列表和autodistill的ontology顺序一致。我通常手动在X-AnyLabeling的标签栏里把类名按顺序创建一遍,这样导入的编号就能对上。
加载完标注后,一张一张过就行。我个人的精修顺序是这样:
先删误检,视觉扫一遍,把明显不对的框直接按Delete删掉。再补漏检,重点关注图片边缘、目标重叠这些模型容易漏的位置。最后修边界,把框太大、太小、偏移的目标重新拉正。
整个过程听起来还是有点工作量,但相比纯手工标注已经轻松了不止一个量级。我测过一个项目,400张图纯手工标了大约10个小时,用这套流程处理完初稿再精修,4个小时左右就完成了,而且边界质量普遍比纯手工标得更稳。
3.4 导出训练集并验证质量
精修完成之后,X-AnyLabeling会按设置里的输出格式保存标注,YOLO格式下就是每张图对应的同名txt。此时检查一下目录结构,原图目录和标签目录分开管理。
训练之前先做一个必要步骤:统计每个类别的样本数量,看看有没有哪个类别数量明显偏少。自动标注经常会漏掉某个类别,如果统计后发现某类很少,就用Grounded-SAM针对这个类别的图片单独再跑一遍,把漏检的补回来。
然后就直接丢给YOLO系列训练。我用这批标注跑过YOLOv8和YOLOv11,效果都还不错。这里插一句,训练完的模型不要急着归档,它还能继续参与标注流程。把它加载到X-AnyLabeling里,对下一批新图片先做推理预标注,再人工修正,这就是迭代标注的工作流。
3.5 从初稿到成品:一次完整执行记录
最后记录一次我实际跑下来的时间线,给大家一个直观参考。
原始数据是1200张工地场景图片,类别是“person”“helmet”“vest”三个类别。先跑autodistill的GroundedSAM,整体耗时约25分钟。检查可视化结果,发现helmet漏检偏多,于是单独用"helmet."作为提示词又跑了一遍,把额外的结果合并进标签目录。然后进入X-AnyLabeling精修,两个人大约花了6个小时完成所有图片的检查和修正,其中前100张比较慢,越到后面越顺手,因为有模型辅助,很多图甚至直接翻页就过了。最终三个类别一共16000多个目标,训练出来的YOLOv8s模型在验证集上mAP50达到92.4%,这个结果直接交付给了业务方。
4. X-AnyLabeling快捷键与高效精修心得
4.1 快捷键速查
X-AnyLabeling本身继承了不少标注工具的通用操作习惯,快捷键用熟之后,精修速度能提升一大截。我把实际使用中频繁用到的高频快捷键整理成下表:
| 操作 | 快捷键 | 说明 |
|---|---|---|
| 上一张图 | A | 翻到上一张图片,自动加载标注 |
| 下一张图 | D | 翻到下一张图片,最常用的按键 |
| 保存 | Ctrl+S | 手动保存当前标注 |
| 撤销 | Ctrl+Z | 撤销上一次操作,画错框时救命键 |
| 删除选中目标 | Delete | 删除当前选中的框或分割掩码 |
| 放大 | Ctrl+鼠标滚轮向上 | 放大地图区域,看小目标时必用 |
| 缩小 | Ctrl+鼠标滚轮向下 | 缩小视野 |
| 拖动画布 | 按住空格+鼠标左键拖动 | 浏览大图时移动画布 |
| 闭合多边形 | 回车 | 多边形标注时结束绘制 |
| 取消当前绘制 | Esc | 撤销正在进行的标注操作 |
注意不同版本的X-AnyLabeling快捷键可能会有差异,在软件菜单的快捷键设置里可以看到当前版本的具体绑定。我第一次更新版本后快捷键被重置过,所以建议打开设置瞄一眼,别凭肌肉记忆按错。
4.2 模型辅助模式的高效用法
除了手工改框,X-AnyLabeling最值得利用的是模型辅助标注。右侧模型面板里可以加载YOLOv8系列、RT-DETR、SAM等模型,加载之后可以对当前图片跑一次推理,模型预测的框会直接生成在画布上,你再手动修正。
这个功能最适合两的阶段:
第一阶段是完全没有自动标注结果时,用预训练模型先豆一遍。比如项目类别是COCO里常见的“person”,可以直接加载YOLOv8n模型跑推理,得到的框做初稿。速度很快,一张图一两秒,之后人工修正。
第二阶段是用自己训练好的模型来辅助标注。每次数据集迭代后,把最新的模型加载进来,对新数据做预标注。这一步极其好用,因为模型是自己训练的,对场景分布和类别都非常了解,初稿质量往往比通用模型高很多。
使用模型辅助时有个建议:模型推理设置的置信度可以降低一点,比如0.25或0.3,保证召回率。还是那句,多出来的误检用Delete批量删很快,漏检补起来才真浪费时间。
4.3 多轮迭代的标注策略
我实际跑项目时和大家的习惯可能不太一样:标注不是一轮完成的,而是两到三轮渐进式迭代。
第一轮先用Grounded-SAM/autodistill出全量初稿,只做轻量精修,目标是让大部分标注“基本能用”,不求精,只求覆盖。然后直接用这批粗标训练一个快速小模型。第二轮用这个小模型对同一批数据重新推理,此时模型已经比较懂这个场景了,对有争议的目标会给出更稳定的判断。第三轮再在X-AnyLabeling里精修,重点只需要放在模型前后判断不一致的少数目标上。
这个策略的好处是前期粗修成本低,训练快速模型能帮自动标注系统学会场景先验,后面精修时焦点特别集中。我自己测试过,同样是1200张图,直接精修一轮要6小时,先粗修再快速训练再精修只要4小时,而且最终标注质量更好。
5. 常见问题与排查技巧实录
5.1 问题速查表
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
X-AnyLabeling在PyCharm里报No module named 'PyQt5' | 当前解释器选错,没装依赖 | 检查PyCharm右下角解释器是否为创建的conda环境,重新安装requirements |
| X-AnyLabeling启动黑屏或窗口空白 | PyQt5版本冲突 | 卸载重装PyQt5,推荐5.15.x版本,或者升级到最新版 |
Linux下启动报libGL.so.1错误 | 缺少OpenGL库 | 执行sudo apt update && sudo apt install libgl1 libglib2.0-0 |
| autodistill跑GroundedSAM没有检测出目标 | 提示词写得不规范,或者阈值太高 | 提示词用英文名词并加英文句号,box_threshold降到0.25以下 |
| 自动标注大量误检 | 阈值设置过低 | 小幅度提升box_threshold和text_threshold,每次调0.05 |
| autodistill安装卡在编译依赖 | torch版本与CUDA不匹配 | 先安装PyTorch再装autodistill,不要装最新版本torch |
| 导出YOLO格式后类别错乱 | ontology字典顺序与类别列表不一致 | 统一按ontology遍历顺序创建X-AnyLabeling类别名 |
| SAM掩码转矩形框后框范围偏大 | 目标的形状不规则 | 在X-AnyLabeling里人工调整,或者改用多边形标注模式精修 |
5.2 几个必须细说的坑
先说说最容易让新手劝退的坑,PyCharm里跑X-AnyLabeling时,明明pip list里能看到PyQt5,运行还是报找不到模块。这个十有八九是解释器选错了。PyCharm的Terminal里默认激活的conda环境,和右上角运行配置里用的解释器,这两个可能不是同一个。在运行配置里手动指定一次解释器,指向你安装依赖的那个环境,问题就解决了。
再一个坑是autodistill第一次运行GroundedSAM时的模型权重下载。如果下载到一半断了,下次运行会因为权重文件不完整而报各种奇怪的错误。解决办法是一旦发现下载异常,就找到本地的权重缓存目录,把不完整的文件清掉再重试,别想着靠断点续传。
还有一个实际标注中容易遇到的问题:X-AnyLabeling明明看到了框,但导出之后发现坐标不对。排查后发现是图像尺寸变了,我有一批图是模型预处理时被resize过的,标注时看着正常,导出时就对不上了。解决办法是标注前把图片统一尺寸,或者导出后做一个分辨率的换算脚本。
5.3 独家实操经验
最后分享几个我这段时间趟出来的经验,常规文档里基本不会写。
第一,自动标注结果合并时要小心重复框。我在Grounded-SAM跑完又用autodistill跑了一遍同类别的图,结果同一目标出现两个重叠框,训练时模型反复学习这种重复标注,容易出现同一目标预测出两个框的现象。合并的时候建议做一次NMS去重,按IoU阈值0.5剔除重叠框。
第二,精修时优先修小目标。小目标本来就是检测难点,如果初稿的小目标没标出来,后面模型学不到小目标的特征,后面再怎么调参都难补。在X-AnyLabeling里精修时,我会把图片缩放到100%以上逐块检查,专门找小目标补框。
第三,Grounded-SAM对稀有类别和抽象类别会失灵。比如“defective weld”这种描述性类别,文本提示很难直接定位。这时候我建议换成训练好的小模型跑辅助预标注,或者直接用X-AnyLabeling手工标注一批后再训练一个专门的小模型。基础模型的语义理解再强,也替代不了项目专属的领域模型。
这套“自动标注初稿+人工精修+模型迭代”的流程,我现在已经当成处理数据集的标准路径了。每次接到新项目,先拿几十张图测试Grounded-SAM出初稿效果,再上autodistill批量跑,最后在X-AnyLabeling里修一遍完事。工具本身不复杂,难的是把每个环节的节奏和阈值调到适合自己的数据场景。说实话,自动标注不会百分之百取代人工,但它能让你把有限的时间花在真正需要专业判断的地方,而不是一遍又一遍重复机械的鼠标拖拽。如果还在为标注发愁,强烈建议把这套流程搭起来跑一次,你会回来感谢自己的。