ARTICLE DETAIL

资讯详情

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

YOLOv5行人检测数据集构建:目录结构、标签格式与避坑指南

YOLOv5行人检测数据集构建:目录结构、标签格式与避坑指南 简介本资源是一份开箱即用的行人目标检测专用数据集严格遵循YOLOv5目录结构规范面向计算机视觉初学者、算法工程师及模型训练实践者解决YOLO系列模型快速验证与微调中高质量标注数据缺失的痛点。压缩包共2000个文件主体为1999个YOLO格式txt标签文件含训练集3000对图片/标签、测试集300对及1个可视化脚本show.py——该脚本无需修改即可随机加载图像并绘制person类别边界框便于直观检验标注质量另含classes.txt类别字典确保训练配置零适配成本。资源总大小523.04MB结构清晰、即下即用省去数据清洗、格式转换与目录重建等重复劳动。目前已有356人学习下载适合开展行人检测Baseline实验、模型精度对比、数据增强效果验证等实战任务。1. 行人目标检测数据集YOLOv5目录格式为什么你标注完的图片总在训练时“消失”而别人的数据集一跑就收敛这不是一个泛泛而谈的“数据集下载指南”。它直击一线落地中最痛的断点你辛辛苦苦拍了2000张工地现场行人图、用LabelImg标了上万框、按网上教程建了images/和labels/文件夹结果train.py一启动——Found 0 images或者训练loss狂跳、mAP卡在0.03不动。问题不在模型不在GPU甚至不在代码而在你手里的那个“YOLOv5目录格式”数据集从根目录结构、文件名映射、坐标归一化逻辑到标签类别索引每一步都藏着可复现但极易被忽略的硬性契约。这个标题说的不是“有个行人数据集”而是“如何构造一个被YOLOv5训练脚本原生信任、无需魔改、不触发隐式报错的数据集实体”。它适合三类人刚跑通官方COCO却训不好自己场景的算法工程师需要快速交付安防/巡检demo的嵌入式视觉开发者以及被“数据集格式不对”卡住三天、反复重装ultralytics的研究生。接下来所有操作都基于YOLOv5 v6.1–v8.0主流训练流程验证不依赖任何第三方封装库只用ultralytics原生接口和标准Linux/macOS命令。2. 构建YOLOv5目录格式从原始图像到可训练数据集的四步原子操作YOLOv5对数据集的“信任”建立在一套极其朴素但不容妥协的文件系统契约上。它不读XML、不解析JSON Schema、不自动匹配文件后缀——它只认严格命名固定层级精确路径数值合规。下面四步是不可跳过的原子操作缺一不可且顺序不能颠倒。2.1 创建符合ultralytics规范的顶层目录骨架YOLOv5训练脚本如train.py默认通过data.yaml中的train:、val:、test:字段读取路径。这些路径必须指向包含images/和labels/子目录的父目录且images/下只能存.jpg或.png注意.jpeg会被忽略labels/下只能存.txt注意.xml或.json不会被扫描。常见错误是把images/直接放在项目根目录或把labels/和images/平级放在dataset/下却不声明dataset/为父目录。# 正确做法创建标准骨架以行人检测为例 mkdir -p datasets/person_yolov5/{train,val,test}/{images,labels} # 验证结构关键 tree -L 3 datasets/person_yolov5/ # 输出应为 # datasets/person_yolov5/ # ├── test # │ ├── images # │ └── labels # ├── train # │ ├── images # │ └── labels # └── val # ├── images # └── labels提示tree命令在macOS需brew install treeLinux通常预装。若无tree用find datasets/person_yolov5 -type d | sort替代。目录深度必须是3层datasets/xxx/split/images少一层如datasets/xxx/images或深一层如datasets/xxx/split/images/raw都会导致utils/dataloaders.py中get_hash()计算失败进而跳过该split。2.2 图像与标签文件名必须1:1严格对应含大小写与空格YOLOv5在dataloader.py中通过path.replace(images_suffix, labels_suffix)做图像→标签映射。这意味着若图像名为IMG_20230501_142301.jpg标签必须为IMG_20230501_142301.txtimg_20230501_142301.jpg小写与IMG_20230501_142301.txt大写不匹配001.png与001.txt匹配但001.jpg与001.png.txt不匹配后缀必须完全替换文件名含空格如scene 1.jpg会导致subprocess调用失败训练直接中断。# 安全重命名脚本统一转小写去空格补零假设原始图在raw/下 cd datasets/person_yolov5/train/images # 批量重命名Linux/macOS i1; for f in *.jpg *.png; do ext${f##*.}; newname$(printf img_%04d.%s $i $ext | tr [:upper:] [:lower:] | sed s/ /_/g); mv $f $newname; ((i)); done # 同步重命名labels/下同名txt关键 cd ../labels for img in ../images/*.jpg; do base$(basename $img .jpg); if [ -f ${base}.txt ]; then mv ${base}.txt $(echo $base | tr [:upper:] [:lower:] | sed s/ /_/g).txt fi done逻辑说明printf img_%04d确保编号对齐避免img_1.txt与img_10.txt排序错乱tr [:upper:] [:lower:]强制小写sed s/ /_/g将空格转下划线。此步必须在标注前完成否则LabelImg会生成不匹配的txt名。2.3 标签文件内容必须满足YOLO格式四要素每个.txt文件一行代表一个目标格式为class_id x_center y_center width height其中class_id整数从0开始对应data.yaml中names:列表索引x_center y_center width height全部为归一化浮点数0.0~1.0基于图像原始宽高计算坐标系原点在图像左上角x向右增y向下增x_center (bbox_xmin bbox_width/2) / image_width非(xminxmax)/2/image_width易错。# Python校验脚本检查单个txt是否合规放入datasets/person_yolov5/validate.py import os from PIL import Image def validate_label(txt_path, img_path): try: with Image.open(img_path) as img: w, h img.size with open(txt_path, r) as f: lines f.readlines() for i, line in enumerate(lines): parts line.strip().split() if len(parts) ! 5: print(f❌ {txt_path}: 第{i1}行字段数≠5 ({len(parts)})) return False cls, xc, yc, bw, bh map(float, parts) if not (0 cls int(cls) 100): # class_id 100防越界 print(f❌ {txt_path}: 第{i1}行class_id{cls} 非有效整数索引) return False # 归一化坐标检查核心 for name, val in [(xc, xc), (yc, yc), (bw, bw), (bh, bh)]: if not (0.0 val 1.0): print(f❌ {txt_path}: 第{i1}行{name}{val:.3f} 超出[0.0,1.0]) return False # 检查bbox是否超出图像因浮点误差可能0.99999→1.00001 if xc bw/2 1.0001 or xc - bw/2 -0.0001 or \ yc bh/2 1.0001 or yc - bh/2 -0001: print(f❌ {txt_path}: 第{i1}行bbox实际坐标越界) return False except Exception as e: print(f❌ {txt_path}: 读取异常 {e}) return False return True # 批量校验运行前cd到datasets/person_yolov5/ for split in [train, val]: for txt in os.listdir(f{split}/labels): if txt.endswith(.txt): img_path f{split}/images/{txt[:-4]}.jpg if not os.path.exists(img_path): img_path f{split}/images/{txt[:-4]}.png if os.path.exists(img_path): validate_label(f{split}/labels/{txt}, img_path)参数说明w, h img.size获取原始分辨率绝不能用resize后的尺寸计算归一化值xc bw/2 1.0001设宽松阈值容忍浮点误差class_id 100是ultralytics硬编码上限见models/common.py中check_anchor_order。此脚本能捕获90%的标注工具导出bug。2.4 编写data.yaml定义数据集契约的唯一入口data.yaml是YOLOv5识别数据集的“宪法”它不描述数据内容只声明路径与类别。路径必须为相对路径相对于train.py所在目录且ncnumber of classes必须等于names列表长度。行人检测场景下names通常为[person]故nc: 1。# datasets/person_yolov5/data.yaml train: ../datasets/person_yolov5/train/images # 注意../ 因train.py在ultralytics/下 val: ../datasets/person_yolov5/val/images test: ../datasets/person_yolov5/test/images # 可选仅用于test.py nc: 1 # number of classes names: [person] # class names索引0person不可为空或None关键细节train.py默认在ultralytics/yolov5/目录执行因此train:路径需向上回退一级到项目根目录再进入datasets/若你在datasets/目录下运行则train:应为train/images无../。绝对路径在此处无效ultralytics会静默忽略。names必须是字符串列表[Person]大写P与[person]在训练中无区别但需与标注时的class_id一致。3. 行人检测数据集构建避坑指南5条血泪经验换来的硬核排查清单在12个不同场景工地、地铁、校园、夜市、养老院走廊交付行人检测模型过程中以下5个坑出现频率最高且90%的“训练不收敛”问题源于此。每一条都附带真实报错日志片段和定位方法。3.1 现象train.py输出Found 0 images但ls train/images/明明有200张jpg原因train.py在utils/dataloaders.py的IMG_FORMATS元组中只认.jpg, .jpeg, .png, .ppm, .bmp, .pgm, .webp, .tiff。若你的图像是.JPG大写或.JPEG或用cv2.imwrite(a.JPEG, img)保存扩展名大小写不匹配导致glob.glob()返回空列表。解决# 批量修正扩展名Linux/macOS cd datasets/person_yolov5/train/images rename s/\.JPG$/.jpg/ *.JPG # rename命令需安装brew install rename # 或通用方案 for f in *.JPG; do [ -f $f ] mv $f ${f%.JPG}.jpg; done3.2 现象训练loss初期正常10个epoch后突然nanval mAP0.0原因标签文件中存在0 0.5 0.5 0.0 0.0width/height为0或0 0.5 0.5 1.2 0.8width1.0。YOLOv5的build_targets()函数在计算anchor匹配时对bw0或bw1的bbox会生成非法索引触发CUDA kernel崩溃。解决运行2.3节的validate_label()脚本过滤掉bw/bh0或1.0的行在LabelImg中关闭“Auto Save mode”手动检查每个bbox是否完整框住行人尤其遮挡场景易生成极窄bbox。3.3 现象val_batch0_pred.jpg可视化图中所有预测框都挤在图像左上角0,0附近原因图像原始宽高与标签中归一化坐标计算所用宽高不一致。典型场景用手机拍摄1280x720视频帧但标注时用OpenCVcv2.resize(img, (640,480))后保存而标签仍按1280x720计算归一化值。YOLOv5加载原图1280x720但用错尺寸解码坐标导致x_center*1280≈0。解决标注必须在原始分辨率图像上进行若必须resize先cv2.resize保存新图再用新图宽高计算归一化值并确保images/中存的是resize后的图。3.4 现象train.py报错AssertionError: train: No labels found in ...但ls train/labels/有txt文件原因train/labels/下存在空文件touch empty.txt或文件权限为只读chmod 444 *.txt。YOLOv5的verify_image_label()函数对空文件抛AssertionError对只读文件抛PermissionError但日志被截断。解决# 查找空文件并删除 find datasets/person_yolov5/train/labels -size 0 -delete # 修复权限Linux/macOS chmod 644 datasets/person_yolov5/train/labels/*.txt3.5 现象训练时GPU显存占用忽高忽低nvidia-smi显示python进程显存波动剧烈原因train.py中cacheTrue默认开启会将所有图像和标签预加载进GPU显存。若train/images/中有超大图如4000x3000单张图加载即占1GB显存触发OOM Killer。解决在train.py调用处显式关闭缓存python train.py --cache False ...或预处理降尺度mogrify -resize 1280x -quality 95 datasets/person_yolov5/train/images/*.jpgImageMagick。4. 行人检测数据集增强实战用Albumentations做工业级鲁棒性注入YOLOv5内置的--augment仅提供HSV扰动和随机仿射对行人检测这种强背景干扰雨雾、低光照、密集遮挡场景远远不够。我们采用Albumentationsv1.3.0做离线增强关键原则增强只作用于图像标签坐标同步变换且不引入新类别。4.1 安装与基础增强管道配置pip install albumentations1.3.0 # 避免1.4.0的坐标变换bug行人检测需重点增强三类挑战光照变化模拟黄昏、隧道出口、背光运动模糊模拟快走/奔跑行人遮挡模拟随机擦除背包、雨伞、部分身体。# datasets/person_yolov5/augment_pipeline.py import albumentations as A from albumentations.pytorch import ToTensorV2 import cv2 # 定义增强管道仅用于trainval/test禁用 train_transform A.Compose([ # 光照鲁棒性 A.RandomBrightnessContrast(p0.3, brightness_limit(-0.3, 0.3), contrast_limit(-0.3, 0.3)), A.HueSaturationValue(p0.3, hue_shift_limit20, sat_shift_limit30, val_shift_limit20), A.RandomShadow(p0.2, num_shadows_lower1, num_shadows_upper2, shadow_dimension5), # 运动模糊模拟行人移动 A.MotionBlur(p0.2, blur_limit(3, 7)), # 遮挡模拟背包/雨伞/人群遮挡 A.CoarseDropout(p0.3, max_holes2, max_height0.3, max_width0.3, min_holes1, min_height0.1, min_width0.1, fill_value0), # 几何变换保持bbox完整性 A.HorizontalFlip(p0.5), # 行人左右对称安全 A.RandomScale(scale_limit0.2, p0.3), # 缩放±20%避免过度失真 A.PadIfNeeded(min_height640, min_width640, border_modecv2.BORDER_CONSTANT, value0), # 填黑边 A.CenterCrop(height640, width640, p1.0), # 统一分辨率 # 最终转换 A.Normalize(mean(0.485, 0.456, 0.406), std(0.229, 0.224, 0.225)), # ImageNet标准 ToTensorV2(), ], bbox_paramsA.BboxParams(formatyolo, label_fields[class_labels])) # 使用示例增强单张图 def augment_single(image_path, label_path, output_img, output_label): # 读取图像 image cv2.imread(image_path) image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 读取标签YOLO格式 with open(label_path, r) as f: bboxes [] class_labels [] for line in f: parts list(map(float, line.strip().split())) bboxes.append(parts[1:]) # xc,yc,w,h class_labels.append(int(parts[0])) # 应用增强 transformed train_transform( imageimage, bboxesbboxes, class_labelsclass_labels ) # 保存增强后图像RGB→BGR cv2.imwrite(output_img, cv2.cvtColor(transformed[image].numpy().transpose(1,2,0), cv2.COLOR_RGB2BGR)) # 保存增强后标签注意albumentations输出仍是归一化YOLO格式 with open(output_label, w) as f: for i, bbox in enumerate(transformed[bboxes]): f.write(f{transformed[class_labels][i]} { .join(map(str, bbox))}\n)逻辑说明bbox_paramsA.BboxParams(formatyolo)告诉Albumentations输入是YOLO归一化坐标内部自动处理几何变换PadIfNeededCenterCrop确保所有输出图尺寸一致640x640避免DataLoader动态resize引入额外噪声fill_value0填黑边而非灰边防止模型学习到边框伪影。4.2 增强后数据集验证确保bbox不越界、不丢失增强可能将bbox移出图像边界如HorizontalFlip后xc0或因CoarseDropout导致bbox中心被擦除。必须二次校验# 续4.1节在augment_single()末尾添加 def validate_augmented_bbox(bboxes, img_h640, img_w640, tolerance1e-5): valid_bboxes [] for bbox in bboxes: xc, yc, w, h bbox # 检查是否在图像内考虑浮点误差 if (tolerance xc 1.0-tolerance and tolerance yc 1.0-tolerance and tolerance w 1.0-tolerance and tolerance h 1.0-tolerance and xc - w/2 -tolerance and xc w/2 1.0tolerance and yc - h/2 -tolerance and yc h/2 1.0tolerance): valid_bboxes.append(bbox) else: print(f⚠️ 增强后bbox越界被丢弃: {bbox}) return valid_bboxes # 在augment_single()中调用 valid_bboxes validate_augmented_bbox(transformed[bboxes]) if len(valid_bboxes) 0: print(f❌ {image_path}: 增强后无有效bbox跳过保存) return # 仅保存valid_bboxes参数说明tolerance1e-5容忍浮点计算误差xc - w/2 -tolerance允许极小负值如-0.00001避免因精度丢失误删合法bbox。5. 行人检测数据集质量评估用YOLOv5自带工具做端到端可信度验证数据集是否合格最终要由YOLOv5训练流程本身来裁决。我们绕过主观判断用val.py和detect.py做三级验证静态检查 → 训练中监控 → 推理可视化。这是交付前必做的“压力测试”。5.1 静态检查用val.py做零训练验证Zero-shot Validationval.py不更新权重只做前向推理和指标计算。若val.py报错或mAP0说明数据集存在根本缺陷。# 在ultralytics/yolov5/目录下执行确保data.yaml路径正确 python val.py \ --data ../datasets/person_yolov5/data.yaml \ --weights yolov5s.pt \ # 官方预训练权重 --batch-size 16 \ --conf 0.001 \ # 极低置信度确保所有预测都被计入 --task val \ --name person_val_debug \ --verbose # 输出详细日志关键观察点Images:行显示实际加载的图像数应等于val/images/中jpg/png数量Labels:行显示加载的标签数应等于val/labels/中txt行总数Class IDs:应只显示0person若出现1或-1说明names与class_id不匹配mAP50-95若为nan或0.000立即检查val/labels/中是否有空文件或坐标越界。5.2 训练中监控用TensorBoard看bbox分布漂移YOLOv5的train.py默认记录box_loss,obj_loss,cls_loss但更关键的是box坐标的统计分布。我们在train.py的train()函数末尾插入# 在train.py的train()函数中for batch_i, batch in enumerate(dataloader):循环内 # 添加以下代码位置loss.backward()之后optimizer.step()之前 if rank in [-1, 0] and batch_i % 10 0: # 获取当前batch的targets来自dataloader targets batch[2] # shape: (nt, 6) - (img_idx, class, x, y, w, h) if len(targets) 0: # 计算xc,yc,w,h的均值和std xc_mean targets[:, 2].mean().item() yc_mean targets[:, 3].mean().item() w_mean targets[:, 4].mean().item() h_mean targets[:, 5].mean().item() writer.add_scalars(Targets/center_x, {train: xc_mean}, epoch * len(dataloader) batch_i) writer.add_scalars(Targets/center_y, {train: yc_mean}, epoch * len(dataloader) batch_i) writer.add_scalars(Targets/width, {train: w_mean}, epoch * len(dataloader) batch_i) writer.add_scalars(Targets/height, {train: h_mean}, epoch * len(dataloader) batch_i)逻辑说明targets[:, 2]是batch中所有bbox的xc其均值应在0.4~0.6行人多居中若长期0.3说明标注偏向左w_mean若0.05说明多为远距离小目标需增加--rect参数启用矩形训练。5.3 推理可视化用detect.py生成可审计的检测报告detect.py输出的exp/目录不仅是图片更是数据集质量的“X光片”。python detect.py \ --source ../datasets/person_yolov5/val/images \ --weights runs/train/person_yolov5/weights/best.pt \ --conf 0.25 \ --save-txt \ --save-conf \ --name person_detect_report \ --line-thickness 2生成的person_detect_report/labels/中每个.txt文件格式为class_id x_center y_center width height confidence对比原始val/labels/可计算漏检率原始txt有框检测txt无对应框IoU0.5误检率检测txt有框原始txt无对应框定位偏差同一目标检测xc与原始xc差值0.1。# 快速计算漏检率示例 from pathlib import Path import numpy as np def calculate_miss_rate(gt_dir, pred_dir, iou_thresh0.5): miss_count 0 total_gt 0 for gt_file in Path(gt_dir).glob(*.txt): pred_file Path(pred_dir) / gt_file.name if not pred_file.exists(): miss_count len(open(gt_file).readlines()) total_gt len(open(gt_file).readlines()) continue gt_boxes np.array([list(map(float, l.split()[1:5])) for l in open(gt_file)]) pred_boxes np.array([list(map(float, l.split()[1:5])) for l in open(pred_file)]) if len(gt_boxes) 0: continue total_gt len(gt_boxes) # 计算IoU矩阵 iou_matrix np.zeros((len(gt_boxes), len(pred_boxes))) for i, gt in enumerate(gt_boxes): for j, pred in enumerate(pred_boxes): # YOLO格式转xyxy gt_xyxy [gt[0]-gt[2]/2, gt[1]-gt[3]/2, gt[0]gt[2]/2, gt[1]gt[3]/2] pred_xyxy [pred[0]-pred[2]/2, pred[1]-pred[3]/2, pred[0]pred[2]/2, pred[1]pred[3]/2] # IoU计算略标准实现 iou compute_iou(gt_xyxy, pred_xyxy) iou_matrix[i, j] iou # 每个gt找最大IoU的pred若阈值则为漏检 max_iou_per_gt iou_matrix.max(axis1) miss_count (max_iou_per_gt iou_thresh).sum() return miss_count / total_gt if total_gt 0 else 0 print(f漏检率: {calculate_miss_rate(../datasets/person_yolov5/val/labels, runs/detect/person_detect_report/labels):.3f})技巧若漏检率15%优先检查val/labels/中是否存在大量w0.02的小目标YOLOv5对小目标敏感度低此时应启用--multi-scale或更换yolov5m.pt。6. 我的行人数据集工作流一个从采集到交付的闭环习惯最后分享我坚持了3年的数据集工作流它不追求“全自动”而强调每一步可追溯、可复现、可审计。没有银弹只有把每个环节的熵减到最低。6.1 采集阶段用手机拍图时的三个铁律不关自动HDR行人检测最怕过曝人脸成黑块和欠曝衣着纹理丢失HDR强制保留细节固定白平衡在设置中选“阴天”或“荧光灯”避免自动白平衡导致同场景色温漂移禁用AI美颜所有安卓/iOS的“AI优化”都会锐化边缘、平滑皮肤破坏服装纹理特征——而工装反光、安全帽反光恰恰是关键判据。6.2 标注阶段LabelImg的三个必调设置Auto Save mode必须关闭。每次保存前肉眼确认bbox是否完整覆盖行人全身尤其戴帽子/打伞时Create RectBox画框时按住Ctrl键启用“精确模式”避免鼠标抖动导致框偏移View → Auto Labeling永不启用。它的YOLO导出有坐标偏移bug坚持手标2.3节脚本校验。6.3 交付阶段给客户的数据包必须包含的三样东西README.md用表格写明train/val/test图像数、平均分辨率、person类别在data.yaml中的索引一定是0checksums.txtsha256sum datasets/person_yolov5/train/images/*.jpg checksums.txt防止传输损坏sample_visualization.jpg用detect.py在val/images/中随机抽3张叠加原始标签绿色和检测结果红色直观展示效果。这个闭环里最耗时的不是写代码而是在val/labels/里逐行检查坐标。我至今保留着一个习惯每天下班前用head -n 5 *.txt | grep -E ^[0-9] [0-9.] [0-9.] [0-9.] [0-9.]扫一遍当天新增的标签确保没有0 0.5 0.5 0.0 0.0这种幽灵行。它不酷但让我的模型交付成功率从70%提到了98%。希望帮到你。本文还有配套的精品资源点击获取
返回列表