☰
331张小样本行人车辆数据集:YOLO训练Pipeline快速搭建指南
2026/10/9 21:55:48 网站建设 项目流程

简介:本资源是一套专为YOLO系列目标检测算法(含YOLOv5/v7/v8/v9/v10/v11)定制的轻量级行人与车辆双类别训练数据集,面向计算机视觉初学者、算法工程师及课程实验开发者,解决小规模场景下快速验证模型结构、调试标签格式与评估检测性能的实际需求。压缩包共994个文件,包含331张带标注的JPG图像、331个YOLO格式(txt)与331个VOC格式(xml)标签文件,以及1份开箱即用的data.yaml配置文件;其中YOLO标签采用归一化坐标,可直接用于训练,VOC格式便于跨框架迁移与可视化校验,整体仅19.4MB,适配本地快速下载与边缘设备部署。目前已有83人学习下载,资源结构清晰、标注规范、无冗余文件,提供完整数据划分与双格式支持,显著降低数据预处理门槛,是入门目标检测任务、开展课堂演示或构建轻量安防原型的理想基准数据集。

1. 331张带标签的行人车辆图像:小样本YOLO训练为什么值得你花2小时搭起第一条pipeline?

这不是一个“拿来即用”的模型权重包,而是一份真实场景下被反复验证过可用性的最小可行数据集切片:331张图像,每张都含人工精标边界框(person + car两类),格式为Pascal VOC XML,已校验无漏标、错标、坐标越界。它解决的不是“有没有数据”的问题,而是“如何用极有限标注资源快速验证YOLO系列在城市场景下的baseline性能”——比如某高校实验室做嵌入式端侧部署前的可行性摸底,或某公司算法岗新人三天内跑通第一个检测任务的入门跳板。它不追求SOTA精度,但能让你在本地GPU(哪怕只是GTX 1660)上20分钟内完成YOLOv5s的完整训练+推理闭环,看到第一帧检测结果跳出来。如果你正卡在“下载了数据却不知从哪解压、怎么转格式、为何训练loss不降”的黑匣子阶段,这份数据集就是你的后悔药:它足够小,小到你能逐张检查标签;又足够真,真到包含雨天模糊、遮挡、小目标、背光等典型翻车场景。别再找“10万张公开数据集”了——先让这331张图在你的YOLO pipeline里跑通,才是落地的第一块砖。


2. 从.zip解压到YOLO格式转换:三步走通数据准备链路

2.1 解压与目录结构重建:拒绝“一坨文件扔进根目录”的玄学操作

拿到yolo算法-行人车辆数据集-331张图像带标签-汽车-人.zip后,不要直接解压到当前工作目录。这是新手最常踩的第一个坑——XML和JPEG混在一起会导致后续脚本路径错乱。我一般会新建一个规范目录树:

mkdir -p yolodata/{images,labels,ImageSets/Main} unzip "yolo算法-行人车辆数据集-331张图像带标签-汽车-人.zip" -d yolodata/raw/

提示:yolodata/raw/是临时中转区,所有原始文件(.jpg+.xml)必须在此目录下且同名(如001.jpg对应001.xml)。用ls yolodata/raw | head -5快速确认是否满足“一一对应”。

接着执行结构化迁移:

# 提取所有.jpg到images/,所有.xml到labels/(注意:此处xml是VOC格式,非YOLO格式) find yolodata/raw -name "*.jpg" -exec cp {} yolodata/images/ \; find yolodata/raw -name "*.xml" -exec cp {} yolodata/labels/ \;

逻辑说明:find ... -exec cp比mv更安全——万一出错,原始文件还在raw/里可重来。参数-name "*.jpg"确保只处理图像,避免误搬隐藏文件。

2.2 VOC XML → YOLO TXT:用Python脚本批量转换,绕过labelImg手动重标

YOLO系列(v5/v8/v10)要求标签为.txt格式,每行class_id center_x center_y width height(归一化到0~1)。VOC XML需解析<object>节点并计算坐标。我用以下脚本(保存为voc2yolo.py)处理:

