331张行人车辆数据集:YOLO小样本目标检测实战指南

发布时间:2026/10/11 18:38:30

331张行人车辆数据集:YOLO小样本目标检测实战指南 简介这是一份面向YOLO系列目标检测学习者的行人车辆标注数据集适用于yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流算法可直接用于模型训练与验证测试帮助初学者和算法工程师快速搭建目标检测实验环境。资源包共994个文件包含331张jpg图像、331个txt标签、331个xml标签以及1个yaml配置文件压缩包约19.4MB其中txt为YOLO格式标注xml为VOC格式标注yaml用于数据集路径与类别配置两种标签格式分别存放便于按需选用。目前已有83人学习下载。数据集已划分好训练与验证结构标注涵盖行人与车辆两类目标坐标采用归一化中心点与宽高表示读者可直接接入训练脚本完成模型微调与效果评估省去数据采集与标注成本适合作为课程设计、毕业设计或算法入门的实战素材。1. 331 张行人车辆数据集够不够跑通一个 YOLO 检测器手上只有 331 张带标签的行人车辆图像第一反应往往是「这点数据能训出什么」。我去年接手一个园区出入口的车辆计数需求时拿到的初始素材就是类似规模——三百多张手机和监控截图混拍标注框画得歪歪扭扭。当时团队里有人主张直接上 BDD100 这种十万级自动驾驶数据集但采集场景对不上园区里全是低速电动车和撑伞行人公开数据集里的高速路况反而成了噪声。最后我们用三百多张自采图做微调mAP0.5 从零基础的 0.31 拉到 0.78误检主要集中在夜间逆光这个结果对「先跑通再迭代」的节奏来说完全够用。这个标题里的「yolo算法-行人车辆数据集-331张图像带标签」本质是一个小样本目标检测的冷启动包图像数量少、类别只有汽车和人、标签格式大概率是 YOLO 的 txt 或 Pascal VOC 的 xml。它解决的不是「训练一个通用检测大模型」而是「在特定场景下快速验证 YOLO 能不能识别你要的目标」。适合谁适合做毕设的学生、做原型验证的嵌入式工程师、以及需要给客户演示「我们这套视觉方案能识别车辆和行人」的售前团队。不适合谁不适合指望直接拿去做量产级自动驾驶感知的人331 张的覆盖度撑不起长尾场景。提示拿到任何小数据集先别急着写训练脚本。花二十分钟统计图像分辨率分布、标注框宽高比、类别是否平衡这三项决定了你后面要不要做增强、要不要改 anchor。2. 从压缩包到 YOLO 可读格式标签转换与目录组织2.1 先判断标签是 xml 还是 txt这决定转换路径331 张图像带标签标签格式无非两种Pascal VOC 的 xml每张图一个 xml里面写 bndbox 的 xmin/ymin/xmax/ymax或 YOLO 的 txt每张图一个 txt每行class x_center y_center width height全部归一化到 0~1。你解压后先看目录里跟图像同名的文件后缀。如果是 xml需要转成 YOLO 格式如果已经是 txt检查数值是否超过 1——超过 1 说明是绝对坐标也得转。常见做法是写一个转换脚本把 xml 里的绝对坐标转成归一化中心点坐标。下面这个脚本我用了很多次处理 331 张图不到两秒import os import xml.etree.ElementTree as ET from PIL import Image # 类别映射根据你的数据集实际类别名修改 CLASS_MAP {car: 0, person: 1, bus: 0, truck: 0} def convert_voc_to_yolo(xml_dir, img_dir, out_dir): os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() # 用图像实际尺寸做归一化不要用 xml 里的 size 字段有些标注工具写错 img_name xml_file.replace(.xml, .jpg) img_path os.path.join(img_dir, img_name) if not os.path.exists(img_path): print(fmissing image: {img_name}) continue w, h Image.open(img_path).size lines [] for obj in root.findall(object): cls_name obj.find(name).text.strip().lower() if cls_name not in CLASS_MAP: continue 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_c (xmin xmax) / 2.0 / w y_c (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 裁剪到 [0,1]防止标注越界导致训练报错 x_c, y_c max(0, min(1, x_c)), max(0, min(1, y_c)) bw, bh max(0, min(1, bw)), max(0, min(1, bh)) lines.append(f{CLASS_MAP[cls_name]} {x_c:.6f} {y_c:.6f} {bw:.6f} {bh:.6f}) with open(os.path.join(out_dir, xml_file.replace(.xml, .txt)), w) as f: f.write(\n.join(lines)) convert_voc_to_yolo(./annotations, ./images, ./labels)逻辑说明遍历 xml 目录用 PIL 读对应图像的真实宽高做归一化而不是信任 xml 里的size字段——很多标注工具在图像旋转或缩放后不会更新这个字段用错了会导致框整体偏移。类别映射表把 car/bus/truck 合并成 0 类person 归为 1 类这是行人车辆检测最常见的二分类策略。参数方面x_c和y_c是框中心点相对整图宽高的比例bw和bh是框宽高比例YOLO 训练时直接读这五个值。如果转换后发现有 txt 文件是空的说明该图里没有目标类别的标注训练时要么删掉这条样本要么在数据配置里忽略空标签文件。2.2 目录结构按 YOLO 官方约定摆别自创层级YOLO 系列v5/v8/v11对目录结构有固定预期图像和标签分开放且文件名一一对应。我一般这样组织dataset/ ├── images/ │ ├── train/ # 约 265 张80% │ └── val/ # 约 66 张20% ├── labels/ │ ├── train/ │ └── val/ └── data.yaml331 张按 8:2 切训练集 264 张、验证集 67 张。切分时注意如果图像来自连续视频帧相邻帧高度相似随机切分会导致验证集里出现训练集的「近邻」mAP 虚高。我一般按拍摄时间段切——前 80% 时间段的图做训练后 20% 做验证。data.yaml内容如下path: ./dataset train: images/train val: images/val nc: 2 names: [vehicle, person]nc是类别数names顺序必须和转换脚本里CLASS_MAP的数值对应否则训练出来的模型会把车标成人。这个文件路径写错是新手最高频的翻车点报错通常是Dataset not found先检查path是相对路径还是绝对路径。2.3 用 YOLOv8 跑通第一轮训练的最小命令环境装好后一条命令就能启动yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/train \ nameexp1参数说明modelyolov8n.pt用 nano 版预训练权重331 张图从零训容易过拟合用 COCO 预训练权重做迁移学习收敛快得多。imgsz640是输入分辨率如果原图普遍小于 640设大了只是白白增加计算量。batch16在 8GB 显存上跑 640 分辨率刚好显存不够就降到 8。patience20表示 20 轮验证指标不提升就早停小数据集通常 60~80 轮就收敛了设 100 轮是留余量。训练完看runs/train/exp1/weights/best.pt这是验证集上表现最好的权重。3. 331 张图训 YOLO 的参数怎么调增强、anchor 与学习率3.1 小样本必须开增强但别开 mosaic 的默认强度331 张图直接训模型见过的车辆角度、光照、遮挡组合太少验证集稍微换个场景就崩。YOLOv8 默认开启 mosaic 增强四图拼接和 HSV 抖动这对小数据集是好事但默认 mosaic 概率 1.0 意味着每张训练图都被拼过331 张的多样性被过度稀释。我一般把 mosaic 降到 0.5同时打开mixup0.1和copy_paste0.1让模型既看到拼接场景也看到原始单图。yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ mosaic0.5 \ mixup0.1 \ copy_paste0.1 \ degrees10.0 \ translate0.1 \ scale0.5 \ fliplr0.5degrees10.0做 ±10 度旋转模拟监控摄像头安装角度偏差translate0.1平移 10%让目标不总在画面中心scale0.5缩放范围 0.5~1.5 倍覆盖远近车辆fliplr0.5水平翻转概率 50%行人车辆左右翻转不改变语义。这些参数加起来等效于把 331 张的样本空间扩了五六倍。注意别开flipud上下翻转车底朝天这种样本在真实场景不存在开了反而引入噪声。3.2 anchor 和损失函数小数据集别自己聚类YOLOv5 时代需要跑 k-means 聚类生成 anchor331 张图聚出来的 anchor 方差极大反而不如用 COCO 预训练的默认 anchor。YOLOv8 已经改成 anchor-free 的 decoupled head直接预测框中心偏移和宽高省掉了这一步。如果你用的是 YOLOv5我建议直接沿用yolov5s.yaml里的默认 anchor别自己聚。损失函数方面YOLOv8 用 TaskAlignedAssigner 做正负样本分配分类损失是 BCE、回归损失是 CIoU DFL。331 张图容易出现正样本太少导致分类分支欠拟合表现是模型能框出位置但类别置信度普遍偏低。这时候把cls损失权重从默认 0.5 提到 0.8或者把box权重从 7.5 降到 5.0让模型更关注分类。这个调整没有理论最优值得看验证集的混淆矩阵——如果车被大量误判为人就提分类权重如果框位置普遍偏移就提回归权重。3.3 学习率和 batch size 的搭配小数据集的玄学区331 张图batch16 时一个 epoch 只有 17 个 iteration100 个 epoch 总共 1700 次参数更新。这个更新次数对 nano 模型够用但对 s 或 m 模型偏少。我一般把lr0从默认 0.01 降到 0.005配合cos_lrTrue余弦退火让学习率从 0.005 平滑降到接近 0。如果 loss 曲线在前 10 轮震荡剧烈说明学习率还是大了降到 0.001 再试。另一个坑是warmup_epochs。默认 3 轮预热在 331 张图上相当于前 51 个 iteration 学习率从 0 线性升到设定值。如果 batch 设得小比如 4一个 epoch 有 66 个 iteration3 轮预热就是 198 次更新占比太高模型还没进入正常学习就消耗了 20% 的训练预算。我一般把warmup_epochs改成 1或者干脆设 0 直接恒定学习率。4. 训练过程排查loss 不降、mAP 虚高、显存溢出怎么破4.1 现象box_loss 从第一轮就卡在 0.8 不降原因通常是标签坐标越界或归一化错误。331 张图里只要有一二十张的框坐标超过 1.0YOLO 在计算 CIoU 时就会产生异常梯度把整个 batch 的回归分支带偏。解决方法是训练前跑一遍校验脚本逐行检查 txt 里的五个数值是否都在 [0,1] 区间以及x_center ± width/2是否越界。我习惯在转换脚本最后加一段断言越界的框直接裁剪而不是丢弃因为丢弃会导致该图某些目标消失模型学到「这类目标不存在」的错误信号。4.2 现象验证集 mAP 0.9 但实际测试一塌糊涂这是小数据集最典型的「虚高陷阱」。331 张图如果按随机切分验证集里很可能有和训练集同一段视频的相邻帧两帧之间只差几毫秒目标位置几乎一样。模型在验证集上等于在「背答案」。解决办法前面提过——按时间段切分或者用感知哈希pHash去重把相似度高于阈值的图只保留一张。我一般用 imagehash 库算汉明距离距离小于 5 的视为重复331 张里通常能筛出 20~40 张近重复图去掉后再切分验证集 mAP 会掉 0.1 左右但那个数字才是真实的。4.3 现象训练到一半 CUDA out of memory331 张图本身不大但 YOLOv8 默认会把整个数据集缓存到内存或显存做增强。如果开了cacheTrue且图像分辨率是 1920×1080331 张图缓存到显存能吃掉 2~3GB加上模型和 batch 数据8GB 卡很容易爆。解决方法是设cacheFalse或者用cacheram只缓存到内存。另一个原因是imgsz设太大331 张图如果原图是 4K设imgsz1280时单张图张量就是 1280×1280×3batch16 直接溢出。降到 640 通常能解决如果目标本身很小比如远处行人只有 20 像素高640 下缩到 10 像素就丢了这时候要么提高分辨率但降 batch要么用切片推理SAHI在推理阶段处理。4.4 现象训练完模型只识别车不识别行人类别不平衡。331 张图里如果车辆标注框有 800 个、行人只有 120 个模型会倾向于把所有疑似目标判成车因为这样分类损失更低。解决手段有三个一是过采样含行人的图像把行人样本多的图在训练列表里重复 2~3 次二是在损失函数里给行人类别更高权重YOLOv8 可以通过cls_pw参数调整三是降低行人的置信度阈值推理时把conf从 0.25 降到 0.15让更多行人候选框通过代价是误检增多需要根据业务容忍度权衡。5. 331 张之后用半自动标注和难例挖掘把数据滚起来331 张跑通只是起点真正让模型可用的关键是持续加数据。我的习惯是第一轮训练完拿best.pt去推理一批未标注的新图把置信度高于 0.6 的预测框直接转成 YOLO 标签置信度在 0.2~0.6 之间的框留给人工复核低于 0.2 的丢弃。这样一轮下来新图的标注成本能降 70%。下面这个脚本把预测结果转成可编辑的 txtfrom ultralytics import YOLO import os model YOLO(runs/train/exp1/weights/best.pt) results model.predict(source./new_images, conf0.2, save_txtTrue, save_confTrue) # save_txt 会在 runs/detect/predict/labels 下生成 txt # 人工只需复核 conf 在 0.2~0.6 的行高于 0.6 的直接采纳 for txt_file in os.listdir(runs/detect/predict/labels): path os.path.join(runs/detect/predict/labels, txt_file) with open(path) as f: lines f.readlines() kept [] for line in lines: parts line.strip().split() conf float(parts[-1]) if conf 0.6: kept.append( .join(parts[:5])) # 去掉 conf 列YOLO 训练不需要 else: kept.append(line.strip()) # 保留 conf 供人工判断 with open(path, w) as f: f.write(\n.join(kept))逻辑说明conf0.2是推理阈值低于这个值的框不输出。save_confTrue让每行末尾多一列置信度方便后续按阈值分流。高于 0.6 的行直接去掉 conf 列变成训练标签0.2~0.6 的行保留 conf 列人工在标注工具里打开时能一眼看出哪些需要重点检查。这个流程跑三轮331 张通常能滚到 1500~2000 张有效样本mAP 能再涨 0.1 以上。难例挖掘的重点是「模型反复判错的图」。我一般把验证集里 FP误检和 FN漏检最多的 20 张图挑出来人工重新标注后加入训练集。这些图往往包含遮挡、逆光、小目标等长尾场景加进去的边际收益远高于随机加 100 张普通图。331 张的初始集里这类难例可能只有十几张但把它们标对比多标 200 张晴天顺光图管用得多。最后说个习惯每次训练完我会把best.pt、data.yaml、训练命令和验证集 mAP 记在一个experiment_log.md里。331 张图跑十轮实验很容易忘记哪组参数对应哪个权重。这个日志后来成了团队里新人复现的「后悔药」——照着记录重跑结果基本能对上。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/11 18:38:30

