ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YOLO人行道检测实战:10300张智慧城市数据集从训练到部署全解析

YOLO人行道检测实战:10300张智慧城市数据集从训练到部署全解析

1. 人行道检测:智慧城市里一块被忽视的"必争之地"

做智慧城市项目这么久,我越来越觉得一个有意思的现象:大家一窝蜂去做车辆检测、车牌识别、违章停车抓拍,反而把最基础、最高频的人行道场景给漏掉了。人行道是什么?它是城市里行人最密集、情况最复杂、管理诉求也最琐碎的空间——盲道被占用、共享单车横七竖八、摊贩占道经营、护栏损坏、路缘石破损,全是问题。但这些问题,多数城市目前还在靠人工巡查 + 市民投诉热线来处理,效率低得吓人。

所以当我拿到这套"人行道场景检测数据集 | 10300张YOLO智慧城市数据集"的时候,第一反应是:这玩意儿比想象中值钱得多。它直接瞄准的就是智慧城市治理里"最后一百米"的感知需求。你要让城市管理者看到问题、响应问题,首先得让"眼睛"长出来——这套数据集就是用来训练那双眼睛的。

对于刚入门YOLO的读者,这套数据集也是一个非常合适的练手对象。10300张的规模很讲究:比学术界的VOC、COCO那种十几万张的巨型数据集轻量得多,但它的场景复杂度、目标尺寸变化、光照多样性又足够真实,完全能让你走完"数据处理 → 模型训练 → 指标调优 → 部署验证"的完整闭环,不会因为数据太少而训练不出来,也不会因为数据太多而跑不动。我自己实际训练下来,用一张消费级显卡,YOLOv8s模型跑100个epoch也就几个小时,中途完全够你观察损失曲线、调参数、等结果。

这篇文章我会分成几个部分来聊:先讲讲人行道检测到底要检测哪些东西、数据集的场景和类别是怎么设计的;然后重点展开从原始标注转成YOLO训练格式的完整细节,这里也是很多人第一次会卡住的地方;接着是训练参数和损失函数曲线的实战解读;最后聊聊模型如何落到智慧城市真实项目里,以及后续扩展方向。整个过程中我会穿插实际训练中踩过的坑和总结的经验,希望能帮你少走弯路。

2. 10300张图的"家底":场景分布、类别设计与标注质量管控

很多人拿到数据集第一件事就是直接开训,我强烈不建议。数据集的"家底"你都不清楚,训练出来效果好不好、哪里有问题,你连排查方向都没有。这套人行道数据集我拆开看了,先说结论:它在场景覆盖上是下了功夫的,但依旧有明显的缺陷和偏向,下面详细拆。

2.1 场景分布:光照、天气、城市风貌的三重覆盖

10300张图如果全部是晴天白天的同一条街,那这个数据集基本没用。我看到的情况是,这套数据主要从三个维度做了覆盖:

  • 光照维度:白天正常光、清晨/黄昏逆光、夜间路灯照明、夜间无路灯但周边商铺灯光干扰。夜间图大概占15%~18%,这个比例在真实项目里其实还偏低——实际城市巡查夜间也是重点,但夜间标注成本高,能做成这样已经不错了。
  • 天气维度:晴天占大头约6成,阴天约3成,雨天和雨后积水反光约占1成。雨天的图对模型很有价值,因为路面反光会极大干扰目标特征提取,没有这部分图,模型一到雨天就"瞎"。
  • 城市风貌维度:包含老城区狭窄人行道、新建宽阔景观道、商业区地砖人行道、居民区水泥路面、工业区附近简陋人行道等。这一点很关键,不同材质的路面纹理差异很大,模型如果只见过一种地砖,换个城市直接泛化失败。

这个覆盖思路值得借鉴。很多自制数据集最大的问题就是"单一样本偏差"——你在A路段拍的照片,训练出来的模型到B路段就废了。人行道这个东西,不同城市、不同城区之间差异巨大,采集时有意混合不同风貌是保证模型可用的底线。

2.2 类别设计:聚焦"可用性"而非"分类炫技"

