☰
YOLOv5数据集目录格式详解:智能小车物品识别实战指南
2026/10/9 19:59:33 网站建设 项目流程

简介:本资源为面向目标检测入门与智能小车视觉应用场景的YOLOv5格式数据集,聚焦智能购买环节中的物品识别任务,适合正在学习YOLO训练流程、需要快速验证检测代码的开发者与高校学生使用。数据采用标准YOLOV5目录结构组织,无需额外转换即可直接投入训练,图像统一为416×416的RGB图片,标注类别为单类purchase,覆盖智能小车对特定目标进行识别以实现智能购买的需求。压缩包共1777个文件,以jpg图像与txt标注文件为主,另含类别字典txt及一个可视化py脚本,整体约26.48MB;其中训练集含710张图片与711个标签,测试集含177张图片与177个标签。可视化脚本可随机读取一张图片绘制边界框并保存至当前目录,无需修改即可运行,便于快速检查标注质量。目前已有157人学习,适合作为目标检测练手与代码测试的轻量级数据支撑。

1. 智能小车物品识别数据集:YOLOv5目录格式到底长什么样

做过智能小车视觉模块的工程师大概都有过这种体验:算法代码跑通了,模型结构也调好了,结果卡在数据集上——标注文件格式不对、目录层级混乱、类别编号从1开始而不是0、图片和标签对不上号。智能小车物品识别这个场景尤其典型,摄像头视角低、物品尺度变化大、背景干扰多,数据集的质量直接决定模型能不能在车上跑出可用效果。而智能购买图像目标检测又是另一个高频需求,货架商品、购物车物品、手持商品的检测框精度要求更高。

这两个场景合在一起,落到工程上就是一件事:你需要一套符合YOLOv5目录格式的目标检测数据集,拿来就能训练,不用再花两天时间做格式转换和路径排查。这篇文章不讲空泛的“数据集很重要”,而是把YOLOv5目录格式的每个文件、每个参数、每个容易翻车的地方拆开讲清楚。适合谁看?正在做智能小车视觉模块的嵌入式工程师、准备训练商品检测模型的算法同学、以及第一次接触YOLOv5数据集格式不知道从哪下手的新手。读完你至少能做到:自己组织一套YOLOv5格式的数据集,跑通训练,并且在mAP不涨的时候知道该查哪里。

2. YOLOv5目录格式拆解:从images到labels的完整映射

2.1 标准目录树与每个文件的职责

YOLOv5对数据集的目录结构有明确的约定,不是随便放放就能跑。常见做法是按照以下层级组织:

dataset/ ├── images/ │ ├── train/ │ │ ├── 000001.jpg │ │ ├── 000002.jpg │ │ └── ... │ ├── val/ │ │ ├── 000101.jpg │ │ └── ... │ └── test/ # 可选 │ └── ... ├── labels/ │ ├── train/ │ │ ├── 000001.txt │ │ ├── 000002.txt │ │ └── ... │ ├── val/ │ │ ├── 000101.txt │ │ └── ... │ └── test/ │ └── ... └── data.yaml

这里有几个硬性约束。第一,images和labels下的子目录名必须一一对应,train对train,val对val,不能一个叫train一个叫training。第二,图片文件和标签文件的主文件名必须完全相同,只是扩展名不同。000001.jpg对应000001.txt,如果写成000001_label.txt,训练时就会报“No labels found”然后所有框都是空的。第三,标签文件是.txt纯文本,不是.xml也不是.json。

每个标签文件的内容格式是:

<class_id> <x_center> <y_center> <width> <height>

五个值之间用空格分隔,每行一个目标。一张图里有三个目标就写三行。class_id从0开始计数,不是从1开始。坐标全部是归一化后的值,范围0到1,不是像素值。这一点是新手最容易翻车的地方——拿到的标注如果是像素坐标,直接写进去训练,模型学出来的框会全部挤在左上角。

2.2 data.yaml的六个关键字段

data.yaml是YOLOv5训练时的数据配置入口,内容不多但每个字段都不能写错:

# data.yaml path: /home/user/dataset # 数据集根目录,绝对路径 train: images/train # 训练集图片路径,相对于path val: images/val # 验证集图片路径,相对于path test: images/test # 测试集图片路径,可选 nc: 5 # 类别数量 names: # 类别名称列表,顺序必须和class_id对应 0: bottle 1: box 2: can 3: bag 4: phone

path字段建议写绝对路径,相对路径在不同工作目录下启动训练时容易找不到文件。train和val写相对于path的路径,注意这里只写到images这一层,YOLOv5会自动把images替换成labels去找对应的标签文件。nc是类别数,names的键值对顺序必须和标注时的class_id严格一致。如果标注时bottle是0,这里bottle就必须写在0的位置,写反了模型会把瓶子识别成盒子,而且loss曲线看起来还挺正常,这种玄学问题排查起来很费时间。

