免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

足球数据集VOC与YOLO格式标注:548张小样本目标检测训练全流程

足球数据集VOC与YOLO格式标注:548张小样本目标检测训练全流程 简介这份足球数据集面向计算机视觉初学者与目标检测实践者用于训练和验证足球目标检测模型解决足球场景下标注数据获取困难的问题。资源采用VOC与YOLO双格式标注包含jpg图片及对应的xml、txt标注文件可直接接入主流检测框架进行训练与评估。压缩包共1645个文件其中548张jpg图片、548个xml标注、549个txt标注整体约29.23MB以rar形式打包无需解压密码解压后按图片、xml、txt三个文件夹分类存放便于快速查看与调用。所有图片均由labelImg人工标注类别统一为football标注过程遵循边界框选准确、目标不遗漏、多轮一致性检查等原则标注质量较为可靠。目前已有141人学习下载适合需要快速搭建足球检测基线、验证模型效果或补充训练样本的读者使用。1. 足球数据集 VOC 和 YOLO 格式目标标注 548 张左右这批数据到底能干什么手里拿到一批 548 张左右的足球场景标注数据同时给了 VOC 和 YOLO 两套格式第一反应不应该是「数据量好少」而是先判断它能撑起什么任务。足球场景的目标检测和通用数据集不一样远景机位下球员只有几十像素高足球经常被腿和草皮遮挡球门、角旗、裁判这些类别又天然长尾。548 张如果标注质量过关、类别聚焦做单类别或三到五类的检测微调是够用的尤其是拿来做预训练模型的领域适配、验证某个改进模块比如 efficient head 这类轻量检测头在密集小目标上的收益比堆一个上万张但标注粗糙的集子更靠谱。这批数据同时提供 VOC 和 YOLO 两种格式说明它大概率是从标注工具LabelImg、Labelme 或 CVAT导出后做过一次转换。VOC 的 XML 是绝对坐标YOLO 的 txt 是归一化后的中心点加宽高两者能不能对上、类别 id 有没有错位是拿到数据后第一个要验的东西。这篇就按「先验数据、再转格式、再跑通训练、最后避坑」的顺序把 548 张足球标注数据从落地到出结果的全流程讲清楚适合刚入门 yolo 训练自己数据集的人也适合手里有类似小样本体育数据、想快速验证方案的人。2. 先搞清楚 VOC 和 YOLO 两套标注到底差在哪2.1 坐标表示绝对像素 vs 归一化中心点VOC 格式每张图对应一个 XML里面每个object记录类别名和bndbox的 xmin、ymin、xmax、ymax全是相对原图的绝对像素值。YOLO 格式每张图对应一个 txt每行是class_id cx cy w h其中 cx、cy、w、h 都是除以原图宽高之后的 0 到 1 之间的浮点数。这个差异决定了你在做数据增强、resize、letterbox 时两种格式的处理逻辑完全不同VOC 改图之后必须同步改坐标YOLO 因为归一化只要不裁剪、不改变宽高比resize 之后坐标基本不用动。足球场景里这个问题特别明显。转播画面通常是 16:9如果你训练时统一 resize 到 640×640 而不做 letterbox球员会被横向压扁VOC 的绝对坐标直接失效YOLO 的归一化坐标虽然数值没变但对应的实际像素位置已经错了。所以拿到 548 张数据先确认原始分辨率分布再决定预处理策略比急着写训练脚本重要得多。2.2 类别映射class_id 从 0 开始还是从 1 开始VOC 的 XML 里存的是类别字符串比如player、ball、goalkeeper。YOLO 的 txt 里存的是整数 id。转换时最容易翻车的地方就是类别顺序有的脚本按字母序排有的按标注工具里的创建顺序排一旦训练时的names列表和转换时的顺序不一致模型学到的就是错位的类别。548 张数据里如果足球和球员的 id 被搞反训练 loss 照样下降但推理时会把球框成球员这种问题不看可视化结果根本发现不了。我一般会先跑一段脚本把 VOC 里所有类别名去重排序生成一个固定的classes.txt然后所有转换、训练配置都以这个文件为唯一来源。这样即使后面加数据、改类别也不会出现 id 漂移。2.3 一个最小校验脚本确认两套格式能对上拿到数据后别急着训练先写个脚本把 VOC 和 YOLO 两套标注做交叉校验读同一张图的 XML 和 txt把 VOC 的绝对坐标按图宽高归一化和 YOLO 的 cx、cy、w、h 对比误差超过 1e-3 就说明转换有问题。import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_norm(xml_path, img_path): 把 VOC 的 bndbox 转成 YOLO 归一化格式用于交叉校验 tree ET.parse(xml_path) root tree.getroot() w, h Image.open(img_path).size boxes [] for obj in root.findall(object): name obj.find(name).text bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) # 转成中心点 宽高再归一化 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h boxes.append((name, cx, cy, bw, bh)) return boxes def load_yolo(txt_path): 读取 YOLO txt返回 class_id 和归一化坐标 rows [] with open(txt_path) as f: for line in f: parts line.strip().split() if len(parts) 5: rows.append(tuple(float(x) for x in parts)) return rows # 逐张对比误差超过阈值就打印出来 for xml_file in os.listdir(annotations): if not xml_file.endswith(.xml): continue stem xml_file[:-4] img_path os.path.join(images, stem .jpg) txt_path os.path.join(labels, stem .txt) voc_boxes voc_to_norm(os.path.join(annotations, xml_file), img_path) yolo_boxes load_yolo(txt_path) if len(voc_boxes) ! len(yolo_boxes): print(f{stem}: 数量不一致 VOC{len(voc_boxes)} YOLO{len(yolo_boxes)}) continue for (name, cx, cy, bw, bh), (cid, ycx, ycy, ybw, ybh) in zip(voc_boxes, yolo_boxes): if abs(cx - ycx) 1e-3 or abs(cy - ycy) 1e-3: print(f{stem}: 坐标偏差过大 {name} {cx:.4f},{cy:.4f} vs {ycx:.4f},{ycy:.4f})这段脚本的关键参数是误差阈值1e-3因为浮点转换和不同工具的四舍五入会带来微小偏差超过这个值基本就是真错了。voc_to_norm里先取图宽高再归一化顺序不能反。跑完之后如果输出为空说明两套格式一致可以放心用如果有大量偏差优先怀疑转换脚本的宽高取错比如用了缩放后的尺寸而不是原图尺寸。3. 把 548 张足球标注喂给 YOLO目录、配置、训练一条龙3.1 目录结构images 和 labels 必须严格对应YOLO 训练对目录结构有硬性要求图片和标签分开放但文件名不含扩展名必须一一对应。548 张数据建议按 8:1:1 切成 train、val、test足球场景类别少val 留 50 张左右足够看趋势test 留 50 张做最终评估。如果某些类别样本极少比如角旗可能只有十几张切分时要保证每个 split 里都有否则 val 的 mAP 会剧烈波动。football_dataset/ ├── images/ │ ├── train/ # 约 438 张 │ ├── val/ # 约 55 张 │ └── test/ # 约 55 张 ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── football.yaml切分脚本不要用随机 shuffle 一把梭足球数据里同一场比赛的连续帧高度相似随机切会导致 train 和 val 里出现几乎一样的图val 指标虚高。常见做法是按视频来源或时间戳分组切分同一段连续帧只进一个 split。3.2 football.yaml类别名和路径的写法YOLO 的配置文件里path是数据集根目录train、val是相对路径names是类别 id 到名称的映射。548 张足球数据如果只标了球员和足球两类就写两行如果还标了球门、裁判按实际来。注意names的顺序必须和转换时生成的 class_id 完全一致。# football.yaml path: /data/football_dataset train: images/train val: images/val test: images/test names: 0: player 1: ball 2: goalkeeper 3: refereepath用绝对路径最稳避免训练时工作目录变化导致找不到数据。names里的中文类别名虽然 YOLO 能读但后续可视化、导出 ONNX 时容易出编码问题建议统一用英文。3.3 训练命令与关键参数小数据集怎么设才不崩548 张属于小样本直接上大模型容易过拟合。常见做法是从预训练权重出发冻结 backbone 先训几个 epoch再解冻全量微调。下面是一条我常用的命令yolo detect train \ datafootball_dataset/football.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.001 \ lrf0.01 \ warmup_epochs3 \ freeze10 \ patience30 \ cacheTrue \ projectruns/football \ nameexp1imgsz640是通用起点但足球远景下球员太小可以试 960 或 1280代价是显存和速度。batch16在单卡 8G 显存上跑 yolov8s 基本安全显存不够就降到 8 并开ampTrue。freeze10冻结前 10 层小数据集上能明显抑制过拟合。patience30表示 30 个 epoch 指标不升就早停避免浪费时间。cacheTrue把 548 张图缓存到内存训练速度提升明显数据量大时再关掉。训练过程中重点看三个指标box_loss是否稳定下降、mAP50在 val 上的走势、以及cls_loss有没有异常反弹。足球这种小目标如果 mAP50 卡在 0.3 以下不动大概率是标注框太小或者 anchor 不匹配需要回头查数据而不是调参。3.4 推理验证拿 test 集看真实效果训练完别只看 val 的曲线用 test 集跑一遍推理把预测框画出来肉眼过一遍。548 张里挑 20 张有代表性的远景、近景、遮挡、逆光做可视化比看数字更能发现问题。yolo detect predict \ modelruns/football/exp1/weights/best.pt \ sourcefootball_dataset/images/test \ conf0.25 \ iou0.5 \ saveTrue \ projectruns/football_predictconf0.25是默认起点足球被遮挡时可以把 conf 降到 0.15 看召回但误检会增多需要权衡。iou0.5控制 NMS 的合并阈值密集球员场景可以适当调高到 0.6避免相邻球员被合并成一个框。4. 足球小目标标注的避坑清单这 5 个坑我踩过4.1 坑一球被标成点训练时 loss 不降现象足球在远景里只有 5 到 10 像素标注时直接点了一个极小的框训练时 box_loss 一直震荡不降。原因YOLO 的回归损失对极小框的梯度不稳定宽高接近 0 时容易除零或梯度爆炸。解决标注时给球一个最小边长比如 8 像素或者把球和最近的球员合并标注训练时开box损失的 CIoU它对小框更友好。4.2 坑二VOC 转 YOLO 后类别 id 错位现象训练 loss 正常下降但推理时球员被识别成球、球被识别成球员。原因转换脚本按字母序生成 class_id而训练 yaml 里的 names 按业务顺序写两边不一致。解决转换前先固定一份classes.txt转换脚本和 yaml 都从这份文件读杜绝手写顺序。4.3 坑三同一场比赛的帧同时进了 train 和 val现象val 的 mAP 高得离谱test 集一跑就掉一半。原因连续帧高度相似随机切分导致数据泄漏。解决按视频片段或时间戳分组切分同一段连续帧只进一个 split切完后用感知哈希查一遍 train 和 val 之间有没有近似重复图。4.4 坑四resize 没做 letterbox球员被压扁现象训练时 mAP 还行部署到实际视频流上检测框位置偏移。原因训练用了直接 resize 到正方形改变了宽高比YOLO 的归一化坐标对应的实际位置和推理时不一致。解决训练和推理统一用 letterbox保持宽高比填充灰边如果必须 resizeVOC 坐标要同步做同样的变换。4.5 坑五548 张里混进了无标注的负样本现象模型在纯草皮或观众席画面上频繁误检。原因数据集里有些图没有目标但没生成对应的空 txt 文件YOLO 默认跳过模型没学到「背景长什么样」。解决无目标的图也要生成空 txt让模型见到负样本同时检查有没有漏标的图漏标比无标更伤模型。5. 小样本足球数据还能怎么榨干三个进阶技巧548 张不算多但用对了能顶上千张。第一个技巧是离线增强补量足球场景的增强不要用随机裁剪会把球裁掉优先用 HSV 抖动模拟不同光照、水平翻转足球场基本对称、以及 mosaic 四图拼接。mosaic 对小球检测提升明显因为它把四张图的球拼到一张里增加了小目标密度。我一般会在训练配置里开mosaic1.0最后 10 个 epoch 关掉让模型适应真实分布。第二个技巧是分层评估不要只看整体 mAP按目标像素面积分桶统计。足球场景里球员可能占 100×200 像素球只有 8×8整体 mAP 会被大目标拉高掩盖小目标的差。用 COCO 的 small/medium/large 口径分别算 AP才能看出模型到底行不行。如果 small 的 AP 低于 0.1优先加高分辨率训练或换更密集的检测头。第三个技巧是拿这批数据做领域适配验证。如果你在做一个通用的检测改进比如换 efficient head、改损失函数548 张足球数据是一个很好的「小样本压力测试」改进在 COCO 上涨 0.5 个点可能只是噪声但在足球小目标上如果 small AP 涨了 3 个点说明改进真的有效。我习惯把这类小数据集当成「试金石」先用它快速筛方案再去大数据集上确认。最后一个习惯每次训完模型把权重、yaml、训练命令、以及 val 和 test 的指标写进一个experiment_log.md548 张数据跑一次可能就十几分钟但方案迭代几十次之后没有日志根本记不清哪个配置对应哪个结果。这个习惯帮我省过很多次「后悔药」。希望帮到你。本文还有配套的精品资源点击获取
返回列表