我注意到这套数据集的类别设计有8到10个类,具体看标注文件时会发现它没有追那种"把城市家具全部识别出来"的极端路线,而是聚焦在用得上、能直接产生管理价值的类别上。大致包括:

  • 人行道区域(sidewalk):作为主类别,模型需要识别整个人行道区域
  • 盲道(blind_path):这个类对无障碍设施巡检价值极大,属于加分项
  • 路缘石(curb):与车道的分界线,对治理车辆违规上人行道很有帮助
  • 护栏/隔离桩(guardrail)
  • 障碍物(obstacle):包括占道堆物、违规停放的非机动车、摊贩货物等

这种类别设计思路是对的。智慧城市项目里,类别的"管理价值"比"学术分类精度"重要得多。你把人行道上的井盖按材质细分出五六个类,识别模型倒是挺累,但城管部门真的需要区分铸铁井盖和复合材料井盖吗?大概率不需要。反而"盲道被占"这个事件,因为有盲道 + 障碍物这两个类别同时出现,就可以基于检测结果做空间推理:障碍物框压住盲道框的时候触发告警,这才是真实场景需要的智能。

2.3 标注质量:数据集的命根子,也是最容易翻车的地方

我在检验这套数据集的时候特别关注标注质量,发现几个值得注意的点:

  • 遮挡处理:数据里多数遮挡目标采用了"可见部分标注"原则,也就是只要目标可见面积超过30%就画框,而不是像COCO那种用大框把遮挡部分也包进去。这个对YOLO训练很友好,因为YOLO的回归框是直接学目标位置,包进大块遮挡物会让框学偏。
  • 过小目标:有一部分远处人行道上的行人,框只有二三十像素。这类框YOLOv8默认的anchor策略下容易漏检,属于高难度样本,但好在占比不大,不会把模型带偏。
  • 模糊帧:雨天镜头沾水、夜间长曝导致的模糊图也在里面,标注文件里没有单独剔除。我的建议是训练前自己筛一遍,避免模糊样本过多拉低整体精度——这个后面细说。

数据集的标注格式是常见的目标检测标注格式,可以转成YOLO训练需要的txt格式。这部分转换工作,恰恰是我见过最多人卡住的环节,下一节重点展开。

3. 把标注转成YOLO能吃的格式:那些容易卡住的细节

数据集拿到手,标注画好了,但你要是直接拿去找YOLO训练,十有八九会报错。YOLO系列(尤其是ultralytics官方仓库)需要的是每张图片对应一个同名txt文件,里面对每一行是"类别编号 + 归一化中心坐标 + 归一化宽高",坐标全部是0到1之间的小数。这个格式和常见的JSON标注格式完全不一样。我在第一次处理时也花了不少时间,总结下来有几个坑值得单独说。

3.1 目录结构:按ultralytics的习惯来

先看目录组织。ultralytics的YOLO默认训练时通过data.yaml里的path字段找到train、val、test三个目录,我建议数据集拿到后就整理成这个结构:

dataset_root/ ├── data.yaml ├── train/ │ ├── images/ │ │ ├── 000001.jpg │ │ └── ... │ └── labels/ │ ├── 000001.txt │ └── ... ├── val/ │ ├── images/ │ └── labels/ └── test/ ├── images/ └── labels/

别看这个结构简单,很多人会栽在图片和标签文件名对不上。YOLO要求txt和jpg的主文件名完全一致,且必须保证一张图对应一个txt(即使这张图没有任何目标,也要一个空的txt,否则训练时ultralytics会跳过该图并可能警告)。我第一次训练时就是漏了一批空标注图的txt文件,导致训练集实际参与训练的图少了近千张,自己还没察觉,等到看指标不对劲回头排查才发现。

3.2 坐标转换:一句话的公式,但单位别搞错

假设原始标注给的是框的左上角坐标(x_min, y_min)和右下角坐标(x_max, y_max),图片宽度为img_w,高度为img_h,转换公式是:

x_center = (x_min + x_max) / 2 / img_w y_center = (y_min + y_max) / 2 / img_h box_w = (x_max - x_min) / img_w box_h = (y_max - y_min) / img_h

