楼梯检测数据集1043张:YOLO与VOC双格式实战与避坑指南
简介这份楼梯目标检测数据集面向计算机视觉入门与进阶开发者适用于安防监控、智能家居、机器人导航等需要识别楼梯区域的场景可直接用于YOLO与VOC双格式的目标检测训练与验证。压缩包共2000个文件包含1043张jpg图片、1043个xml标注文件与957个txt标签文件另有数据集说明文档整体约9.49MB图片分辨率清晰且未做数据增强标注以矩形框形式给出标签仅staircase一类共1224个标注框类别顺序以labels文件夹中的classes.txt为准。目前已有89人学习下载。读者可借助该数据集快速搭建楼梯检测基线模型省去自行采集与标注的成本同时利用VOC与YOLO双格式灵活适配不同训练框架便于对比实验与迁移学习是开展目标检测实践与课程设计的实用素材。1. 楼梯数据集1043张为什么这个冷门场景值得你花一个周末跑通楼梯检测在目标检测里属于典型的小而难场景。说它小是因为公开数据集里专门做楼梯的少得可怜1043 张这个量级放在 COCO、BDD100 面前几乎可以忽略说它难是因为楼梯的视觉特征高度依赖拍摄角度——正面拍是一排排水平横线侧面拍是斜向的锯齿结构俯拍又变成一组平行矩形同一个物体在图像里能呈现出完全不同的纹理。更麻烦的是楼梯经常和栏杆、扶手、台阶边缘、地砖纹理混在一起模型很容易把栏杆当成楼梯主体或者把带条纹的地毯误判成台阶。这个数据集的价值就在这里1043 张图同时提供 YOLO 格式和 VOC 格式两套标注意味着你不需要自己从 LabelImg 开始标拿到就能直接进训练流程。YOLO 格式是class x_center y_center width height的归一化坐标VOC 格式是 XML 里的xmin ymin xmax ymax绝对坐标两套格式覆盖了目前主流训练框架的输入需求。适合谁做室内机器人导航、盲人辅助出行、扫地机越障、AR 场景理解这几个方向的从业者以及想找一个数据量不大、能快速跑通全流程的练手项目的 YOLO 入门者。1043 张的规模单卡跑 100 到 300 轮一个下午就能看到收敛结果这对建立手感比拿 COCO 跑一周更有效。2. 拿到 zip 先别急着解压YOLO 与 VOC 双格式的目录结构和字段对照2.1 两套格式到底差在哪为什么都要留YOLO 格式和 VOC 格式的本质区别是坐标表示方式。YOLO 用归一化中心点加宽高所有值都在 0 到 1 之间好处是跟图像尺寸解耦换分辨率不用改标注VOC 用绝对像素坐标的左上角和右下角好处是直观、方便做可视化校验和跟其他工具链对接。维度YOLO 格式VOC 格式标注文件.txt每行一个目标.xml每图一个文件坐标形式class cx cy w h归一化xmin ymin xmax ymax绝对像素类别表示数字索引从 0 开始字符串name字段目录组织images/与labels/平行JPEGImages/与Annotations/平行主流消费方Ultralytics YOLO 系列早期 SSD、Faster R-CNN、部分评测脚本保留两套格式的实际意义在于训练用 YOLO 格式最省事但如果你要拿这个数据集去对比一个 VOC 时代的老模型或者要把标注导进某些只认 XML 的标注复核工具VOC 那套就是后悔药。我一般会先把两套都解压到独立目录确认图片文件名能一一对应再决定用哪套进训练。2.2 解压后的目录自检脚本拿到压缩包后第一件事不是直接开训而是确认图片和标注是否配对完整。下面这段脚本扫描图片目录和标注目录找出只有图没有标注、或只有标注没有图的孤儿文件。import os from pathlib import Path # 按你实际解压后的路径改这三行 IMG_DIR Path(stair_dataset/images) LBL_DIR Path(stair_dataset/labels) EXTS {.jpg, .jpeg, .png, .bmp} imgs {p.stem for p in IMG_DIR.iterdir() if p.suffix.lower() in EXTS} lbls {p.stem for p in LBL_DIR.iterdir() if p.suffix.lower() .txt} only_img imgs - lbls # 有图无标注 only_lbl lbls - imgs # 有标注无图 print(f图片总数: {len(imgs)}) print(f标注总数: {len(lbls)}) print(f有图无标注: {len(only_img)} - {sorted(only_img)[:10]}) print(f有标注无图: {len(only_lbl)} - {sorted(only_lbl)[:10]})逻辑说明用Path.stem取不含扩展名的文件名做集合运算这是最稳的配对方式避免因为.jpg和.JPG大小写不一致导致误判。参数上EXTS集合按你实际图片格式增减如果数据集里混了.webp要补进去。跑完如果only_img和only_lbl都是 0说明配对干净如果有零星几个通常是标注时删图没删标注直接删掉对应文件即可不要留着让训练脚本去报错。2.3 类别索引必须自己核一遍YOLO 格式的类别是数字但数字对应什么名字数据集里不一定有classes.txt。VOC 的 XML 里有name字段这是你反查类别映射的唯一可靠来源。下面脚本从 VOC 标注里统计所有类别名并给出建议的索引顺序。import xml.etree.ElementTree as ET from pathlib import Path from collections import Counter ANN_DIR Path(stair_dataset/Annotations) counter Counter() for xml_file in ANN_DIR.glob(*.xml): tree ET.parse(xml_file) for obj in tree.getroot().findall(object): name obj.find(name).text.strip() counter[name] 1 for idx, (name, cnt) in enumerate(sorted(counter.items())): print(f索引 {idx}: {name} 出现 {cnt} 次)逻辑说明findall(object)遍历每张图里的所有目标find(name).text取类别字符串。统计完你会看到类似stair、handrail、step这样的类别分布。如果只有stair一类那就是单类检测训练配置里nc1如果有多个类别索引顺序必须和 YOLO 的data.yaml里names列表严格一致错一位整个训练就废了。这一步是血泪经验我见过太多人直接抄别人的names顺序结果模型把栏杆全标成楼梯。3. 用 Ultralytics 把 1043 张楼梯图跑起来从 data.yaml 到第一次收敛3.1 环境配置与最小依赖Ultralytics 的 YOLO 系列目前是楼梯这种小数据集最省心的选择一条pip就能装完不需要自己编译 Darknet。环境上Python 3.9 到 3.11 都稳CUDA 版本跟你的显卡驱动对齐即可。# 建议在独立虚拟环境里装避免和系统里的 torch 打架 python -m venv venv_stair source venv_stair/bin/activate # Windows 用 venv_stair\Scripts\activate pip install ultralytics # 如果要用 GPU 训练确认 torch 能识别到卡 python -c import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))逻辑说明ultralytics包会自动拉取匹配的torch和torchvision一般不用手动指定版本。最后那行检查必须输出True和你的显卡型号如果输出False说明装成了 CPU 版训练会慢到让你怀疑人生。参数上如果你显卡显存小于 6GB后面训练时batch要往下压。3.2 data.yaml 的四个必填字段Ultralytics 训练只认一个 YAML 配置文件路径、类别数、类别名三样必须对。# stair.yaml path: /abs/path/to/stair_dataset # 数据集根目录用绝对路径最稳 train: images/train # 相对 path 的训练图目录 val: images/val # 相对 path 的验证图目录 nc: 1 # 类别数按 2.3 统计结果填 names: # 顺序必须和 YOLO 标注里的数字索引一致 0: stair逻辑说明path用绝对路径能避免在哪个目录下执行脚本带来的玄学问题。train和val是相对path的子路径Ultralytics 会自动去对应位置找同名.txt标注——注意它默认标注在images同级替换成labels所以你的目录结构最好是images/train配labels/train。nc和names的对应关系是硬约束names的键必须从 0 连续到nc-1中间不能跳号。3.3 划分训练验证集1043 张怎么分1043 张不算多验证集留太多会浪费训练数据留太少评估波动大。常见做法是 8:2即 835 张训练、208 张验证。如果场景里拍摄角度差异大正面、侧面、俯拍都有建议按角度分层抽样而不是随机切否则验证集可能全是正面图指标虚高。import random, shutil from pathlib import Path SRC_IMG Path(stair_dataset/images) SRC_LBL Path(stair_dataset/labels) DST Path(stair_dataset_split) random.seed(42) # 固定种子保证每次划分一致方便复现 stems sorted(p.stem for p in SRC_IMG.glob(*.jpg)) random.shuffle(stems) split int(len(stems) * 0.8) train_stems, val_stems stems[:split], stems[split:] for subset, items in [(train, train_stems), (val, val_stems)]: (DST / images / subset).mkdir(parentsTrue, exist_okTrue) (DST / labels / subset).mkdir(parentsTrue, exist_okTrue) for s in items: shutil.copy(SRC_IMG / f{s}.jpg, DST / images / subset / f{s}.jpg) shutil.copy(SRC_LBL / f{s}.txt, DST / labels / subset / f{s}.txt) print(f训练集 {len(train_stems)} 张验证集 {len(val_stems)} 张)逻辑说明random.seed(42)是复现的关键不固定种子的话每次划分不同指标没法横向对比。shutil.copy保留原文件方便你后面换划分比例重跑。参数上如果你的图片扩展名不是.jpg把两处f{s}.jpg改成实际扩展名。跑完检查stair_dataset_split下四个子目录的文件数是否对得上。3.4 启动训练与关键参数yolo detect train \ datastair.yaml \ modelyolo11n.pt \ epochs200 \ imgsz640 \ batch16 \ patience50 \ projectruns/stair \ nameexp1逻辑说明modelyolo11n.pt用 nano 版起步1043 张数据量下 nano 足够参数量小、收敛快等跑通后再换s或m版对比。epochs200配合patience50意思是 50 轮验证指标不涨就早停避免过拟合。imgsz640是默认值楼梯的台阶纹理比较细如果显存允许可以提到 768 或 896小目标召回会好一些。batch16在 8GB 显存上比较稳显存不够就降到 8。训练日志里重点看mAP50和mAP50-95两条曲线前者涨到 0.85 以上、后者到 0.6 以上对单类楼梯检测就算能用了。4. 楼梯检测的避坑清单五条我踩过的真实翻车记录4.1 验证集 mAP 很高实际推理全是框现象训练日志里mAP50冲到 0.92拿手机拍一张自家楼梯去推理模型在整张图上画了几十个重叠框或者一个框都没有。原因验证集和训练集来自同一批拍摄设备、同一批场景分布几乎一致模型学到的是这批图的楼梯长这样而不是楼梯这个概念。1043 张如果全是一个小区、一个楼层拍的过拟合会非常严重。解决从验证集里单独抽 20 到 30 张完全没参与训练的、不同场景的图做一次外部测试。如果外部测试掉到 0.5 以下说明泛化不行要么补数据要么上更强的数据增强mosaic、scale、hsv_h调大。我一般会在data.yaml之外再建一个test目录训练完单独跑yolo detect val指向它。4.2 把栏杆标成了楼梯类别混淆现象推理结果里楼梯两侧的金属栏杆被框成stair真正的台阶反而漏检。原因楼梯和栏杆在图像里空间上紧挨着标注时如果边界画得不严模型学到的特征会重叠。尤其是侧面拍摄栏杆的斜线和台阶的斜线方向一致纹理特征高度相似。解决回到标注层面检查 XML 里stair的xmin/ymin/xmax/ymax是否把栏杆区域包进去了。如果数据集本身标注就含糊训练再久也没用。另一个办法是加一个handrail类别让模型学会区分两者但这需要重新标注成本高。折中方案是训练时开copy_paste增强人为制造一些楼梯和栏杆分离的样本。4.3 图片和标注文件名大小写不一致导致静默丢数据现象训练日志显示train: 835 images但你明明有 835 张图实际参与训练的却少了几十张mAP怎么调都上不去。原因Ultralytics 在配对图片和标注时如果图片是.JPG而标注是.jpg.txt或者文件名大小写不一致会静默跳过不报错。Windows 上不区分大小写Linux 上区分跨平台迁移时特别容易中招。解决用 2.2 的脚本先做一次配对检查确认only_img和only_lbl都是 0。如果发现大小写问题批量重命名统一成小写。这个坑最阴的地方是它不报错你只会觉得模型怎么学不会其实是数据根本没喂进去。4.4 学习率默认值在小数据集上偏大现象训练前 20 轮 loss 剧烈震荡mAP上下跳收敛很慢。原因Ultralytics 的默认学习率是按 COCO 这种十万级数据集调的1043 张的规模下同样的学习率会让梯度更新过猛模型在最优解附近来回横跳。解决把lr0从默认的 0.01 降到 0.001 到 0.005 之间lrf保持 0.01。同时把warmup_epochs从 3 提到 5让模型前几轮慢慢进入状态。改完再跑loss 曲线会平滑很多。这个参数没有万能值1043 张我一般从 0.003 起步试。4.5 显存溢出发生在第 0 轮而不是训练中现象命令敲下去还没开始训练就报CUDA out of memory。原因Ultralytics 在训练前会做一次缓存和增强的预分配如果imgsz设得大、batch又没降预分配阶段就爆了。另外如果之前有残留的 Python 进程占着显存也会导致新任务起不来。解决先nvidia-smi看有没有僵尸进程有就kill掉。然后把batch减半、imgsz降到 640 再试。如果还不行加cacheFalse关掉内存缓存。显存这玩意儿就是硬约束别硬扛降参数比换卡快。5. 从 1043 张到能用验证策略与一个提点小技巧训练跑完不是终点怎么判断这个模型能不能上你的实际场景才是关键。我一般分三步验证。第一步用yolo detect val在独立测试集上跑一遍看mAP50-95和混淆矩阵重点看漏检率FN和误检率FP哪个高。楼梯场景里漏检比误检危险漏了台阶可能导致机器人踩空所以召回率优先。第二步拿一段实际场景的视频做逐帧推理观察框的抖动情况——如果相邻帧之间框的位置跳来跳去说明模型对边缘的定位不稳这时候要考虑加时序平滑或者换更大的模型。第三步把模型导出成 ONNX在目标部署环境上跑一次确认推理速度和精度没有明显掉点。# 导出 ONNX方便部署到非 Python 环境 yolo export modelruns/stair/exp1/weights/best.pt formatonnx imgsz640 opset12 # 在独立测试集上评估 yolo detect val modelruns/stair/exp1/weights/best.pt datastair.yaml splittest逻辑说明opset12是兼容性比较好的版本太新的 opset 有些推理引擎不认。导出后建议用onnxruntime跑一张图和 PyTorch 的输出做数值对比误差在 1e-3 以内算正常。提点小技巧楼梯检测里台阶的重复纹理容易让模型在垂直方向上定位偏移。如果你的应用对台阶高度敏感可以在推理后处理里加一个约束——同一张图里检测到的多个stair框如果它们的宽度接近、水平位置重叠就把它们的y坐标做一次聚类对齐取中位数修正。这个后处理不需要重训几行代码就能把垂直定位的方差压下来。import numpy as np def align_stair_boxes(boxes, tol20): boxes: Nx4 的 xyxy 数组对水平重叠的框做 y 对齐 if len(boxes) 2: return boxes boxes boxes.copy() # 按 x 中心排序把水平位置接近的归为一组 order np.argsort((boxes[:, 0] boxes[:, 2]) / 2) boxes boxes[order] groups, cur [], [0] for i in range(1, len(boxes)): if abs((boxes[i, 0] boxes[i, 2]) / 2 - (boxes[cur[-1], 0] boxes[cur[-1], 2]) / 2) tol: cur.append(i) else: groups.append(cur); cur [i] groups.append(cur) for g in groups: if len(g) 1: y_med np.median(boxes[g, 1]) # 取 ymin 中位数 h_med np.median(boxes[g, 3] - boxes[g, 1]) for idx in g: boxes[idx, 1] y_med boxes[idx, 3] y_med h_med return boxes逻辑说明tol20是水平中心距离阈值单位像素按你图像分辨率调640 输入下 20 到 30 比较合适。这个函数只动ymin和ymax不碰水平方向避免把本来正确的左右边界改坏。参数上如果你的场景里楼梯是斜向的这个对齐反而会帮倒忙用之前先确认你的应用里楼梯大致是水平朝向。最后说个习惯我每次拿到一个新数据集不管多小都会先花半小时把配对检查、类别统计、可视化抽检这三件事做完再开训练。1043 张的楼梯数据集这三步加起来不到二十分钟但能省掉后面几小时的无效调参。数据干净模型才可能干净。希望帮到你。本文还有配套的精品资源点击获取