简介:本资源面向计算机视觉初学者与行人检测方向开发者,提供一套可直接复用的YOLOv5-6.0行人检测训练权重与配套数据集,解决街道、公路等场景下行人目标检测的模型训练与验证需求。压缩包共约2000个文件、378.52MB,以jpg图像与txt标注为主,辅以yaml配置、py训练脚本、pt权重及少量xml、sh、md等文件,覆盖数据、代码、权重与说明文档的完整链路。资源内含3000张多行人图像,标注同时提供VOC与YOLO两种格式,并附有训练曲线图,模型基于一万余条数据训练,准确率达90%以上,类别为person。已有6309人学习下载,读者可据此快速完成环境搭建、模型复现与效果评估,也可直接用于二次训练或迁移到自有行人检测任务中,节省数据标注与调参成本。
1. 拿到一份 YOLOv5 行人检测权重和 3000 张数据集,先别急着训练
你手上如果有一个yolov5-6.0-person_detect.zip,里面装着 3000 张行人数据集和一份训练好的权重,最该做的不是马上train.py跑起来,而是先搞清楚这三件事:权重是在什么数据上训的、数据集标注格式对不对、推理时的输入尺寸和置信度阈值是多少。我见过太多人拿到权重直接套自己的监控画面,结果满屏漏检,回头骂模型不行,其实是没对齐训练分布。
行人检测这个任务在 YOLOv5 生态里属于「看起来简单、落地全是坑」的典型。COCO 预训练权重里 person 类确实能检出人,但密集场景、小目标、遮挡、夜间红外画面下,通用权重的召回率会掉得很难看。所以一份专门用 3000 张行人数据微调过的权重,价值就在于它把特征空间往「人」这个类上收窄了。这篇文章就围绕这份权重和数据集,把从环境搭建、数据校验、推理验证到微调训练、量化部署的完整链路讲清楚,适合已经跑通过 YOLOv5 demo、想把它真正用到行人检测场景的工程师。
2. 权重和数据集到手后的第一轮体检:别让格式问题浪费一晚上
2.1 先确认权重版本和数据集目录结构
YOLOv5 的权重文件后缀是.pt,但 6.0 版本和 7.0 版本的模型结构有差异,直接混用会报KeyError或者加载后精度异常。拿到yolov5-6.0-person_detect.zip后,先解压看目录,常见结构是权重放在weights/下,数据集按 YOLO 标准格式组织:
person_detect/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── person_detect.yaml如果解压出来是JPEGImages+Annotations这种 VOC 结构,说明数据集还没转成 YOLO 格式,需要先转换。YOLO 格式的标签是每张图对应一个.txt,每行class_id x_center y_center width height,坐标全部归一化到 0~1。行人检测通常只有一类,所以class_id恒为 0。
提示:先看
person_detect.yaml里的nc和names,如果nc: 1且names: ['person'],说明是单类行人检测;如果nc: 80,那这份权重很可能是 COCO 全类微调后只保留 person 的,推理时要注意类别索引。
2.2 用脚本校验标签,避免训练时 loss 直接 NaN
标签里只要有一个坐标超出 [0,1] 或者宽高为 0,训练几个 epoch 后 loss 就可能变 NaN。我一般会先跑一个校验脚本,把问题样本挑出来:
import os import numpy as np label_dir = "person_detect/labels/train" bad_files = [] for txt in os.listdir(label_dir): if not txt.endswith(".txt"): continue path = os.path.join(label_dir, txt) with open(path, "r") as f: lines = f.readlines() for i, line in enumerate(lines): parts = line.strip().split() if len(parts) != 5: bad_files.append((txt, i, "字段数不对")) continue cls, x, y, w, h = map(float, parts) # 坐标必须在 0~1 之间,宽高必须大于 0 if not (0 <= x <= 1 and 0 <= y <= 1 and 0 < w <= 1 and 0 < h <= 1): bad_files.append((txt, i, f"坐标异常: {parts}")) # 宽高过小说明是标注错误或极小目标 if w * h < 1e-4: bad_files.append((txt, i, f"目标过小: {parts}")) print(f"问题文件数: {len(bad_files)}") for item in bad_files[:20]: print(item)这段脚本做三件事:检查每行是否恰好 5 个字段、检查归一化坐标是否越界、检查宽高乘积是否过小。w * h < 1e-4这个阈值对应原图约 10x10 像素的目标,行人检测里这种目标要么是标注错误,要么是远景小目标,训练时容易带偏梯度。跑完如果问题文件超过 5%,建议直接剔除这些样本重新生成标签,而不是硬训。
2.3 统计类别分布和图像尺寸,决定输入分辨率
3000 张行人数据集不算大,如果里面正样本(含人的图)和负样本(纯背景)比例失衡,模型会偏向预测背景。用下面这段代码快速统计:
import os import cv2 from collections import Counter img_dir = "person_detect/images/train" label_dir = "person_detect/labels/train" sizes = [] pos, neg = 0, 0 for img_name in os.listdir(img_dir): img_path = os.path.join(img_dir, img_name) img = cv2.imread(img_path) if img is None: continue h, w = img.shape[:2] sizes.append((w, h)) txt = os.path.join(label_dir, os.path.splitext(img_name)[0] + ".txt") if os.path.exists(txt) and os.path.getsize(txt) > 0: pos += 1 else: neg += 1 print("正样本:", pos, "负样本:", neg) print("尺寸分布:", Counter(sizes).most_common(5))如果负样本占比超过 30%,训练时要把hyp里的fl_gamma调低或者增加正样本采样权重。尺寸统计决定imgsz设多少:如果大部分图是 1920x1080,直接 resize 到 640 会让远处行人变成几个像素,建议用imgsz=960或切片推理。我一般会看尺寸分布的中位数,取中位数短边的 1/2 作为imgsz起点。
3. 用这份权重跑通推理:从单图到视频流的参数怎么调
3.1 最小推理命令和置信度阈值的选择
YOLOv5 6.0 的推理入口是detect.py,加载这份行人权重的最小命令:
python detect.py \ --weights weights/person_detect.pt \ --source test_images/ \ --img-size 640 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --device 0--conf-thres是置信度阈值,行人检测里这个值很关键。设 0.25 是通用起点,但监控场景下远处行人得分普遍偏低,可以降到 0.15 看召回;如果误检太多(把树影、广告牌上的人像检出来),再往上调到 0.4。--iou-thres控制 NMS 合并,密集人群场景下 0.45 容易把挨着的人合并成一个框,可以提到 0.6。--img-size要和训练时一致,如果权重是用 640 训的,推理用 1280 不会提升精度,反而因为尺度不匹配掉点。
注意:
--device 0表示用第一块 GPU,如果只有 CPU 就写--device cpu,但 640 输入下单张推理大概 200~400ms,视频流会卡。
3.2 批量推理和结果落盘的目录约定
实际项目里很少一张张跑,通常要批量处理整个文件夹并保存可视化结果:
python detect.py \ --weights weights/person_detect.pt \ --source /data/videos/ \ --img-size 640 \ --conf-thres 0.3 \ --save-txt \ --save-conf \ --project runs/detect \ --name person_exp1 \ --exist-ok--save-txt会把检测框按 YOLO 格式写到runs/detect/person_exp1/labels/,--save-conf在每行末尾加上置信度。这两个参数在做后续跟踪或统计人流时必开,否则你只能看到画了框的图,拿不到结构化数据。--exist-ok允许覆盖同名目录,调试阶段省事,但正式跑批建议去掉,避免误覆盖上一次结果。
3.3 视频流推理的帧率优化和跳帧策略
用--source 0直接读摄像头时,瓶颈往往在预处理和后处理,不在模型本身。我一般会做两件事:一是把--img-size降到 480 或 512,二是跳帧推理。YOLOv5 的detect.py本身不支持跳帧,需要改LoadStreams或者在外面包一层:
import cv2 import torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='weights/person_detect.pt', force_reload=False) model.conf = 0.3 model.iou = 0.5 cap = cv2.VideoCapture(0) frame_id = 0 while True: ret, frame = cap.read() if not ret: break frame_id += 1 # 每 3 帧推理一次,其余帧复用上次结果 if frame_id % 3 == 0: results = model(frame, size=640) boxes = results.xyxy[0].cpu().numpy() for x1, y1, x2, y2, conf, cls in boxes: cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.imshow('person', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()跳帧的代价是快速移动的行人框会滞后,如果做跟踪,建议用卡尔曼滤波补帧,而不是简单复用。model.conf和model.iou是直接改模型属性,比命令行参数更灵活,适合在代码里动态调整。
4. 想在自己的数据上继续微调:3000 张够不够、超参怎么设
4.1 微调还是从头训:看你的场景和这份权重的差距
3000 张行人数据训一个 YOLOv5s 从零开始,大概率欠拟合,mAP 能到 0.5 就不错了。但如果这份权重已经在类似场景(比如街景、监控)上训过,你只是补充一些特定角度或光照的样本,那微调 50~100 个 epoch 就能有明显提升。判断标准很简单:用你的验证集跑一遍现有权重,如果 mAP@0.5 已经超过 0.6,说明特征空间基本对,微调即可;如果低于 0.3,要么场景差异太大,要么标注有问题,先解决数据再谈训练。
微调时学习率要降,YOLOv5 默认lr0=0.01是从头训的配置,微调建议lr0=0.001,lrf=0.01,并且冻结前几层:
python train.py \ --weights weights/person_detect.pt \ --data person_detect.yaml \ --epochs 80 \ --batch-size 16 \ --img-size 640 \ --lr0 0.001 \ --lrf 0.01 \ --freeze 10 \ --hyp data/hyps/hyp.scratch-low.yaml--freeze 10表示冻结 backbone 前 10 层,只训 neck 和 head。行人检测的底层特征(边缘、纹理)和通用目标差异不大,冻结能防止小数据集过拟合。--hyp选hyp.scratch-low.yaml是因为它做了更强的数据增强(mosaic、mixup 比例更高),3000 张图需要靠增强撑住泛化。
4.2 关键超参:anchor、mosaic 和 warmup 的取舍
YOLOv5 6.0 默认 anchor 是基于 COCO 聚类的,行人检测里人的宽高比集中在 1:2 到 1:4 之间,和 COCO 的 anchor 分布有偏差。如果微调后小目标召回一直上不去,可以用--noautoanchor关掉自动 anchor,然后自己用 k-means 在 3000 张数据上重新聚类:
python utils/autoanchor.py \ --data person_detect.yaml \ --weights weights/person_detect.pt \ --img-size 640这个脚本会输出建议的 anchor 尺寸,替换到模型配置里。mosaic 增强在微调后期建议关掉,因为 mosaic 拼接会让行人被裁切,最后 10 个 epoch 用--close-mosaic 10让模型适应真实分布。warmup 阶段warmup_epochs=3对微调足够,太长反而浪费。
4.3 训练过程看什么指标:mAP、召回和 val_loss 的联动
训练日志里重点看三个数:metrics/mAP_0.5、metrics/recall和val/box_loss。mAP 涨但 recall 不涨,说明模型在提高已检出目标的精度,但漏检没改善,这时候要降conf-thres看验证集,或者检查标注里有没有漏标的人。val/box_loss如果连续 10 个 epoch 不降反升,说明过拟合了,提前停或者加大weight_decay。我一般会在--patience 20的基础上,自己看results.csv画曲线,mAP_0.5:0.95比mAP_0.5更能反映框的定位质量,行人检测里定位准比分类准更重要。
5. 部署到边缘设备:量化、转换和推理速度的坑
5.1 从 .pt 到 ONNX 再到 RK3568 的转换链路
标题热词里提到yolov5量化rk3568和树莓派4b部署yolov5,这两条路我都踩过。先说通用链路:.pt→ ONNX → 目标平台格式。导出 ONNX:
python export.py \ --weights weights/person_detect.pt \ --include onnx \ --img-size 640 \ --batch-size 1 \ --opset 12 \ --simplify--opset 12是兼容性比较好的版本,--simplify会用 onnx-simplifier 去掉冗余节点。导出后一定要用onnxruntime跑一遍验证输出和 PyTorch 一致,否则后面量化误差会放大。RK3568 的 NPU 工具链(RKNN-Toolkit)对 ONNX 的算子支持有限,YOLOv5 里的Focus层和SiLU激活经常需要替换,常见做法是导出时把Focus换成Conv,激活换成ReLU或LeakyReLU。
5.2 量化时的精度损失和校准集选择
RKNN 和 TensorRT 的 INT8 量化都需要校准集,校准集选不好,行人检测的召回能掉 20 个点。我一般从训练集里抽 200~500 张,覆盖不同光照、遮挡、密度场景,不要只用白天的清晰图。量化脚本里do_quantization=True,dataset指向校准图片列表:
from rknn.api import RKNN rknn = RKNN() rknn.config(mean_values=[[0, 0, 0]], std_values=[[255, 255, 255]], target_platform='rk3568', quantized_dtype='asymmetric_quantized-8') rknn.load_onnx(model='person_detect.onnx') rknn.build(do_quantization=True, dataset='calib_list.txt') rknn.export_rknn('person_detect.rknn')mean_values和std_values要和训练时的归一化一致,YOLOv5 默认是 0~1 归一化,所以 std 写 255。量化后必须在板子上跑验证集,对比 FP32 和 INT8 的 mAP,如果掉超过 5 个点,要么增加校准集,要么对敏感层(比如检测头)保持 FP16。
5.3 树莓派 4B 上的实测帧率和内存占用
树莓派 4B 用 ONNX Runtime 跑 YOLOv5s 640 输入,单核大概 1.5~2 FPS,四核并行能到 4~5 FPS,内存占用 500MB 左右。想再快只能降输入到 320 或者换 YOLOv5n。我实测过--img-size 320下能到 8~10 FPS,但小目标行人基本检不到,适合近距离场景。如果一定要在树莓派上跑 640,建议用 NCNN 或 OpenVINO,比 ONNX Runtime 快 30% 左右。散热也要注意,连续跑 10 分钟以上会降频,帧率掉一半,加个风扇是刚需。
6. 几个让我熬夜的排查记录和一条验证习惯
6.1 权重加载成功但推理全图只有一个框
现象:detect.py跑完,每张图只输出一个覆盖全图的大框,置信度 0.9 以上。原因:标签格式错了,把class_id x y w h写成了x y w h class_id,模型学到的「目标」就是整张图。解决:用 2.2 的校验脚本检查字段顺序,重新生成标签。这个坑我踩过两次,第二次是因为转换脚本里split()后索引写反了。
6.2 训练 loss 正常但 mAP 一直是 0
现象:train.py跑完 100 epoch,box_loss降到 0.05,但mAP_0.5始终是 0。原因:person_detect.yaml里的val路径指向了空文件夹,或者验证集标签和图片没对上(文件名差一个后缀)。解决:检查val: person_detect/images/val下有没有图,labels/val下有没有同名.txt,用os.path.splitext对齐文件名。
6.3 量化后模型在板子上输出全零
现象:RKNN 模型加载成功,推理输出全是 0 或 NaN。原因:校准集图片的预处理和训练不一致,比如训练用了 BGR,量化时用了 RGB,或者mean_values设错。解决:在校准脚本里显式用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)并确认std_values和训练归一化匹配。我一般会先用一张训练集图片在 PC 上跑 RKNN 模拟器,输出和 ONNX 对比,一致了再上板子。
6.4 视频推理越跑越慢,最后卡死
现象:detect.py读视频流,前 100 帧正常,之后帧率线性下降。原因:--save-txt和--save-conf每帧都写文件,IO 阻塞了推理线程,或者LoadStreams的队列堆积。解决:把结果先存内存,每 100 帧批量落盘;或者用多进程,一个进程推理,一个进程写文件。树莓派上还要注意 SD 卡写入速度,换 USB 3.0 固态会好很多。
6.5 一条验证习惯:先过拟合 10 张图
每次拿到新权重或新数据,我会先挑 10 张图,用--epochs 200 --batch-size 2训到 loss 接近 0,然后在这 10 张图上推理。如果 mAP 不是 1.0,说明数据管道或标签有问题,不用继续训 3000 张。这个习惯帮我省了至少几十个小时的无效训练。过拟合小样本是验证整条链路最快的办法,比看日志猜问题靠谱得多。
希望帮到你。
本文还有配套的精品资源,点击获取