简介手提袋检测数据集取自COCO2017提取全部含handbag的图片与标注统一转为VOC与YOLO两种格式类别仅handbag样本7133个。数据分两部分发布本压缩包为第二部分zip打包约395MB。包内txt文件为YOLO格式标签共7134个xml为VOC格式标签共7133个jpg原始图像7133张。三类文件对应清晰可直接用于YOLOv5/YOLOv8训练也可在Faster R-CNN、SSD等框架中读取。省去COCO标注转格式环节特别适合快速验证检测算法的研究者、备赛选手与初学者单一类别便于专项调参与误差分析目前已有490人学习下载。1. 手提袋检测数据集7133张单类样本VOC与YOLO双格式一次给齐做目标检测的同行应该都有过这种经历模型结构调好了训练脚本写好了结果卡在数据上。想检测手提袋handbag翻遍公开数据集要么是COCO这种多类别大而全、单一类别样本量不够聚焦要么是网上零零散散下载的图片标签格式五花八门还得自己写脚本清洗转换一折腾就是两三天。这份数据集就是从COCO2017里把handbag类别单独提取出来做成了VOCxml和YOLOtxt两套标签共7133张图片属于拆分成两部分后的第二部分。适合直接用YOLOv5、YOLOv8或者SSD这类框架训练手提袋检测模型的人也适合需要VOC格式做迁移学习或做数据增强实验的人群。省掉的是从COCO全量数据里筛类别、转格式、对编号这一整套重复劳动拿到手整理好目录就能开训。2. 数据集内部结构VOC与YOLO两套标签的完整解读2.1 文件清单与命名规则从文件名能看出什么先看项目正文里给出的这些文件名handbag_coco2017_0170.txt handbag_coco2017_05471.txt handbag_coco2017_04049.txt handbag_coco2017_04330.txt handbag_coco2017_01494.txt handbag_coco2017_02313.txt handbag_coco2017_05193.txt handbag_coco2017_02819.txt handbag_coco2017_02455.txt handbag_coco2017_05036.txt拿handbag_coco2017_05471.txt来说名字拆成三段看handbag是类别名coco2017表示来源是COCO2017数据集05471是它在COCO原图中的编号。这么做的好处是万一你想回溯原始图片、查某张样本的原始标注信息拿着这个编号去COCO2017的标注JSON里一查就能定位。实际下载解压后目录里除了这些txt还会有对应的xml标签文件以及图片文件三者靠同名前缀关联。这里提醒一个很多人第一眼会忽略的点标注文件列表给出的都是txt但摘要里说了VOC和YOLO两种格式都有即xml和txt各一套。也就是说同一张图片会对应两个标签文件——xml里存的是xmin, ymin, xmax, ymax这样的绝对坐标txt里存的是归一化后的center_x, center_y, width, height。两份标签描述的是同一批目标只是格式不同。2.2 两种标注格式的字段含义与坐标换算VOC格式的xml标签典型内容长这样annotation folderhandbag/folder filenamehandbag_coco2017_05471.jpg/filename size width640/width height480/height depth3/depth /size object namehandbag/name bndbox xmin118/xmin ymin96/ymin xmax412/xmax ymax389/ymax /bndbox /object /annotation关键字段就三块filename对应图片文件名size里的宽高是计算归一化坐标的依据bndbox里的四个值就是目标框的左上角和右下角绝对像素坐标。YOLO格式的txt则长这样0 0.4140625 0.5052083 0.459375 0.6104167一行的五个数字依次是类别id、归一化中心点x、归一化中心点y、归一化宽度、归一化高度。拿上面这行验证一下(0.4140625 * 640, 0.5052083 * 480)算出来就是(265, 242.5)对应绝对坐标的中心点0.459375 * 640 294是框宽0.6104167 * 480 293是框高。反推回去左上角(265 - 147, 242.5 - 146.5)即(118, 96)右下角(265 147, 242.5 146.5)即(412, 389)和上面xml里的数值对得上。这种双格式设计对实际工程很实用。YOLO系列训练直接读txt省去在线解析xml的耗时而VOC格式方便你在LabelImg里打开二次标注也方便做数据增强时回退到绝对坐标计算。2.3 为什么同一份数据要做两套标签做检测训练的都知道不同框架对标签格式的要求不一样。YOLOv5、YOLOv8原生吃txtSSD的VOC版本实现要吃xml如果以后想试DETR这类基于COCO格式的模型手里有VOC格式也能转。这份数据直接提供两种格式省掉的是最无聊也最容易出错的转换环节——坐标归一化、类别id映射、文件一一对应任何一步错了标签就废了。另外还要注意“第二部分”这个概念。摘要里写得很清楚这批是拆分后的第二部分数据。手里只有第二部分的样本量类别覆盖可能不如完整数据全面所以训练前建议先检查一下是否有配套的第一部分。如果两份数据要合并使用合并时要处理一个最常见的坑txt和xml文件里如果类别id是从0开始编号的两部分数据如果各自独立编号合并前必须统一类别映射关系。3. 用这份数据跑YOLO训练目录组织与命令落地3.1 推荐的目录组织方式从网上下载的数据集往往解压出来就是一堆图片和标签堆在一起直接扔进训练脚本大概率报错。我一般会先在项目根目录重新整理一遍结构按照YOLO训练的习惯组织handbag_dataset/ ├── images/ │ ├── train/ │ │ ├── handbag_coco2017_0170.jpg │ │ └── ... │ └── val/ │ ├── handbag_coco2017_01494.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── handbag_coco2017_0170.txt │ │ └── ... │ └── val/ │ ├── handbag_coco2017_01494.txt │ └── ... ├── data.yaml └── handbag.xml # VOC格式标签单独归拢到另一个目录这一步可以用个简单脚本完成推荐用软链接而不是复制文件省磁盘空间mkdir -p handbag_dataset/{images/{train,val},labels/{train,val}} # 假设下载解压后的原始目录是 raw/图片和txt都在里面 # 按8:2随机划分train和val python split_dataset.py --source raw/ --output handbag_dataset/split_dataset.py里通常干三件事读原始文件列表按比例随机切分把图片和对应的txt标签成对移动到目标目录。切分时务必保证每张图片都找到同名的txt否则训练时候YOLO会跳过没有标签的图片最后算出来的mAP是虚高的。操作完之后检查一下两边的文件数量是否对得上用一行命令就能办到find handbag_dataset/images/train -name *.jpg | wc -l find handbag_dataset/labels/train -name *.txt | wc -l两个数字一致说明图片和标签是成对搬过去的。3.2 修改data.yaml与类别配置文件YOLO训练时数据集的配置写在data.yaml里核心就三项训练集图片路径、验证集图片路径、类别名列表。这份数据集只有一个类别handbag所以配置很简单train: handbag_dataset/images/train val: handbag_dataset/images/val nc: 1 names: [handbag]这里最容易翻车的点是nc和names的对应关系。数据集的txt标签里类别id是0names列表第一项必须是handbag。如果某个txt文件里出现了类别id为1的标注而配置里只有nc: 1训练会直接报错或者所有id1的标注被忽略。建议训练前写个一行命令扫描所有txt检查类别id的最大值cat handbag_dataset/labels/train/*.txt handbag_dataset/labels/val/*.txt | awk {print $1} | sort -n | uniq -c输出应该是只有一行0开头的计数如果出现了1 xxx说明数据里有脏标签要排查是不是格式转换时类别id偏移了。3.3 训练命令与参数选择数据准备好之后train和val两个目录都有了可以用YOLO系列的训练入口直接开跑yolo detect train datahandbag_dataset/data.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0如果用的是YOLOv5对应命令是python train.py --data handbag_dataset/data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100参数选择上有几个实际考量。imgsz640是COCO预训练模型的默认输入尺寸手提袋这类目标在图片里尺寸跨度大有的整体占了大半张图有的只是街拍场景里的一个配件640分辨率算是一个稳定折衷。epochs100在这个数据量级下够用了单类别检测收敛快通常训练到60个epoch损失就平稳了。batch大小看显存16G显存跑yolov8n、batch16问题不大如果显存小就降到8。训练过程中要重点看两个指标Box_Precision和Box_Recall。手提袋检测有个特点很多目标存在遮挡和形变手提袋的提手部分在行人场景里经常被身体挡住。如果recall偏低不用急着加epochs先检查是不是验证集里混入了大量遮挡严重的样本这类样本对mAP的影响比较大。训练完成后模型权重会存在runs/detect/train/weights/best.pt直接用这个权重做推理就行。测试单张图片的推理效果yolo detect predict modelruns/detect/train/weights/best.pt sourcetest_images/handbag_demo.jpg4. 避坑指南手提袋数据集最常见的四个问题4.1 类别id错位导致标注全部失效现象训练时Loss正常下降但验证集的mAP一直徘徊在0.2以下明显不正常。原因数据集的txt标签里类别id为0但如果你把这份数据和其他数据集合并或者修改过data.yaml的names列表顺序比如把names: [handbag]改成了names: [person, handbag]那么原标签里的0会被当成personhandbag类别反而没有对应标注模型等于在学一个错误的映射。解决合并数据集前先统一类别id映射表重新生成txt标注而不是直接改配置文件。如果只是单独用这份数据训练前务必确认data.yaml的names第一项就是handbag不要自作主张去调整顺序。4.2 验证集里图片数量比标注文件多现象脚本报错提示某张jpg找不到对应txt程序中断。原因原始数据在整理划分时没做成对校验。有些数据源里图片是完整的但个别图片没有目标标注文件生成时被跳过了或者标注文件生成了但对应图片损坏被删除。这类不等配对问题在从大数据集里筛选子集时特别常见。解决写个脚本按图片目录遍历逐个检查同名txt是否存在。缺了就把图片挪到无标签目录不参与训练。import os from pathlib import Path img_dir Path(handbag_dataset/images/train) label_dir Path(handbag_dataset/labels/train) missing [] for img_path in img_dir.glob(*.jpg): label_file label_dir / (img_path.stem .txt) if not label_file.exists(): missing.append(img_path) for img_path in missing: no_label_dir img_dir.parent / no_label no_label_dir.mkdir(exist_okTrue) img_path.rename(no_label_dir / img_path.name) print(f处理完成共移出 {len(missing)} 张无标签图片)这段脚本逻辑很简单但能在训练前把潜在隐患都清掉。4.3 把VOC标签和YOLO标签搞混现象用YOLO训练时读取xml文件或者反过来在需要voc格式的框架里喂了txt报出坐标越界或解析失败的错误。原因这份数据集同时包含两套标签目录里很容易混放。txt是归一化坐标直接读出来是0到1的小数xml是绝对像素坐标两者混用轻则框偏重则训练直接崩。解决VOC标签单独放一个目录不要和YOLO的txt混在一起。训练YOLO模型就只让脚本读txt目录xml目录保持独立。如果日后需要从VOC转YOLO也要单独写转换脚本处理不要在训练流程里夹带转换逻辑。4.4 预训练权重与数据集来源不匹配现象使用COCO预训练权重开始训练前几个epoch的loss下降特别快但之后的mAP上不去。原因COCO预训练权重里包含80类其中就有handbag。模型初始特征提取器已经能认出袋类目标但如果数据集里手提袋的尺度分布和COCO原始分布差异大——比如你的场景全是密集小目标——模型需要更多迭代重新适应而固定backbone会拖慢适配速度。解决如果数据尺度分布差异大前30个epoch可以设置freeze10冻结backbone前10层之后再解冻。如果场景简单、目标尺度均衡直接用完整权重微调就行通常50个epoch内就能收敛。5. 进阶技巧训练前写个校验与格式互转工具链5.1 标签完整性校验脚本训练跑了一半才发现数据有问题是最痛苦的。我现在拿到任何检测数据集第一步不是急着开训而是先跑一遍完整校验。针对这份手提袋数据我习惯写一个脚本同时验证VOC和YOLO两套标签的完整性、坐标合法性和格式一致性import xml.etree.ElementTree as ET from pathlib import Path def validate_yolo_txt(txt_path, img_width, img_height): errors [] with open(txt_path, r) as f: for line_num, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: errors.append(f第{line_num}行字段数不为5) continue cls_id, cx, cy, w, h int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) if cls_id ! 0: errors.append(f第{line_num}行类别id异常: {cls_id}) if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): errors.append(f第{line_num}行坐标越界: {parts[1:]}) return errors def validate_voc_xml(xml_path): errors [] 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) for obj in root.iter(object): name obj.find(name).text if name ! handbag: errors.append(f类别名异常: {name}) bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) if not (0 xmin xmax img_w and 0 ymin ymax img_h): errors.append(fVOC坐标越界: ({xmin},{ymin},{xmax},{ymax})) return errors这段脚本干了三件事检查txt每行是不是5个字段类别id是否都是0归一化坐标是否在合法区间检查xml里类别名是否统一为handbag绝对坐标是否越界。跑一遍能把数据里99%的脏标签揪出来。坐标越界这个问题在从COCO转格式时经常出现——原图标注框有极少数是超出图片边界的转成txt时如果没做裁剪归一化后的w或h可能略大于1训练时会导致anchor计算异常。5.2 一键互转VOC转YOLO的场景与实现虽然这份数据两套格式都给了但实际动手改数据时难免会有变动比如你想合并第一部分和第二部分的VOC标注或者要加标注师补充的xml框就得自己再转一次。反过来有些模型工具链只认VOC格式也需要从txt反推回xml。这里给出VOC转YOLO的核心代码我加过一些处理越界框的逻辑import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, output_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.iter(object): name obj.find(name).text if name ! handbag: continue bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) # 越界框裁剪 xmin max(0, xmin) ymin max(0, ymin) xmax min(img_w, xmax) ymax min(img_h, ymax) # 裁剪后目标退化则跳过 if xmax xmin or ymax ymin: continue cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f0 {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(output_path, w) as f: f.write(\n.join(lines))这段转换脚本最值得注意的就是越界框裁剪逻辑。原数据集里的标注框偶尔会超出图片边界几个像素直接转换会导致归一化坐标出现负数或大于1训练时这些框的IoU损失计算会出问题。裁剪之后再过滤掉退化框能保证每一行输出都是合法标注。从那以后我拿到任何VOC标注数据都会先跑一遍这段逻辑再训练没有再被坐标越界坑过。希望这篇拆解能帮到你让你的数据集处理环节少走点弯路。本文还有配套的精品资源点击获取