智能体工程化实战:从 API 计费到合规分发的关键设计

把智能体从 demo 推进到生产,难点往往不在模型调用本身,而在工程化:如何稳定聚合多模型、如何按调用计费、如何把能力合规地分发出去。本文结合一线落地经验,梳理几个关键设计点。一、多模型聚合:别把业务绑死在单一模…

2026/10/11 19:33:32

十月十日,与黑猫 Shell 调试内核的静谧午后

十月十日,秋阳正好。 午后的阳光穿过百叶窗的缝隙,在深灰色的实木办公桌上切出一道道明暗交替的光栅。窗外的银杏树叶已经开始泛出淡淡的金黄,偶尔一阵秋风拂过,树叶沙沙作响。研发大楼的走廊里依旧回荡着匆忙的脚步声&#xff0c…

2026/10/11 19:33:32

C语言指针入门:从内存地址到调试实战

如果票选C语言里劝退率最高的知识点,指针应该能排进前三。我当年刚学的时候也被绕得晕头转向,书上一句“指针就是变量的地址”,可我脑子里总在犯嘀咕:地址到底长什么形状?直到后来在调试器里亲眼盯着一块内存、看着变量…

2026/10/11 19:33:32

编译原理实验:正则表达式转NFA与Lex扫描器实战全解

简介:本资源为编译原理课程实验报告文档,适用于计算机科学与技术专业本科生,也适合正在学习编译器前端知识、需要参考正则表达式到NFA转换实现及Lex词法分析器设计的学习者。实验依托Engintime CP Lab平台完成,报告详细梳理了从领…

2026/10/11 19:28:32

具身智能落地指南:从VLA模型到系统集成

简介:《具身智能发展报告(2024年)》是由中国信通院与北京人形机器人创新中心联合发布的研究报告,面向AI与机器人领域的研究者、工程师及政策制定者,系统梳理具身智能的概念内涵、技术体系、应用潜力与未来趋势。报告从…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