需要特别注意,如果你从标注工具导出的坐标不是像素值而是已经被缩放到0~1之间的百分比坐标,那就不能再除以img_w和img_h了。这个坑我见过不止一次:有人拿到已经是归一化坐标的标注直接再除以图片宽高,结果小数点又挪了两位,训练出来检测框全部缩在图片左上角,看起来像模型"学疯了"。实际上只要框坐标范围不在0~1之间,模型就不可能收敛出合理结果。

3.3 data.yaml的类别顺序必须和txt的类别编号一一对应

这是另一个高频踩坑点。你的txt文件里每个目标的第一个数字是类别编号,比如0代表人行道、1代表盲道。data.yaml里的names列表顺序必须严格保持一致:

# data.yaml path: /absolute/path/to/dataset_root train: train/images val: val/images test: test/images nc: 8 names: 0: sidewalk 1: blind_path 2: curb 3: guardrail 4: obstacle 5: pedestrian 6: bicycle 7: vehicle_on_sidewalk

如果names顺序和标注文件里的编号对不上,训练过程不会报错,但模型输出的类别就是错位的——你以为是检测"盲道",它实则学的是"路缘石"。很多可视化测试时才发现模型把A类标成B类,又回头查标注文件,白白耽误时间。拿到数据集第一件事,我建议先加载任意一张图和对应的txt,用OpenCV把框画出来人工核对一遍,确认类别编号的对应关系,再进训练流程。

3.4 数据集划分:不要直接拿test目录当验证集

很多公开数据集的目录结构里会自带val和test,但val和test的用途完全不同。val是在训练过程中用来定期评估模型、指导调参的;test是最后模型定稿后,用来做一次终极评估的。如果你把test的图也参与到了训练过程中(比如为了"增加训练数据量",把test合进train),那后续报告的所有test指标都会虚高,完全失去了评估意义。我看到这套数据集的划分大约是train 8000、val 1300、test 1000,比例合理,不建议自行合并。

另外,划分数据集时务必保证类别分布均衡。可以写个小脚本统计train和val中每个类别的目标数,如果某个类别在val里占比过低,评估指标方差会很大,一次随机划分的偶然性就会掩盖真实模型水平。

4. 训练实测:参数选择、损失曲线暗语与常见翻车点

数据格式弄好以后,训练本身反而简单了——ultralytics的YOLO把多数工程细节都封装好了。但"能跑通"和"训得好"完全是两回事。我在这套人行道数据集上实测了YOLOv8s和YOLOv8m两个版本,下面把训练配置、结果解读和翻车经验展开聊聊。

4.1 训练配置:从合理默认值出发

我先用的命令大概是这样的:

yolo detect train \ model=yolov8s.pt \ data=data.yaml \ epochs=120 \ imgsz=640 \ batch=16 \ device=0 \ patience=15 \ project=run_sidewalk \ name=yolov8s_640

几个参数的选择逻辑:

  • imgsz=640:这是速度和精度的中间值。数据集里有一些小目标(远处行人、障碍物),如果你追求更高精度可以试试768甚至896,但显存占用会明显上涨。我用640先跑了一版作为基线,后续再对比896。
  • batch=16:根据显卡显存来的,如果你的卡是8G显存,batch=16配imgsz=640可能会爆显存,建议降到8,或者开启cache=ram减少磁盘IO压力。
  • patience=15:训练过程如果连续15个epoch在验证集上没有明显提升就提前停止。这个参数对于10300张规模的数据集来说是合理的,可以有效节约时间。

需要强调的是,这里用的是预训练权重yolov8s.pt做迁移学习,而不是从随机权重开始训。城市场景和COCO里面那些日常物体有不少重叠(行人、车辆、自行车等),加载预训练权重相当于让模型带着"看过世界"的经验来学习人行道场景,收敛速度更快,精度也普遍更高。如果你从头训练,120个epoch可能才刚刚起步。

4.2 损失曲线怎么看:别只看总loss