2.3 从零组织一套智能小车物品识别数据集的完整步骤

假设你手头有一批智能小车拍摄的物品图片,以及对应的标注文件(可能是VOC XML格式或者COCO JSON格式),需要转成YOLOv5格式。以下是可复现的操作流程。

第一步,建立目录骨架:

# 创建标准YOLOv5数据集目录结构 mkdir -p dataset/images/train dataset/images/val mkdir -p dataset/labels/train dataset/labels/val

第二步,划分训练集和验证集。常见做法是按8:2或9:1划分,智能小车场景下如果图片总数少于2000张,建议按8:2,验证集至少留100张以上,否则mAP波动会很大。

import os import random import shutil # 原始图片目录和标注目录 src_images = "raw_images" src_labels = "raw_labels" dst_root = "dataset" # 获取所有图片文件名(不含扩展名) all_files = [os.path.splitext(f)[0] for f in os.listdir(src_images) if f.endswith(".jpg")] random.seed(42) # 固定随机种子,保证可复现 random.shuffle(all_files) split_idx = int(len(all_files) * 0.8) train_files = all_files[:split_idx] val_files = all_files[split_idx:] # 复制图片和标签到对应目录 for phase, files in [("train", train_files), ("val", val_files)]: for name in files: shutil.copy(f"{src_images}/{name}.jpg", f"{dst_root}/images/{phase}/{name}.jpg") shutil.copy(f"{src_labels}/{name}.txt", f"{dst_root}/labels/{phase}/{name}.txt") print(f"训练集: {len(train_files)} 张, 验证集: {len(val_files)} 张")

这段脚本做了三件事:固定随机种子保证每次划分结果一致、按比例切分文件列表、把图片和标签成对复制到目标目录。注意random.seed(42)这行,不固定种子的话每次重新划分数据集,验证集变了,mAP就没法横向对比,调参时根本分不清是模型改进了还是验证集换了。

第三步,如果标注是VOC XML格式,需要转成YOLO的txt格式:

import xml.etree.ElementTree as ET import os # 类别映射表,必须和data.yaml中的names一致 class_map = {"bottle": 0, "box": 1, "can": 2, "bag": 3, "phone": 4} def voc_to_yolo(xml_path, img_w, img_h): """将VOC XML标注转换为YOLO格式的标签行""" tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.findall("object"): cls_name = obj.find("name").text if cls_name not in class_map: continue # 跳过未定义类别 cls_id = class_map[cls_name] bbox = obj.find("bndbox") xmin = float(bbox.find("xmin").text) ymin = float(bbox.find("ymin").text) xmax = float(bbox.find("xmax").text) ymax = float(bbox.find("ymax").text) # 转换为归一化的中心点坐标和宽高 x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h # 裁剪到[0,1]范围,防止标注越界 x_center = max(0, min(1, x_center)) y_center = max(0, min(1, y_center)) width = max(0, min(1, width)) height = max(0, min(1, height)) lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") return lines

转换逻辑的核心是坐标归一化:VOC给的是左上角和右下角的绝对像素坐标,YOLO要的是中心点坐标加宽高,并且全部除以图片的宽高做归一化。保留6位小数足够,YOLOv5内部会再做一次缩放。裁剪到[0,1]是防止标注人员手抖把框拖出图片边界,越界的坐标会导致训练时loss异常。

2.4 用YOLOv5自带脚本做数据校验

YOLOv5仓库里有一个utils/general.py中的检查逻辑,但更直接的方式是训练前跑一次dry-run。常见做法是用小epoch数先跑一轮:

# 用1个epoch快速验证数据集格式是否正确 python train.py --data data.yaml --epochs 1 --batch-size 4 --img-size 640 --weights yolov5s.pt

如果数据集有问题,这一步会直接报错,比如“No labels found in …”说明标签路径不对,“Label class 5 exceeds nc=5”说明类别编号超了,“invalid label”说明坐标格式有问题。花两分钟跑一轮,比训练到一半才发现问题再回头改要划算得多。

3. 智能购买场景下的类别设计与标注策略

3.1 类别粒度怎么定:从“瓶装水”到“500ml矿泉水”的取舍

智能购买图像目标检测和智能小车物品识别在类别设计上有一个共同难点:类别粒度太粗,模型学不到区分性特征;太细,标注成本爆炸且样本不均衡。我一般会按以下原则做取舍。

第一,按功能用途分大类,不按品牌分小类。比如“饮料瓶”作为一个类,不要分成“可乐瓶”“雪碧瓶”“矿泉水瓶”。原因很简单:智能购买场景下用户关心的是“这是什么类型的物品”,不是“哪个牌子”。而且品牌包装更新频繁,今天标了明天换包装,模型就废了。

