ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLO双类行人数据集实战:7203张图像从校验到训练全流程

YOLO双类行人数据集实战:7203张图像从校验到训练全流程 简介面向YOLO系列算法的行人检测数据集服务于目标检测与行人识别场景适合具备一定Python和深度学习基础的研究者、学生及算法工程师直接使用。压缩包共2000个标注文件以xml格式为主同时提供yolo格式txt标签与voc格式xml标签两套标注坐标均按图像宽高归一化处理标签与图像一一对应yolo格式每行依次记录类别索引、中心点横纵坐标及宽高比例数值范围在0到1之间。另附data.yaml配置文件数据已按比例划分训练集和验证集解压即可在yolov5、yolov8、yolov7、yolov9、yolov10、yolo11等主流版本上训练与测试。已有138人下载学习。数据集包含不同拍摄条件下的行人目标标注信息规范免去手动转换标签、划分数据集的重复劳动便于快速搭建行人检测基线也可用于YOLO系列算法间的效果对比和课程项目实战。1. 一份7203张的双类行人数据集能解决什么实际问题拿到“yolo算法-行人数据集-7203张图像带标签-人-主人.zip”这种命名规整的数据包第一反应是这包料不是随便凑的7203张图像、每张都有对应txt标签class分为“人”和“主人”两类刚好吃透YOLO算法的输入要求。和数据打交道这些年我见过太多“数据集”解压出来图像和标签对不上、类别ID错乱、坐标越界的烂摊子而这套数据最大的价值是它把行人检测里最常遇到的双类问题——普通行人和带宠物主人——直接做成了可训练的格式。适合两类人一是准备第一次用YOLO做行人检测的工程师想找一份能直接跑通流程的数据练手二是做安防监控、社区客流统计、宠物门店分析这类场景的算法同学需要区分行人和主人的标签数据来验证模型。接下来我会从解压开始逐步把数据校验、划分、训练参数和踩坑点讲一遍。2. YOLO算法选型与数据集结构先看懂再动手2.1 YOLO算法迭代与行人检测的匹配度行人检测这几年基本被深度学习模型包圆了。两阶段检测器像Faster R-CNN精度虽然高但推理速度在视频流场景下撑不住——一路监控24路并发单卡顶多跑三四路成本直接劝退。单阶段的YOLO算法从v3开始就把实时性做到了可商用级别到YOLOv5和YOLOv8这一代coco预训练权重、自动锚框、Mosaic增强都成了标配训练自定义行人数据集的门槛比前几年低了一个数量级。这套数据集命名里直接带“yolo算法”说明标签组织方式就是给YOLO系列准备的。YOLO不认VOC那种xml也不认COCO那种json它只认最简单的txt——每行一个目标五个浮点数加一个类别ID。数据包里的“标签”指的就是这套txt标注图像和标签文件同名不同后缀训练时按文件名的stem匹配。为什么YOLO能靠一个txt文件支撑起整个检测流程核心在于它有data.yaml把txt和图像目录组织成规范结构。选择YOLO做行人检测还有一个现实理由部署链路成熟。训练完的.pt权重可以导出onnx或TensorRT engine从边缘盒子到服务端GPU都能跑。对做行人检测的团队来说模型能否和现有监控系统快速集成比单纯刷高一个点的mAP更值钱。不过要泼一盆冷水YOLO各版本间的训练命令和配置并不完全兼容。YOLOv5的train.py、val.py、detect.py脚本结构非常固定YOLOv8换成CLI入口yolo detect train参数风格也变了。拿这份数据集跑训练前先确认你选定的代码库版本和训练命令是配套的别把v5的命令直接扔给v8跑会报一堆参数解析错误。2.2 7203张图像的labels目录YOLO标注格式逐行解读进入正题。解压后通常会有images和labels两个目录images下全是jpg或png图像labels下是同名txt标签文件。打开任意一个txt文件内容类似这样0 0.5123 0.4234 0.1234 0.4567 1 0.6001 0.5121 0.0987 0.3210每行五个数依次是类别ID、目标中心点x坐标、目标中心点y坐标、目标宽度w、目标高度h。后四个值全部归一到[0,1]区间。坐标归一化是最容易出问题的环节——如果标注软件导出的是像素绝对值没归一化就扔给YOLO训练loss会直接起飞。对于这份数据集的“人-主人”双类设计类别ID 0代表person普通行人类别ID 1代表owner带宠物/牵狗的主人。你可以在动手训练前先写个小脚本统计一下两类目标的数量比确认是否存在严重类别不平衡。7203张图像看起来量不小但如果owner只占个位数百分比后面训练就要考虑类别权重或重采样。# inspect_labels.py from collections import Counter from pathlib import Path labels_dir Path(yolo行人数据集_7203/labels) cls_counter Counter() total_boxes 0 for txt in labels_dir.glob(*.txt): with open(txt, r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f[格式异常] {txt.name}: {line.strip()}) continue cls_id int(parts[0]) cls_counter[cls_id] 1 total_boxes 1 print(f总标注框数: {total_boxes}) print(f类别分布: {dict(cls_counter)})这个脚本逻辑很直接遍历labels目录下所有txt每一行按空白字符切分成5段段数不对就报告格式异常否则提取类别ID累计计数。跑完后如果person和owner比例超过10:1建议在训练参数里提高cls_loss权重或对owner图像做针对性增强避免模型把owner学成person的“变体”。参数方面没有额外入参路径写死成数据集解压目录即可如果你想改成命令行传参用sys.argv[1]或argparse接一个路径参数就行。2.3 标签与图像的对应关系文件命名必须严格配对关于图像和标签的一一对应关系这里多说一句。以往我见过不少数据包标注文件和图像文件的数量对不上有些甚至一张图像对应多个标签文件或者标签文件命名带了额外前缀。正常YOLO数据集命名的要求是图像vid_00001.jpg对应的标签必须是vid_00001.txt不能是vid_00001(1).txt或vid_00001_anno.txt否则YOLO扫描标签目录时找不到匹配对直接跳过该图像。这点在处理这份“7203张图像带标签”的数据时尤其要注意。拿到手第一件事用脚本比对两个目录的stem集合。如果出现差异先补标签或删图像再做划分。常见做法是写一个五行的集合差运算from pathlib import Path img_stems {p.stem for p in Path(images).glob(*.jpg)} lab_stems {p.stem for p in Path(labels).glob(*.txt)} print(缺标签的图像:, img_stems - lab_stems) print(缺图像的标签:, lab_stems - img_stems)这段脚本用集合减法定位不匹配的样本。如果“缺标签的图像”为空说明每张图像都有对应标签可以进行下一步。如果非空优先处理这些孤立样本避免它们在训练时被当背景图用。2.4 类别定义“人-主人”双类检测的业务价值与标注边界行人检测数据集很多但大部分只标一个person类。这套数据把“主人”单独分出来价值在于业务场景确实需要区分“普通行人”和“带宠物的人”。比如小区门禁识别业主是否在遛狗商场客流统计要分析带宠物顾客的占比公园巡逻机器人要重点跟踪牵狗人群避免冲突。从模型角度看person和owner在视觉特征上有大量重叠——owner本身也是人只是多了牵引绳、宠物或者主人的动作姿态。这种类间相似度高的双类检测正好是压力测试YOLO分类头的好素材。训练时如果两类目标在空间上高度重叠比如owner的框同时框住了人和宠物模型容易学成“同一区域出两个类别”推理时出现双框叠加。这类问题可以在后处理层面用NMS类别混淆处理来抑制也可以回到标注层面重新审视框边界标注owner时框体应该严格围住“主人”这个人而不是把宠物也圈进来。3. 数据预处理实操从ZIP到可训练的YOLO目录结构3.1 解压后先做三件事完整性校验、损坏图像清理、路径统一拿到zip包先别急着训练先解压然后做完整性校验。我的习惯是命令行解压到固定工作目录再写脚本检查图像能不能被正确解码。很多标注数据集在流传过程中会丢文件或者图像本身是损坏的直接喂给YOLO会在训练中途报错中断。mkdir -p datasets unzip yolo算法-行人数据集-7203张图像带标签-人-主人.zip -d datasets/ cd datasets ls images | wc -l # 应该等于7203 ls labels | wc -l # 应该等于7203这里的wc -l统计文件数量如果和解压包声明不符说明数据不完整。数量对上了再往下走。接下来用OpenCV做图像完整性检查顺手把非RGB三通道图像统一转成RGB# precheck_images.py import cv2 from pathlib import Path images_dir Path(datasets/yolo行人数据集_7203/images) broken [] for img_path in images_dir.glob(*.jpg): img cv2.imread(str(img_path), cv2.IMREAD_COLOR) if img is None: broken.append(img_path.name) continue if len(img.shape) ! 3 or img.shape[2] ! 3: broken.append(img_path.name) if broken: print(f发现 {len(broken)} 个问题图像:) for name in broken[:20]: print(name) else: print(全部7203张图像完整性检查通过)这段脚本用cv2.imread读图返回None说明图像损坏或格式不支持shape[2]不等于3说明是灰度图或带透明通道的PNG。对YOLO来说灰度图也能训练但既然数据包叫“行人数据集”统一转RGB会让后续迁移预训练权重的效果更稳定。如果检测到损坏图像直接移动到broken目录留档不要原地删除免得后面想追溯原始数据时找不到。3.2 划分训练集/验证集/测试集8:1:1脚本实现数据校验通过后接下来做数据集划分。YOLO训练要求train和val分开目录结构常见划分比例是8:1:1其中测试集用于最终评估。划分时按“图像同名标签”成对操作不能打乱配对关系。# split_dataset.py import random import shutil from pathlib import Path random.seed(42) # 固定随机种子保证可复现 src_images Path(datasets/yolo行人数据集_7203/images) src_labels Path(datasets/yolo行人数据集_7203/labels) dst_root Path(datasets/person_owner) for subset in [train, val, test]: (dst_root / subset / images).mkdir(parentsTrue, exist_okTrue) (dst_root / subset / labels).mkdir(parentsTrue, exist_okTrue) all_stems [p.stem for p in src_images.glob(*.jpg)] random.shuffle(all_stems) n len(all_stems) n_train int(n * 0.8) n_val int(n * 0.1) assignments ( [(s, train) for s in all_stems[:n_train]] [(s, val) for s in all_stems[n_train:n_train n_val]] [(s, test) for s in all_stems[n_train n_val:]] ) for stem, subset in assignments: img_src src_images / f{stem}.jpg lab_src src_labels / f{stem}.txt shutil.copy2(img_src, dst_root / subset / images / f{stem}.jpg) if lab_src.exists(): shutil.copy2(lab_src, dst_root / subset / labels / f{stem}.txt) print(ftrain{n_train}, val{n_val}, test{n - n_train - n_val})这段脚本有三个值得注意的点。第一固定random.seed(42)这样换机器重新划分能得到完全相同的train/val/test组合后续对比实验才有意义。第二用copy2而不是move保留原始数据不动划分错了有后悔药。第三如果某个stem缺标签图像照样进划分但标签不会被复制——这种情况下建议从数据集中剔除该图像否则训练时它会被当背景图使用无形中给模型灌入了“无目标”的负样本。比例参数写法上int(n * 0.8)和int(n * 0.1)在n7203时分别是5762和720剩余721进test整体比例接近8:1:1。3.3 标签与图像对齐校验避免YOLO训练时的漏检划分完成后还要再跑一遍对齐校验。这次不是看文件数量而是逐行检查标签内容。YOLO对标签格式极为敏感类别ID超出nc范围、坐标小于0或大于1、bbox宽高小于等于0都会让loss计算变得不稳定。# validate_labels.py from pathlib import Path for subset in [train, val, test]: labels_dir Path(fdatasets/person_owner/{subset}/labels) for txt in labels_dir.glob(*.txt): with open(txt, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f[格式错误] {txt.name}: {line.strip()}) continue cls_id int(parts[0]) x, y, w, h map(float, parts[1:]) if cls_id not in (0, 1): print(f[类别越界] {txt.name}: cls{cls_id}) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): print(f[坐标越界] {txt.name}: {line.strip()}) if w * h 0.0001: print(f[框过小] {txt.name}: {line.strip()})类别越界常见于标注工具序号和YOLO类别ID不一致——比如标注时从1开始编号导出后没减1。坐标越界则多出在图像resize后标签没跟着缩放。框过小通常是误标注产生的噪声框面积小于图像万分之一的框基本无法被下采样后的特征图捕捉到留着只会干扰loss。这个脚本跑完如果输出为空数据集就可以进训练环节了。参数上0.0001这个阈值可以按实际图像分辨率调整4K图像可以放宽到0.000051080P建议保持1e-4的量级。4. 训练配置与超参数把双类行人检测跑起来4.1 自定义data.yamlnc、names和路径的常见坑YOLO训练的第一步是写data.yaml。这个文件决定了数据集在哪里、有几个类别、类别名字是什么。很多人训练翻车第一步就栽在路径写法上。# person_owner.yaml train: ./datasets/person_owner/train/images val: ./datasets/person_owner/val/images test: ./datasets/person_owner/test/images nc: 2 names: 0: person 1: owneryaml里的路径是相对当前工作目录的train和val必须指向images目录而不是labels目录YOLO会自动拼接labels路径。命名空间names的顺序必须和标签文件里的cls_id一一对应如果标签里cls_id1是owner但names[1]写成person训练不会报错但mAP计算和可视化推理时类别名会张冠李戴。路径这里有个高频坑Windows下用反斜杠写路径比如train: .\datasets\...YOLO在解析yaml时反斜杠会被当成转义字符路径直接失效。统一用正斜杠或相对路径最省心。另外如果train和val指向同一个目录训练时的mAP曲线会虚高因为验证集就是训练集本身评估结果没有参考意义。4.2 YOLOv5s vs YOLOv8n双类数据集的模型选型有了data.yaml下一步是选模型。当前做行人检测主流就两系YOLOv5和YOLOv8v9/v10也能用但生态和教程成熟度不如前两者。对7203张图像的中等规模数据集我一般推荐YOLOv5s或YOLOv8n作为起点。模型参数量推理速度GPU适合场景YOLOv5s7.5M约2ms/帧精度与速度均衡社区资源最多YOLOv8n3.2M约1.5ms/帧轻量部署嵌入式设备YOLOv5m21M约4ms/帧精度优先允许较大延迟7203张图像不算大也不算小用YOLOv5s起步精度够用且显存压力小。YOLOv8n的优势是模型体积小但遇到小尺寸行人目标时轻量模型的特征表达力弱一些容易漏检。如果项目后续要部署到Jetson这类边缘设备选YOLOv8n并配合TensorRT如果只是服务端推理YOLOv5s性价比最高。4.3 训练命令、batch_size和epochs参数设定选好模型后训练命令需要考虑batch_size和epochs。假设用YOLOv5常见做法是cd yolov5 python train.py \ --data ../datasets/person_owner.yaml \ --weights yolov5s.pt \ --batch-size 16 \ --epochs 100 \ --img 640 \ --device 0 \ --workers 4 \ --project runs/train \ --name person_owner_expbatch_size的设定直接由显存决定。16G显存跑YOLOv5s加640分辨率batch_size开到16比较稳如果显存只有8G降到8或者把--img降到416。很多人上来就开batch_size 64结果OOM报错只好重启——与其这样不如一开始就按显存的1/2预留buffer。epochs建议先跑100观察mAP曲线在60-80之间是否进入平台期。如果到100个epoch还在缓慢上升再加50如果50个epoch之后loss开始震荡说明学习率高了模型在最优解附近来回跳。--workers 4是数据加载线程数Windows下偶尔会因为多进程报错遇到就降到2或0。4.4 训练日志监控loss和mAP曲线的读取方法训练启动后YOLO会在runs/train/exp目录下输出每轮的日志和曲线图。常看的指标有三个box_loss框回归损失、obj_loss置信度损失、cls_loss分类损失。对“人-主人”这种类间相似度高的任务cls_loss的下降速度往往慢于box_loss这正常不用焦虑。真正要警惕的是cls_loss在训练集上持续下降、验证mAP却停滞——这说明模型在记忆训练集特征泛化出了问题。tensorboard --logdir runs/train # 浏览器打开 http://localhost:6006TensorBoard里能直观看到PR曲线、混淆矩阵、每类的mAP0.5。对双类数据集重点关注owner类的AP是否比person类低一大截。如果低超过10个百分点大概率是类别不平衡导致的回到第2章的类别统计对owner做重采样或增加增强强度。还有一个实用技巧每5个epoch存一次checkpoint--save-period 5这样即使训练中途崩了也能从最近一次保存的权重继续跑不用从头再来。5. 行人检测训练避坑指南4个常见问题与排查5.1 现象训练loss出现nan或长时间不下降现象训练到某几个epochloss栏直接显示nan或者loss卡在某个值附近十几个epoch纹丝不动。原因nan多半是标签里有非法值——要么坐标是inf要么bbox宽高为负要么类别ID超出了nc范围。loss不下降则通常是学习率初始值太大模型在梯度方向上反复横跳。解决先跑第3章的标签校验脚本把越界行打印出来定位再检查训练命令里的--lr默认0.01对大部分情况够用不要为了追求快速收敛手动调大。我见过手写--lr 0.05把loss直接干成nan的纯属自找麻烦。如果是自定义数据集里混入了空标签文件0字节txt也会导致obj_loss异常把这些空文件删掉再重跑。5.2 现象训练mAP很高验证mAP却不到一半现象训练集上mAP0.5已经跑到0.9以上切换验证集后直接掉到0.4以下。原因数据划分有问题。最常见的是train和val目录指到了同一个地方或者划分时没有固定随机种子导致验证集中出现了大量和训练集重复的图像。另一个冷门原因是数据包本身存在重复图像——同一张图改名后分别出现在train和val里。解决用md5sum对所有图像计算哈希值找出重复文件确认data.yaml里train和val路径没有指向同一目录。这个问题一旦出现靠调参救不回来只能重新划分数据集。md5sum datasets/person_owner/train/images/*.jpg | sort train.md5 md5sum datasets/person_owner/val/images/*.jpg | sort val.md5 comm -12 train.md5 val.md5 # 输出两个集合共有的行即重复图像comm -12取两个文件的交集如果输出为空说明没有重复。这一步在正式训练前做一次能省下后面排查泛化问题的半天时间。血的教训之前有个项目验证mAP虚高到0.85部署后实测只有0.5查了一整天才发现是划分脚本忘了固定随机种子。5.3 现象owner类别频繁误检为person现象训练完成后跑推理owner区域被同时打出person和owner两个框或者全是person。原因类别间相似度过高。owner本身是人特征层的前几层完全重合模型在浅层学到的都是“人”的共性特征只有到深层才能区分牵引绳和宠物。如果owner类的训练样本又少分类头根本学不到区分性特征。解决在训练时给cls_loss加类别权重YOLOv5可以用--cls 0.6调大分类损失的占比从默认的0.5往上加数据层面对owner样本做复制粘贴增强把带宠物的行人区域裁剪后随机粘贴到不同背景人为增加owner样本的数量和场景多样性。还有一种思路是退化成单类检测先检测人再用额外的分类头判断是否携带宠物但这属于方案重构不推荐在数据充足时优先考虑。5.4 现象小尺寸行人漏检严重现象验证集中检测不到远处的小目标行人precision和recall在小目标区间断崖下跌。原因YOLO把输入图像缩放到640分辨率一个在原始图像里只有20×40像素的行人下采样后可能只剩2×4个像素映射到特征图上特征完全丢失。解决先把--img从640提到960小目标召回率会有肉眼可见的提升代价是训练速度变慢显存占用也会涨一截如果不行再用SAHI这类切片推理工具把图像切成多个slices分别检测再合并结果。对“人-主人”数据集来说小目标问题主要出在监控远景场景切片推理是投入产出比最高的解法。另外注意增强参数里的--scale 0.5这类随机缩放如果设置太大训练时把目标缩得太小也会加剧小目标漏检。6. 验证与进阶用混淆矩阵和推理测试收口6.1 用混淆矩阵量化双类混淆训练结束后YOLO会在验证阶段自动输出confusion_matrix.png但很多时候大家只看mAP就关了浪费了这张图。对双类检测来说混淆矩阵能精确回答“owner被误判成person的概率是多少”。如果这个数字超过10%说明分类头对类别边界的学习还不够彻底优先回头查第5.3节的类别平衡问题。python val.py \ --data ../datasets/person_owner.yaml \ --weights runs/train/person_owner_exp/weights/best.pt \ --conf-thres 0.25 \ --iou-thres 0.45val.py跑完会输出每个类别的precision、recall和mAP0.5。对行人检测recall比precision优先级更高——漏检一个行人比误检一个背景更致命所以如果阈值调整需要做取舍我会把conf-thres从0.25降到0.15牺牲少量precision换取更高的recall。6.2 推理测试与导出onnx模型验证指标过了最后一步是推理测试。不要只看测试集指标要拿几段真实场景视频跑一下看模型在连续帧上的表现是否稳定。单帧指标高但连续帧抖动的模型部署后体验很差。python detect.py \ --weights runs/train/person_owner_exp/weights/best.pt \ --source ../datasets/person_owner/test/images \ --conf-thres 0.25 \ --save-txt --save-conf python export.py \ --weights runs/train/person_owner_exp/weights/best.pt \ --include onnx \ --opset 12导出onnx是为了后续部署。用onnxruntime或者TensorRT加载推理速度和资源占用都比直接跑PyTorch模型更好。导出后建议先用onnxruntime跑一遍相同的test图像对比输出框和PyTorch原版的差异确保转换没有引入精度损失。我的习惯是每次拿到一份新的行人数据集都先花一个晚上跑通“校验→划分→短训→验证”这条最小闭环确认数据没有问题再投入完整训练。这个流程走多了你会发现大部分训练事故都不是模型的问题而是数据在前置环节埋了雷。双类“人-主人”的设定给了你一个很好的起点去检验YOLO的分类能力希望这篇文章能帮你把数据集真正跑起来也把该避的坑提前避开。本文还有配套的精品资源点击获取
返回列表