ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

宠物猫狗识别检测数据集:3947张xml与yolo双格式标签使用指南

宠物猫狗识别检测数据集:3947张xml与yolo双格式标签使用指南 简介这份宠物猫狗识别检测数据集面向从事深度学习目标检测的科研人员、学生与工程开发者用于训练和验证猫狗目标检测模型解决宠物识别场景中样本不足、标注不规范的问题。资源包共2000个文件包含3947张jpg图像、3947个xml标注文件与3947个txt标注文件分别对应VOC与YOLO两种主流标注格式压缩包约388.12MB可直接接入常见检测算法流程。图像中猫狗目标形态多样、背景丰富标注精准无误适合作为课程实验、算法对比与项目落地的训练素材。目前已有2092人学习下载说明其在宠物检测方向具有较高的参考价值。使用者可据此快速构建训练集与验证集省去自行采集与标注的成本将精力集中于模型结构设计与调参优化对入门学习与科研实践均有帮助。1. 宠物猫狗识别检测数据集3947 张 xml 与 yolo 双格式标签到底怎么用你拿到一个标注好的宠物猫狗识别检测数据集3947 张图每张图配了 xml 和 yolo 两种格式的标签第一反应大概率是「直接丢进 YOLO 开训」。但我见过太多人卡在第一步xml 解析出来的框和图片对不上或者 yolo 格式的类别索引错位训出来的模型把猫认成狗。这个数据集的核心价值不在于图片数量而在于双格式标签给了你一条从 VOC 生态迁移到 YOLO 生态的完整链路。xml 格式适合做数据校验、可视化复查和跨框架转换yolo 格式适合直接喂给 ultralytics 系列训练器。如果你正在做宠物识别、智能喂食器、家庭监控里的猫狗区分或者只是想找一个中等规模、标注质量可控的检测数据集练手这套 3947 张的体量刚好卡在「能训出东西」和「单卡能跑完」之间。下面我会把 xml 解析、格式转换、训练配置和踩坑点拆开讲让你拿到数据后能直接复现一条可用的检测流水线。2. xml 标签解析与数据校验先把黑匣子打开2.1 为什么不能跳过 xml 直接训 yolo很多人觉得既然有 yolo 格式标签xml 就是多余的。但实际项目中xml 是你唯一能低成本做数据审计的入口。yolo 的 txt 标签只有归一化后的中心点和宽高你很难一眼看出某个框是不是标到了背景上。xml 里保留了原始像素坐标、图片宽高、类别名称甚至有些数据集还会带 difficulty 或 truncated 字段。我一般会先用 xml 做三件事检查图片和标签是否一一对应、统计每个类别的框数量和尺寸分布、把可疑框可视化出来人工过一遍。3947 张的规模写个脚本十分钟能跑完但能帮你省掉后面训到一半发现标签错位的后悔药。2.2 用 Python 批量解析 xml 并生成校验报告下面这段脚本会遍历所有 xml提取图片尺寸、类别、边界框并输出一份统计报告。注意 xml 解析用标准库 xml.etree.ElementTree 就够了不需要额外装 lxml除非你的 xml 有命名空间或超大文件。import os import xml.etree.ElementTree as ET from collections import defaultdict import json def parse_voc_xml(xml_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) objects [] for obj in root.findall(object): name obj.find(name).text bndbox obj.find(bndbox) xmin int(float(bndbox.find(xmin).text)) ymin int(float(bndbox.find(ymin).text)) xmax int(float(bndbox.find(xmax).text)) ymax int(float(bndbox.find(ymax).text)) objects.append({ name: name, bbox: [xmin, ymin, xmax, ymax], w: xmax - xmin, h: ymax - ymin }) return img_w, img_h, objects def audit_dataset(xml_dir): stats defaultdict(int) size_dist [] bad_files [] for fname in os.listdir(xml_dir): if not fname.endswith(.xml): continue path os.path.join(xml_dir, fname) try: img_w, img_h, objs parse_voc_xml(path) except Exception as e: bad_files.append((fname, str(e))) continue for o in objs: stats[o[name]] 1 size_dist.append((o[w], o[h])) # 检查框是否越界 for o in objs: xmin, ymin, xmax, ymax o[bbox] if xmin 0 or ymin 0 or xmax img_w or ymax img_h: bad_files.append((fname, fbbox out of range: {o[bbox]})) report { total_xml: len([f for f in os.listdir(xml_dir) if f.endswith(.xml)]), class_counts: dict(stats), bad_files: bad_files[:20], avg_box_w: sum(w for w, h in size_dist) / len(size_dist) if size_dist else 0, avg_box_h: sum(h for w, h in size_dist) / len(size_dist) if size_dist else 0, } return report if __name__ __main__: report audit_dataset(./annotations/xmls) print(json.dumps(report, indent2, ensure_asciiFalse))逻辑说明parse_voc_xml 负责单个 xml 的字段提取audit_dataset 做全量遍历和异常收集。参数上xml_dir 指向你存放 xml 的目录脚本会自动过滤非 xml 文件。输出报告里 class_counts 能告诉你猫和狗各有多少框如果某一类特别少后面训练要考虑类别平衡。bad_files 会列出越界框和解析失败的文件这些必须人工处理否则训练时会被静默跳过或产生错误梯度。2.3 图片与标签一一对应的检查方法xml 解析完只是第一步你还需要确认每张图片都有对应的 xml且文件名能对上。常见做法是提取图片目录和 xml 目录的文件名主干做集合差集。如果差集不为空说明有图片没标或者有标签没图。我一般会写一个简单的 bash 命令先看数量# 统计图片和 xml 数量 find ./images -type f \( -name *.jpg -o -name *.png \) | wc -l find ./annotations/xmls -type f -name *.xml | wc -l # 找出没有对应 xml 的图片 comm -23 (find ./images -type f -name *.jpg -printf %f\n | sed s/\.[^.]*$// | sort) \ (find ./annotations/xmls -type f -name *.xml -printf %f\n | sed s/\.[^.]*$// | sort)这段命令先分别统计数量再用 comm 做差集。注意 -printf 是 GNU find 的扩展macOS 上需要装 coreutils 或者改用 basename。如果差集输出很多行说明数据组织有问题先别急着转换格式。3. xml 转 yolo 格式转换脚本与四个边界坑3.1 VOC 到 YOLO 的坐标映射原理VOC xml 用的是绝对像素坐标 (xmin, ymin, xmax, ymax)YOLO txt 用的是归一化后的 (x_center, y_center, width, height)且所有值都在 0 到 1 之间。转换公式不复杂x_center (xmin xmax) / 2 / img_wy_center (ymin ymax) / 2 / img_hwidth (xmax - xmin) / img_wheight (ymax - ymin) / img_h。但坑就藏在细节里图片宽高从哪来、类别索引怎么定、浮点数保留几位、越界框怎么处理。下面这个脚本是我在多个项目里反复用过的版本直接抄就行。import os import xml.etree.ElementTree as ET CLASSES [cat, dog] # 根据你的数据集实际类别顺序修改 def convert_bbox(img_w, img_h, bbox): xmin, ymin, xmax, ymax bbox # 裁剪到图片范围内防止越界 xmin max(0, min(xmin, img_w)) ymin max(0, min(ymin, img_h)) xmax max(0, min(xmax, img_w)) ymax max(0, min(ymax, img_h)) if xmax xmin or ymax ymin: return None x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h return x_center, y_center, w, h def voc_to_yolo(xml_path, output_txt_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASSES: continue cls_id CLASSES.index(name) bndbox obj.find(bndbox) bbox [ float(bndbox.find(xmin).text), float(bndbox.find(ymin).text), float(bndbox.find(xmax).text), float(bndbox.find(ymax).text) ] result convert_bbox(img_w, img_h, bbox) if result is None: continue x_center, y_center, w, h result lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(output_txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: xml_dir ./annotations/xmls out_dir ./labels/yolo os.makedirs(out_dir, exist_okTrue) for fname in os.listdir(xml_dir): if fname.endswith(.xml): voc_to_yolo( os.path.join(xml_dir, fname), os.path.join(out_dir, fname.replace(.xml, .txt)) )逻辑说明CLASSES 列表的顺序决定了 txt 里第一列的类别索引必须和训练时的 data.yaml 里 names 顺序完全一致。convert_bbox 里做了裁剪和有效性检查如果框裁剪后宽高为负或零直接丢弃避免产生无效标签。浮点数保留 6 位是 YOLO 官方推荐的精度再高没必要再低可能影响小目标。3.2 类别索引错位最常见的翻车点我见过最频繁的翻车就是类别索引对不上。xml 里写的是 cat 和 dog你转换时 CLASSES 写成 [dog, cat]训练时 data.yaml 又写成 names: [cat, dog]结果模型学到的 cat 其实是 dog。这种错误在训练 loss 上不会报错只有推理时才会发现。解决办法只有一个转换脚本、data.yaml、推理代码三处的类别顺序必须来自同一个配置源。我一般会单独写一个 classes.json所有地方都读它。{ names: [cat, dog], nc: 2 }然后在转换脚本和训练配置里都引用这个文件而不是硬编码。这样改一处就全改不会漏。3.3 图片尺寸不一致时的处理策略3947 张图里很可能混着不同分辨率的图片。xml 里每张图都有自己的 width 和 height转换时用的是各自的值所以归一化坐标是正确的。但训练时 YOLO 会统一 resize 到 imgsz如果原图长宽比差异很大resize 后框会变形。常见做法是训练时开启 rect 模式或者用 letterbox 填充。ultralytics 默认会做 letterbox你不需要手动处理但要在 data.yaml 里确认 imgsz 设置合理。如果小目标多imgsz 至少 640如果图片本身很小可以适当降低。3.4 空标签文件和纯背景图的处理有些图片可能没有目标对应的 xml 里 object 数量为零。转换后会生成空的 txt 文件。YOLO 训练时空 txt 表示这张图是背景负样本这是有用的不要删。但如果空文件太多会导致正负样本失衡。我一般会统计空标签比例如果超过 20%考虑从训练集里剔除一部分纯背景图或者在 data.yaml 里调整采样权重。4. 用 YOLO 训练宠物猫狗检测模型参数配置与验证4.1 数据集目录结构与 data.yaml 写法YOLO 训练要求固定的目录结构images 和 labels 分开各自下面再分 train 和 val。转换完的 txt 要和图片同名同路径。下面是一个标准的目录树和对应的 data.yaml。path: ./pet_dataset train: images/train val: images/val names: 0: cat 1: dog注意 path 是数据集根目录train 和 val 是相对路径。names 的键值对顺序必须和转换时的 CLASSES 一致。如果你有 test 集可以再加一行 test: images/test。4.2 训练命令与关键参数解释ultralytics 的训练命令很简洁但参数选不对训出来的模型要么过拟合要么欠拟合。下面是我在 3947 张规模下常用的配置。yolo detect train \ data./pet_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience20 \ device0 \ project./runs \ namepet_exp1参数说明model 选 yolov8n 是因为 3947 张不算大n 版本参数量小不容易过拟合而且单卡 8G 显存就能跑。epochs 设 100 配合 patience 20如果 20 轮验证指标不升就早停。lr0 是初始学习率0.01 是 SGD 的常用值如果你用 AdamW 可以降到 0.001。batch 16 在 640 分辨率下大约占 6G 显存显存不够就降到 8。device 0 指定第一块 GPUCPU 训练会慢到无法接受。4.3 训练过程监控与指标解读训练开始后runs/pet_exp1 目录下会生成 results.csv 和 weights 文件夹。重点看三个指标box_loss、mAP50、mAP50-95。box_loss 持续下降说明模型在学但如果 val 的 box_loss 开始上升而 train 的还在降就是过拟合了。mAP50 到 0.8 以上基本可用mAP50-95 到 0.5 以上算不错。如果 50 轮后 mAP50 还在 0.3 以下先回去检查标签格式和类别索引大概率是数据问题不是模型问题。4.4 推理验证用测试图看实际效果训练完用 best.pt 跑几张测试图直接看框和类别。yolo detect predict \ model./runs/pet_exp1/weights/best.pt \ source./test_images \ conf0.25 \ saveTrueconf 0.25 是置信度阈值低于这个值的框不显示。如果发现漏检多降到 0.1 看看是不是模型没学到如果误检多升到 0.5。保存的图片在 runs/detect/predict 下肉眼过一遍比看指标更直观。5. 避坑与排查xml 解析和 yolo 训练里的血泪经验5.1 现象xml 解析报 ParseError提示 not well-formed原因xml 文件里有非法字符比如未转义的 或 或者文件编码不是 UTF-8。有些标注工具导出的 xml 会带 BOM 头ElementTree 也会报错。解决先用xmllint --noout *.xml批量检查报错的文件用文本编辑器打开把非法字符转义或删掉。如果是 BOM 问题用sed -i 1s/^\xEF\xBB\xBF// file.xml去掉。5.2 现象转换后的 txt 里类别索引全是 0但明明有猫有狗原因CLASSES 列表里只写了一个类别或者 xml 里的 name 字段和 CLASSES 里的字符串不完全匹配比如多了空格或大小写不同。解决在转换脚本里加一行print(set(obj.find(name).text for obj in root.findall(object)))先看看 xml 里实际写了什么。然后确保 CLASSES 里的字符串和它完全一致包括大小写和空格。5.3 现象训练 loss 正常下降但推理时框全偏了原因xml 里的 width 和 height 和实际图片尺寸不一致。有些数据集在标注时图片被 resize 过但 xml 里记的是原图尺寸或者反过来。解决用 PIL 或 OpenCV 读每张图的实际尺寸和 xml 里的 size 字段对比。不一致的图片要么重新标注要么在转换时用实际图片尺寸而不是 xml 里的尺寸。5.4 现象mAP50 卡在 0.2 上不去换模型也没用原因标签文件里有大量越界框或宽高为负的框训练时被静默跳过导致有效样本远少于预期。解决回到第 2 章的校验脚本把 bad_files 全部打印出来人工修复或删除这些样本。修复后重新转换、重新训练。5.5 现象训练时提示 no labels found但 labels 目录里明明有 txt原因YOLO 要求图片和标签的路径严格对应。比如 images/train/abc.jpg 对应 labels/train/abc.txt。如果你把 txt 放在了 labels/train/ 但图片在 images/train/ 的子目录里就会找不到。解决用find labels -name *.txt | head和find images -name *.jpg | head对比路径结构确保去掉 images 和 labels 前缀后相对路径完全一致。6. 进阶技巧用 xml 做数据增强和难例挖掘xml 格式除了转换还能帮你做更精细的数据增强。比如你想对猫狗做马赛克增强但不想把框切坏可以先用 xml 读出每张图的框再决定马赛克拼图时哪些框保留、哪些丢弃。我一般会写一个脚本把 xml 里的框按面积排序面积小于 32x32 的视为小目标在增强时单独处理。另一个技巧是难例挖掘用训练好的模型在验证集上推理把置信度低但实际有目标的图挑出来回看对应的 xml检查是不是标注漏了或者框不准。3947 张的规模跑一轮难例挖掘大概能找出几十张问题图修完之后 mAP 通常能涨 2 到 3 个点。这些操作都不复杂但需要你先把 xml 解析和格式转换的链路跑通。我自己现在拿到任何 VOC 格式的数据集第一件事就是跑一遍校验脚本第二件事是转换后抽 20 张可视化第三件事才是开训。这个习惯帮我省了太多半夜调参的时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表