夜间行人目标检测实战:5000张数据集与YOLO11三平台训练指南

发布时间:2026/10/5 17:03:44
夜间行人目标检测实战:5000张数据集与YOLO11三平台训练指南 简介针对夜间监控场景中行人检测精度不足、低光数据稀缺的问题这份配套说明PDF提供了一套完整的夜间行人检测数据集方案面向计算机视觉与安防监控方向的开发者。资料共1个PDF文件包体约6.07MB内附数据集基本情况介绍、标注规范说明、缩略图与标注截图预览以及百度网盘获取方式。数据集由5000张真实场景图片构成覆盖夜间街景、道路、遮挡及严重遮挡行人等丰富样本均采用LabelImg人工精细标注提供VOC、COCO、YOLO三种通用格式标签可直接用于YOLO等主流算法训练。同时附赠YOLO11一键训练脚本支持GPU、CPU、Mac三平台另有博主完整训练结果日志可供对比参考。目前已有611人学习下载适合安防监控、自动驾驶等场景下从事夜间行人检测研究的开发者快速上手使用。1. 夜间行人目标检测数据集5000张图解决什么又要怎么用如果你做过夜间行人目标检测数据集大概率经历过这种尴尬白天跑得很好的模型一到晚上就像瞎了一样漏检。原因是光照不足、对比度低、行人与背景融合加上夜间车辆灯光干扰。现在拿到一份5000张夜间行人图片的数据集而且带VOC、COCO、YOLO三种格式标签配套YOLO11一键训练脚本支持GPU(GPUs)、CPU、Mac三平台新手也能直接跑。我按自己实际做训练的顺序把数据集怎么核对、训练脚本怎么改、三平台怎么适配、以及哪些坑一定要避开一步步讲清楚。适合想快速验证夜间行人检测方案、不想自己标数据或者正在做安防、自动驾驶相关项目的人。2. 数据集构成与三种标签格式VOC、COCO、YOLO分别怎么选拿到一份带三种格式标签的数据集第一件事不是急着训练而是把格式差异搞清楚。VOC、COCO、YOLO是目标检测标注最常见的三种存储方式分别对应XML、JSON、TXT三种文件形态用错一个字段后面的训练全是白费。2.1 三格式标签的底层差异XML、JSON、TXT的使用边界VOC格式每张图对应一个XML文件里面用bndbox记录物体框的绝对像素坐标比如xmin10/xmin这样人类可读但每张图一个文件遍历时要拼路径。COCO格式是整个数据集汇总到一个JSON文件里结构分images、annotations、categories三段每个标注是一个bbox: [x, y, width, height]同样是绝对像素。YOLO格式最“薄”每张图对应一个TXT文件一行一个目标五个数字分别是class, x_center, y_center, width, height四个坐标全部归一化到0-1之间。为什么一个数据集要给三种格式因为不同工具链吃不同口味。用LabelImg标注顺手导出就是VOC转到mmdetection或Detectron2要COCO JSON用ultralytics训练YOLO11直接吃YOLO TXT。把你常用的框架告诉对方对方给对应格式迁移成本最低。就算三种格式齐全我也建议先做标签体检防止坐标写错、类别名不一致。下表是三种格式的快速对照格式存储方式框坐标归一化典型工具VOC每图一个XMLxmin/ymin/xmax/ymax绝对像素LabelImg, mmdetectionCOCO整个集一个JSON[x, y, width, height]绝对像素Detectron2, mmdetectionYOLO每图一个TXTclass, x_center, y_center, w, h0-1ultralytics, DarknetYOLO格式在训练时最省内存因为不需要一次性加载一个大JSON文件每张图读一个小txt对显存和内存都友好。但它的坐标是归一化的一旦和原图尺寸对不上训练时框就会飘。还有一个容易忽略的点三种格式的文件命名必须和图片一一对应。VOC的XML要和jpg同名YOLO的txt也要和jpg同名。如果数据集里顺序乱了训练时会自动匹配到错误的图框画在完全不相关的对象上。检查方法很简单ls images/train | wc -l和ls labels/train | wc -l数量相等后抽样几个对照文件名确认后缀匹配。下面是一个常见的数据集目录结构5000张图通常按4:1分训练和验证集night_pedestrian/ ├── images/ │ ├── train/ # 约4000张 │ └── val/ # 约1000张 ├── voc/ │ ├── Annotations/ # 每张图的XML标签 │ └── JPEGImages/ # 原图或软链接 ├── coco/ │ ├── annotations/ │ │ ├── train.json │ │ └── val.json │ └── images/ └── yolo/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml拿到的目录不一定长这样但核心思想不变原图按split分好标签按框架分好。如果你的包只给了VOC想转成YOLO别靠手算公式先看一下2.2的体检脚本确认原图尺寸和标注坐标到底对不对。2.2 拿到数据集后先做三件事数图、查类别、验坐标我习惯在训练前跑一个体检脚本否则到训练报错再回头找标签时间全浪费了。先看数量和类别再验证YOLO坐标是否越界。下面这个脚本可以直接跑from pathlib import Path yolo_root Path(night_pedestrian/yolo) for split in [train, val]: img_dir yolo_root / images / split lbl_dir yolo_root / labels / split imgs list(img_dir.glob(*.jpg)) print(f[YOLO] {split}: {len(imgs)} imgs) bad 0 class_ids set() for img in imgs: txt lbl_dir / (img.stem .txt) if not txt.exists(): print(f missing label: {img.name}) bad 1 continue for line in txt.read_text().splitlines(): parts line.strip().split() if len(parts) ! 5: bad 1 break cls_id parts[0] x, y, w, h map(float, parts[1:]) class_ids.add(cls_id) if not (0.0 x 1.0 and 0.0 y 1.0 and 0.0 w 1.0 and 0.0 h 1.0): bad 1 break print(f classes: {sorted(class_ids)}) print(f invalid label lines: {bad})这段代码做了三件事统计每个分片下的图片数量检查每个jpg是否都有对应的txt标签按行解析YOLO标签验证坐标都在0-1之间。bad变量用来记录缺失标签和越界坐标一旦有越界就说明转换时除以了错误的图像宽高。很多翻车就是从这一步开始的VOC的绝对像素除以了缩放后的图宽而不是原图宽结果看起来正常的框其实已经出界。如果检测出来有问题或者你想把VOC/COCO转成YOLO手动换算也不难。设图像宽W高HVOC的框是xmin, ymin, xmax, ymaxCOCO的框是x, y, w, h换算公式如下# VOC - YOLO x_center ((xmin xmax) / 2) / W y_center ((ymin ymax) / 2) / H w (xmax - xmin) / W h (ymax - ymin) / H # COCO - YOLO x_center (x w / 2) / W y_center (y h / 2) / H w_norm w / W h_norm h / H注意COCO的bbox是左上角坐标加宽高很多新手误以为是中心点坐标结果画出来的框偏移半个身位。转换后一定要再用上面的体检脚本跑一遍确认没有越界。COCO格式也可以用Python快速检查import json with open(night_pedestrian/coco/annotations/train.json) as f: coco json.load(f) print(images:, len(coco[images])) print(annotations:, len(coco[annotations])) print(categories:, coco[categories])这里只统计了数量和类别你可以再遍历annotations检查每个bbox长度是否为4以及是否落在对应图像的宽高范围内。如果一张图有多个标注还可以顺便看看有没有重复框。2.3 用YOLO格式训练时data.yaml怎么写YOLO11训练的第一步是喂一个数据集描述文件data.yaml它告诉模型图像和标签在哪儿、类别有几类。常见写法如下# night_pedestrian/yolo/data.yaml path: . # 相对于本yaml文件的根目录 train: images/train val: images/val names: 0: personpath是根目录路径建议直接写成.因为上面目录结构里data.yaml就放在night_pedestrian/yolo/下images/train直接相对它。如果你把data.yaml放在别处就要写相对路径或绝对路径。names里只列了person一个类别这是因为夜间行人数据集通常只标注行人。如果你的数据集还有骑行者标注就要多写几类并且类别顺序必须和txt标签里的第一个数字一致否则训练会“指鹿为马”。写好后可以先用下面的命令扫描标签里实际出现的类别ID再回头核对namescat night_pedestrian/yolo/labels/train/*.txt | awk {print $1} | sort -u如果输出0和1而names里只有0: person就说明有标签把背景当成了一个类要么删掉无效行要么修改yaml。这种问题通常在训练开始前就要解决拖到训练中报错再返工心态容易崩。3. 用YOLO11做一键训练从数据集目录到训练命令数据集格式确认无误后下一步就是写训练脚本。标题里要求“支持GPU(GPUs)/CPU/Mac三平台”所以脚本不能写死device0必须自动检测设备同时把训练参数暴露成命令行参数这样不用改代码就能换配置。3.1 为什么选择YOLO11而不是YOLOv8以及环境的取舍YOLO11是ultralytics维护的YOLO系列当前实现相比YOLOv8在特征提取模块和注意力机制上做了优化小目标检测表现更好。在夜间行人这种低光、小尺寸、遮挡多的场景YOLO11的改进更实用。模型规格有n/s/m/l/x几个档次夜间行人检测我一般用yolo11s.pt起步m可以冲精度n图快但容易漏x在普通显卡上训练时间太长。如果你的显卡显存只有8GB就选yolo11n或yolo11s不要碰m以上。这里要说明一点ultralytics的YOLO11不是单独安装一个叫yolo11的包而是通过pip install ultralytics获得。安装之后用YOLO(yolo11s.pt)会自动下载对应预训练权重前提是网络能连默认权重仓库。如果网络受限也可以手动把.pt文件放到项目目录路径写成./yolo11s.pt。3.2 一键训练脚本设备自动检测与参数透传下面这个Python脚本是训练入口核心是pick_device函数它按优先级返回计算设备手动指定 CUDA MPS CPU。MPS对应Mac的GPU加速CPU是最后兜底。import torch import argparse from ultralytics import YOLO def pick_device(forceNone): if force: return force if torch.cuda.is_available(): return 0 if hasattr(torch.backends, mps) and torch.backends.mps.is_available(): return mps return cpu if __name__ __main__: parser argparse.ArgumentParser(descriptionYOLO11 train for night pedestrian) parser.add_argument(--weights, defaultyolo11s.pt) parser.add_argument(--data, defaultnight_pedestrian/yolo/data.yaml) parser.add_argument(--imgsz, typeint, default640) parser.add_argument(--epochs, typeint, default100) parser.add_argument(--batch, typeint, default16) parser.add_argument(--device, defaultNone) args parser.parse_args() device pick_device(args.device) print(f[Device] {device}) model YOLO(args.weights) model.train( dataargs.data, imgszargs.imgsz, epochsargs.epochs, batchargs.batch, devicedevice, )pick_device的优先级已经写清楚--device参数可以强制指定比如--device mps或--device 0,1。多GPU传入时需要加引号否则shell会把逗号当作分隔符。启动命令很简单python train_yolo11.py --data night_pedestrian/yolo/data.yaml --weights yolo11s.pt --epochs 100 --batch 16Mac机器上如果脚本检测不到MPS就自动跑CPU但你会看到[Device] cpu。GPU机器想用第二块卡就--device 1。两卡並行可以用--device 0,1。3.3 训练参数里那些“玄学”imgsz、epochs、batch、patienceimgsz是输入分辨率夜间行人普遍偏小建议不要低于640。显存够的话试--imgsz 1280小目标召回能涨几个点但训练时间翻倍。epochs默认100对5000张图足够但夜间数据方差大建议加--patience 20连续20个epoch验证指标不涨就早停。batch的影响不是线性的batch太大容易训爆太小loss震荡。我的习惯是batch16配640分辨率如果显存不够先用--batch -1让脚本自动探测最大batch。YOLO11默认开启马赛克增强但夜间低光场景下马赛克拼接出的图可能让模型学到纹理错觉。我血泪经验是把mosaic降到0.5再打开亮度扰动效果比默认好。完整的train调用可以这样扩展model.train( dataargs.data, imgszargs.imgsz, epochsargs.epochs, batchargs.batch, devicedevice, mosaic0.5, hsv_h0.015, hsv_s0.4, hsv_v0.4, patience20, )hsv_h/s/v分别是色调、饱和度、亮度的随机扰动范围。夜间图像本身暗把亮度扰动开大一点能模拟不同光照强度但不要调太狠否则行人会被随机调成黑色反而学不到特征。3.4 训练日志怎么看loss曲线和验证指标训练结束后ultralytics在runs/detect/train/下生成last.pt、best.pt和results.csv。不要只盯最终mAP要看曲线train/box_loss和train/cls_loss是否稳步下降val/box_loss是否和train保持同步。如果两者差距越来越大说明过拟合了。夜间行人这种单一类别任务val/box_loss一般在2左右mAP50在0.5-0.7之间都算正常。如果mAP低到0.2基本是标签有问题或训练集验证集划分不一致先回头查数据集。训练完用best.pt在验证集上单独跑一次确认不是中间某个epoch的偶然结果python -c from ultralytics import YOLO; YOLO(runs/detect/train/weights/best.pt).val(datanight_pedestrian/yolo/data.yaml, splitval)这个命令会输出完整验证报告包括各类别AP。如果你想看预测效果用predict方法抽几张夜间图同时保存可视化结果。4. 三平台环境适配GPU(GPUs)/CPU/Mac上的坑与验证标题里写了“GPU(GPUs)/CPU/Mac三平台”说明这套脚本要能在不同设备上无障碍切换。但环境适配的坑比想象中多最常见的不是代码问题而是PyTorch装错了版本。4.1 环境检测一条命令看清CUDA、MPS和PyTorch版本在跑训练之前先用命令确认环境别一上来就装包。我习惯按顺序检查python -c import torch; print(torch.__version__); print(torch.cuda.is_available()) nvidia-smi如果torch.cuda.is_available()输出False但nvidia-smi能看到显卡说明你装的是CPU版PyTorch。这是最经典的翻车点去PyTorch官网按自己的CUDA版本选安装命令不要复制网上过时的命令。驱动方面nvidia-smi显示的CUDA版本是驱动支持的版本PyTorch自带的CUDA runtime只要不大于这个数就能用不需要严格相等。Mac平台检查MPSpython -c import torch; print(hasattr(torch.backends, mps) and torch.backends.mps.is_available())输出True说明可用。注意PyTorch的MPS支持还在完善某些算子没有实现训练到一半报错很正常后面避坑章节专门讲。4.2 多GPU训练batch、显存与分布式配置多卡训练在ultralytics里只是把device设为0,1但有一个重要细节每张卡的batch是总batch除以卡数。比如--batch 32 --device 0,1每卡16张。如果你的显卡是8GB显存16张640x640的图很可能溢出报CUDA out of memory。我一般先降到--batch 16 --device 0,1即每卡8张。如果还想用更大的总batch开梯度累积model.train(..., batch16, device0,1, accumulate4)accumulate4表示每4次反向传播才更新一次权重等效总batch变成64但显存占用不变。还有一个实用参数是cacheTrue把图像缓存到内存减少硬盘IO等待但只对CPU内存有效显存不足时用不上。多卡训练不需要改data.yaml因为每张卡共享数据集路径。只要path是相对路径且脚本是从night_pedestrian/yolo/目录启动就能找到。4.3 CPU和Mac的取舍先跑通再上量CPU训练5000张图、100个epoch会非常慢我一般用subset0.1先跑5个epoch验证整个流程数据读取、模型搭建、前向反向、验证都正常再全量跑。在Mac上MPS比CPU快很多但内存和显存共享batch别设太大。我的经验是Mac上用yolo11n.pt、imgsz640、batch8训练比较稳如果报内存不足就降到4。还有一个坑Mac上MPS的浮点精度和CUDA不完全一样loss曲线会有些许差异这正常不影响最终权重。但如果你在Mac上训练后把权重拿到GPU机器上推理精度基本一致只是速度差异明显。4.4 三平台环境适配清单平台推荐设备常见检查命令建议模型建议batchNVIDIA GPUcudanvidia-smitorch.cuda.is_available()yolo11s16-32纯CPUcputorch.backends.mps不适用yolo11n4-8Mac Apple Siliconmpstorch.backends.mps.is_available()yolo11n/s4-8如果你在公共环境中无法用nvidia-smi也可以看torch.version.cuda和torch.cuda.get_device_name(0)。注意虚拟环境下装PyTorch时很多人漏装torchvision配套版本导致ultralytics导入时报错所以建议用pip list | grep torch检查三个包torch、torchvision、ultralytics。5. 避坑与常见问题夜间行人检测训练必须注意的五个坑夜间行人检测涉及大量低光、小目标和遮挡样本训练过程中有不少坑。我把自己踩过的、身边同事掉过的坑整理成下面五条每条都按“现象 - 原因 - 解决”的方式说方便你直接对照。5.1 训练时loss不降但验证指标正常先查数据增强和预训练权重现象训练loss一直忽上忽下甚至越来越大但验证mAP还在缓慢上升。原因YOLO11默认开启马赛克等强增强夜间低光图经过几何拼接后本身就难学习loss震荡是正常的但“只涨不降”就危险。另一个原因是没加载预训练权重从yolo11s.yaml随机初始化夜间这种单一类别任务很难学。解决确认--weights yolo11s.pt不要写错成yaml文件。然后把mosaic从默认1.0降到0.5mixup调到0.0先关掉部分增强让loss曲线稳定下来再逐步打开。5.2 标签坐标越界训练里“行人”全成废标签现象训练日志出现大量WARNING: Ignoring corrupted image或loss为NaN。原因从VOC/COCO转YOLO时归一化除以了错误的宽高比如图像被resize过但标注坐标还是原图尺寸。也有可能是把两个XML合并到了一个txt里导致一行解析失败。解决用2.2里的体检脚本扫描打印越界行。如果是单张图越界找到原图的真实宽高重新计算归一化值如果是合并问题把多行拆分。修正后重新体检直到invalid label lines: 0再训练。5.3 Mac上MPS训练到一半报错不是你的问题现象训练到第30个epoch时突然报NotImplementedError: MPS not implemented for add_。原因PyTorch的MPS后端对部分算子不完善ultralytics某些增强或loss用到了不兼容算子往往和具体版本有关。解决先升级PyTorch到最新版很多算子问题在更新后就解决了。还不行就改用devicecpu慢但稳。另一个办法是把mosaic关掉我遇到过马赛克拼接触发不支持的算子关掉后MPS反而能跑到底。5.4 多GPU训练显存不足不要只调batch现象CUDA error: out of memory或者训练进程直接被系统杀掉。原因除了batch还有可能是数据加载进程占用显存或者模型在验证时也占了一份显存。有些人只调batch从32降到8还是爆但没看workers。解决先把--batch 8 --device 0,1再把workers2数据加载线程数调小避免子进程抢占显存。如果不够开cacheTrue和accumulate4前者加快IO后者等效扩大batch但不增显存。5.5 夜间召回率低小目标才是主角现象mAP50到了0.6但视频里远处的行人总是漏检。原因夜间行人在图像里可能只有十几个像素训练时默认640分辨率下小目标特征太弱标注里小目标占比又低模型学不到。解决训练时用--imgsz 1280同时设置scale0.5让模型见更多尺度的目标。验证时单独统计小目标AP用6章的代码。我上次就是只看了整体mAP实际一跑车灯眩光场景就露陷之后把输入尺寸加大才把夜间召回拉回来。6. 进阶验证与调优用帧序列和低光指标评估夜间行人模型光看mAP50不够。夜间场景的模型我会多跑两步验证第一步是用model.val()拿每个类别的AP按面积分段看小目标表现第二步是把best.pt放到一段夜间视频上跑看连续帧的框是否跳来跳去。训练好的权重在runs/detect/train/weights/best.pt用下面代码快速输出分尺寸指标from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) metrics model.val(datanight_pedestrian/yolo/data.yaml, splitval) print(mAP50:, metrics.box.map50) # 按面积段统计小目标(area 32^2)、中目标(32^2 ~ 96^2)、大目标 if hasattr(metrics.box, ap50): for i in range(3): ap50 metrics.box.ap50[i] print(farea category {i}: AP50 {ap50:.3f})这段代码打印的结果里如果小目标AP明显低于中目标就需要继续调。我遇到过mAP50达到0.7但小目标AP只有0.15的情况于是把imgsz从640改成1280小目标AP翻倍。但这样做推理速度下降要权衡。我个人的教训是夜间行人不能只看平均精度还要看在阴影里、车灯亮斑旁的行人能不能稳定检出。曾经有个项目我只看mAP结果在夜间停车场测试时路灯下的行人也漏了一半。后来把验证集单独收集了200张低光图每次训练完都跑一遍模型确实更“抗造”。上面这段代码就是每次训练完的必做检查你可以把它写进一个eval.sh跑完训练自动执行。希望帮到你。本文还有配套的精品资源点击获取