ARTICLE DETAIL

资讯详情

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

夜间行人检测数据集与YOLO11跨平台训练实战

夜间行人检测数据集与YOLO11跨平台训练实战 简介面向目标检测与夜视监控场景学习者这套资料以PDF说明文档形式提供夜间行人检测数据集的获取入口与使用指引。数据集本身包含5000张夜间、低光真实场景图片覆盖街景行人、道路行人、遮挡及严重遮挡行人等情况经labelimg标注并同时提供VOC(xml)、COCO(json)、YOLO(txt)三种格式可直接接入YOLO等算法进行训练。配套还给出YOLO11一键训练脚本支持GPU(GPUs)、CPU、Mac(M芯片)多平台运行并附博主训练结果日志作参考。因数据集体量较大托管于百度网盘包内以1个PDF承载体积约6.07MB内含数据集基本情况与获取方式。目前已有611人学习下载。1. 夜间行人目标检测数据集方案5000张图解决的不只是“量”夜间行人目标检测的坑大多数不在模型结构而在数据分布和训练脚本的可用性。白天跑得正常的模型到晚上监控画面里经常漏检、误检因为训练数据里根本缺少足够的夜间样本。这套方案的核心是给你一份5000张夜间行人图、VOC/COCO/YOLO三种格式齐全的标签外加一个能在GPU、CPU、Mac三平台直接跑YOLO11训练的一键脚本。它解决的是数据层面和工程层面的落地障碍适合正在做安防监控、辅助驾驶、园区巡检等夜间场景的从业者也适合想用现成数据集把YOLO11全流程跑通的新手。2. 拆解夜间行人数据集5000张图的构成逻辑三格式标签如何打通2.1 夜间行人为什么比白天难检测从数据分布到特征退化夜间行人检测难不是简单“把图调亮”就能解决。光照不足时行人轮廓与背景的对比度下降色彩信息近乎失效模型只能依赖边缘和局部纹理。更麻烦的是夜间行人的形态和白天差异很大有人穿反光背心有人撑伞有人低头看手机屏幕光把面部照成一块过曝区域。这些都会让白天模型学到的特征分布发生偏移所以专门挑选夜间图像构建数据集是在矫正数据域的偏差。5000张图这个规模在目标检测里不算大但对夜间行人这类单一类别场景够用。常见做法是划分为train/val/test三份比例按8:1:1或者用ultralytics的自动切分。关键在保证夜间场景的多样性不同路灯密度、雨天、逆光、远处小目标都要占一定比例否则模型在验证集刷分很高一上真实场景就露馅。我整理数据集时习惯按场景先做一次粗筛确保不是同一个路口反复拍了5000张——那种数据等于只有几百张的多样性训练到后面出问题是必然的。实际整理时建议单独统计每个场景下的行人框数量。5000张图如果平均每张不到1个行人正样本偏少模型容易把大量背景误判成行人反过来若某几张图里有十来个行人也不要让它们主导整批数据可通过按帧抽帧或下采样平衡。目标检测的数据质量看的从来不是图片总数而是有效标注框的覆盖度。2.2 把VOC/COCO/YOLO三格式串联起来txt才是YOLO11训练的入口VOC、COCO、YOLO三种标注格式本质是同一批框的三种表达方式。VOC用XML文件记录目标名称和边界框坐标坐标是像素绝对值COCO用一个JSON文件统一管理除框坐标外还带图片路径、尺寸等元信息YOLO格式则是每个txt对应一张图每行记录类别id和归一化中心坐标、宽高。YOLO11的ultralytics训练接口只读取YOLO格式所以拿到VOC或COCO标签后第一件事就是转换成YOLO txt。下面这个脚本能把VOC的XML批量转成YOLO标签转换后可直接交给YOLO11训练import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_txt_path, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue class_id class_names.index(name) bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 坐标归一化到0~1YOLO格式只认相对值 x_center (x1 x2) / 2.0 / img_w y_center (y1 y2) / 2.0 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines)) class_names [pedestrian] xml_dir annotations txt_dir labels os.makedirs(txt_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): voc_to_yolo( os.path.join(xml_dir, xml_file), os.path.join(txt_dir, xml_file.replace(.xml, .txt)), class_names )逻辑说明先解析XML里size节点拿到原始宽高再遍历object节点把每个行人框从左上角右下角坐标转成归一化中心坐标加宽高。YOLO训练读取标签时只认txt里这些0到1的小数如果坐标大于1或出现负数训练会报错或直接忽略该目标。转换时几个容易踩的坑。一是XML如果来自裁剪后的图片宽高和原图对不上归一化结果会错位转换前最好抽样比对几份文件的图像尺寸。二是类别名必须和之后训练yaml里的names顺序完全一致否则id错位模型会把行人学到别的类别上去。三是COCO转YOLO时COCO的bbox是左上角坐标加宽高而YOLO要中心坐标很多手动转换脚本漏掉“除以2”这一步框整体偏移到右下角训练时loss不降但val分数一路走低。COCO转YOLO的常见做法是直接解析JSON按image_id聚合标注import json import os from collections import defaultdict coco_json annotations.json label_dir labels os.makedirs(label_dir, exist_okTrue) with open(coco_json) as f: data json.load(f) img_id_to_name {img[id]: img[file_name] for img in data[images]} img_id_to_w {img[id]: img[width] for img in data[images]} img_id_to_h {img[id]: img[height] for img in data[images]} img_anns defaultdict(list) for ann in data[annotations]: img_anns[ann[image_id]].append(ann) for img_id, anns in img_anns.items(): img_w img_id_to_w[img_id] img_h img_id_to_h[img_id] lines [] for ann in anns: cat_id ann[category_id] x, y, w, h ann[bbox] # COCO的bbox是[x, y, width, height] x_center (x w / 2.0) / img_w y_center (y h / 2.0) / img_h lines.append(f{cat_id} {x_center:.6f} {y_center:.6f} {w / img_w:.6f} {h / img_h:.6f}) out_name os.path.splitext(img_id_to_name[img_id])[0] .txt with open(os.path.join(label_dir, out_name), w) as f: f.write(\n.join(lines))需要单独强调的一点COCO JSON里的category_id通常从1开始编号和yaml里names列表的0起始下标不是一回事转换时最好先建一张id映射表把1对应到0、2对应到1否则训练时类别直接错乱。转换完成后建议用ultralytics自带的predict接口渲染几张图确认框的位置和类别对不对。这一步不能省——标签质量直接决定训练结果框错位的图哪怕只有几十张也会给loss曲线添乱。把labels目录和images目录放在同一个父目录下保持train/val/test结构一致后续yaml配置就不会踩路径坑。3. YOLO11跨平台训练脚本GPU、CPU、Mac三端的配置与自动设备选择3.1 环境配置GPU、CPU、Mac三条路线里的版本坑YOLO11是ultralytics维护的开源框架安装入口就是ultralytics包但跨平台训练的差异在torch后端。NVIDIA GPU需要CUDA版torch纯CPU机器装CPU版即可Mac如果是Apple Silicon芯片用MPS后端能把GPU用起来。对0基础入门来说最常见的翻车是直接pip install torch结果在GPU机器上装成了CPU版训练速度慢一个数量级而且不报错特别迷惑人。常见做法是先建独立conda环境再按平台装torchconda create -n yolo11 python3.10 -y conda activate yolo11 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics参数说明第一行创建Python 3.10独立环境避免和系统Python或其它深度学习包互相污染。第二行是关键--index-url指定了CUDA 12.1的PyTorch wheel源这样装完torch.cuda.is_available()才会返回True。如果机器驱动是CUDA 11.8把cu121改成cu118如果不确定驱动版本先跑nvidia-smi看右上角CUDA Version再决定装哪个版本。Mac用户命令更简单但有一个细节Apple Silicon上要确认装的是arm64版torch而不是Intel版。装完务必验证MPSpython -c import torch; print(torch.__version__); print(torch.backends.mps.is_available())输出True说明torch能调用Mac的GPU。很多人在Mac上训练YOLO11发现设备列表只有cpu就是MPS没被正确识别。另外Mac外接高分辨率显示器时系统可能把大量统一内存分给图形界面训练batch稍微大一点就容易触发共享内存不足这时把batch降到8以下通常能缓解。拿到任何一台机器我都建议先跑一个推理脚本确认环境就绪而不是直接开训from ultralytics import YOLO model YOLO(yolo11n.pt) results model.predict(test.jpg, devicecpu) print(results[0].boxes)这里用CPU跑是为了先把框架本身、权重下载、图片读取这些环节排查干净。能正常出框再切到GPU训练环境问题不会混在一起排查。3.2 一键训练脚本的骨架自动探测设备、batch防呆与断点续训一个真正能称得上“一键”的训练脚本至少要做三件事解析命令行参数、自动探测可用计算设备、把ultralytics的train调用包一层。下面这个骨架可直接改来用import argparse import torch from ultralytics import YOLO def detect_device(prefer): if prefer auto: if torch.cuda.is_available(): return cuda:0 elif torch.backends.mps.is_available(): return mps else: return cpu return prefer def main(): parser argparse.ArgumentParser(descriptionYOLO11 跨平台训练入口) parser.add_argument(--data, typestr, defaultnight_pedestrian.yaml) parser.add_argument(--epochs, typeint, default100) parser.add_argument(--batch, typeint, default16) parser.add_argument(--imgsz, typeint, default640) parser.add_argument(--weights, typestr, defaultyolo11n.pt) parser.add_argument(--device, typestr, defaultauto, choices[auto, cuda, cpu, mps]) parser.add_argument(--name, typestr, defaultnight_run) parser.add_argument(--resume, typestr, defaultNone, help断点续训传 last.pt 路径) args parser.parse_args() device detect_device(args.device) print(fdetect device: {device}) if device cpu and args.batch 8: print([warning] CPU 训练建议 batch 8) if device mps and args.batch 16: print([warning] Apple Silicon 建议 batch 16) if args.resume: model YOLO(args.resume) model.train( dataargs.data, epochsargs.epochs, batchargs.batch, imgszargs.imgsz, devicedevice, nameargs.name, resumeTrue, ) else: model YOLO(args.weights) model.train( dataargs.data, epochsargs.epochs, batchargs.batch, imgszargs.imgsz, devicedevice, nameargs.name, optimizerAdamW, lr00.001, ) if __name__ __main__: main()逻辑说明detect_device在auto模式下按cuda、mps、cpu的优先级探测脚本拿到任何一台机器上都不会因设备不可用而崩溃。batch防呆提示写在启动阶段CPU上超过8、MPS上超过16会有明显内存压力提前警告比训练中途被杀好。断点续训逻辑在resume参数里一旦训练中断把runs/detect/night_run/weights/last.pt路径传给--resumeultralytics会从最近的权重继续而不是从头再来。这个功能对长训练特别重要网络断了、内存被杀、停电都能找回进度算是一键脚本里的后悔药。跑起来就是一行命令python train.py --data night_pedestrian.yaml --epochs 100 --batch 16 --weights yolo11n.pt没显卡的机器--device留auto让它降级到cpu或mps。如果租用了GPU服务器想多卡并行把device改成0,1,2,3就行ultralytics会自动按卡数拆分batch。夜间数据量不大单卡通常足够但多卡能明显加快实验迭代。4. 训练脚本里的关键参数data.yaml、权重选择与epoch/batch/imgsz调优4.1 data.yaml的写法路径、nc、names一个都不能错ultralytics的train接口要求一个YAML文件描述数据集路径和类别信息5000张图的夜间行人数据集yaml通常长这样path: ./night_pedestrian train: images/train val: images/val test: images/test nc: 1 names: 0: pedestrian几个细节需要注意path是数据集根目录train/val/test指向的是存放图片的目录而不是标签目录ultralytics会自动在同级目录下找labels。如果标签和图片目录层级不一致就用labels_train之类的键显式指定。我踩过这个坑标签放在data/labels/train图片在data/images/train训练时框架报找不到标签改成显式映射后才解决。0基础小白最容易在这里栽跟头的是相对路径问题。训练启动后报Dataset not found多半是当前工作目录和yaml里的相对路径对不上。最简单的办法是在脚本里打印os.path.abspath(./night_pedestrian)把绝对路径填进yaml一劳永逸。类别数也要同时核对如果数据集除行人也标注了骑行者nc改成2names改成{0: pedestrian, 1: cyclist}。夜间场景里骑电动车的人形态和行人差异很大单独设类通常比混在一起检测效果好。4.2 模型权重怎么选yolo11n、yolo11s还是yolo11mYOLO11系列按深度和宽度分n/s/m/l/x几个型号。夜间行人检测受限于夜间特征微弱太小的模型容易欠拟合但数据只有5000张太重的模型又容易过拟合。常见起点是yolo11n.pt先跑通全流程若验证集mAP不理想再换yolo11s或yolo11m训练一轮。n型号在CPU上还能勉强推理m型号在无独显机器上训练几乎寸步难行。选型还要看部署目标。如果最终要跑到摄像头等边缘设备上训练时最好就锁定n型号因为s/m体积上去之后端侧推理帧率下降明显K230这类集成芯片一般只能跑n型号的裁剪版本。如果只做离线分析服务器GPU推理那么s或m对夜间小目标的召回率会明显更好。4.3 epoch、batch、imgsz与夜间小目标的取舍训练参数不是越大越好。5000张图不算海量epoch设太多会快速过拟合batch受显存限制imgsz对夜间小目标影响最直接——行人离摄像头远时在640分辨率下可能只有20像素高放大到1280能保留更多细节但显存占用翻了四倍。硬件环境epochbatchimgsz说明CPU 8核无独显1004640建议用yolo11n时间成本高RTX 3060 12G10016640日常训练均衡点RTX 4090 24G100321280小目标检测可上1280Mac MPS芯片10016640按脚本防呆提示控制batch夜间行人经常是小目标时常用做法是把imgsz设为960或1280batch相应调小mAP对小目标的提升会很明显。但注意yolo11n本身是轻量模型分辨率提高后推理速度下降边缘设备上要权衡。优化器方面默认auto在数据量不大时通常选SGD但我用AdamW跑夜间数据集收敛更稳loss曲线没那么抖。在train接口里显式指定optimizerAdamW学习率lr0设为0.001。夜间检测的loss曲线和白天相比跳跃更大学习率偏大会在前几个epoch就震荡。ultralytics默认patience100意思是val分数100轮不涨自动停。5000张图训100轮通常几十个epoch就能收敛把patience设成30能省不少时间也不会错过最佳权重。数据增强保持默认即可hsv_h0.015、translate0.1这些增强对夜间场景没坏处反而能在5000张图基础上模拟更多亮度和位置变化。5. 避坑记录YOLO11训练脚本跑通后最容易翻车的五个环节5.1 标签坐标越界或负数导致loss异常现象训练到中途loss突然跳到无穷大或者某个类别完全学不出来检查txt标签发现里面有1.2、-0.3这类越界值。原因标注工具对紧贴图像边缘的行人导出坐标时越界也可能是VOC/COCO转换脚本对裁剪过的图做了二次归一化导致正确标签被算错。解决在训练前加一段标签清洗逻辑遍历labels目录把坐标裁剪到0到1之间过滤掉宽高小于0.001像素的无效框。写一个数据校验脚本跑完再开训能省掉后面好几个小时的排查时间。import os import glob label_dir labels for txt_path in glob.glob(os.path.join(label_dir, *.txt)): cleaned [] with open(txt_path) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cid, xc, yc, w, h parts xc, yc, w, h map(float, [xc, yc, w, h]) if w 0.001 or h 0.001: continue xc max(0.0, min(1.0, xc)) yc max(0.0, min(1.0, yc)) w max(0.001, min(1.0, w)) h max(0.001, min(1.0, h)) cleaned.append(f{cid} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(cleaned))逻辑说明逐行解析每个标签过滤无效框、裁掉越界坐标再把结果写回。这个脚本跑完原本会导致训练的标签问题基本清零后续再遇到异常优先怀疑数据分布而不是数据格式。5.2 CPU或Mac上内存直接爆掉现象batch设成16在CPU机器上跑运行几分钟系统内存占满训练进程被kill掉日志里出现Killed。原因CPU训练没有独立显存管理每一批数据和中间特征图全在内存里batch越大内存消耗越猛。Mac的MPS是统一内存架构batch过大同样会迅速吃满内存。解决把batch降到4或2同时把数据加载workers设成0或1避免多进程预取叠加内存压力。使用第3章脚本里的防呆提示CPU不超过8、MPS不超过16但实际保险起见CPU用4更稳妥。5.3 验证集mAP很高但接真实夜间视频全是漏检现象训练结束val分数不错mAP50到0.9一接摄像头或真实夜间视频帧行人漏了一半。原因验证集和训练集来自同一批数据分布刷分容易。真实夜间视频里有动态模糊、过曝灯光、雨滴干扰这些在离线数据集里没有被充分覆盖。解决单独留出一部分真实设备拍的夜间视频帧做硬测试集完全不进训练过程。用这些帧做最终评估不看val集指标。如果差距大把这些帧混回训练集再训一轮通常next强不少。5.4 训练中断后没开resume十几个小时白跑现象训练到第80个epoch服务器重启或内存被杀重新运行脚本发现又从第0个epoch开始。原因训练默认不从上次权重续跑而是重新初始化如果没保存last.pt或脚本不支持resume进度全部丢失。解决用第3章脚本里的--resume参数把last.pt路径传进去。ultralytics的resumeTrue逻辑会读取上一次训练的配置文件、学习率和当前epoch继续训练而不是重新开始。养成习惯训练命令里始终保留--name参数让每次实验的输出目录可辨识中断后能在runs/detect下对号入座找权重。5.5 类别id和names不对齐导致模型学错目标现象训练loss很快降到很低但推理时所有检测框都打在错误目标上或全部预测成背景。原因txt标签里的类别id和yaml里names列表顺序不一致。比如COCO转YOLO时没有做id映射0在训练yaml里是pedestrian但数据里0号框实际是其他目标。解决转换脚本里强制加入id映射表并在训练前抽样打印一个txt文件的前几行核对id含义。第2章COCO转换代码里专门留了映射说明这个环节不值得省时间。6. 跑通训练后的验证闭环mAP、PR曲线与夜间增强的进阶调试6.1 用测试集重新评估不要只看训练保存的val结果训练结束后不要只盯train loss。ultralytics会在保存目录生成results.png、confusion_matrix.png和PR曲线但更可靠的是手动对test集跑一遍评估from ultralytics import YOLO model YOLO(runs/detect/night_run/weights/best.pt) metrics model.val(datanight_pedestrian.yaml, splittest) print(metrics.box.map50, metrics.box.map)这两行输出的是mAP50和mAP50-95。mAP50-95比mAP50严格不少夜间小目标多如果两个数字差距大说明模型只对高置信度的简单样本稳定对遮挡、模糊目标还不稳需要回头调imgsz或增强参数。6.2 夜间视频帧级增强与多模态纠错跑通YOLO11只是第一步。真实落地时我会先对视频流做帧采样再对夜间帧做自适应直方图均衡或Retinex增强后再送入模型比直接推理在低照度下更稳。还有一种常见的进阶组合将yolo目标检测和多模态AI分析接起来做智慧交通事故检测夜间场景下视觉置信度低时让多模态模型对局部画面做二次确认能补掉一部分漏检和误判。最后说一个自己的教训最早拿这份5000张夜间数据集练手时图省事直接用白天模型finetuneepoch设到300结果过拟合到val集出不来门。后来老老实实按100轮跑把标签清洗和真实视频硬测试集加上才把夜间漏检率压下来。YOLO11在这个任务上的门槛不高真正的工程难点在数据管线和验证手段是否扎实希望帮到你。本文还有配套的精品资源点击获取
返回列表