331张图像小样本YOLO训练:行人车辆检测实战与部署边界
简介这是一份面向YOLO系列目标检测学习者的行人车辆标注数据集适用于yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流算法可直接用于模型训练与验证测试适合入门练手或课程项目实践。资源包共994个文件包含331张jpg图像、331个txt标签、331个xml标签以及1个yaml配置文件压缩包约19.4MB其中txt为YOLO格式标注xml为VOC格式标注两种格式分别存放便于按需选用data.yaml已划分好数据集省去手动整理环节。标注采用归一化中心点与宽高比例类别索引从0开始涵盖汽车与行人两类目标。目前已有83人学习下载读者可借此快速搭建训练流程、验证数据增强与模型调参效果并对比YOLO与VOC两种标注格式的转换与使用差异为后续自定义数据集标注与迁移学习提供参考。1. 331张图像的行人车辆数据集小样本YOLO训练到底能不能落地手上拿到一个标注好的行人车辆数据集331张图像带YOLO格式标签类别就两个汽车和人。第一反应大概率是——这么点数据能训出能用的模型吗我一开始也这么想但实际跑过几轮之后发现这个量级在特定场景下完全能打关键看你怎么用。这个数据集解决的核心问题是快速验证一个行人车辆检测方案是否可行而不是直接上生产。适合谁适合刚入门YOLO想跑通全流程的人适合需要快速做demo验证产品思路的团队也适合做边缘设备部署前想先摸清模型下限的工程师。331张图像听起来少但如果场景集中、标注质量过关配合迁移学习和合理的数据增强mAP能到可用的水平。下面把我从数据检查到训练调参再到部署验证的完整路径拆开讲每一步都给出可复现的操作。2. 拿到331张带标签图像后先做这三项数据体检2.1 标签格式确认与类别映射YOLO格式的标签是每张图对应一个txt文件每行格式为类别索引 中心x 中心y 宽度 高度坐标都是归一化到0到1之间的浮点数。331张图像带标签第一步不是急着训练而是确认标签文件和图像文件是否一一对应以及类别索引到底对应什么。常见做法是写个脚本快速统计import os from pathlib import Path from collections import Counter img_dir Path(images) label_dir Path(labels) img_files {p.stem for p in img_dir.glob(*.jpg)} label_files {p.stem for p in label_dir.glob(*.txt)} # 检查配对情况 only_img img_files - label_files only_label label_files - img_files print(f仅有图像无标签: {len(only_img)}) print(f仅有标签无图像: {len(only_label)}) # 统计类别分布 class_counter Counter() for lbl in label_dir.glob(*.txt): with open(lbl) as f: for line in f: parts line.strip().split() if parts: class_counter[int(parts[0])] 1 print(类别分布:, dict(class_counter))这段代码做两件事一是找出图像和标签不匹配的文件二是统计每个类别的标注框数量。如果发现某个类别只有几十个框那训练时就要考虑过采样或者调整损失权重。参数方面img_dir和label_dir按实际路径改类别索引从0开始通常0是行人、1是汽车但一定要跟数据集提供方确认别自己猜。2.2 图像尺寸分布与标注框尺寸统计331张图像的尺寸可能不统一直接resize到640×640会带来什么问题小目标变得更小大目标比例失真。先统计一下原始尺寸和标注框的宽高分布import cv2 import numpy as np widths, heights [], [] box_areas [] for img_path in img_dir.glob(*.jpg): img cv2.imread(str(img_path)) h, w img.shape[:2] widths.append(w) heights.append(h) lbl_path label_dir / (img_path.stem .txt) if lbl_path.exists(): with open(lbl_path) as f: for line in f: parts line.strip().split() if len(parts) 5: bw, bh float(parts[3]) * w, float(parts[4]) * h box_areas.append(bw * bh) print(f图像宽度范围: {min(widths)}-{max(widths)}, 均值: {np.mean(widths):.0f}) print(f图像高度范围: {min(heights)}-{max(heights)}, 均值: {np.mean(heights):.0f}) print(f标注框面积中位数: {np.median(box_areas):.0f} 像素)如果标注框面积中位数低于32×32像素就属于小目标检测范畴训练时输入分辨率不能降太多建议保持640甚至更高。如果图像本身分辨率差异大比如有的1920×1080有的640×480那就要在数据加载时统一处理策略——要么全部letterbox到640×640要么分组训练。2.3 数据增强策略的取舍331张图像做增强不是越多越好。我一般会开这几项随机水平翻转概率0.5、随机缩放0.5到1.5倍、随机平移0.1、HSV色彩抖动色调0.015、饱和度0.7、亮度0.4。马赛克增强mosaic对小数据集提升明显但要注意如果图像里目标本身就密集mosaic拼接后可能造成目标截断反而引入噪声。提示331张图像如果场景单一比如都是同一路段、同一时间段拍的增强参数可以激进一些如果场景本身多样增强反而可能让模型学到不相关的纹理。类别不平衡时可以在数据加载器里对包含稀有类别的图像做重复采样。比如行人标注框只有汽车的三分之一那就把包含行人的图像在每个epoch里多采样一次。这个操作在YOLO的dataloader里改一下采样权重就行不用改网络结构。3. 用YOLOv8在331张图上跑通训练配置文件与关键参数3.1 数据集yaml配置与目录结构YOLOv8要求的数据集配置文件是一个yaml里面指定训练集、验证集路径和类别名称。331张图像建议按8:2划分训练集264张、验证集67张。如果数据量再少可以考虑交叉验证但331张用固定验证集就够了。目录结构建议这样组织dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml内容path: ./dataset train: images/train val: images/val names: 0: person 1: car这里path是数据集根目录train和val是相对路径。类别索引必须和标签文件里的数字对应names里的顺序就是索引顺序。如果标签里0是car、1是person那names也要反过来写否则训练出来的模型会把类别搞混。3.2 训练命令与超参数设置用YOLOv8n或YOLOv8s这种小模型就够了331张图像训大模型纯属浪费算力还容易过拟合。我一般用YOLOv8s参数量适中在边缘设备上也能跑。yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs200 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience50 \ augmentTrue \ mosaic1.0 \ mixup0.1 \ copy_paste0.1 \ device0 \ projectruns/train \ nameped_car_331逐项说明epochs200是因为小数据集需要更多轮次收敛但配合patience50早停验证集50轮不提升就停。lr00.01是初始学习率小数据集可以适当降低到0.005避免震荡。mosaic1.0表示始终开启mosaic增强mixup0.1和copy_paste0.1是额外增强概率低一点防止过拟合。batch16在显存够的情况下尽量大一点331张图一个epoch也就17个batch。如果显存不够把batch降到8同时把lr0按比例降到0.005。imgsz640是标准输入尺寸如果标注框普遍偏小可以提到1280但训练时间会翻倍。3.3 训练过程监控与早停判断训练启动后重点看三个指标box_loss、cls_loss和mAP50。前10个epoch loss下降快是正常的如果50个epoch后box_loss还在0.5以上说明模型没学好要么是学习率太大要么是标注有问题。from ultralytics import YOLO model YOLO(runs/train/ped_car_331/weights/best.pt) metrics model.val(datadataset/data.yaml, imgsz640, batch16) print(fmAP50: {metrics.box.map50:.4f}) print(fmAP50-95: {metrics.box.map:.4f}) print(f每类AP: {metrics.box.ap50})验证时注意看每类的AP如果行人AP远低于汽车说明行人类别样本太少或者标注质量差。331张图像里如果行人只有几十个框AP低是正常的可以通过增加行人类别的损失权重来缓解在训练命令里加cls1.5把分类损失放大。注意验证集不要用来调参调参看训练集的loss曲线验证集只在最后评估用。331张图像如果反复在验证集上调很快过拟合。4. 小数据集训练行人车辆检测的五个翻车现场4.1 现象训练loss正常下降但验证mAP始终在0.2以下原因标注框坐标归一化时用了错误的图像尺寸。比如图像实际是1280×720但标注时按640×640算的导致所有框位置偏移。331张图像如果来自不同来源尺寸不统一这个问题特别常见。解决写脚本逐张检查标注框是否超出图像边界以及框的宽高是否合理。正常标注框的宽高应该在0.01到0.9之间如果大量框的宽高接近1.0说明归一化用错了分母。4.2 现象模型把汽车检测成行人或者两个类别置信度都很低原因类别索引映射错了。标签文件里0和1对应的类别和data.yaml里的names不一致。有些数据集标注时0是car但训练时按0是person配的。解决打开几个标签文件结合图像看一眼确认0到底对应什么。如果不确定把两个类别的AP分别打出来AP异常低的那个大概率是映射错了。4.3 现象训练到100轮后box_loss突然飙升原因学习率没有衰减或者衰减太慢模型在局部最小值附近震荡。331张图像的小数据集学习率对训练稳定性影响很大。解决用余弦退火学习率调度在训练命令里加cos_lrTrue或者把lrf设成0.001让学习率降到初始值的千分之一。另外检查一下有没有脏数据比如某张图的标注框坐标是NaN。4.4 现象验证集mAP比训练集低很多差距超过0.3原因过拟合。331张图像训200个epoch模型把训练集背下来了。数据增强不够或者模型太大都会导致这个问题。解决先看训练集和验证集的loss曲线如果训练loss持续下降但验证loss在某个点后开始上升就是过拟合。减小模型YOLOv8n代替YOLOv8s、增加增强强度、加dropoutYOLOv8里用dropout0.1、早停。4.5 现象推理时检测框大量重叠NMS后只剩一个框原因标注时同一个目标被标了多个框或者两个目标挨得太近。331张图像如果标注质量参差不齐这个问题很常见。解决训练前做一次标注清洗用IoU阈值0.7检查同一张图里有没有高度重叠的同类框有就合并或删除。推理时把NMS的IoU阈值从0.45调到0.5到0.6之间给密集目标留更多框。5. 331张图像训完后的模型能干什么验证与部署的边界5.1 用混淆矩阵和PR曲线判断模型真实水平训练完不要只看mAP把混淆矩阵和PR曲线拉出来看。混淆矩阵能告诉你模型把多少汽车误判成了行人PR曲线能看出在不同置信度阈值下的召回率和精确率。from ultralytics import YOLO import matplotlib.pyplot as plt model YOLO(runs/train/ped_car_331/weights/best.pt) results model.val(datadataset/data.yaml, plotsTrue, save_jsonTrue) # 混淆矩阵和PR曲线会自动保存到runs/val目录下看混淆矩阵时重点关注对角线以外的数值。如果汽车和行人之间的误判超过10%说明两个类别的特征区分度不够要么增加样本要么在损失函数里加大类间距离的惩罚。5.2 导出ONNX并在CPU上测推理速度331张图像训出来的模型参数量小导出ONNX后在CPU上也能跑。导出命令yolo export modelruns/train/ped_car_331/weights/best.pt formatonnx imgsz640 simplifyTrue导出后用onnxruntime测一下单张推理耗时import onnxruntime as ort import numpy as np import time sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name dummy np.random.randn(1, 3, 640, 640).astype(np.float32) # 预热 for _ in range(5): sess.run(None, {input_name: dummy}) start time.time() for _ in range(50): sess.run(None, {input_name: dummy}) print(f平均推理耗时: {(time.time()-start)/50*1000:.1f} ms)如果CPU上单张超过100ms说明模型还是偏大换YOLOv8n重新训。331张图像训YOLOv8n和YOLOv8s的mAP差距通常在3到5个点以内但速度差一倍。5.3 什么场景下这个模型直接能用什么场景必须补数据331张图像训出来的行人车辆检测模型在以下场景可以直接用固定摄像头、光照条件稳定、目标尺度变化不大、背景单一。比如小区门口的行人车辆统计、停车场出入口的车辆计数。以下场景必须补数据夜间或低光照、雨雪雾天气、目标密集且遮挡严重、摄像头角度变化大。这些场景下331张图像覆盖不到模型会漏检或误检。补数据时优先补困难样本比如夜间行人、被部分遮挡的车辆每类再补200到300张就能明显提升。我自己的习惯是每次训完模型先拿一段没参与训练的实拍视频跑一遍看漏检和误检集中在什么场景然后针对性地补那类数据。331张图像是个起点不是终点。希望帮到你。本文还有配套的精品资源点击获取