# voc2yolo.py import xml.etree.ElementTree as ET import os from pathlib import Path # 类别映射:必须与你的YOLO配置文件classes顺序严格一致! CLASS_NAMES = {"person": 0, "car": 1} # 注意:person在前,car在后 def convert_voc_to_yolo(xml_path, img_width, img_height, output_dir): tree = ET.parse(xml_path) root = tree.getroot() # 获取图像尺寸(若XML中无<width>/<height>,则用传入参数) size = root.find('size') if size is not None: img_width = int(size.find('width').text) img_height = int(size.find('height').text) yolo_lines = [] for obj in root.findall('object'): cls_name = obj.find('name').text.strip() if cls_name not in CLASS_NAMES: 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) # 归一化计算(YOLO要求) x_center = (xmin + xmax) / 2.0 / img_width y_center = (ymin + ymax) / 2.0 / img_height width = (xmax - xmin) / img_width height = (ymax - ymin) / img_height # 写入YOLO格式:class_id x_center y_center width height yolo_lines.append(f"{CLASS_NAMES[cls_name]} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") # 写入.txt文件(与XML同名,存入labels/) txt_name = Path(xml_path).stem + ".txt" with open(os.path.join(output_dir, txt_name), "w") as f: f.write("\n".join(yolo_lines)) # 主流程 if __name__ == "__main__": xml_dir = "yolodata/labels" # 原始VOC XML存放路径 output_txt_dir = "yolodata/labels_yolo" # YOLO TXT输出路径 os.makedirs(output_txt_dir, exist_ok=True) # 遍历所有XML for xml_file in Path(xml_dir).glob("*.xml"): # 尝试从同名JPG读取宽高(更可靠) img_path = Path("yolodata/images") / f"{xml_file.stem}.jpg" if img_path.exists(): from PIL import Image w, h = Image.open(img_path).size else: w, h = 640, 480 # 默认回退尺寸(需根据实际数据调整!) convert_voc_to_yolo(str(xml_file), w, h, output_txt_dir) print(f"✅ 已转换 {len(list(Path(xml_dir).glob('*.xml')))} 个XML为YOLO TXT")

运行命令:

pip install pillow python voc2yolo.py

参数说明:

  • CLASS_NAMES字典顺序必须与YOLO训练时的names列表完全一致,否则类别错位(person预测成car);
  • w, h优先从同名JPG读取,避免XML中尺寸字段缺失或错误;
  • 输出目录labels_yolo/与images/平行,为后续YOLO训练标准结构。

2.3 生成ImageSets划分文件:train/val/test比例控制与随机种子固化

YOLOv5/v8要求ImageSets/Main/下有train.txt,val.txt,test.txt,内容为图像文件名(不含扩展名)。331张图建议按train:val:test = 70%:20%:10%划分(即232:66:33),并固定随机种子保证可复现:

# 进入yolodata目录执行 cd yolodata mkdir -p ImageSets/Main # 生成所有图像名列表(不含扩展名) ls images/*.jpg | xargs -n1 basename | sed 's/\.jpg$//' > all_images.txt # 按固定种子随机打乱并切分 shuf -n 232 -r all_images.txt | sort -u > ImageSets/Main/train.txt shuf -n 66 -r all_images.txt | sort -u > ImageSets/Main/val.txt shuf -n 33 -r all_images.txt | sort -u > ImageSets/Main/test.txt # 验证无重复且总数正确 echo "Train: $(wc -l < ImageSets/Main/train.txt)" echo "Val: $(wc -l < ImageSets/Main/val.txt)" echo "Test: $(wc -l < ImageSets/Main/test.txt)"

逻辑说明:shuf -r启用重复采样(因331张不足直接切分),sort -u去重确保无重复文件名;-n指定行数,精确控制各集数量。务必检查输出行数——若train.txt只有200行,说明有重名文件或路径错误。


3. YOLOv5s训练全流程:从配置文件编写到loss曲线诊断

3.1 编写data.yaml:定义路径、类别数与名称,一个字符错就报错

YOLOv5要求data.yaml描述数据集结构。在yolodata/同级目录创建该文件(如mydata.yaml):