训练过程中你会看到box_loss、cls_loss、dfl_loss三条曲线的变化,很多新手只盯着loss本身有没有降低,却忽略了几个重要信号:

  • box_loss持续下降代表回归框在变准:人行道场景里最大的难点是部分框是长条形的(盲道、路缘石),这种长宽比极端的目标对回归损失很敏感,如果box_loss曲线出现平台期,很可能是这类样本在拖后腿。
  • cls_loss下降缓慢要警惕类别不平衡:比如"盲道"出现的频次如果远低于"人行道",cls_loss可能主要由高频类别主导,低频类别的分类能力得不到有效提升。解决办法包括增加低频类别样本权重或使用数据增强加重复采样。
  • dfl_loss是分布焦点损失,跟边界质量相关:它掉不下去往往意味着边界框边缘定位不稳定,尤其夜间低光照的样本容易产生这种现象。

我跑的那版YOLOv8s,前30个epoch三条loss下降都很猛,从第40个epoch开始变缓,到第80个epoch左右验证集指标基本稳定,patience机制在第105个epoch触发了早停。整体看,这个数据集规模下训练收敛节奏正常,不存在明显欠拟合。

4.3 实战评测:mAP到0.86,但夜间和远小目标拉胯

训练结束后看验证集指标,YOLOv8s在mAP50上大概到0.86,mAP50-95在0.58左右。听上去不错,但拆开来看就有意思了:

  • 人行道、路缘石这类大面积目标,AP都在0.9以上,属于"闭眼都能检测"的级别。
  • 盲道这种细长纹理型目标,AP中等,约0.72。原因是盲道本身只靠砖面纹理和周围地砖区分,光照一变特征就糊了。
  • 夜间样本的AP整体比白天低15%左右,这个符合预期但依然是硬伤。城市智慧治理夜间是重灾区,夜间模型能力弱直接影响项目落地。
  • 远距离小目标(30像素以下的障碍物)召回率偏低,大量漏检。

我试过把imgsz提高到896,小目标mAP能提升4~5个百分点,但推理速度下降了近一半。如果你的落地场景是巡检车低速行驶,896完全可接受;如果是无人机高速飞行或实时视频流,640更稳妥。

4.4 训练中真实踩过的三个坑

这里分享三个我实际碰到并解决的问题,希望对你有帮助:

第一个坑是标签类别错位。我训练第一个版本时直接用了数据集的原始标注,没有做随机抽样可视化,训练完成后测试发现模型把"障碍物"全部识别成了"自行车"。排查了半天发现是data.yaml的names顺序和txt里的编号顺序差了一位。这个问题在上一节已经强调过,再次提醒:训练前务必可视化一批标注框,不要信任任何人的"已对齐"承诺。

第二个坑是模糊图处理。数据集里有少量拍摄时运动模糊和对焦不准的图,刚开始我没有处理,训练出来的模型在真实视频流上会对快速移动的目标产生跳跃性误检。后来我用了一个模糊检测脚本,把Laplacian方差低于阈值的图单独分到一类,测试后确认这些模糊图对模型负面影响明显,果断从训练集剔除,稳定了不少。

第三个坑是数据增强参数。ultralytics默认开启的马赛克增强(mosaic)对大多数人行道场景图效果很好,因为它能模拟多个场景拼接,相当于变相增加了场景多样性。但对于那些本身遮挡就严重的样本,马赛克增强会让小目标更加难以辨别。我建议训练后期(比如最后30个epoch)可以关闭mosaic,让模型进入"精调"阶段,常常能在验证集上再挤出一两个点。ultralytics里可以通过在超参配置或训练过程中调整增强策略来实现,跑模型时留意一下这个设置项。

5. 从测试指标到智慧城市落地:部署与迭代建议

模型训练完、指标看着挺漂亮,这只是第一步。智慧城市项目的特殊性在于:测试集指标高 ≠ 现场效果好。真实场景的复杂程度远高于数据集,光照、天气、遮挡、视角变换各种因素叠加,上线前必须做充分的鲁棒性验证,否则等着你的就是一场接一场的"现场翻车"投诉。

5.1 先跑一遍真实场景的视频流,别急着接系统