第二,外观差异大于30%才单独设类。比如“纸盒”和“塑料瓶”外观差异明显,分两类没问题。“大纸盒”和“小纸盒”如果只是尺寸差异,不建议分两类,因为YOLOv5对尺度变化本身就有一定的适应能力,强行分类反而导致小样本类别mAP极低。

第三,类别数控制在5到15之间。少于5类,模型容易过拟合;多于15类,在智能小车这种算力受限的平台上,推理速度和精度都会明显下降。如果确实需要检测很多种物品,常见做法是先做粗分类再做细分类,两级级联。

3.2 标注框的四个边界规则

标注质量直接决定模型上限。以下四条规则是我踩过坑之后总结出来的。

规则一:框要贴紧目标边缘,不留空隙也不过度收缩。留空隙会让模型学出偏大的框,过度收缩会让模型漏检边缘特征。判断标准是:框的边线应该刚好压住目标的最外轮廓像素。

规则二:遮挡目标按可见部分标注。如果一个瓶子被另一个盒子挡住了一半,框只标可见的那一半,不要脑补被遮挡的部分。脑补出来的框和实际推理时模型看到的不一致,反而降低精度。

规则三:密集排列的目标逐个标注,不合并。货架上并排的五瓶水就是五个框,不要画一个大框把五瓶水全包进去。合并标注会让模型学出“一大片区域都是目标”的错误认知。

规则四:小于图像面积0.5%的目标直接忽略。智能小车摄像头分辨率有限,太小的目标标注了模型也学不到,反而引入噪声。如果确实需要检测小目标,应该提高摄像头分辨率或者用切图推理。

3.3 用脚本做标注一致性检查

标注人员多了之后,不同人的标注风格会有差异。写一个检查脚本,在训练前跑一遍:

import os def check_labels(label_dir, img_dir, nc): """检查标签文件的格式和数值范围""" issues = [] for txt_file in os.listdir(label_dir): if not txt_file.endswith(".txt"): continue txt_path = os.path.join(label_dir, txt_file) img_name = os.path.splitext(txt_file)[0] + ".jpg" img_path = os.path.join(img_dir, img_name) # 检查图片是否存在 if not os.path.exists(img_path): issues.append(f"图片缺失: {img_name}") continue with open(txt_path, "r") as f: for line_num, line in enumerate(f, 1): parts = line.strip().split() if len(parts) != 5: issues.append(f"{txt_file} 第{line_num}行: 字段数={len(parts)},应为5") continue cls_id = int(parts[0]) if cls_id < 0 or cls_id >= nc: issues.append(f"{txt_file} 第{line_num}行: class_id={cls_id} 超出范围[0,{nc-1}]") coords = [float(x) for x in parts[1:]] for i, v in enumerate(coords): if v < 0 or v > 1: issues.append(f"{txt_file} 第{line_num}行: 坐标值{v}超出[0,1]") return issues # 使用示例 problems = check_labels("dataset/labels/train", "dataset/images/train", nc=5) for p in problems[:20]: # 只打印前20条 print(p) print(f"共发现 {len(problems)} 个问题")

这个脚本检查四件事:标签文件对应的图片是否存在、每行是否恰好5个字段、class_id是否在有效范围内、坐标是否归一化到[0,1]。训练前跑一遍,能拦掉大部分低级错误。

4. 避坑与排查:训练不收敛时先查这五个地方

4.1 现象:loss从第一轮就不下降

原因通常是标签格式错误。最常见的是坐标没有归一化,还是像素值。比如x_center写成了320而不是0.5,YOLOv5读取后虽然不会报错,但计算loss时预测值和目标值差距巨大,梯度爆炸或者直接nan。

解决:用上面的check_labels脚本跑一遍,确认所有坐标值都在0到1之间。如果发现大量坐标大于1,说明标注转换时漏了除以图片宽高这一步。

4.2 现象:训练正常但mAP始终在0.1以下

原因可能是类别编号和data.yaml中的names顺序不一致。比如标注时bottle是0,但data.yaml里bottle写在了1的位置。模型学到的“0号类别”和验证时认为的“0号类别”不是同一个东西,mAP自然上不去。

解决:打印data.yaml的names,再随机抽几个标签文件看class_id分布,确认对应关系。这个坑很隐蔽,因为loss曲线看起来完全正常,只有mAP不涨。

4.3 现象:验证集mAP远低于训练集mAP

原因通常是训练集和验证集的数据分布不一致。比如训练集全是白天拍摄的图片,验证集混入了夜间图片;或者训练集物品摆放整齐,验证集物品杂乱堆叠。