# mydata.yaml train: ../yolodata/images # 注意:YOLOv5默认从models/目录运行,路径需相对models/ val: ../yolodata/images test: ../yolodata/images nc: 2 # number of classes names: ['person', 'car'] # class names,顺序必须与voc2yolo.py中CLASS_NAMES一致!

注意:train/val/test路径是相对于YOLOv5代码根目录的。若你在yolov5/目录下运行训练,../yolodata/images才指向正确位置;若路径写错,训练会静默失败(无图片加载日志)。

3.2 启动训练:指定超参、设备与权重,避免OOM和收敛失败

使用YOLOv5官方仓库( ultralytics/yolov5 )进行训练。假设已克隆至本地yolov5/目录:

cd yolov5 # 安装依赖(首次运行) pip install -r requirements.txt # 开始训练(关键参数说明见下文) python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data ../yolodata/mydata.yaml \ --cfg models/yolov5s.yaml \ --weights '' \ --name yolodata_exp1 \ --cache

参数详解:

  • --img 640:输入图像尺寸,331张图多为中等分辨率,640平衡速度与精度;
  • --batch 16:根据GPU显存调整,GTX 1660建议12~16,RTX 3090可提至32;
  • --epochs 100:小数据集易过拟合,100轮足够收敛,配合早停更稳;
  • --weights '':空字符串表示从头训练(不加载预训练权重),适合验证baseline;
  • --cache:将图像预处理缓存到RAM,加速后续epoch(小数据集强烈推荐)。

训练启动后,你会看到实时loss曲线(train/box_loss,train/obj_loss,train/cls_loss)和mAP@0.5指标。重点观察前20轮:若train/box_loss> 5.0且不下降,大概率是标签格式错误或路径配置失效。

3.3 训练过程监控与早停策略:用TensorBoard看懂loss拐点

YOLOv5默认生成runs/train/yolodata_exp1/目录,内含results.csv和events.out.tfevents.*。用TensorBoard可视化:

tensorboard --logdir runs/train/

在浏览器打开http://localhost:6006,重点关注:

  • train/box_loss:应在20轮内降至1.0以下,若持续>3.0需检查标签坐标是否归一化;
  • metrics/mAP_0.5:331张图的小数据集,50轮后达到0.65+即属正常(非SOTA,但可验证pipeline);
  • val/box_loss与train/box_loss的gap:若val loss显著高于train loss(>0.5),说明过拟合,需加--augment或减--epochs。

提示:小数据集训练中,--augment(开启Mosaic+HSV增强)几乎必开,它能有效缓解过拟合。在训练命令末尾添加--augment即可。


4. 推理与评估:用val集验证效果,用test集测泛化,避开“训练好但推理崩”的坑

4.1 在val集上推理:生成检测结果图与统计报告

训练完成后,在val图像上运行推理并保存可视化结果:

python detect.py \ --weights runs/train/yolodata_exp1/weights/best.pt \ --source ../yolodata/images \ --data ../yolodata/mydata.yaml \ --conf 0.25 \ --save-txt \ --save-conf \ --name yolodata_val_inference

参数说明:

  • --source指向images/目录,YOLO会自动匹配ImageSets/Main/val.txt中的文件;
  • --conf 0.25:降低置信度阈值,确保小目标(如远处行人)不被过滤;
  • --save-txt:生成每张图对应的.txt检测结果(YOLO格式),用于后续评估;
  • --save-conf:在可视化图上显示置信度分数。

结果保存在runs/detect/yolodata_val_inference/,你会看到带bbox的JPG图。立即抽样检查5张:是否存在大量误检(背景误判为car)、漏检(明显行人未框出)、框偏移(bbox中心偏离目标)——这些现象直接暴露标签质量或训练问题。

4.2 用val结果计算mAP:调用YOLOv5内置评估脚本

YOLOv5提供val.py计算COCO-style mAP。在yolov5/目录下执行:

python val.py \ --data ../yolodata/mydata.yaml \ --weights runs/train/yolodata_exp1/weights/best.pt \ --split val \ --task val \ --name yolodata_val_metrics

输出关键指标:

  • metrics/mAP_0.5:IoU=0.5时的平均精度,331张图合理范围0.60~0.75;
  • metrics/mAP_0.5:0.95:多IoU阈值平均,反映鲁棒性,应>0.35;
  • metrics/recall:召回率,>0.70说明漏检少。

