首页 / 资讯中心 / 文章详情

交通信号灯检测实战:自建YOLO数据集全流程经验总结

交通信号灯检测实战:自建YOLO数据集全流程经验总结 ★ FEATURED ARTICLE
开头写一段场景引入得让读者有代入感。我去年做某个辅助驾驶视觉项目时发现最难的不是模型结构而是数据本身。项目需求很明确在城市路口识别红绿灯、箭头、倒计时数字让系统在复杂路况下能提前判断通行状态。我拿来现成的国外开源数据集试了一圈效果相当尴尬——远处的小灯体漏检严重倒计时数字被当成杂碎目标最离谱的是路口的红色广告牌经常被认成红灯。折腾了两周后我决定放弃拿来主义老老实实搭一套面向国内交通场景的YOLO数据集。从采集、清洗、标注、转换到训练调优全流程走完模型表现才真正稳定下来。这篇文章就把我在这个过程中的关键步骤和踩坑记录整理出来给正在做同类交通信号检测项目的朋友一个可复用的参考。1. 为什么国内交通信号检测不能直接套用现成数据集1.1 国内外路口的信号灯形态差异远比想象中大很多做目标检测的朋友一开始都会图省事直接下载国外机构公开的交通信号数据集来训练比如某些基于欧美路况采集的数据集。但国内路口的信号灯形态和国外差别非常大这种差异直接决定了模型的泛化能力。国外数据集里的信号灯大多是横排安装灯体本身较小拍摄视角多为路口全景远处的灯在画面中只占很小面积。而国内常见的是竖排信号灯有些带倒计时数字显示屏有些是复合箭头灯组有些安装在悬臂杆上横跨车道有些在路侧低矮立柱上。再加上国内路口经常存在满屏红灯倒计时的组合一个灯体内既有圆形灯也有数字区域模型如果不经过针对性训练很容易把同一个灯体拆成两个目标或者把倒计时数字区域误认为独立的信号灯。另一个问题是颜色呈现的差异。国内一些路口使用LED点阵式倒计时屏颜色偏红偏亮和信号灯本身的颜色非常接近国外数据集中这类样本极少模型学到了圆形红灯的特征却学不会红灯旁边还有一块更亮的红色数字区域这种组合关系。所以用国外数据集训练的模型到国内路况上性能下降是必然的。1.2 真实路口场景的复杂度决定了数据覆盖面除了灯体形态差异真实路口的复杂场景是数据集的第二个关键维度。我在搭建数据集时专门统计了一个普通城市路口会出现的干扰情况早晚高峰时段路口车辆密集前车刹车灯、尾灯和信号灯同时出现在画面中颜色高度相似。正午逆光条件下信号灯整体偏暗红色灯体的饱和度下降模型容易漏检。夜间场景中LED灯体发光强烈周围存在光晕和反射灯体边缘模糊。雨雾天气下灯体清晰度下降玻璃外壳上的水渍会产生反光条纹。这些场景如果数据集中覆盖不足模型在某个特定时段或天气下的表现就会崩塌。比如我最初只用白天正常光照的数据训练到了傍晚低照度时模型的召回率直接降了20个百分点。后来补了足够多的黄昏、夜间样本才恢复回来。所以做国内交通信号检测的第一步不是急着下载数据集或调模型而是先想清楚我的模型要部署在什么场景什么路况什么时间段然后围绕这些场景去构建数据。数据覆盖度是模型性能的天花板模型结构只是逼近这个天花板的手段。2. 采集方案与类别体系设计先把边界定清楚2.1 数据采集的几种可行路径自建数据集的第一步是采集原始素材。我试过几种方式各有利弊行车记录仪视频抽帧这是最接近真实部署场景的方式。行车记录仪固定在挡风玻璃上视角、高度、运动状态都和实际使用场景一致。我采集了多个路口的行车视频覆盖不同时段然后用抽帧工具每隔5-10帧抽取一张。这个方式成本低素材量大但要注意画面中红灯时前车遮挡的情况很多需要后期筛选。手机手持拍摄灵活性高可以站在行人视角、天桥视角、路侧视角拍摄补充车载视角之外的多样性。但手机拍摄容易产生手持抖动模糊且视角和实际部署差异较大只能作为补充数据。网络公开视频片段可以获取到更多样的天色、天气、路口结构但来源复杂、清晰度参差不齐而且需要仔细筛选和确认授权合规。我的做法是只用于补充极端天气素材比如暴雨、雾天正样本仍然以自采为主。采集中一个容易被忽略的问题是路线单一化。如果每次都走同一条路同一个路口模型会严重过拟合到这条路的灯体外形和视角上。我后来调整的策略是规划了至少10条不同走向的路线覆盖高架桥下、新建路口、老式路口、多车道宽路口等不同类型样本多样性明显提升。2.2 类别定义少而精避免类别间混淆这是整个数据集中最关键也最容易出错的一步。交通信号灯的检测类别看起来简单无非就是红灯、绿灯、黄灯再加几个方向箭头。但实际标注时你会发现类别之间存在着严重的视觉相似性需要提前划清边界。我在项目中先定义了以下基础类别类别ID名称说明0red_circle红色圆形灯体含满屏红灯1green_circle绿色圆形灯体含满屏绿灯2yellow_circle黄色圆形灯体3red_left红色左转箭头4red_right红色右转箭头5red_straight红色直行箭头6green_left绿色左转箭头7green_right绿色右转箭头8green_straight绿色直行箭头9countdown倒计时数字显示区域这个设计有两条原则第一灯体类和箭头类分开而不是统一标成red_light。因为箭头灯的语义和圆形灯完全不同如果合并成一类模型虽然能检测到灯却无法区分能否转向这对实际决策系统是致命的。第二倒计时单独作为一类而不是拆成0-9十个数字类。拆成数字类虽然可以做数字识别但会引入大量标注成本而且倒计时数字区域在画面中通常很小十个类别的样本量会被严重稀释。我的做法是先把倒计时区域整体检测出来后续如果需要识别具体数字再单独训练一个OCR模块或分类网络去处理。这样职责清晰模型也更容易收敛。2.3 样本数量与场景分布怎么规划类别定义好之后接下来是样本规模。以我的项目为例总共标注了约2.2万张图片包含约4.5万个信号灯实例。分布上大致遵循以下比例场景占比白天正常光照40%清晨/黄昏低照度20%夜间25%雨雾/逆光等特殊天气15%我的一个体会是夜间数据不要贪多。一开始我以为夜间越多越好结果夜间数据占到40%后模型在白天正常光照下的表现反而有点下降因为夜间灯体亮度过高模型学到的是发光的红色圆形区域对白天低饱和度的红色灯体反而判断犹豫。后来把夜间数据压到25%左右并适当增加白天逆光样本平衡之后两边表现都恢复了。每类样本的具体数量我的底线是每个箭头类至少3000个实例主灯类5000个以上倒计时区域至少4000个。低于这个量训练出来的模型在对应类别上的精度会明显波动尤其是右转箭头这种在部分路口很少出现的类别需要特意去有此类信号灯的路口补采。这里也分享一个经验如果某些类别实在难以采到足够样本可以考虑在数据增强阶段做针对性合成但合成样本的比例最好控制在15%以内否则模型容易对合成纹理过拟合。3. 清洗与标注实操数据质量是训练效果的隐形天花板3.1 初步筛选哪些帧可以直接扔掉从视频里抽出来的原始帧质量参差不齐直接拿去标注就是在浪费人力。我第一次做数据集时图快忽略了清洗环节结果标注团队在模糊帧和过曝帧上花了大量力气标注出来的框位置也不准训练时模型反复震荡。后来总结了四条筛选标准凡是命中任意一条的帧直接删除运动模糊车辆转弯、颠簸导致的画面拖影灯体边缘已经无法分辨。这种帧即使标注了框的边界也是错的会向模型传递错误信息。严重过曝或欠曝灯体发光区域一片纯白或者整个画面黑到完全看不到灯体轮廓。颜色信息都丢失了没法标注。目标遮挡超过50%比如前车正好挡在信号灯前面只露出一小部分。这种样本价值极低除非是为了专门训练遮挡鲁棒性否则建议删掉。目标过小灯体在画面中宽度小于15像素时人眼都很难确认这个灯到底是红是绿标注出来的类别大概率也是错的导入训练只会变成噪声。我实测下来小于15x15像素的目标即使标注了YOLO也很难学到有效特征直接放弃更划算。筛选这一步看似简单但对后续所有环节的影响非常大。干净的数据集标注效率至少能提升三成训练收敛速度也更快。3.2 标注工具与框规范的选择清洗完之后就可以进入标注环节。我试过两个主流开源标注工具单机快速标注首选LabelImg轻量直接适合个人和小团队多人协同或者需要做复杂标签管理时用Label Studio支持在线标注和多人审核效率更高。工具本身不是重点重点在于边界框的标注规范。交通信号灯的边界框怎么画是个很容易被忽视但影响很大的问题。信号灯有外壳和发光区域两部分我的建议是圆形灯体标注时包含整个黑色外壳而箭头类只标注箭头发光区域本身。原因很简单圆形灯体在点亮时发光区域边界不清晰会出现光晕如果只标发光部分不同帧里框的大小会跟着光晕变化导致标注不一致模型学到的框回归目标就是乱的。包含外壳后框的位置稳定模型容易收敛。箭头灯则相反箭头的发光区域轮廓清晰而外壳内还有数字、装饰等其他元素如果把外壳整体框进去模型会误把其他元素也当作箭头特征反而干扰分类。至于框与框重叠的情况比如同一个灯组内红灯和倒计时区域靠得很近甚至部分重叠我的处理原则是重叠面积不超过50%时两个目标都标注超过50%时优先标注主要目标通常是灯体被遮挡的小目标就不标了。这样做可以避免模型中两个锚点抢同一个区域的情况。3.3 标注质量检查别省这一步标注完不等于结束我专门留出时间做质量审核方法很简单但非常有效抽检制度随机抽10%的已标注图片由另一位标注员重新审核重点检查类别是否正确、框是否贴合、有没有漏标。红灯被标成绿灯这种错误如果不及时发现对模型来说是致命的。可视化检查把标注框画回原图用拼接图的方式快速扫一遍。我能直观看到哪些框偏离目标、哪些框大小异常。规则校验写一个脚本统计所有标注框的宽高比、面积分布。正常信号灯框的宽高比集中在1:1到1:3之间如果出现大量极端宽高比说明标注可能有误比如把远处的路灯灯柱也框进来了。我踩过的坑是有一批夜间数据没有做抽检结果发现标注员把红色LED广告屏的局部区域当成了红灯框进去了一共有一百多张。这些噪声数据混入训练集后模型在夜间场景对广告屏的误检率明显上升后来把这批数据清洗掉并补充了正确标注才恢复。所以质检看似费时间其实是给训练省时间。4. 从原始标注到YOLO格式转换与增强的关键细节4.1 YOLO标注格式的核心规则清洗好的数据如果用LabelImg标注默认导出的是VOC格式的XML文件而YOLO训练需要的是txt格式所以必须做一次格式转换。理解YOLO标注格式的原理是这一步的基础。YOLO的txt标注文件里每一行对应一个目标五个数值分别是class_id center_x center_y width height其中center_x、center_y、width、height都是归一化后的浮点数范围0到1计算公式是像素坐标除以图片的宽或高。class_id是整数对应你的类别编号。举个例子一张1280x720的图片里某个红灯目标的边界框像素坐标是x_min400y_min300x_max600y_max450那么center_x (400 600) / 2 / 1280 0.390625center_y (300 450) / 2 / 720 0.520833width (600 - 400) / 1280 0.15625height (450 - 300) / 720 0.208333转换脚本的逻辑很简单遍历所有标注文件读入每个目标的边界框坐标和类别名按上述公式计算归一化值再写入对应的txt文件。这个环节最需要注意的是类别名称到ID的映射关系确保XML里的red_circle对应txt里的0不能错位否则会在训练时造成类别混乱而且这种错误很难通过loss曲线发现。4.2 目录组织与数据集划分转换完成后文件目录建议按YOLO标准格式组织dataset/ ├── train/ │ ├── images/ │ │ ├── img_0001.jpg │ │ └── ... │ └── labels/ │ ├── img_0001.txt │ └── ... └── val/ ├── images/ └── labels/图片和标注txt必须放在同名的images和labels子目录下。这样做的好处是训练框架可以直接从路径推断对应的标注文件不用额外管理映射关系。关于训练集和验证集的划分有一个大家容易忽略的坑按视频文件划分而不是按单张图片随机划分。同一个视频连续帧之间高度相似如果这些相似帧一部分进了训练集一部分进了验证集验证集的指标会虚高因为模型相当于见过了验证图片的邻居帧。我的做法是先把每个视频的所有帧归为一个整体然后按视频维度随机划分80%的视频帧进训练集20%进验证集。这样才能真实反映模型在未见场景上的泛化能力。4.3 数据增强策略哪些该用哪些不该用YOLO系列模型内置了丰富的数据增强策略但交通信号检测这个场景需要谨慎选择。我这里直接给结论该开的增强mosaic四张图拼接成一张能有效提升模型对小目标的检测能力因为拼接后目标相对占比更小模型被迫学习更紧凑的特征表达。亮度对比度扰动模拟黄昏、逆光、夜间等光照变化增强模型对光照的鲁棒性。轻微模糊和噪声模拟雨雾、镜头污渍场景提升模型在低画质条件下的表现。该关的增强水平翻转这个要非常注意。圆形灯体水平翻转后类别不变没问题但箭头灯水平翻转后左转箭头就变成了右转箭头类别完全变了。如果打开随机水平翻转而不同步修改标签模型会学到完全混乱的箭头方向。我在项目中采取的做法是开启水平翻转但在增强代码里自动将箭头类的左右标签互换具体可以这样处理如果原标签是red_left翻转后改为red_right同时修改归一化坐标的x值为1-x。如果你的数据处理流程不支持这种自动标签调整那就干脆关闭水平翻转避免得不偿失。极端色彩扰动信号灯颜色是核心识别依据过度的色调偏移会把红灯变成橙色甚至紫色破坏颜色特征影响分类精度。所以色彩增强幅度要控制在能够保持颜色语义的范围内。样本不均衡的问题也在这个阶段处理。右转箭头在部分路口很少出现训练时模型对该类别的特征学习不充分导致精度偏低。我的处理办法有两个一是对少数类别的样本进行过采样复制多份参与训练二是借助mosaic增强把少数类别样本拼接进更多训练图片提高它们的出现频率。实测下来过采样结合mosaic之后右转箭头的Recall从78%提到了89%效果还是比较明显的。5. 训练配置与调优实测从模型选型到参数验证5.1 模型选型轻量还是高精度数据准备到位后终于进入模型训练环节。YOLO系列发展到现在有多个版本我在项目中主要对比了轻量级和中等规模两种配置轻量级模型参数量小、训练和推理速度快适合部署在嵌入式设备中等规模模型精度更高但对算力要求也更高。以实际场景来说交通信号检测是一个典型的小目标检测任务信号灯在画面中通常占比很小尤其是在远处路口场景中可能只有二三十个像素。中等规模模型的特征表达能力更强小目标检测精度明显优于轻量级模型。所以我的建议是如果你的部署设备算力允许优先选择中等规模模型只有在设备算力严格受限时才考虑轻量级模型但要做好精度损失的心理准备。输入分辨率同样关键。我用640x640分辨率训练时远处信号的漏检率偏高提高到896x896后小目标的Recall提升了约5个百分点。代价是训练时间变长、推理速度变慢但这个trade-off在交通信号这种安全关键场景中是值得的。如果你的设备实在跑不动高分辨率推理后续可以再用小分辨率模型做迁移学习压缩但初始训练仍然建议用高分辨率让模型先学习到更精细的特征。5.2 关键训练超参数的经验值以下是我经过多轮实验后认为比较合理的超参数配置可以直接作为起点参数推荐值说明img size896小目标多时提高分辨率收益明显batch size16-32根据显存调整epochs200配合早停策略optimizerSGD或AdamW都行SGD稳定AdamW收敛快初始学习率0.01前50个epoch用warmup预训练权重COCO预训练迁移学习收敛更快训练过程我习惯开着早停机制如果连续30个epoch验证集loss不再下降就自动停止并保存最佳权重。实测下来大部分模型在120到160个epoch之间就已经收敛没必要死磕到200个epoch。5.3 训练过程中的常见信号与判断方法训练中的loss曲线和验证指标需要结合起来看。我总结过几个判断模型状态的实用信号train loss持续下降val loss也持续下降模型还在学习继续训练。train loss下降但val loss反弹上升过拟合了需要增加数据增强强度或者降低模型复杂度或者提前停止。train loss和val loss都停在某个值不动可能是学习率太低或者模型容量不够试着调高学习率或换更大的模型。类别loss单独偏高某个类别比如倒计时区域的loss明显高于其他类别说明这个类别的特征不够区分需要补充该类别的样本或者单独调整该类别的损失权重。除了loss曲线验证集的指标同样重要。交通信号检测场景中我特别关注Recall而不是Precision。原因很简单漏检一个红灯可能导致车辆闯红灯这是安全风险而误检的情况可以通过后处理逻辑比如结合路况上下文来过滤。所以在调优时如果Precision和Recall出现冲突我通常优先保证Recall。我还习惯在验证集上输出混淆矩阵专门检查类别之间的混淆情况。有一次发现红灯和倒计时区域混淆严重模型经常把倒计时里的红色数字区域当成红灯。后来分析发现是这两类样本中倒计时区域的框经常和红灯区域的框重合导致特征重叠。解决办法是扩大了倒计时区域的标注范围同时将它的类别定义从数字调整为包含数字的显示屏区域与红灯的边界区别开混淆率明显下降。6. 部署环节的误检漏检与应对方法6.1 误检的来源比想象中复杂模型训练完成后部署到实车或边缘设备上新的问题才真正暴露出来。我在实测中遇到的最典型误检是模型把一些看起来像信号灯的物体识别成了交通信号。红色广告屏路口商场外墙的大型LED屏当画面中出现大面积的红色圆形象素区域时模型会给出高置信度的红灯预测。前车尾灯组夜间排队等红灯时前车的两个红色尾灯在YOLO的特征层面和红灯非常相似尤其是当尾灯形成对称圆形时误检概率很高。红色交通标志牌某些禁令标志是红圈加斜杠红圈部分和红色圆形灯在颜色和形状上有一定相似度。这些误检单纯靠模型很难彻底消除我的处理思路是从数据和后处理两个方向同时入手数据层面收集这些典型误检场景的负样本加入训练集并标注为背景类别以外的干扰对象。这里有一个比较取巧的做法单独增加一个distractor类别把广告屏、红色标志牌、尾灯等标注为这个类别让模型学会把它们和真正的信号灯区分开。相比单纯让模型把它们当背景这种做法能强制模型学到不是信号灯的特征边界效果更直接。6.2 后处理与跟踪策略结合时序信息消除跳变后处理方面一个低成本但很有效的方法是区域约束。信号灯在画面中的位置不是随意的通常集中在路口区域的上方或路侧。部署时可以根据摄像头安装角度和位置在图像上预先定义信号灯可能出现的ROI区域推理时只保留ROI内的检测结果ROI外的检测框直接丢弃。这个方法能过滤掉很大一部分广告屏误检因为广告屏通常位于画面两侧或远处。另一个方法是时间序列平滑。信号灯的颜色变化是有逻辑的不会在一帧内从红跳到绿再跳回红。我在部署代码里加了一个轻量级的跟踪器对每个信号灯目标做跨帧关联记录其在最近N帧中的颜色状态。如果某个目标在连续帧中频繁变化颜色且变化顺序不符合交通信号逻辑就判定为误检降低其置信度。实测下去这个策略让夜间尾灯误检率降低了约60%。6.3 小目标漏检与推理性能的平衡小目标漏检是另一个部署痛点。远处路口的信号灯在画面中确实很小即便训练时用了896分辨率部署推理时如果为了帧率把输入分辨率降到640小目标检测能力还是会打折扣。这里我给出几种实测有效的方案方案一推理时保持高分辨率输入。如果设备帧率允许推理分辨率直接沿用训练时的896不做压缩这是最简单直接的办法。方案二切片辅助推理。把高分辨率图像切成多个重叠切片分别送入模型检测再合并结果。思路类似放大镜专门解决小目标问题。缺点是推理时间翻倍但对远处信号灯漏检改善非常明显。方案三模型轻量化与量化。如果最终部署设备算力紧张可以使用通道剪枝或量化方式压缩模型。量化时需要注意校准数据的选择我通常从训练集中挑出包含各种光照条件的代表性图片作为校准集量化后的模型精度损失控制在2%以内。关于帧率我的经验是在通用边缘设备上中等规模模型加高分辨率输入大概能跑到20到30毫秒一帧对信号灯检测这种实时性要求不极高的场景来说完全够用。如果追求更高的并发处理能力可以再考虑批次推理和异步流水线但那是部署细节里的优化方向了。最后说点个人体会。这个项目让我印象最深的不是YOLO模型本身有多强大而是数据在目标检测任务中的决定性作用。同样的模型结构、同样的超参数使用自建的高质量国内交通信号数据集训练和使用网上随便下的开源数据集训练验证集mAP能差出十个百分点以上。交通信号检测是一个安全相关的场景模型的每一次漏检和误检都可能影响实际决策这种场景下更值得在数据上下笨功夫。如果你也在做类似的项目我的建议是不要急着换更大的模型先回头审视你的数据集是否真实覆盖了你的部署场景数据的场景多样性、标注一致性和类别边界清晰度往往比模型结构更能决定最终效果。
阅读完成 · 觉得有帮助?
咨询建站