1. 项目概述:车站客流状态图标识别系统
这个项目是我去年参与的一个地铁站智能化改造工程中的核心模块。简单来说,就是用摄像头实时识别车站内各种客流状态图标(比如拥挤、缓行、畅通等),然后通过大屏和手机APP推送给乘客。听起来简单?实际操作中我们遇到了图标变形、光线干扰、实时性要求高等一系列头疼问题。
传统方案用的是OpenCV模板匹配,但在实际车站环境中准确率只有60%左右。后来我们尝试了YOLOv5,效果提升到85%,但遇到密集小目标时还是不够理想。直到YOLOv11的C3k2结构和MambaOut模块出现,配合新型FDConv卷积,最终在测试集上达到了96.3%的mAP,推理速度在Jetson Orin Nano上也能保持28FPS。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心技术解析
2.1 YOLOv11的架构创新
YOLOv11相比前代最大的改进就是引入了C3k2模块和MambaOut机制。C3k2不是简单的3x3卷积堆叠,而是采用了一种交叉跨步卷积结构:
python复制class C3k2(nn.Module):
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
super().__init__()
c_ = int(c2 * e)
self.cv1 = FDConv(c1, c_, 1, 1)
self.cv2 = FDConv(c1, c_, 1, 1)
self.cv3 = FDConv(2 * c_, c2, 1)
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, k=(3,3)) for _ in range(n)))
def forward(self, x):
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))
这种结构有三个关键优势:
- 双路特征提取保留更多细节(对识别小图标特别重要)
- 跨步连接避免梯度消失
- 参数效率比传统C3模块高约30%
2.2 MambaOut机制的实战价值
MambaOut是受状态空间模型启发设计的注意力机制,但比传统注意力更轻量。在我们的客流图标识别场景中,它的作用尤为明显:
- 对光照变化鲁棒:车站内早晚光线差异大,MambaOut能动态调整特征权重
- 处理遮挡能力强:当图标被乘客部分遮挡时仍能保持较高识别率
- 计算开销小:相比Transformer注意力,内存占用减少45%
实测对比数据:
| 模块类型 | mAP@0.5 | 推理速度(FPS) | 显存占用(MB) |
|---|---|---|---|
| SEAttention | 92.1% | 22 | 1243 |
| CBAM | 93.4% | 20 | 1312 |
| MambaOut | 96.3% | 28 | 876 |
2.3 FDConv的部署优势
FDConv(Frequency Decomposition Conv)是我们最终选择的核心卷积算子,相比传统卷积有三个实战优势:
- 频域分解:将特征图分解为高低频成分分别处理,对模糊图标的识别准确率提升明显
- 硬件友好:特别适配Jetson Orin的Tensor Core,实测比标准Conv快1.8倍
- 参数共享:通过频域参数复用,模型大小减少约15%
重要提示:FDConv在PyTorch中的实现需要自定义CUDA kernel才能发挥最大效能,直接使用Python实现会损失约40%的性能优势。
3. 数据准备与模型训练
3.1 数据采集的坑与经验
我们最初用爬虫收集了2万张车站图标图片,但实际训练发现效果很差。后来总结出客流状态图标数据的特殊性:
- 透视变形:乘客视角拍摄的图标往往有严重形变
- 光照干扰:车站灯光反射、阴影等问题突出
- 多尺度问题:同一图标在不同距离拍摄大小差异可达10倍
最终我们采用三种数据采集方案组合:
- 实地拍摄:20个车站,每个点位5个角度,共3.6万张
- 模拟渲染:Blender生成带随机光照和形变的合成数据
- 数据增强:特别设计了透视变换+光照抖动的增强组合
3.2 半自动标注方案
采用Label Studio + SAM2的方案大幅提升了标注效率:
- 先用SAM2生成初步分割掩码
- 人工在Label Studio中修正边界
- 自动导出YOLOv11格式的标注文件
关键技巧:
- 对模糊图标的标注要适当扩大边界(约5-10像素)
- 对遮挡情况要标注可见部分而非完整图标
- 建立图标属性标签体系(如"拥挤-红色-闪烁")
3.3 模型训练细节
我们的最佳训练配置:
yaml复制# yolov11s-c3k2.yaml
backbone:
- [-1, 1, FDConv, [64, 3, 2]] # 0-P1/2
- [-1, 1, C3k2, [128]]
- [-1, 1, FDConv, [128, 3, 2]] # 2-P2/4
- [-1, 3, C3k2, [256]]
- [-1, 1, MambaOut, [256]] # 注意力层
- [-1, 1, FDConv, [256, 3, 2]] # 5-P3/8
- [-1, 6, C3k2, [512]]
- [-1, 1, MambaOut, [512]]
- [-1, 1, FDConv, [512, 3, 2]] # 8-P4/16
- [-1, 6, C3k2, [1024]]
- [-1, 1, MambaOut, [1024]]
训练参数关键点:
- 初始lr=0.01,采用cosine衰减
- 使用AdamW优化器(比SGD稳定)
- 添加了FocalLoss处理类别不平衡
- 冻结前3个epoch的backbone
4. 部署优化实战
4.1 Jetson Orin Nano环境配置
在Orin Nano上部署遇到的最大挑战是CUDA核心的利用率问题。我们的解决方案:
- 使用TensorRT 8.6+进行模型转换
- 针对FDConv定制plugin
- 启用DLA加速
关键配置命令:
bash复制# 转换模型
trtexec --onnx=yolov11s.onnx \
--saveEngine=yolov11s.engine \
--fp16 \
--best \
--plugins=fdconv_plugin.so
# 启用DLA
sudo nvpmodel -m 0 # 10W模式
sudo jetson_clocks
4.2 RKNN平台适配
对国产RK3588平台的适配要点:
- 需要将FDConv拆解为常规Conv+频域变换
- 量化时特别注意MambaOut层的精度损失
- 使用RKNN-toolkit2的混合量化策略
实测性能对比:
| 平台 | 精度(mAP) | 功耗(W) | 帧率(FPS) |
|---|---|---|---|
| Orin Nano | 96.1% | 10 | 28 |
| RK3588 | 95.3% | 8 | 22 |
| 骁龙865 | 94.7% | 5 | 18 |
5. 实际应用中的调优经验
5.1 动态推理技巧
我们发现车站不同时段的识别需求不同:
- 早晚高峰:侧重速度,可以降低输入分辨率
- 平峰时段:侧重精度,启用更大模型
实现方案:
python复制def dynamic_inference(img, model, is_peak_hour):
if is_peak_hour:
img = cv2.resize(img, (640,640))
conf_thresh = 0.4
else:
img = cv2.resize(img, (896,896))
conf_thresh = 0.3
results = model(img)
return process_results(results, conf_thresh)
5.2 误检过滤方案
实际部署中发现三类典型误检:
- 乘客衣物上的类似图案
- 广告牌中的几何图形
- 灯光反射造成的虚影
我们的解决方案组合:
- 时域连续性检测(真图标通常持续显示)
- 空间位置验证(真图标有固定安装位置)
- 多帧投票机制
5.3 系统级优化
完整的处理流水线优化:
- 前端:使用GStreamer实现多路视频低延迟采集
- 中台:Redis流式处理检测结果
- 后端:规则引擎+状态机管理图标状态变迁
延迟实测:
| 环节 | 耗时(ms) |
|---|---|
| 视频采集 | 8 |
| 推理 | 35 |
| 后处理 | 5 |
| 状态更新 | 2 |
| 总计 | <50ms |
6. 项目演进方向
目前正在试验两个改进方向:
- 将C3k2与轻量化视觉Transformer结合
- 探索FDConv在频域的可解释性分析
一个小技巧分享:在模型最后添加一个简单的频域分析头,可以直观显示模型关注的是图标的形状特征还是颜色特征,这对调试帮助很大。
