干这行久了,你会发现真正决定YOLO系列检测模型能不能落地的人,往往不是那个写网络结构的人,而是那个在后面做数据集的同事。模型结构再强,喂进去的标注乱七八糟,训练时loss掉不下去,测试时mAP上不来,最后背锅的还是“数据不行”。所以在做YOLO26这类新版本项目时,我拿到手的第一件事永远不是改网络,而是把数据集结构和标注流程从头捋一遍。这篇内容就围绕YOLO26训练自己的数据集展开,重点讲数据集怎么收集、标注怎么做、格式怎么转换、坑在哪里,全程按我实际做项目的顺序来,适合已经装好YOLO26环境、正准备整理训练数据的同学。
我默认你对目标检测和YOLO有基本概念,不需要知道网络内部每个模块的数学推导,但至少你要能跑通一个demo。如果连训练命令还没run过,先把环境弄好,再回头看数据部分也不迟,因为数据集和标注这块工作,说难不难,但一旦跑偏,后期返工成本非常高。
1. YOLO26项目的数据集设计:先想清楚再动手
很多人做自己的数据集时有个习惯,先把图片堆在一起,找标注工具画框,画完就训练。这种流程跑demo没问题,但如果是个人项目、大作业或者公司项目,最后一定会在某个环节卡住。不是标签格式不对,就是类别忘记统一,最麻烦的是发现正样本太少,模型根本学不出来。
1.1 明确检测任务与数据形态
动手标第一张图之前,先想清楚你要检测什么、在什么场景下检测。YOLO26沿用了YOLO系列的anchor-free架构思维和通用检测流程,但它对不同数据形态的容忍度差别很大。比如你要做的是自然场景下的行人检测,那通用监控摄像头或者手机拍的街景图都能用;但如果你负责的是高空无人机视角的小目标检测,那俯拍角度、光照条件、目标尺度跟普通图片完全不同。
我自己做项目时习惯写一份简单的任务说明,记录下面几件事:
- 目标类别:目标类别列表长什么样,比如“gun、knife、bottle”,或者“person、car、bicycle”。
- 检测场景:室内、室外、红外、X光安检机、无人机俯拍还是卫星遥感。
- 目标尺寸范围:研究对象在图片里是大目标还是小目标,占比大概多少。
- 视角和相机位置:平视、俯视、还是多视角混合。
- 标注粒度:要矩形框、旋转框、分割掩码,还是只需要一个关键点。
这些约束直接决定你选公开数据集还是自己采集,决定你用普通矩形标注工具还是旋转框工具,也决定你后续需不需要额外做图片切片。否则到了建模环节会发现自己花了大量时间清理低质量图片,反而把项目周期拖慢。
有一个很典型的例子:X光安检物品检测。这类图片跟自然图像完全不同,背景是统一的透视成像,物品互相堆叠严重,遮挡非常多。如果你只是随手找普通图片来凑数,训练出来根本没法在安检机上用。所以做数据集之前一定得搞清楚成像设备和真实分布。
1.2 数据来源与合规获取
数据集的获取渠道通常分三类:公开数据集、自己采集、合成数据。
公开数据集是起步最快的方式。做通用物体检测,COCO官网数据集和VOC数据集基本是首选。COCO的标注是json格式,类别有80类,适合做迁移学习或者预训练;VOC数据集是xml标注,类别20类,很多人拿它做YOLO系列的数据集练习。
如果是特殊业务场景,可以找垂直数据集。比如X光安检物品检测数据集,很多开源项目里都已经整理成VOC和YOLO两种格式;无人机视角的人车检测也有不少公开数据,遥感领域有DOTA数据集,里面是旋转框标注。用的时候注意看协议,很多学术数据集只允许科研用途,商用还要单独申请授权。
如果你要做的是非常具体的项目,比如“检测厂区里人员有没有戴安全帽”,公开数据集大概率不够,需要自己采集。自己采集时有几个细节我吃过亏:
- 不要只在晴天中午拍,要有阴天、逆光、傍晚、夜晚补光等不同光照条件。
- 不要只从固定机位拍摄,模型很容易学到“只在画面下半部分出现目标”这种错误规律。
- 采集视频后抽帧要注意时间间隔,别从连续帧里抽太密,否则训练集和验证集之间高度相似,测试结果虚高。
合成数据是这几年越来越常用的补数据方式,用3D渲染或图像拼接生成大量带标注样本。生成式模型也可以帮忙扩场景,但一定要人工检查,因为AI生成图片里可能出现结构错乱的物体,反而把模型带偏。
1.3 数据量、类别分布与难例样本
YOLO26这类新模型对数据量的要求并没有传说中那么夸张。如果做单类目标检测,样本质量高、场景覆盖合理,几千张图可以训到能用的水平;但如果做多类检测,每个类别几百张图、每张图只有一个小目标,那某个类别很容易出现欠拟合。
更科学的目标是给每个类别建立一个基本盘。比如类别A出现500次、类别B出现500次、类别C出现500次,这里“次”指的是标注框数量,不是图片数量。我见到很多人统计数据集时只看图片数量,忽略了框数量,结果有的类每张图10个框,有的类每张图只有0.1个框,模型自然会偏向高频类。
类别不平衡的解决办法常用重采样、重复增强、加入更多难例。难例样本指的是那些遮挡严重、目标模糊、背景干扰大的样本。有些人喜欢把难例剔掉,觉得标注起来麻烦,但模型真正到现场常常挂在难例上。训练集里保留一定比例的难例很有必要,验证集里也要刻意放一些有挑战的图,免得模型自我感觉良好,一到测试就崩。
2. 标注格式与工具选型:从LabelImg到CVAT
标注是数据集构建中最耗时、最枯燥、也最容易出错的一步。第一次画框的人可能觉得这有什么难的,把物体框住就行。真正做过就会明白,边界画到哪里、遮挡目标怎么处理、极小目标要不要标,这些都需要一套规则。没有规则的数据集,训练过程就是玄学。
2.1 三种主流标注格式对照(VOC/COCO/YOLO)
VOC格式是xml文件,每个图片对应一个标注xml,记录图片路径、尺寸、目标类别和边界框坐标,边界框坐标是绝对值,单位是像素。
YOLO格式是txt文件,每行一个目标,格式是“class_id x_center y_center width height”,其中坐标经过了归一化,数值在0到1之间,类别从0开始编号。YOLO26训练自己的数据集时,用的一般就是这种格式。
COCO格式是一个大json文件,包含images、annotations、categories三个主要字段。images字段存的是所有图片信息,比如id、宽高、文件名;annotations字段把每张图上所有标注框统一管理,每个框的坐标格式是[x, y, width, height],这里的x和y是左上角坐标,没有归一化。
三种格式之间经常互相转换,转换时最常出问题的就是坐标换算。VOC转YOLO时,中心点坐标等于(xmin + xmax) / 2除以图片宽度,框宽等于(xmax - xmin)除以图片宽度。这个公式别看简单,日期一长、脚本一复杂,有人就会把左上角坐标直接除以图片宽度当成归一化结果,出来的框全偏。
下面是我常用的一张转换对照表:
| 格式 | 存储方式 | 坐标定义 | 归一化 | 适合场景 |
|---|---|---|---|---|
| VOC | 每张图片一个xml | xmin, ymin, xmax, ymax | 否,绝对像素 | 数据公开、传统模型 |
| COCO | 整个数据集一个json | x, y, width, height | 否,绝对像素 | 大规模数据集、检测与分割 |
| YOLO | 每张图片一个txt | x_center, y_center, width, height | 是,0~1 | YOLO系列训练 |
2.2 常用标注工具横向对比
标注工具现在选择很多,不用死守某一款。推荐几款主流的,按项目规模选。
LabelImg是老牌工具,图形界面简单,适合个人标注几百张图玩一玩。支持VOC和YOLO格式导出,画框操作直接,但使用时会发现一些体验问题:批量操作弱、多人协同基本没有、工程化能力不足。数据量超过1000张还要找别人帮忙标,就别用LabelImg,效率太低。
Make Sense.ai是浏览器端工具,不需要安装,把图片拖进页面就能画框,支持VOC、COCO、YOLO格式导出。胜在零门槛,适合快速样板标注,但因为数据都在浏览器里跑,太大的数据集会比较卡。
CVAT是我现在的主力工具,它开源自Intel,支持图片、视频、多人协同、复杂标签体系,还内置了自动标注和插值功能。CVAT对矩形框、多边形、关键点、分割掩码都有支持,适合中大型项目,也适合教学和团队协作。部署可以选择Docker自托管,也可以用官方在线版,但线上版有上传大小限制,数据敏感的话还是建议本地部署。
Label Studio偏文本和多模态标注多一些,如果是纯目标检测标注,它的矩形框功能够用,但我个人更习惯把Label Studio留给文本项目,图像检测统一用CVAT。
标注工具的选型不是越专业越好。如果你的项目就是课程大作业,数据量几百张,Make Sense.ai和LabelImg完全够用。如果项目是真实落地场景,后面还要不断迭代数据,那直接上CVAT,省得后面迁移平台。
2.3 实操心得:用CVAT做多人标注与二次审核
多人协作标注时,最容易出现的问题是“每个人对目标的定义不一样”。比如标注“人骑自行车”这个目标,有人认为人和自行车应该分开框,有人认为应该合并成一个主体。如果队伍里没有统一规则,最后得到的模型就会学到混乱的语义。
我的做法是先起草一份标注规范,重点内容包括类别定义、几何边界规则、遮挡与截断处理规则、极小目标处理规则。比如规定:“截断目标只要可见区域大于完整目标面积的50%就必须标注”“边界框必须紧贴可辨识区域,不能把大幅背景包进来”。标注规范写完,先让几个人各标50张图,计算一下标注一致性。一致性的粗略算法很简单:两个人分别标同一批图,计算检测框IoU,如果同类目标框IoU平均值低于0.7,说明规则没定义清楚,需要回炉。
在CVAT里分配任务时,我会把同一批图同时分配给不同标注员,然后开启“任务复核”功能。标注完成后由审核人逐张检查,发现问题直接标记返修。还要利用CVAT的job管理能力,把按批次导入的图片划分成多个task,每个task绑定一组标注员,避免一张大任务拖到最后集中爆发。
实操中强烈建议在标注前,先加载一个训练好的YOLO模型到CVAT做预标注,标注员只需要调整错框和补充漏框。这个功能能把纯手工标注时间压缩到原来的三分之一。预标注有漏检没关系,因为漏掉的框就是模型当前的盲区,优先补充给标注员,反而能有效提升后续迭代效果。
3. 核心实操:构建一个自己的YOLO26训练集
前面讲了理论和方法,接下来用一套我自己整理过的X光安检物品检测为例,记录完整流程。我不展开训练内容,只聚焦数据集和标注部分。这个例子同样适用于无人机视角、人员入侵检测、垃圾分类等场景,只要把类别和目录换掉就行。
3.1 示例场景:X光安检物品检测数据集整理
项目背景是做一个安检场景下的物品检测,目标类别包括gun、knife、bottle、lighter等几类。收集到的原始图片来自公开的X光安检物品检测数据集,里面已经有一部分整理成VOC和YOLO格式,但我需要先统计数据分布,决定要不要补充难例。
拿到数据后的第一步永远是统计。我会写一段脚本,把每张图片的xml或者txt读进来,统计每个类别的框数量、图片尺寸分布、每张图中的目标数量。
import os from collections import defaultdict label_dir = 'labels/train' class_count = defaultdict(int) image_count = 0 for filename in os.listdir(label_dir): if not filename.endswith('.txt'): continue image_count += 1 with open(os.path.join(label_dir, filename), 'r', encoding='utf-8') as f: for line in f: parts = line.strip().split() if len(parts) >= 5: cls_id = int(parts[0]) class_count[cls_id] += 1 print('图片数量:', image_count) print('各类别标注框数量:', dict(class_count))运行之后如果发现gun类别只有100个框,knife类别有1200个框,就需要针对性做数据增强或者采集补充,否则训练出来的gun召回率会很惨。
这里给一个值得参考的数量阶梯。类别少、目标尺寸大、背景简单时,每个类别至少保留200~400个标注框。类别多、目标遮挡严重、背景复杂时,每个类别尽量到800个框以上。如果实在没有那么多,可以先用公开数据做预训练,再在自己的小数据集上微调,但过拟合风险要自己控制。
3.2 标注结果转换与清洗脚本
原始数据集可能是VOC标注,也可能是COCO标注,但YOLO26通常接收的是一张图片对应一个txt文件的YOLO格式。所以我需要一个稳定的转换脚本。
从一个自定义数据集的目录结构说起,规范的目录长下面这样:
dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamlimages文件夹存图片,labels文件夹存与图片同名的txt标注文件,data.yaml里写训练与验证路径、类别数量、类别名称。
把VOC格式转成YOLO格式的脚本我可以直接贴在这里,这是最常用的标准版:
import os import xml.etree.ElementTree as ET classes = ['gun', 'knife', 'bottle', 'lighter'] def convert_voc_to_yolo(xml_file, out_dir, image_width, image_height): tree = ET.parse(xml_file) root = tree.getroot() lines = [] for obj in root.iter('object'): cls_name = obj.find('name').text if cls_name not in classes: continue cls_id = classes.index(cls_name) xmlbox = obj.find('bndbox') xmin = float(xmlbox.find('xmin').text) ymin = float(xmlbox.find('ymin').text) xmax = float(xmlbox.find('xmax').text) ymax = float(xmlbox.find('ymax').text) if xmax <= xmin or ymax <= ymin: continue x_center = (xmin + xmax) / 2.0 / image_width y_center = (ymin + ymax) / 2.0 / image_height w = (xmax - xmin) / image_width h = (ymax - ymin) / image_height x_center = min(max(x_center, 0.0), 1.0) y_center = min(max(y_center, 0.0), 1.0) w = min(max(w, 0.0), 1.0) h = min(max(h, 0.0), 1.0) lines.append(f'{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}') base_name = os.path.splitext(os.path.basename(xml_file))[0] out_path = os.path.join(out_dir, base_name + '.txt') with open(out_path, 'w', encoding='utf-8') as f: f.write('\n'.join(lines))有几个点你要注意。第一,解析的image_width和image_height必须是xml里记录的原始图片真实宽高,不能拿一个变量糊弄过去。第二,坐标越界要自动裁剪到0到1之间,不然YOLO26训练时会把超出范围的框当成错误样本。第三,txt文件最后一行有没有换行不影响训练,但如果你要跑某些检查脚本,统一格式更省心。
另外还需要检查标签文件是否与图片一一对应。常见的问题是下载的数据集里有些图片没有标注文件,这些图默认是背景图,如果少量背景图混入训练集会增加误检负样本,但如果大量背景图混入,模型会偏向预测“什么都没有”,所以背景图数量也要控制。
3.3 数据集划分与验证:让YOLO26乖乖读起来
数据集不能只建train和val,也不能把所有图片都放在train里。标准的划分方式是train:val:test = 8:1:1或者7:2:1。个人项目可以不设test,但至少要留val用来每轮评估。
写一个划分脚本可以自动将图片按比例复制到不同目录:
import os import random import shutil random.seed(2026) source_images = 'raw_images' source_labels = 'raw_labels' train_img_dir = 'dataset/images/train' val_img_dir = 'dataset/images/val' test_img_dir = 'dataset/images/test' os.makedirs(train_img_dir, exist_ok=True) os.makedirs(val_img_dir, exist_ok=True) os.makedirs(test_img_dir, exist_ok=True) all_files = [f for f in os.listdir(source_images) if f.endswith('.jpg') or f.endswith('.png')] random.shuffle(all_files) train_count = int(len(all_files) * 0.8) val_count = int(len(all_files) * 0.1) for i, filename in enumerate(all_files): base_name = os.path.splitext(filename)[0] label_file = os.path.join(source_labels, base_name + '.txt') if not os.path.exists(label_file): continue if i < train_count: out_img_dir = train_img_dir elif i < train_count + val_count: out_img_dir = val_img_dir else: out_img_dir = test_img_dir shutil.copy(os.path.join(source_images, filename), out_img_dir) out_label_dir = out_img_dir.replace('images', 'labels') os.makedirs(out_label_dir, exist_ok=True) shutil.copy(label_file, out_label_dir)分割之后,要做一个完整检查。我每次训练前都会在根目录跑这样一个验证脚本:
- 所有标注文件里的类别索引是否在类别列表范围内。
- 所有标注坐标是否在0到1之间而且宽高为正数。
- train和val的类别分布是否与整体分布大致一致。
- 所有图片能否被OpenCV或PIL正常读入。
- 图片颜色通道是3通道还是灰度图,灰度图需要转成3通道,不然某些预训练权重加载会报形状错误。
做完以上检查,再启动YOLO26训练,你的数据集才算是真正准备好了。
4. 常见问题与排查技巧实录
整理YOLO26数据集和标注的过程中,我踩过不少坑。下面挑几个出现频率最高的问题,做成一份排查记录,你直接把现象和解决方案对照着看就行。
4.1 标注环节翻车现场
第一种情况是“标注框全部偏移”。训练完可视化时发现检测框和真实物体位置差很多,第一反应是模型没收敛,但仔细看训练样本图,它自己的标注框就画歪了。这种问题多半是标注规范没定好。比如要求“边界框紧贴目标可见边缘”,但标注员把红色轮廓也当成gun的一部分框进去,框就偏大;或者目标被遮挡时,本应只框可见部分,有人却脑补了被遮挡区域。
第二种情况是“漏标”。漏标对模型的影响比错标更隐蔽。普通背景下漏标偶尔出现,模型还能兜住;但在密集场景里漏标率一高,很多真实目标被当成背景,导致模型在那些区域输出极低置信度。所以数据标注完成后一定二检,特别是密集人群、货物堆叠这类场景。
我个人的经验是,标注过程要设置“空图复核”。有些标注员看到复杂图片直接跳过不标,结果后台生成了大量只有背景没有目标的图片。YOLO系列训练时背景图占比过高,网络会牺牲对目标的敏感度来降低整体loss,最终表现为find rate下降。
4.2 格式转换的隐藏坑
格式转换真的是重灾区。第一种典型错误是VOC转YOLO时把xmin和xmax直接相加除以2当成中心点,但忘了除以图片宽度,导致标注坐标变成几千的像素值。YOLO26读入txt时一旦坐标大于1,会直接丢弃还是截断,不同实现版本不一样,不论哪种都会污染数据。
第二种典型错误是类别索引不连续。比如你的类别列表是[‘person’, ‘car’, ‘bicycle’],但是txt文件里写的类别是0、1、2,问题不大;但如果你手工整理了很多来源的数据,有人把person记为0,有人把person记为1,而0对应的是另一个类,模型就会彻底混乱。建议转换完以后统计一遍每个类别索引的数量,再和类别名称对应起来看。
第三种是图片尺寸不一致导致坐标失效。YOLO格式默认是归一化的,换了分辨率依然能用,但很多数据集里的txt还是按原图分辨率生成,没有做归一化。转换前必须拿到图片的真实宽高,不能想当然。我用OpenCV读图尺寸的代码如下:
import cv2 img_path = 'some_image.jpg' h, w, c = cv2.imread(img_path).shape print(w, h)4.3 训练表现差?先查数据再看模型
模型训练后精度上不去,很多人立刻去调YOLO26的网络结构或者训练参数,但往往根源在数据。这种情况下我建议按优先级排查:
- 第一看训练集loss和验证集loss是不是差距很大,差距大通常意味着过拟合,问题往往是数据量太少或增强策略不够。
- 第二看loss是否一直在震荡不下降,有可能是标注噪声太高,最好随机挑几十个txt文件,把标注框可视化在图片上,一眼就能看出噪声有多夸张。
- 第三看模型预测结果是否存在类别混淆,例如把bottle识别成lighter,这时候要回看标注样本,看看是不是两个类的边界框经常重叠或者语义不清晰。
排查时不要只盯着一张表格,要有“看预测图习惯”。每训练几个epoch,随便抽几张验证集的图片把预测框画上去,人眼扫一遍比任何指标都更能发现异常。
我用一个表格汇总一下高频问题和解决方案:
| 问题现象 | 常见原因 | 解决建议 |
|---|---|---|
| 训练loss始终不降 | 标注框坐标越界或类别索引错误 | 写脚本清洗txt,随机抽样可视化 |
| 验证mAP高但测试效果差 | 数据划分太相似或测试集场景单一 | 重新划分,确保测试集与训练集场景有差异 |
| 小目标完全检测不到 | 小目标框太少/标注框过小 | 增加小目标样本,使用图像切片策略 |
| 类别之间互相混淆 | 标注语义不清或边界框包含太多重叠背景 | 重写标注规范,人工复检冲突样本 |
| 图片加载报错 | 图片文件损坏或灰度图 | 统一图片格式,预处理转RGB |
| 训练时没有任何数据加载 | 图片目录路径错误或txt文件名与图片名不一致 | 检查data.yaml路径和文件名对应关系 |
5. 进阶:怎么把数据集价值榨干
数据集不是标完一次就结束了,尤其是做YOLO26改进或者人员入侵检测这类真实项目,数据集必须跟着模型一起迭代。很多同学训练一轮之后就认为任务完成,但那样做往往只发挥出数据潜能的三成。
5.1 用预标注降低标注成本
CVAT的自动标注功能很适合做成一个闭环。第一步先拿YOLO26预训练权重或者已经训好的旧模型对一批新图片推理,把结果自动导入标注任务;第二步让标注员只做“修正错框、补充漏框、删除误检”三件事。由于预标注通常能覆盖大部分目标,人工修改量比从头画框少得多。
这个方法要特别注意模型旧预测结果的偏向。如果旧模型对某类目标存在系统性漏检,比如它总是漏掉暗光下的行人,那么新补充样本里这种现象会被保留。应对办法是定期加入对抗性难例,比如主动收集低照度或遮挡严重的图片,单独跑一轮预标注,把模型置信度很低的区域进行人工重点标注。
5.2 多轮迭代与主动学习思路
数据集标注应当分批次进行,不要一次性标注几万张。第一次先用2000张图训练基线模型,然后用模型在未标注数据池里做推理,选出模型最不确定的样本,交给人工标注。不确定性可以来自置信度得分低,也可以来自相邻类别得分接近。把这些样本标好加入训练集,模型精度提升通常比随机加入数据更明显。
这个思路在专业领域叫主动学习,在工业化项目里非常实用。比如大风电场巡检项目,图片数量动辄几万张,如果全量标注预算太高,按不确定性排序只标注顶部部分样本,很可能用一半数据达到接近全量数据的效果。但注意不确定性筛选不能只看平均置信度,因为一些本来就困难的样本即使重复标注也无法稳定学出来,这时候需要人工设定一个难度上限,超过上限就先放弃,等模型结构改进了再回来处理。
5.3 从YOLO26延伸到更多任务的扩展建议
YOLO26系列通常不只做矩形目标检测。你做人员入侵检测时,除了人形框,往往还需要判断人员是否越界,这要结合图像坐标和场景约束。如果你用YOLO26做姿态检测,就要把标注从矩形升级为关键点,关键点标注对像素级精度要求更高,标注工具也要切换成CVAT的关键点模式。
做分割任务时,标注需要用掩码。掩码标注比画框慢得多,这时候可以采用“先画多边形再转换掩码”的方式,不要直接用画笔去涂像素边界。CVAT里可以画多边形标注,导出时转成segmentation格式,效率高很多。
做视觉关系数据集时,标注难度进一步升级,要标注主体框、客体框和二者关系类别,例如“人-骑-自行车”。这类数据的标注规范比单个框复杂得多,任何一方语义模糊都会导致关系分类噪声变大。我的建议是先做目标检测标注,等模型能稳定出框,再做关系推理的数据收集。
我把这些内容放在一篇文章里,其实就是想说明一件事:别把时间全花在调YOLO26的网络参数上,数据集的建造、标注和清洗才是项目稳定性的基本盘。我在实际做项目时发现,每次认真把标注规范多写清楚一点、把格式转换脚本写得更完善一点,后续训练报错和测试返工就会肉眼可见地变少。做YOLO26训练自己的数据集,流程上最难的不是跑通代码,而是每一张图背后那个看不见的标注质量。如果你现在正准备开始标注数据,暂停一分钟,先画一份简易的标注规范出来,然后再去打开工具,后面你会感谢这个决定。