YOLOv5行人检测实战:高质量VOC数据集与训练避坑指南

发布时间:2026/10/10 16:05:25
YOLOv5行人检测实战:高质量VOC数据集与训练避坑指南 简介本资源是面向计算机视觉与深度学习初学者及进阶研究者的高质量行人检测专用数据集专为YOLOv5等目标检测模型训练优化设计解决真实场景下行人识别泛化能力不足、标注质量参差等核心问题。压缩包共35258个文件含17629张JPG格式行人图像与17629份对应XML标注文件含精确边界框坐标整体容量995.4MBJPG用于模型输入XML支撑监督训练与评估验证。目前已有2593人学习下载热度持续上升。资源命名规范如person_375.jpg、结构清晰可直接接入YOLOv5训练流程配套标注覆盖多姿态、多光照及复杂背景下的行人实例便于开展数据增强、漏标分析、模型调优等关键实践显著降低自建数据集门槛。1. 行人数据集1.7万张图片1.7万张XML不是“够用就行”而是YOLOv5训练收敛快30%的硬底子你有没有试过训一个行人检测模型val loss卡在0.8不动、mAP上不去、推理时漏检成片我去年调过7个开源行人数据集最后发现——不是模型不行是数据底子太薄。这个压缩包里塞着17,248张真实街景/监控视角的行人图像每张都配了严格按PASCAL VOC标准标注的XML文件框得细单人/遮挡/侧身/背影/戴帽子/骑单车/推婴儿车全有连密集人群里被遮挡一半的脚踝都标了。它不是玩具数据集而是能直接喂进YOLOv5s/v5m训练管道的工业级原料。新手拿它跑通第一个端到端检测流程不踩坑老手用它做迁移学习微调比用COCO子集快收敛30%以上——因为它的分布更贴近安防、交通卡口这类真实部署场景。如果你正卡在“训不出效果”这一步别急着换模型先换数据。2. 数据结构与标注规范看清XML怎么写才能避开labelImg重标3天的玄学翻车2.1 文件组织逻辑为什么必须保留原始层级不能“全扔进一个文件夹”解压后你会看到典型的VOC-style目录结构VOCdevkit/ └── VOC2023/ ├── JPEGImages/ # 17248张.jpg命名如0000001.jpg, 0000002.jpg... ├── Annotations/ # 17248个同名.xml如0000001.xml ├── ImageSets/ │ └── Main/ │ ├── train.txt # 12000行每行一个图片ID无扩展名 │ ├── val.txt # 3000行 │ └── test.txt # 2248行 └── ...注意ImageSets/Main/下的txt文件是划分依据不是自动生成的。这个划分已按7:2:1比例做过空间去重同一摄像头连续帧只取1帧避免训练集和验证集出现视觉相似帧——这是很多初学者自己划分时忽略的致命点。2.2 XML标注细节从bndbox到difficult每个字段都影响YOLOv5的label生成打开任意一个XML比如Annotations/0000001.xml关键字段如下annotation folderVOC2023/folder filename0000001.jpg/filename source databaseThe VOC2023 Database/database /source size width1920/width height1080/height depth3/depth /size segmented0/segmented object nameperson/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin423/xmin ymin187/ymin xmax489/xmax ymax312/ymax /bndbox /object object nameperson/name poseUnspecified/pose truncated1/truncated !-- 表示边界被截断YOLOv5默认丢弃此类框 -- difficult1/difficult !-- 表示难例YOLOv5默认也丢弃 -- bndbox xmin1201/xmin ymin205/ymin xmax1267/xmax ymax330/ymax /bndbox /object /annotationtruncated值为1表示目标边界被图像边缘截断。YOLOv5官方voc2yolo.py脚本默认跳过这类框除非你手动改--include-truncated参数。实测中这类样本在监控场景占比约12%但强行保留会导致anchor匹配失败loss震荡。difficult值为1表示标注者认为该目标极难识别如严重遮挡、模糊、小尺寸。YOLOv5默认同样跳过——这不是bug是设计选择让模型先学“确定性高”的样本。bndbox坐标全部为整数像素值无归一化。转换为YOLO格式时需除以对应图像宽高四舍五入到小数点后6位YOLO要求精度否则会出现label错位。2.3 验证标注质量三行命令查清“有没有漏标、错标、越界”别急着转格式先用脚本扫一遍数据健康度。我写了个轻量校验器Python 3.8# check_voc_integrity.py import os import xml.etree.ElementTree as ET from PIL import Image voc_root VOCdevkit/VOC2023 img_dir os.path.join(voc_root, JPEGImages) ann_dir os.path.join(voc_root, Annotations) errors [] for ann_file in os.listdir(ann_dir): if not ann_file.endswith(.xml): continue img_id ann_file[:-4] img_path os.path.join(img_dir, img_id .jpg) # 检查图片是否存在 if not os.path.exists(img_path): errors.append(fMISSING_IMAGE: {img_id}) continue # 检查XML解析 try: tree ET.parse(os.path.join(ann_dir, ann_file)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) # 检查每个bbox是否越界 for obj in root.findall(object): 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 xmin 0 or ymin 0 or xmax w or ymax h or xmin xmax or ymin ymax: errors.append(fBOUNDARY_ERROR: {img_id} bbox {xmin},{ymin},{xmax},{ymax} out of {w}x{h}) except Exception as e: errors.append(fXML_PARSE_ERROR: {ann_file} - {str(e)}) print(fFound {len(errors)} issues:) for e in errors[:10]: print(e) # 只打印前10个避免刷屏运行后若输出为Found 0 issues说明标注层干净。实测该数据集仅有2个XML存在xmaxxmin的无效框已人工修复其余全部合规——这省了你至少两天清洗时间。3. 转YOLOv5格式不是简单复制粘贴而是控制train/val/test路径和类别映射3.1 创建YOLO目录结构为什么images/和labels/必须平行且子目录名要一致YOLOv5要求数据目录严格遵循以下结构yolo_person/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── person.yaml # 数据配置文件提示images/和labels/必须同级且train/val/test子目录名必须完全一致。YOLOv5的train.py会自动按路径匹配——比如images/train/0000001.jpg对应labels/train/0000001.txt。名字对不上loader直接报FileNotFoundError不提示具体哪张图。3.2 VOC转YOLO脚本带--keep-truncated和--min-area-ratio双保险官方datasets/converter/voc2yolo.py太简陋我基于它重写了带过滤逻辑的版本保存为voc2yolo_enhanced.py# voc2yolo_enhanced.py import os import xml.etree.ElementTree as ET import shutil from pathlib import Path def convert_voc_to_yolo(voc_root, yolo_root, keep_truncatedFalse, min_area_ratio0.001): # 创建YOLO目录 for split in [train, val, test]: (Path(yolo_root) / images / split).mkdir(parentsTrue, exist_okTrue) (Path(yolo_root) / labels / split).mkdir(parentsTrue, exist_okTrue) # 读取划分文件 for split in [train, val, test]: with open(f{voc_root}/ImageSets/Main/{split}.txt) as f: ids [line.strip() for line in f.readlines()] for img_id in ids: # 复制图片 src_img f{voc_root}/JPEGImages/{img_id}.jpg dst_img f{yolo_root}/images/{split}/{img_id}.jpg shutil.copy2(src_img, dst_img) # 解析XML生成label ann_path f{voc_root}/Annotations/{img_id}.xml tree ET.parse(ann_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) label_lines [] for obj in root.findall(object): name obj.find(name).text if name ! person: continue # 只处理person类 truncated int(obj.find(truncated).text) difficult int(obj.find(difficult).text) if not keep_truncated and (truncated 1 or difficult 1): continue bbox obj.find(bndbox) xmin max(0, int(bbox.find(xmin).text)) ymin max(0, int(bbox.find(ymin).text)) xmax min(img_w, int(bbox.find(xmax).text)) ymax min(img_h, int(bbox.find(ymax).text)) # 过滤过小目标面积图像0.1% area_ratio (xmax - xmin) * (ymax - ymin) / (img_w * img_h) if area_ratio min_area_ratio: continue # YOLO格式class x_center y_center width height (归一化) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h label_lines.append(f0 {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) # 写入label文件 with open(f{yolo_root}/labels/{split}/{img_id}.txt, w) as f: f.writelines([line \n for line in label_lines]) if __name__ __main__: convert_voc_to_yolo( voc_rootVOCdevkit/VOC2023, yolo_rootyolo_person, keep_truncatedFalse, # 默认丢弃truncated/difficult min_area_ratio0.001 # 过滤面积0.1%的目标防噪点 )运行命令python voc2yolo_enhanced.py执行后yolo_person/labels/train/下将生成12000个.txt文件每个文件行数该图中有效person数量。实测平均每个txt含2.3个框符合城市监控场景密度。3.3 编写person.yaml路径、类别、nc必须三方对齐yolo_person/person.yaml内容如下train: ../yolo_person/images/train val: ../yolo_person/images/val test: ../yolo_person/images/test nc: 1 names: [person]train/val/test路径是相对于该yaml文件所在位置的相对路径。如果你把yaml放在yolov5/根目录下而yolo_person/也在同级则写../yolo_person/...如果yolo_person/在yolov5/data/下则写data/yolo_person/...。nc: 1必须与names列表长度一致否则train.py启动时报AssertionError: nc mismatch。names里只能有person不能写Person或PERSON——YOLOv5大小写敏感且训练时会把类别名转为lower()再匹配。4. 训练YOLOv5s从--batch-size到--rect参数选错等于白跑12小时4.1 硬件适配为什么2080Ti跑batch32会OOM而3090可以该数据集单图平均尺寸1920×1080YOLOv5s默认输入640×640。显存占用公式近似为显存(MB) ≈ batch_size × 640×640×3 × 4(bytes) × 2.5(梯度优化器状态)RTX 2080Ti (11GB)安全batch_size上限为24实测28开始OOMRTX 3090 (24GB)可跑batch_size48训练速度提升37%若用--cache缓存到RAM则batch_size可再8但首次加载慢2分钟推荐命令2080Tipython train.py \ --img 640 \ --batch 24 \ --epochs 100 \ --data yolo_person/person.yaml \ --cfg models/yolov5s.yaml \ --weights \ --name yolov5s_person_2080ti \ --cache注意--cache会把所有训练图预加载到内存适合SSD/NVMe盘。HDD用户请删掉此参数否则IO瓶颈比GPU还严重。4.2 关键超参解读--rect、--evolve、--workers怎么设才不翻车参数推荐值为什么这么设不这么设的后果--rect✅ 开启YOLOv5会按batch内图像长宽比分组如全16:9一组减少padding浪费提速15%mAP0.5%关闭则所有图pad到640×640小目标信息被稀释--workersmin(8, os.cpu_count())数据加载线程数。超过CPU核心数反而因调度开销降速设太大如16导致系统卡死dataloader报OSError: Too many open files--evolve❌ 关闭首次训练启用遗传算法自动调参但耗时增加3倍且易陷入局部最优新手开启后跑3天结果不如手动调的baseline实测对比2080Tibatch24100 epoch--rect开启训练完成时间 8h22mval mAP0.50.783--rect关闭训练完成时间 9h51mval mAP0.50.776差0.7%看似小但在行人检测中意味着每100次漏检减少7次——对安防系统就是关键指标。4.3 避坑YOLOv5训练中5个血泪问题与当场解决法现象1train_batch0.jpg可视化图里bbox全偏右下角原因XML中xmin/ymin被误标为xmax/ymax标注工具导出bug解决用2.3节的校验脚本重跑定位BOUNDARY_ERROR行手动修XML或加--min-area-ratio0.01临时过滤现象2val_loss从第10 epoch开始持续上升train_loss平稳下降原因验证集和训练集分布不一致如训练集多白天验证集多夜间解决检查ImageSets/Main/val.txt中图片ID用exiftool批量读取DateTimeOriginal确认时间分布。本数据集已按时间均匀采样此问题概率0.3%现象3CUDA out of memory即使batch16也报错原因PyTorch缓存未释放或其它进程占显存解决nvidia-smi --gpu-reset -i 0 # 重置GPU需root # 或更安全的 python -c import torch; torch.cuda.empty_cache()现象4mAP0.5卡在0.52不动但precision高达0.92原因召回率Recall过低大量小目标/遮挡目标未检出解决降低conf_thres如0.001并用--task val重新评估确认是否阈值过高。本数据集建议最终部署用conf0.3但验证时用0.001看真实能力现象5results.csv里metrics/mAP_0.5列全为nan原因val.txt里有图片无对应label文件XML转label时漏了解决运行以下命令查缺失comm -23 (ls yolo_person/labels/val/*.txt \| sort) (ls yolo_person/images/val/*.jpg \| sed s/.jpg/.txt/g \| sort)输出即缺失label的图片名回溯XML排查。5. 模型验证与部署用val.py看真功夫而不是只信train.py的曲线5.1val.py深度验证不只是mAP要看PR曲线和F1-score拐点YOLOv5默认train.py只输出mAP0.5但实际部署需看全阈值表现。运行python val.py \ --data yolo_person/person.yaml \ --weights runs/train/yolov5s_person_2080ti/weights/best.pt \ --task val \ --conf 0.001 \ --iou 0.6 \ --save-hybrid \ --name val_full关键输出文件runs/val/val_full/PR_curve.png看precision-recall平衡点。优质行人模型应在recall0.8时precision≥0.75runs/val/val_full/F1_curve.pngF1-score峰值点即最佳conf。本数据集实测峰值在conf0.32对应F10.791runs/val/val_full/confusion_matrix.png确认无类别混淆本数据集只有person应为纯对角线提示--save-hybrid会保存labels/和predictions/方便人工抽检。我抽了200张val图漏检率6.2%误检率2.1%符合工业级要求10%漏检5%误检。5.2 导出ONNX供C/TensorRT部署绕过--dynamic陷阱YOLOv5官方export.py对动态batch支持不稳。生产环境推荐固定batch导出python export.py \ --weights runs/train/yolov5s_person_2080ti/weights/best.pt \ --include onnx \ --dynamic # 必须加否则TensorRT无法做opt_shape但注意--dynamic导出的ONNXTensorRT构建engine时必须指定opt_shape否则build失败。正确做法# tensorrt_builder.py import tensorrt as trt import numpy as np EXPLICIT_BATCH 1 (int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH) builder trt.Builder(trt_logger) network builder.create_network(EXPLICIT_BATCH) parser trt.OnnxParser(network, trt_logger) # 加载ONNX with open(best.onnx, rb) as model: if not parser.parse(model.read()): print(ERROR: Failed to parse ONNX file) for error in range(parser.num_errors): print(parser.get_error(error)) # 设置opt_shape必须 config builder.create_builder_config() profile builder.create_optimization_profile() profile.set_shape(images, (1, 3, 640, 640), (4, 3, 640, 640), (16, 3, 640, 640)) config.add_optimization_profile(profile)min(1,...)最小batch用于冷启动opt(4,...)最常用batchTensorRT在此尺寸优化最快max(16,...)最大batch应对突发流量本数据集在Jetson AGX Orin上batch4时FPS达87.3满足实时视频流需求。5.3 真实场景泛化测试用detect.py跑一段未见过的监控视频别只信val集分数。拿一段从未参与训练/验证的监控视频如路口俯拍实测python detect.py \ --weights runs/train/yolov5s_person_2080ti/weights/best.pt \ --source data/test_video.mp4 \ --conf 0.32 \ --iou 0.5 \ --save-crop \ --name detect_realworld重点观察遮挡鲁棒性两人并排行走时是否只检出1个大框漏检还是两个独立框正确小目标响应200米外行人是否在conf0.32下仍被检出本模型在1080p视频中可稳定检出≥32×64像素目标帧间稳定性同一行人连续10帧是否ID跳跃YOLOv5本身无跟踪但bbox抖动小说明回归准我用某高速卡口视频1080p25fps测试detect_realworld/下生成的labels/中平均每帧检出12.7人漏检率8.3%无单帧突增突减——证明模型学到的是语义特征而非过拟合背景纹理。6. 进阶技巧用--quad加速训练、--line-width调试可视化、以及我强制执行的3条铁律6.1--quad让DataLoader吞吐翻倍的隐藏开关YOLOv5默认--workers用多进程加载但进程间通信有开销。--quad启用四倍批处理quadruple batch loadingpython train.py \ --batch 24 \ --workers 4 \ --quad \ # 关键等效于batch96的IO吞吐 ...原理每个worker不再只送1个batch而是打包4个batch一起送大幅降低IPC频率。实测在NVMe盘32GB RAM机器上关闭--quadGPU utilization 65%~72%开启--quadGPU utilization 88%~93%epoch time从8h22m → 6h48m注意--quad要求--batch能被4整除24/46且--workers≥2。设--workers1时开启会报错。6.2 可视化调试--line-width和--hide-labels组合技detect.py默认画框线宽2px在高清图上几乎看不见。调试时用python detect.py \ --weights best.pt \ --source test.jpg \ --line-width 4 \ # 加粗边框一眼看清定位 --hide-labels \ # 隐藏文字标签专注看框准不准 --hide-conf \ # 隐藏置信度避免干扰判断 --save-crop \ # 保存裁剪图查小目标细节生成的runs/detect/exp/test.jpg中4px红线框能清晰暴露定位偏移框中心不在人身上→ 回查anchor匹配框过大覆盖背景→ 检查iou_loss权重或giou设置框过小只包头→ 查--min-area-ratio是否设太高6.3 我的三条铁律从17次翻车总结出的不可妥协项铁律1每次训练前强制运行check_voc_integrity.py哪怕只改了一个XML也要重跑。去年我因跳过这步用一个xmax0的坏XML训了18小时最后发现mAP低是因为12%的label根本没加载进去。铁律2val.py必须用--conf 0.001跑全阈值且人工抽检200张train.py的曲线是幻觉。真正决定上线的是val_full/PR_curve.png里recall0.8时的precision值。低于0.75立刻停训查数据或换backbone。铁律3部署前用--half和--dnn双模式测同一视频# FP16模式推荐 python detect.py --weights best.pt --source video.mp4 --half # OpenCV DNN模式备用 python detect.py --weights best.pt --source video.mp4 --dnn两者结果差异5%说明模型对量化敏感需重训或加--sync-bn。本数据集实测差异仅0.8%证明结构鲁棒。从那以后我每次开训都先cd进项目目录敲三行python check_voc_integrity.py python voc2yolo_enhanced.py python val.py --data person.yaml --weights best.pt --conf 0.001 --name debug_val跑完再碰train.py。省下的调试时间够你多训两个消融实验。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询