解决:检查划分数据集时的随机种子是否固定,确认两个集合的拍摄条件、光照、背景尽量一致。如果确实需要模型适应多种条件,应该在训练集中就包含这些变化,而不是留给验证集去“考验”模型。

4.4 现象:模型对某些类别完全检测不到

原因可能是该类别样本数太少,或者标注框尺寸异常。YOLOv5的anchor是基于COCO数据集统计的,如果你的目标尺寸和COCO差异很大,默认anchor可能匹配不上。

解决:先统计每个类别的样本数和框的宽高分布。如果某个类别样本数少于总样本的5%,考虑补充数据或者用过采样。如果框的宽高比极端(比如细长条),可以用k-means重新聚类生成自定义anchor:

# 用YOLOv5自带脚本聚类生成自定义anchor python utils/autoanchor.py --data data.yaml --img-size 640

4.5 现象:推理时框的位置整体偏移

原因通常是训练时的img-size和推理时的输入尺寸不一致,或者标签坐标在转换时用了错误的图片宽高。比如图片实际是640x480,但转换时按640x640算的,y方向坐标就会整体偏移。

解决:确认转换脚本中读取的图片宽高和实际图片一致。用PIL或OpenCV读取图片尺寸时注意EXIF方向信息,有些手机拍摄的图片EXIF里带了旋转标记,直接读会得到错误的宽高。

5. 用YOLOv5训练智能小车物品识别模型的参数调优技巧

5.1 小目标检测的img-size与anchor设置

智能小车摄像头通常安装位置较低,拍摄的物品在画面中占比不大,属于小目标检测场景。YOLOv5默认的img-size是640,对于小目标建议提高到960或1280。但要注意,img-size提高后显存占用和推理时间都会增加,在嵌入式平台上需要做权衡。

一个实用的技巧是:先用640跑一轮baseline,看mAP和推理速度。如果mAP明显偏低且推理速度有余量,再提高到960。不要一上来就上1280,训练时间翻倍不说,小数据集上还容易过拟合。

anchor方面,用autoanchor脚本重新聚类。智能小车场景下的物品框通常偏小,默认anchor中较大的那几个可能根本用不上,重新聚类能让anchor更贴合实际数据分布。

5.2 数据增强参数的场景化调整

YOLOv5默认开启了mosaic、mixup、HSV增强等。在智能购买场景下,有几个参数需要根据实际情况调整。

mosaic增强默认概率是1.0,它把四张图拼成一张。这个增强对小目标检测很有帮助,但如果你的物品经常被遮挡,mosaic可能引入不真实的拼接边界。建议先用默认值跑,如果验证集mAP波动大,把mosaic降到0.5试试。

HSV增强中的hsv_h(色调)、hsv_s(饱和度)、hsv_v(亮度)默认分别是0.015、0.7、0.4。智能小车在室内外切换时亮度变化大,hsv_v可以适当提高到0.5。但如果你的场景光照稳定,调太高反而让模型学到无关的颜色变化。

# 训练命令示例,带关键参数说明 python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img-size 960 \ --batch-size 8 \ --epochs 100 \ --mosaic 0.5 \ --hsv-v 0.5 \ --project runs/train \ --name smart_cart_v1

5.3 用验证集曲线判断过拟合与欠拟合

训练过程中重点看三个曲线:train/box_loss、val/box_loss、metrics/mAP_0.5。

如果train/box_loss持续下降但val/box_loss在某个epoch后开始上升,说明过拟合了。解决方法是增加数据增强、减少模型参数量(换yolov5n或yolov5s)、或者早停。

如果两个loss都下降很慢且mAP低于0.3,说明欠拟合。检查学习率是否太低、anchor是否匹配、类别是否太难区分。

如果mAP在某个值附近震荡不涨,常见原因是学习率到了平台期。YOLOv5默认用余弦退火调度,一般不需要手动调。但如果数据集特别小(少于500张),可以把学习率从0.01降到0.001试试。

5.4 导出模型到智能小车端的注意事项

训练完成后导出ONNX或TensorRT时,注意输入尺寸要和训练时一致。如果训练用960,导出时也写960。另外,YOLOv5的推理输出包含三个尺度的特征图,后处理中的NMS阈值需要根据实际场景调。智能购买场景下物品密集,NMS的iou阈值建议从默认的0.45降到0.3到0.4之间,避免相邻物品的框被误删。

我自己的习惯是:每次改完数据集或训练参数,先跑1个epoch确认没有格式报错,再跑10个epoch看loss趋势是否正常,最后才跑完整训练。这样虽然多花了几分钟,但省下了大量“训练到一半发现数据有问题”的后悔药时间。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询