1. 项目背景与核心价值
红绿灯识别是智能交通系统和自动驾驶领域的基础技术之一。传统计算机视觉方法在复杂光照条件和多角度场景下表现不稳定,而深度学习技术通过端到端的学习方式,能够有效提升识别准确率和鲁棒性。我在实际车载设备部署中发现,一个可靠的识别系统需要同时解决三大挑战:实时性要求(<100ms/帧)、小目标检测(远距离信号灯可能只占图像5×5像素)、多状态分类(红/黄/绿/灭灯状态)。
这个项目特别适合两类开发者:
- 自动驾驶方向的学习者想要掌握感知层核心技术
- 嵌入式AI工程师需要优化模型在边缘设备的部署 我们将使用YOLOv5s作为基线模型,最终实现模型在Jetson Xavier上的30FPS实时推理。
2. 数据集构建与增强策略
2.1 数据采集规范
优质数据集应包含以下场景覆盖:
- 光照变化(逆光/夜间/黄昏)
- 天气条件(雨雪/雾天)
- 视角变化(仰拍/俯视/侧向)
- 距离变化(5-200米)
推荐使用BDD100K、LISA Traffic Light Dataset等开源数据集,我整理了包含12,487张标注图像的混合数据集(样本分布见下表):
| 场景类型 | 样本数量 | 标注框平均大小 |
|---|---|---|
| 白天正常 | 5,212 | 32×32px |
| 夜间 | 3,045 | 28×28px |
| 雨雾天气 | 2,117 | 25×25px |
| 强逆光 | 2,113 | 20×20px |
2.2 数据增强方案
针对小目标检测的特殊处理:
train_transforms = [ Albumentations.RandomRain(drop_length=5, blur_value=3, p=0.3), # 模拟雨滴模糊 Albumentations.RandomShadow(num_shadows=2, p=0.4), # 阴影干扰 Albumentations.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=15, val_shift_limit=10, p=0.5), Albumentations.CLAHE(clip_limit=3.0, tile_grid_size=(8,8), p=0.3), # 增强低对比度场景 Albumentations.ZoomBlur(max_factor=1.1, p=0.2) # 运动模糊模拟 ]关键技巧:对小于32×32px的标注框禁用Mosaic增强,避免小目标在拼接时信息丢失
3. 模型架构与优化
3.1 改进的YOLOv5s结构
在原始架构基础上进行三处关键修改:
- 替换SPPF为SPPCSPC模块,提升小目标特征保留能力
- 在Neck部分添加CBAM注意力模块
- 输出层使用解耦头(Decoupled Head)
class CBAM(nn.Module): def __init__(self, c1, reduction=16): super().__init__() self.channel_attention = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d(c1, c1//reduction, 1), nn.ReLU(), nn.Conv2d(c1//reduction, c1, 1), nn.Sigmoid() ) self.spatial_attention = nn.Sequential( nn.Conv2d(2, 1, 7, padding=3), nn.Sigmoid() ) def forward(self, x): ca = self.channel_attention(x) * x sa = torch.cat([torch.max(ca,1)[0].unsqueeze(1), torch.mean(ca,1).unsqueeze(1)], dim=1) sa = self.spatial_attention(sa) return ca * sa3.2 损失函数改进
采用VarifocalLoss替换原始FocalLoss:
VFL(p, q) = -q*(q*log(p) + (1-q)*log(1-p))其中q为IoU-aware分类得分,对高质量预测给予更高权重。
4. 部署优化实战
4.1 TensorRT加速配置
在Jetson Xavier上的优化步骤:
- 导出ONNX时设置dynamic_axes仅包含batch维度
- 构建引擎时启用FP16和sparsity:
trtexec --onnx=model.onnx --fp16 --sparsity=enable \ --minShapes=images:1x3x640x640 \ --optShapes=images:8x3x640x640 \ --maxShapes=images:16x3x640x6404.2 后处理优化
使用CUDA实现并行NMS,处理延时从15ms降至3.2ms:
__global__ void parallel_nms_kernel(float* boxes, float* scores, int* indices, float iou_threshold, int max_output) { // 每个block处理一个类别的NMS int class_idx = blockIdx.x; // ...核函数实现细节 }5. 实测性能与调优记录
在交叉路口实测中的关键指标:
| 场景 | 准确率 | 误检率 | 推理时延 |
|---|---|---|---|
| 晴天日间 | 98.7% | 0.3% | 28ms |
| 夜间城市道路 | 95.2% | 1.1% | 31ms |
| 暴雨高速路 | 89.8% | 2.4% | 34ms |
遇到的典型问题及解决方案:
绿灯误识别为红灯:
- 原因:LED频闪导致颜色采样异常
- 修复:在预处理添加temporal filtering,取连续3帧中位数
远处小目标漏检:
- 原因:下采样导致特征丢失
- 修复:在640x640输入基础上增加1280x1280的second-stage检测
夕阳场景误检:
- 原因:色温接近红灯
- 修复:在HSV空间增加饱和度阈值判断
这个项目最耗时的部分其实是数据标注阶段——我们开发了半自动标注工具,先用预训练模型生成伪标签,再人工修正,效率提升4倍。模型部署时要注意电源管理配置,我在Jetson上关闭了DVFS后,推理延迟波动从±8ms降到了±2ms。