
做视觉模型的人大概都经历过这种绝望模型推理只要几毫秒标注一箱图却要熬好几个通宵。我接手的第一个数据项目是两千张工业零件图做实例分割标注第一周只完成了三百多张剩下的硬是被客户催着赶工。后来我开始研究自动标注把 X-AnyLabeling、autodistill、Grounded-SAM 组合起来用硬是把标注周期从三周压到了四天左右。这篇文章就是我完整跑通这套流程之后的一次复盘包括每款工具怎么打开、参数怎么调、输出怎么衔接以及我在生产环境里踩过的坑。如果你正在为检测或分割项目造数据集或者想用基础模型给人工标注打底这篇应该能在你开工之前就帮你避掉大部分问题。1. 先看清三个工具在标注链条上分别扮演什么角色1.1 手工标注的真实痛点和自动标注到底能帮多少忙很多人一听到自动标注第一反应是机器能标谁还用人但实际做过项目的人都知道自动标注解决的核心不是无人化而是把人的劳动从重复画框里解放出来。手工标注的隐性成本不只是时间还有一致性一个人连续标了四个小时之后框的边距会不自觉变大凹进去的轮廓会偷懒少点几个点这还只是一天之内的漂移。如果换成多人协作标注风格差异更明显后期清洗数据比标注本身还痛苦。自动标注的价值在于它可以提供一个几乎零成本的初稿让人工从空白画布上画画变成在已有结果上做增删改。我的实际经验是在一张图上从零画一个分割掩码需要 30 到 60 秒但校对一张自动生成的结果只需要 5 到 15 秒前提是预标注质量不低于 60% 的可用率。所以整套流程的思路并不复杂——让大模型先干粗活人工专心做精修再让小模型接力形成一条可持续产出的标注链路。1.2 三款工具的能力边界与配合关系先说结论这三个工具不是竞争关系而是链条上的不同环节。X-AnyLabeling这是一个带完整图形界面的本地标注工具支持矩形、多边形、关键点、线段、掩码等常见标注形式。它最大的特点是把一批深度模型直接集成到了界面上包括 SAM、Grounding DINO、YOLO 系列等可以边标注边调用模型做辅助。它的角色是人工校验出口和格式转换中枢最后进训练集的数据基本都要在这里过一遍。Grounded-SAM这是由 Grounding DINO 与 SAM 串起来的自动标注管线。Grounding DINO 负责根据文本提示检测出目标框SAM 负责在框内生成高精度的分割掩码。它的角色是批量初稿生成器适合在没有标注数据的冷启动阶段快速造一批预标注结果。autodistill这是 Roboflow 推出的自动标注与模型蒸馏框架。它让你先定义好类别然后调用一个大型基础模型去自动标注你的数据再用这些自动标注数据训练一个小模型。它的角色是持续生产力当目标小模型训练到一定效果后可以替代大模型继续标注新增数据。三个工具放在同一张表里看会更清楚工具核心能力操作方式主要输出适合阶段X-AnyLabeling交互式标注、模型辅助精修、格式转换图形界面COCO / VOC / YOLO 等人工校对与数据交付Grounded-SAM文本提示驱动的批量检测与分割命令行 / Python掩码 JSON冷启动预标注autodistill基础模型自动标注 目标模型训练Python API数据集 训练权重数据循环迭代明白分工之后整套流程的轮廓就出来了先让 Grounded-SAM 或 autodistill 批量产预标注再用 X-AnyLabeling 做人工修正导出 COCO 或 YOLO 格式训练小模型最后小模型再配合人工抽检继续扩数据。下面我从 X-AnyLabeling 开始把每个环节的细节展开讲。2. X-AnyLabeling 上手核心用法与打开方式2.1 安装与启动Windows 和 Linux 两条路线热词里全是x-anylabeling 使用说明x-anylabeling 怎么打开可见大部分人卡在了第一步。其实这个工具的使用门槛很低但打开方式确实有好几种我分别说。Windows 路线最省事的办法是直接下载编译好的安装包解压后双击X-AnyLabeling.exe就能打开。如果你想跑最新源码、调用更多模型就克隆源码git clone https://github.com/CVHub520/X-AnyLabeling.git cd X-AnyLabeling pip install -r requirements.txt python main.py这里有个细节源码方式启动前建议把依赖装到一个干净的 Python 虚拟环境里因为它依赖 PyQt5、onnxruntime、opencv-python 等一堆包和已有环境里的 torch 版本如果冲突了界面会启动失败或者模型加载时直接闪退。Linux 路线我主力环境是 Ubuntu 20.04安装依赖后直接用python main.py启动。如果你运行后提示窗口无法显示很大概率是缺少系统级的图形库常见的是libxcb-cursor0。这一步别急着查 Python 环境先跑一下sudo apt-get install libxcb-cursor0另外要注意的是Linux 下如果要用 GPU 跑模型onnxruntime 的版本不能装错。我踩过最尴尬的坑是装成了普通的onnxruntime界面也能跑但模型推理全部走 CPU一张千元级显卡在旁边闲着自动标注慢得让人怀疑人生。正确做法是根据自己的 CUDA 版本安装onnxruntime-gpu具体版本号建议去官方发布页对照一下不要盲装最新版。打开之后的界面左侧是文件树和当前图片列表中间是画布右侧是标注属性和模型控制面板。第一次打开可能没有模型可用需要先去模型管理里下载权重这里会受网络环境影响比较大的 SAM 权重建议用带断点续传的工具拉下来再手动放到对应目录。2.2 界面布局、快捷键与模型调用逻辑X-AnyLabeling 的交互习惯继承了 LabelImg/AnyLabeling 那一套常用快捷键如下快捷键功能W新建矩形框E新建多边形D删除当前选中标注Ctrl Z撤销上一步Ctrl S保存当前标注A/D切换上一张 / 下一张图片模型调用逻辑是它和普通标注工具最大的差异你不需要事先用一批数据训练完再标注而是可以随时加载一个辅助模型让它针对当前图片输出建议。我常用的组合是加载 Grounding DINO 做检测建议再加载 SAM 做掩码精修。操作流程是这样的在右侧模型列表中选择 Grounding DINO 对应的模型配置加载权重。在提示词输入框里输入类别比如cat . dog .点预测。界面会在图上画出一批候选框置信度高的直接生成标注。对不满意的框用 SAM 的点选提示模式点击目标中心和边界让模型重新生成掩码。这一步最关键的不是怎么点选而是理解人工在这里的真正职责是判断不是绘制。我习惯把模型建议当成一个具备一定可信度的同事它标出来的框我会快速检查边界贴合度明显离谱的删掉轻微偏移的用Ctrl Z回退后在局部加点微调效率会比从零画高很多。2.3 基于内置 Grounding DINO 的提示标注实操很多人不知道 X-AnyLabeling 里已经内置了 Grounding DINO不用单独拉一个命令行环境。实际使用中提示词的写法会直接影响召回率和准确率。我的经验是三个原则。第一类别之间用英文句号隔开比如car . pedestrian . bicycle .不要用 and 连接逗号也尽量少用。第二类别词尽量用你观察到的外观词汇而不是功能词汇。比如resistor和axial lead resistor在特定数据集里前者更容易漏检后者虽然长一点但召回率明显高。第三如果图片背景复杂提示词里不要加入对背景的描述词比如不要写car on road这会让模型去搜索整个语义场景而不是目标本身。生成候选框之后X-AnyLabeling 允许你对结果做批量接受或逐条修正。我常用的策略是先把小阈值的结果全部展示出来用快捷键快速浏览一遍把明显误检的全选删除然后再放大检查真正感兴趣的目标是否都被召回。这一步肉眼过的速度非常快比一张张从零画快得多。2.4 标注数据导入导出格式转换X-AnyLabeling 支持导入和导出的格式比较全我实际主要用的是 COCO 和 YOLO 两种。这里有个非常容易踩的坑导出 YOLO 格式时类别顺序取决于项目里的类别列表顺序而不是你在标注框里写的文字标签。如果你在不同工具之间来回导了几次类别顺序很容易错位最后训练时模型会在类别上鬼打墙。我的习惯是在一开始就固定一个classes.txt所有工具都用这个文件来约定类别顺序。Grounded-SAM 生成的标注、X-AnyLabeling 导出的 YOLO、autodistill 生成的文件夹全部严格对齐这个顺序。宁可多花十分钟做一次格式校验也不要等到损失曲线异常时再回来怀疑数据因为数据问题永远是训练里最难排查的。3. Grounded-SAM用一句话给整批图片做预标注3.1 检测器与分割器是怎么协作的Grounded-SAM 的完整项目一般是指 IDEA-Research 开源的 Grounded-Segment-Anything它把两个模型的优势接了起来Grounding DINO 负责把文本提示转成目标框SAM 负责把目标框转成精细的像素级掩码。用一个类比来解释Grounding DINO 是一个视力很好但手指很粗的寻物助手它能在图片里快速指出你要的东西大概在这个位置SAM 是一个对边界非常敏感的雕刻师只要给它一个框或一个点它就能把目标边缘切得很干净。前者擅长理解和搜索后者擅长细节和轮廓二者串起来就是一条完整的语言到掩码生产线。这里要注意一个容易误判的点Grounded-SAM 的输出质量上限由 Grounding DINO 的检测质量决定。如果 Grounding DINO 根本没检测到目标SAM 再强也没有用如果检测框偏了SAM 则可能把框内的干扰背景也一起分割进来。所以预标注调优的重点放在检测环节而不是分割环节。3.2 批处理命令与关键参数官方仓库里的演示脚本默认针对单张图片实际做项目时显然不可能一张张跑。我对这些脚本做了一层薄封装把它们包成了一个按目录批量处理的循环核心参数如下版本不同字段可能有差异但思路通用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_dir ./images \ --output_dir ./auto_labels \ --text_prompt valve . pipe . flange . \ --box_threshold 0.35 \ --text_threshold 0.25 \ --nms_threshold 0.8三个阈值参数是最值得花时间调的box_threshold目标框置信度阈值默认 0.35 左右。调低会让更多候选框被保留召回率上升但误检变多调高则相反。冷启动阶段我建议先设低一点宁可多产出误检也不要漏检因为漏检在人工校对阶段需要重新绘制成本远高于删除一个错误框。text_threshold文本匹配阈值也就是模型对这个目标确实属于文字描述的类别的置信度。如果类别长得像比如左法兰和右法兰这个阈值需要适度提高否则两个类别会互相污染。nms_threshold非极大值抑制阈值主要用来消除同一目标的重叠框。阈值越高保留的重复框越多太低又可能把紧密相邻的真实多个目标误杀成一个。一般保持 0.8 左右不用大动。权重方面GroundingDINO-SwinT 大概 700MBSAM ViT-H 接近 2.4GB如果你显存有限可以把 SAM 换成 ViT-B分割精度牺牲不大推理速度和显存占用会友好很多。实在没 GPU 也能跑但那种慢的程度个人建议直接放弃自动标注老老实实手工画可能更快。3.3 输出结果怎么落盘、怎么转成可训练格式批量跑完之后输出目录里会有一堆 JSON 文件每个 JSON 记录了一张图片的检测框、掩码的 RLE 编码、置信度和类别信息。这里提醒一句不同版本和不同封装脚本输出的 JSON 结构不一定一致我踩过一次把 RLE 当成普通数组去解析的坑转换脚本跑了一半才报警。所以拿到一个不熟悉的输出格式第一件事不是写转换函数而是打印一条记录看看结构。这一步看起来慢实际上能省掉后面最痛苦的排错时间。我自己一般会写一个很小的转换脚本把它转成 X-AnyLabeling 能识别的格式或者直接转成 COCO 格式import json with open(annotations.json) as f: data json.load(f) # 这里按实际字段结构调整 for image_id, image_name in enumerate(data[images]): print(image_id, image_name) for ann in data[annotations]: print(ann[category_name], ann[bbox], ann[segmentation])转换完成后我建议先把它放进 X-AnyLabeling 打开一遍千万不要直接拿去训练。即使 Grounded-SAM 在测试集上看着效果不错真实业务数据里总会在某个角落出现类别混淆。在标注工具里过一遍相当于给数据集上了第一道保险。4. autodistill让基础模型替你打工再蒸馏出小模型4.1 蒸馏思路为什么适合数据标注autodistill 的核心思路是先用一个能力很强但昂贵的基础模型去自动标注你的数据然后用这些数据训练一个能力足够但便宜的小模型。这个思路听起来像知识蒸馏但在数据标注场景下它的价值更直接——你要的不只是一个小模型而是一条可以持续产出标注数据的生产链路。我理解它的收益其实来自两头。一头是基础模型不需要训练开箱即用省去了前期整理人工标注数据的过程另一头是目标小模型训练完之后推理成本可能降低一个数量级之后处理新增数据就可以脱离大模型在小模型基础上配合人工抽检继续迭代。等到业务场景变化或者类别列表调整再回到基础模型重新生成一轮数据形成一个闭环。4.2 ontology 定义与基础模型选择autodistill 的使用习惯是从定义一个 ontology本体/类别描述开始的。我用过的一个版本是这样写的pip install autodistill autodistill-grounded-samfrom autodistill_grounded_sam import GroundedSAM from autodistill.detection import CaptionOntology ontology CaptionOntology({ person: person, hard hat: hard-hat, })左边的字符串是基础模型理解用的自然语言提示右边是最终数据集里的类别名。这一步要特别注意左边的提示词不要偷懒直接复制类别名一定要写成基础模型更容易理解的自然语言描述必要时可以给同一类别配多个提示词比如car和sedan car同时映射到car能明显提升召回率。基础模型的选择也不是越多越好。我实际横向测过几类简单来说如果你只做目标检测且类别是常见物体GroundedSAM 组合是好选择如果你的类别非常小众或者描述困难建议换用 DETIC 这类更强调零样本分类的模型。不要一上来就堆一个大模型先拿一个 100 张的小批次跑通流程再决定是否换更强的底座。4.3 从自动标注到目标模型训练的完整代码流程下面是我跑通的一个最小流程数据文件夹里放着未经标注的图片autodistill 会直接在图片旁边生成对应的标注文件from autodistill_grounded_sam import GroundedSAM from autodistill.detection import CaptionOntology from autodistill_yolov8 import YOLOv8 ontology CaptionOntology({ pill bottle: bottle, medicine box: box, }) base_model GroundedSAM(ontologyontology) dataset base_model.label( input_folder./raw_images, output_folder./labeled_dataset, )执行完之后./labeled_dataset里会有一个自动标注好的数据集图片和标注文件已经排好目录结构。接着直接训练目标模型target_model YOLOv8(yolov8n.pt) target_model.train(./labeled_dataset, epochs50)训练完成后这个目标模型就可以接手下一批数据的预标注。autodistill 框架的好处在于它把用大模型标注和用小模型训练两件事的接口统一了如果你后续想换目标检测器或者换基础模型代码结构几乎不用大改。不过有一点必须提醒框架的版本迭代很快API 字段在不同版本之间可能变化比如CaptionOntology和新的Ontology写法我现在写的代码到了你本地上可能微调一两个参数这是正常现象不要慌看两眼官方示例就能对上。5. 把它们串起来一个 2000 张图片的实际标注流程复盘5.1 流程设计预标注、人工修正、二次挖掘说完了每个工具我把它们串成一个完整流程以我实际做过的两千张药品包装图片项目为蓝本。第一步用 Grounded-SAM 跑第一轮预标注。这个阶段不追求完美目的是把图片里的主要目标先捞出来阈值我故意调得偏低接受一部分误检。跑完之后人工在 X-AnyLabeling 里抽检 10% 的数据看看漏检严重还是误检严重做一次阈值小调整。第二步把 Grounded-SAM 的输出转成 X-AnyLabeling 项目能识别的格式人工逐张校对。这一步是整套流程里耗时最长的但因为你是在改别人的结果而不是从零画速度会快很多。我当时的统计是第一阶段自动标注用了一个多小时人工校对花了差不多两天但最后的标注质量反而比纯手工更稳定因为每张图的标准都是对着同一套模型输出校正出来的风格偏差小。第三步把校对完的标注结果导出成 COCO 格式先在 X-AnyLabeling 里用脚本做一次完整性校验比如检查是否有空类别、类别顺序是否和约定一致、是否有超出图片边界的框。校验通过后丢到训练脚本里训一版 YOLOv8n。第四步用训练好的小模型去推断那些不在第一批里的图片生成第二轮预标注。这一轮同样进 X-AnyLabeling 校对但人工工作量明显比第一轮少因为小模型在一个场景里的表现只会越来越稳。后续有新增数据就继续走这个循环。5.2 效果实测三个环节的时间分布与收益我整理了当时的粗略时间统计环节耗时说明Grounded-SAM 批量预标注约 1.5 小时2000 张图GPU 单卡含初期权重下载X-AnyLabeling 人工校对约 2 天两人轮流人均每天 500 张左右autodistill 目标模型训练与二次标注约 1 天包含训练、推理、抽检纯手工标注对照组估约 3 周按一张实例分割图 40 秒估算只看数字自动加人工的方案不一定比纯人工快出一个数量级但真正拉开差距的是后续纯手工标注到第 500 张的时候已经积累了一套完整的标注习惯可以随时用来训练一个不错的模型而纯手工方案要全部标完才有数据可用。这种提前收敛的现金流价值在项目时间表上是致命的。5.3 这类流程适合哪些业务不适合哪些业务我用了好几轮之后对这套流程的适用边界有一个很明确的判断。适合的场景包括目标类别是有限集合且外观可描述的图片背景相对可控的对分割边界精度要求不是病理级严苛的数据量大但人工标注资源紧张的。不适合的场景我也踩过类别之间差异极其细微、需要领域专家才能区分的目标边缘和背景颜色完全相同、SAM 无法从框内区分出边界的以及每个目标都要标到像素级无瑕疵的高精度业务。这些场景下自动标注产出的初稿要么太脏要么需要长时间精修省下来的时间又赔回去了。所以我在设计流程时从来不自欺欺人地说全自动标注完成。真正的表述是自动生成初稿 人工校对终稿这个定位让团队里的每个人都没有幻觉也知道人工校对环节不可删除。6. 生产环境里的坑和我的取舍建议6.1 阈值、提示词和类别平衡最容易翻车的地方自动标注翻车通常不是模型跑崩了而是指标选择错误。我把最常见的几类问题列出来一是低阈值导致的背景误检。尤其在做分割标注时低阈值会把像是目标的背景纹理也圈进来。这时候不要只盯着少数误检案例调参数而是应该抽一批人眼扫一遍统计误检率占比再决定是不是阈值开太低。二是提示词过泛导致的类别污染。比如你想标black cable提示词写cable模型会连白色线缆也画出来但写black cable .又可能在暗色背景下漏检。我一般会在本体定义里同时保留 2 个变体提示词然后在验证集上对比召回选胜出的那组。三是类别不均衡。自动标注模型天然偏向易检测的类别数据里 80% 是A 类大目标可能最后生成 90% 的 A 类标注。这不是 bug是真实分布。对策是在第二轮训练时手动做采样平衡别等到训练时才发现类别全崩了。6.2 GPU 资源、权重管理与多目标场景显存是另一个现实问题。Grounded-SAM 要同时加载 Grounding DINO 和 SAM两个模型加起来对显存的胃口不小。我的解决方案是分割模型优先用轻量版本检测模型不动图片长边统一缩放到 1024 像素左右batch size 固定为 1。在 8GB 显存的卡上这种方法虽然慢一点但能稳定跑完。权重管理也要养成习惯。所有模型权重统一放一个目录命名带版本号不要散落在各个项目里。我见过同事为了节省磁盘空间把 SAM 权重删了结果下次跑流程又花了半天重新下载这种时间成本完全是不必要的。多目标并存的场景要格外注意 NMS 阈值。有一次我处理货架上的商品商品挨得极近NMS 阈值设高了之后相邻的两个商品被并成了一个框分割掩码直接横跨两个物体人工修正比重新标注还费劲。后来把 NMS 阈值降下来再配合小目标专用策略才把这个问题压住。6.3 我的原则自动标注是预标注不是免标注整个流程跑下来我最想分享的体会不是哪个工具好用而是一个工作原则自动标注系统永远只能做初稿人工抽检和终审不可删除。原因很朴素基础模型的能力上限不是你的业务上限。你的数据里总有一些目标是公开模型没有充分训练过的你的业务方对于边界多贴一个像素是有验收标准的你最终要交付的训练集必须达到某种一致性。这些都不能靠一个通用模型自动保证。所以我建议每个项目阶段都定一个人工抽检的比例。冷启动阶段人工逐张校对比例 100%第一轮小模型出来后新数据校对比例降到 50%等到模型在同类场景稳定跑赢基础模型再逐步降到 30%。这个比例不是拍脑袋定的而是我拿误检漏检率倒推出来的安全线。低于 30% 的时候数据里的噪声就开始在训练指标上露面了。最后再分享一个小技巧我会在每轮自动标注开始前固定抽 50 张图作为质检基准集人工完成一次精标之后每轮自动标注结果都拿这 50 张图做对比。哪个模型版本效果变差了、哪个提示词调整让召回上升了一目了然。数据标注工作看起来是体力活但它其实是整个模型项目里最值得投入的复利环节前期每一分对流程的打磨都会在后期的每一轮训练里还回来。