简介:这份资源面向目标检测方向的学习者与工程实践者,提供一套基于YOLO系列的半自动标注数据集代码,用于缓解大规模图像标注耗时耗力的问题。其核心思路是先人工标注少量样本训练出初版模型,再用模型对剩余图像做预标注,最后人工复核修正误检,从而显著降低标注成本。压缩包共5个文件,约7KB,包含2个Python脚本、1个yaml数据集配置文件、1个使用说明txt及1个系统隐藏文件,脚本分别承担自动标注与单图检测功能,配置文件用于指定数据集路径与类别信息。资源已获得523人学习关注,说明其在数据标注场景中具有一定实用价值。读者可据此快速搭建预标注流程,理解模型权重加载、图片路径与xml输出路径的配置方式,并掌握从少量标注到批量预标注再到人工校验的完整工作流,适合需要处理大批量图像标注任务的目标检测开发者参考使用。
1. 半自动标注这套代码,到底省的是哪一段人力
手上接过一个身份证检测的项目,两万张图,客户催着两周出标注。纯手工拉框,一个人一天撑死标八百张,算下来得二十五天,直接翻车。后来换了个思路:先手标三百张训练一版 YOLOv5,拿初版模型去预测剩下的图,把预测框直接写成 XML,再人工过一遍修正误检漏检。这套yolov5自动标注.zip干的就是中间这段——把模型预测结果批量转成标注文件,省掉的是「从零画框」这一步,留下的是「检查修正」这一步。
它适合两类人:一类是数据集量大、标注预算有限的目标检测从业者,另一类是已经有一版能跑的 YOLOv5 权重、想快速扩充数据集的算法同学。包里东西不多:auto_label.py是主脚本,detect_image_only.py是纯推理的辅助脚本,custom_data.yaml是数据集配置,外加一份使用步骤说明.txt。核心逻辑就一句话:读图、推理、把检测框按 VOC 的 XML 格式落盘。下面把它拆开讲清楚,包括参数怎么改、坑在哪、怎么验证标出来的东西能不能用。
2. 从权重到 XML:auto_label.py 的推理链路与参数落点
2.1 为什么是「先训少量再预标注」而不是直接上大模型
很多人第一反应是找个通用检测模型直接标,比如 COCO 预训练的权重。问题是通用模型的类别和你自己的目标对不上——身份证、工牌、特定零件这类目标,COCO 里根本没有对应类,模型要么不框,要么框成一堆无关的东西,预标注的可用率极低,人工修正的成本比从零标还高。
半自动标注的前提是「领域内先验」。你手标的那三百张,作用不是凑数,是让模型学会你这个场景下目标长什么样、在什么位置、什么尺度。三百张听起来少,但对于单一类别、背景相对固定的场景(身份证、卡片、面板类),YOLOv5 微调后 mAP 能到一个可用的水平,预标注的召回率通常能到七八成,剩下两三成靠人工补。这个比例下,总工时能压到纯手工的三分之一左右。
选 YOLOv5 而不是更新的版本,是因为这套脚本的推理接口是按 YOLOv5 的DetectMultiBackend和non_max_suppression写的,权重格式、输入尺寸、置信度阈值的处理都对齐了 v5 的约定。你换成 v8 或 v11 的权重,加载那一步就可能报错,除非自己改推理部分。所以这份代码的边界很清楚:权重必须是 YOLOv5 训练出来的.pt。
2.2 四个必须改对的路径参数
脚本第 62 到 65 行是全部需要你动手的地方,四个变量对应四个路径。原文给的是相对路径写法,实际跑的时候建议全改成绝对路径,避免工作目录不一致导致的找不到文件。
# auto_label.py 第 62-65 行附近 path = r"auto_label/images" # 待标注图片所在目录 xml_path = r"auto_label/images" # 输出的 xml 标注文件保存目录 yolo_model_weight = './weight/IDCard_v6x_best.pt' # 训练好的 YOLOv5 权重 data_conf = './data/custom_data.yaml' # 数据集配置文件逐个说清楚:
path是输入目录,脚本会遍历这个目录下的图片。注意它一般只扫一层,如果你的图按子文件夹分好了,要么改成递归遍历,要么先把图拍平到一个目录里。我一般会先ls auto_label/images | wc -l确认图片数量,跑完再对一遍 XML 数量,数量对不上就是有图被跳过了。
xml_path是输出目录。原文把它和输入目录写成同一个,意味着 XML 会和原图混在一起。图少无所谓,图多了目录会很乱,而且下一轮如果拿这个目录当输入,脚本可能把 XML 也当图片去读。稳妥做法是单独建一个auto_label/xml目录。
yolo_model_weight指向你的.pt权重。这里有个容易忽略的点:权重里保存的类别名和custom_data.yaml里的names必须一致,否则写出来的 XML 里类别名会错位,人工检查时看到的标签是错的,后面训练直接污染数据集。
data_conf是数据集配置文件,YOLOv5 推理时用它来拿类别数和类别名。它的结构就是标准的 v5 格式:
# custom_data.yaml path: ../datasets/custom train: images/train val: images/val nc: 1 names: ['idcard']nc是类别数,names是类别名列表。推理阶段其实只用到nc和names,train/val路径填不填不影响跑通,但建议填对,方便你后面直接拿这个 yaml 去训练。
2.3 推理到 XML 的转换逻辑
脚本内部做的事,拆开就是三步:加载模型、逐图推理、把框写成 XML。推理部分用的是 YOLOv5 的标准流程,输入尺寸默认 640,置信度阈值和 NMS 的 IoU 阈值在脚本里通常有默认值。转换部分是把归一化的xywh还原成像素坐标,再按 VOC 的 XML 结构写出来。
# 推理与坐标还原的核心逻辑(示意,实际以脚本为准) img = cv2.imread(img_file) results = model(img, size=640) # 输入尺寸,小目标可调大 pred = non_max_suppression(results, conf_thres=0.25, iou_thres=0.45) for det in pred: if det is not None and len(det): # det 的 xywh 是相对原图的归一化坐标 det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img.shape).round() for *xyxy, conf, cls in det: # 写进 XML 的 bndbox ...conf_thres是置信度阈值,默认 0.25。这个值直接决定预标注的松紧:调低,召回高但误检多,人工要删一堆框;调高,误检少但漏检多,人工要补一堆框。身份证这种目标清晰、背景简单的场景,我一般会把它提到 0.4 到 0.5,宁可漏一点也别让误检淹没人工。iou_thres是 NMS 的重叠阈值,默认 0.45,目标密集、容易框重叠的场景可以适当调低。
scale_coords那一步是把模型输入尺寸下的坐标映射回原图尺寸。如果你的原图分辨率特别大(比如 4000 像素宽),而推理尺寸只有 640,小目标在缩放后会糊掉,检测效果打折。这种情况要么把推理尺寸提到 1280,要么先把大图切块再标。
2.4 跑通第一轮并核对结果
改完参数直接跑:
python auto_label.py跑完先别急着人工检查,做两件事核对。第一,数 XML 文件个数,和输入图片数对比:
ls auto_label/images/*.jpg | wc -l ls auto_label/xml/*.xml | wc -l两个数应该相等。少了说明有图读取失败或推理异常,去看终端有没有报错。第二,随便打开一个 XML 看结构对不对:
<annotation> <folder>images</folder> <filename>0001.jpg</filename> <size> <width>1920</width> <height>1080</height> <depth>3</depth> </size> <object> <name>idcard</name> <bndbox> <xmin>412</xmin> <ymin>233</ymin> <xmax>1508</xmax> <ymax>842</ymax> </bndbox> </object> </annotation>重点看name是不是你的类别名、bndbox的四个值有没有超出图片宽高。如果xmax大于width,说明坐标还原那步有问题,通常是scale_coords的输入尺寸传错了。这一步核对花两分钟,能省掉后面返工几小时。
3. 预标注结果怎么验、怎么修、怎么进训练集
3.1 用 detect_image_only.py 做可视化抽检
XML 是给训练用的,肉眼看不直观。包里那个detect_image_only.py就是干这个的——它只做推理并把框画在图上,不写 XML。用它抽检几十张,能快速判断预标注的整体质量。
python detect_image_only.py --weights ./weight/IDCard_v6x_best.pt \ --source auto_label/images --conf 0.4--source可以是单张图、目录或通配符。--conf和主脚本里的阈值保持一致,这样看到的框和写进 XML 的框是同一批。抽检时重点看三类问题:漏检(该有的目标没框)、误检(背景被框了)、框不准(框偏大偏小)。如果漏检集中在某个尺度或某种光照条件下,说明训练样本没覆盖到,得补标这类图再重训。
3.2 人工修正的取舍:哪些框值得改
预标注不可能全对,人工检查要有优先级,不然两万张图逐张精修,省下来的时间又还回去了。我的做法是分三档:
高置信度且框位置合理的,直接过,不动。这类通常占六七成,是省下来的主要工时。
置信度中等、框大致对但边界有偏差的,微调四个坐标。这类占两三成,改起来快。
漏检和明显误检的,手动补框或删框。这类占一成左右,是最花时间的部分,但量小。
修正工具用 LabelImg 或 Labelme 都行,它们能直接读 VOC 的 XML,改完存回去格式不变。注意 LabelImg 默认可能存成 YOLO 的 txt 格式,要在设置里切回 PascalVOC,否则格式混了后面训练读不进去。
3.3 修正后的数据集怎么组织进 YOLOv5 训练
修完的 XML 要转成 YOLOv5 训练用的 txt 格式(每行cls x_center y_center w h,全部归一化)。v5 官方仓库里有voc2yolo.py之类的转换脚本,也可以自己写一个,逻辑就是把 XML 的绝对坐标转成归一化中心点格式。
# xml 转 yolo txt 的核心换算 w = xmax - xmin h = ymax - ymin x_center = (xmin + xmax) / 2 / img_w y_center = (ymin + ymax) / 2 / img_h w_norm = w / img_w h_norm = h / img_h转换完按images/train、labels/train、images/val、labels/val的目录结构放好,custom_data.yaml里的路径指过去,就能直接开训。第二轮训练出来的模型比第一版强,可以再拿它去标剩下的图,形成迭代。这就是半自动标注真正的价值——不是一次省力,是每轮都在滚雪球。
提示:每轮迭代后,把人工修正过的图单独留一份,作为下一轮的验证集。这样你能量化地看到模型是不是真的在变好,而不是凭感觉。
4. 避坑:这套脚本跑起来最容易翻车的五个地方
4.1 权重类别和 yaml 对不上,XML 里全是错标签
现象:跑完打开 XML,name字段是person、car这种,但你明明只标身份证。
原因:custom_data.yaml里的names和权重训练时的类别顺序不一致。YOLOv5 的类别是按索引对应的,权重里names[0]是idcard,你 yaml 里names[0]写成了别的,写出来的标签就错位。
解决:打开权重训练时用的那个 yaml,把names原样抄过来。不确定的话,用python -c "import torch; ckpt=torch.load('xxx.pt'); print(ckpt['model'].names)"把权重里的类别名打出来,以它为准。
4.2 输入输出同目录,第二轮把 XML 当图片读
现象:第一次跑正常,第二次跑报错说读不了某张图,或者 XML 数量翻倍。
原因:path和xml_path设成了同一个目录,第一轮生成的 XML 混在图片里,第二轮遍历时把 XML 也当输入了。
解决:输入和输出目录分开,xml_path单独建一个目录。已经混了的,用find . -name "*.xml" -delete清掉重跑。
4.3 大分辨率图小目标漏检严重
现象:原图 4K,目标只占几十个像素,预标注几乎框不到。
原因:推理尺寸默认 640,大图缩到 640 后小目标信息丢失。
解决:把推理尺寸提到 1280 甚至 1536,代价是显存和耗时上升。显存不够就切块推理,把大图裁成带重叠的小块分别标,再合并。或者干脆在训练阶段就用切块后的图,让模型适应小目标。
4.4 置信度阈值照搬默认值,误检淹没人工
现象:预标注框一大堆,人工删框删到手酸,比从零标还累。
原因:conf_thres用了默认的 0.25,对简单场景太松。
解决:先拿几十张图试不同阈值,看误检和漏检的平衡点。身份证这类场景从 0.4 起调,逐步往上加,直到误检明显减少而漏检还能接受。这个值没有标准答案,取决于你的场景和人工成本。
4.5 坐标超出图片边界,训练时报越界
现象:训练时提示某个 label 的坐标大于 1 或小于 0。
原因:scale_coords还原时输入尺寸传错,或者原图有 EXIF 旋转信息导致宽高读反。
解决:转换前统一用 PIL 读图并ImageOps.exif_transpose处理旋转,确保宽高和实际像素一致。转换后加一道校验,把x_center、y_center、w、h不在(0,1]区间的行打出来,人工确认是丢弃还是修正。
5. 把预标注接进迭代闭环:一个可复用的阈值调优技巧
这套代码跑通不难,难的是让它每一轮都比上一轮省力。我踩过最大的坑是:第一版模型标完,人工修完直接拿去训练,第二轮模型没变好多少,因为修正的样本和原始训练集混在一起,模型学到的还是老分布。后来改了个做法,把「预标注—人工修正—重训」当成一个闭环来管,效果才稳定下来。
具体操作是维护三个集合。seed是最初手标的那三百张,永远留在训练集里,保证基础分布不漂。auto是每轮预标注后人工修正过的图,按轮次打标签,比如auto_r1、auto_r2。hard是每轮里漏检和误检最严重的那批图,单独拎出来,下一轮训练时给更高的采样权重。这样模型每轮都在补自己的短板,而不是在已经会的样本上重复。
阈值这块也有个可复用的调法。不要一次定死conf_thres,而是每轮跑三个值——比如 0.3、0.4、0.5——各标一小批(一两百张),统计人工修正的耗时。哪个阈值下「预标注可用框数 / 总框数」最高、人工改动最少,就用哪个。随着模型变强,最优阈值会往上走,因为模型的置信度越来越可信。我一般每两轮重调一次,把当前最优值记在使用步骤说明.txt旁边,免得下次忘了上轮用的多少。
# 批量试三个阈值,分别输出到不同目录对比 for c in 0.3 0.4 0.5; do python auto_label.py --conf $c --xml_path auto_label/xml_c$c done跑完对比三个目录里 XML 的框数量和抽检图,选人工负担最小的那个。这个循环跑上三四轮,预标注的可用率通常能从最初的六七成提到九成以上,人工基本只剩微调。
注意:每轮重训前,务必把验证集固定下来,不要用当轮预标注的图当验证集,否则指标虚高,你会误以为模型已经很好。
从那以后我每次接标注量大的项目,都强制先跑一轮半自动标注的闭环,哪怕只有几百张图也先走一遍流程,确认阈值和目录结构没问题再放量。这套yolov5自动标注.zip里的脚本不复杂,但把「先训少量、再预标注、人工修正、迭代重训」这条链路串起来了,省下的是实打实的画框时间。希望帮到你。
本文还有配套的精品资源,点击获取