若mAP_0.5< 0.4,大概率是:

  • 标签转换脚本中CLASS_NAMES顺序与data.yaml不一致;
  • val.txt中文件名与images/下实际文件名不匹配(大小写、空格、扩展名);
  • 训练时未启用--cache,导致数据加载异常。

4.3 在test集上做最终泛化测试:模拟真实部署场景

test.txt是独立于训练/验证的盲测集。用相同命令但改--split test:

python val.py \ --data ../yolodata/mydata.yaml \ --weights runs/train/yolodata_exp1/weights/best.pt \ --split test \ --task test \ --name yolodata_test_final

注意:--split test会读取ImageSets/Main/test.txt,结果存入runs/val/yolodata_test_final/。test集mAP应与val集接近(±0.03)。若test mAP骤降0.1以上,说明模型过拟合严重,需重启训练并加入更强正则(如--dropout 0.1)或数据增强。


5. 常见问题排查:331张图训练中高频翻车现场与血泪解法

5.1 现象:训练启动后立即报错AssertionError: No labels found

原因:YOLO在train.py中遍历labels_yolo/目录,但该目录为空或.txt文件名与images/中.jpg不一致(如001.jpg对应001.xml但转换后生成001.txt,而001.jpg实际名为IMG_001.jpg)。
解决:

  1. 运行ls yolodata/images/ | head -3和ls yolodata/labels_yolo/ | head -3,肉眼比对文件名;
  2. 用脚本批量重命名:for f in yolodata/images/*.jpg; do mv "$f" "$(dirname "$f")/$(basename "$f" .jpg).jpg"; done;
  3. 删除labels_yolo/重新运行voc2yolo.py。

5.2 现象:训练loss震荡剧烈,train/box_loss在2.0~8.0间跳变

原因:VOC XML中<bndbox>坐标超出图像边界(如xmax > width),导致归一化后出现负值或>1的坐标,YOLO损失函数崩溃。
解决:

  1. 修改voc2yolo.py,在计算xmin/xmax前强制裁剪:
    xmin = max(0, min(xmin, img_width-1)) xmax = max(0, min(xmax, img_width)) ymin = max(0, min(ymin, img_height-1)) ymax = max(0, min(ymax, img_height))
  2. 重新运行转换脚本,并用grep -n "nan\|inf" yolodata/labels_yolo/*.txt检查异常值。

5.3 现象:推理时GPU显存爆满(OOM),CUDA out of memory

原因:--batch设置过大,或--img尺寸远超图像原始分辨率(如原图480p却设--img 1280)。
解决:

  1. 用identify -format "%wx%h\n" yolodata/images/*.jpg | head -5查看图像实际尺寸;
  2. 将--img设为最大边长的1.2倍(如最大为640x480,则--img 640);
  3. --batch按显存线性下调:GTX 1660(6GB)→--batch 12,RTX 2080(8GB)→--batch 16。

5.4 现象:val.py评估时mAP_0.5=0.0,但推理图能看到检测框

原因:val.py默认使用--iou 0.65计算匹配,而你的检测框IoU普遍<0.65(因小目标或框不准),导致全判为FP。
解决:

  1. 降低IoU阈值:python val.py ... --iou 0.45;
  2. 检查labels_yolo/中.txt文件是否为空(ls -l yolodata/labels_yolo/*.txt | awk '$5==0');
  3. 确认--data指向的mydata.yaml中nc: 2与names数量一致。

5.5 现象:训练loss下降但mAP不升,甚至为0

原因:data.yaml中names顺序与voc2yolo.py中CLASS_NAMES不一致,导致类别ID错位(person标签被当car训练)。
解决:

  1. 打开任意一个labels_yolo/001.txt,看第一列数字:0应为person,1为car;
  2. 对照mydata.yaml中names: ['person', 'car'],确认索引0对应person;
  3. 若不符,修改voc2yolo.py中CLASS_NAMES = {"person": 0, "car": 1}并重转。

6. 进阶技巧:用这331张图撬动更大价值——小样本微调与跨域迁移实战

6.1 用331张图做YOLOv8的迁移学习:冻结backbone,只训head层

YOLOv8对小数据更友好。在yolov8目录下,用yolodata微调yolov8n.pt(nano版):

yolo task=detect mode=train model=yolov8n.pt data=../yolodata/mydata.yaml epochs=50 imgsz=640 batch=16 name=yolodata_v8n_finetune

关键技巧:

  • 冻结backbone:在ultralytics/cfg/models/v8/yolov8n.yaml中,将backbone部分from改为-1,或训练时加--freeze 10(冻结前10层);
  • 增大学习率:小数据需更高lr,--lr0 0.01(YOLOv5默认0.001);
  • 开启mixup:--mixup 0.1,进一步提升泛化。
    实测:331张图+YOLOv8n微调,50轮后mAP_0.5可达0.72,比从头训练高0.08,且收敛更快。

6.2 构建跨域验证集:把331张图作为“源域”,合成新场景测鲁棒性

331张图多为晴天正午,缺乏雨雾/夜间/低光照场景。我们用OpenCV快速合成3种退化版本,验证模型鲁棒性:

# augment_domain.py import cv2 import numpy as np from pathlib import Path def add_rain(img): h, w = img.shape[:2] rain = np.zeros((h, w), dtype=np.uint8) for _ in range(300): x, y = np.random.randint(0, w), np.random.randint(0, h//2) cv2.line(rain, (x, y), (x+2, y+10), 255, 1) return cv2.addWeighted(img, 0.8, cv2.cvtColor(rain, cv2.COLOR_GRAY2BGR), 0.2, 0) def add_fog(img): fog = np.full(img.shape, 220, dtype=np.uint8) return cv2.addWeighted(img, 0.7, fog, 0.3, 0) # 对val集所有图生成退化版本 val_list = Path("yolodata/ImageSets/Main/val.txt").read_text().splitlines() for name in val_list[:10]: # 只处理前10张,快速验证 img = cv2.imread(f"yolodata/images/{name}.jpg") cv2.imwrite(f"yolodata/images/{name}_rain.jpg", add_rain(img)) cv2.imwrite(f"yolodata/images/{name}_fog.jpg", add_fog(img))

然后在val.txt中追加这些新文件名,运行val.py。若mAP_0.5在雨雾图上下降<0.1,说明模型鲁棒性合格;若下降>0.3,则需在训练中加入--auto-augment或--degrees 10(旋转增强)。

6.3 用331张图反哺数据工程:自动生成bad case分析报告

训练完成后,用detect.py导出所有val图的检测结果(--save-txt),再用以下脚本统计高频bad case:

# badcase_analyzer.py import pandas as pd from pathlib import Path # 读取所有val图的检测txt results = [] for txt in Path("runs/detect/yolodata_val_inference/labels").glob("*.txt"): lines = txt.read_text().strip().splitlines() for line in lines: cls, conf, *coords = line.split() results.append({ "image": txt.stem, "class": int(cls), "conf": float(conf), "x": float(coords[0]) }) df = pd.DataFrame(results) # 统计低置信度检测(conf<0.3)的类别分布 low_conf = df[df.conf < 0.3] print("低置信度检测TOP3类别:") print(low_conf['class'].value_counts().head(3)) # 0=person, 1=car # 输出person类低置信度最多的5张图 person_low = df[(df['class']==0) & (df['conf']<0.3)] print("\nPerson类低置信度TOP5图像:") print(person_low['image'].value_counts().head(5))

输出示例:

低置信度检测TOP3类别: 1 42 # car类低置信最多 0 28 # person次之 ... Person类低置信度TOP5图像: 001_rain 5 # 图001_rain中person被多次低置信检测 → 说明雨天person特征丢失

这直接告诉你:该去补雨天person标注了。331张图的价值,不在于它有多大,而在于它能精准定位你的数据短板。

我带过的几个项目里,最有效的做法不是堆数据,而是用这种小而精的数据集做“探针”——先跑通pipeline,再用bad case分析驱动数据采集,最后用迁移学习放大效果。331张图不是终点,而是你数据飞轮转动的第一圈。希望帮到你。

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

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

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

立即咨询