不管你是做后端分析还是边缘端实时处理,我建议先拿几段真实的城市道路监控视频或巡检车录制的视频跑一遍检测结果,保存输出视频逐帧看。重点看三件事:

  • 误报率:是不是有大量正常地砖纹理被误判为障碍物?人行道的砖缝、阴影、树影是最常见的误报来源。如果在雨天、黄昏这些光照复杂时段误报频发,那就要考虑在检测后增加时序滤波——连续N帧都检出同一个目标才触发告警,能毙掉大量随机误报。
  • 漏检目标:特别是小障碍物和夜间目标。漏检比误报更致命,因为误报可以靠管理流程过滤,漏检就是公开的系统漏洞。
  • 帧率:1080p视频流如果推理帧率低于15FPS,很多动态行为(行人快速穿过、车辆驶入人行道)根本抓不住轨迹。速度不够的时候,要么剪枝量化模型,要么换更小的模型变体,要么降低输入分辨率只对特定ROI区域做检测。

5.2 模型压缩与平台适配

  1. TensorRT部署:如果你的推理环境是NVIDIA的GPU(比如Jetson Orin、边缘盒子),把权重转成TensorRT FP16格式,推理速度能提升2~3倍。如果不做这一步,很多边缘设备的算力根本跑不动实时视频分析。
  2. OpenVINO迁移:如果是Intel的CPU平台,拿OpenVINO做转换和优化是最成熟路线,转换过程本身不难,但要注意重新跑一遍验证集,确保优化后精度不掉太多。
  3. 量化为INT8:对检测框精度要求不算极端苛刻的场景(比如违规占道预警,允许框偏几个像素),INT8可以进一步提速,但是可能出现"精度断崖",必须亲自做指标对比再决定。

5.3 针对硬伤做定向补充数据

回到这套数据集本身的短板,我测试后觉得最值得补充的数据有三类:

  • 夜间雨天人行道:这是城市管理问题的高发时段,也是模型目前最弱的场景。建议专门去做夜间雨天采集,哪怕只补1000张,对夜间AP的提升都会很明显。
  • 近距离仰拍视角:现有数据很多是路侧枪机视角或者平视视角,但有些城市会用低角度球机拍人行道,视角一变、目标形变大,模型泛化能力不一定够。
  • 非机动车占道专项数据:共享单车、外卖电动车占用人行道是高频问题,如果类别设计里这类目标占比不够高,实际使用时检出率会很感人。

5.4 下一步:从"检出"到"事件理解"的数据集扩展

很多人以为目标检测数据集的价值只在于训练一个框,但真正让人行道场景产生管理价值的是"事件判断"。比如"盲道被占"这个事件,靠单帧检测框就能做初步规则判断;但"摊贩长期占道经营"需要多帧时序判断;"护栏损坏后长时间未修复"需要跨天比对同一个目标的位置和状态,这已经不是单纯的检测任务了。

所以我的建议是,如果你要基于这个数据集长期做智慧城市项目,下一步可以这样扩展:

  • 给数据增加属性标签:在检测框之外,增加"是/否占道""是/否破损""是/否违规"这类细粒度属性,做成多任务数据集,一次推理同时输出位置和状态。
  • 补充时序片段:整理一批同一机位连续几十帧的短视频片段,训练目标跟踪模型或者做事件规则引擎,让系统具备"持续观察"的能力。
  • 引入多模态信息:不少智慧城市项目会在检测模型后面接音频分析、文本描述或大模型推理,比如"检测到一个障碍物框,结合周边路况生成一条告警描述"。这个方向很热,数据集的边界也就从"框标注"扩展到了"场景理解标注"。

这套10300张的人行道场景检测数据集,作为起步的底子是够格的——它的场景多样性、类别设计、标注规范都比常见的"玩具数据集"高出不少,很适合用来跑通YOLO的完整流程,也适合作为智慧城市巡检项目的第一份训练材料。

我个人在实际训练中的感受是,这个数据集最值得琢磨的地方不在于那0.86的mAP,而在于通过训练它,你会真正理解"数据分布对模型上限的决定性作用"。白天再多加一万张,可能都不如补五百张夜间雨图来得有效。做智慧城市视觉项目,永远要把数据策略放在模型架构前面——模型是能工巧匠,但没有好材料,也做不出好家具。后面如果你用这套数据集跑出了什么有意思的结果,或者补充了哪些更"讲究"的数据,欢迎来和我聊聊,咱们可以再往多任务检测和事件级推理的路子上多折腾几轮。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进