☰
YOLO11-C3k2-MambaOut-SFSC:复杂场景下楼层标识小目标检测实践
2026/10/19 4:44:44 网站建设 项目流程

车站里的楼层标识识别,听起来是个特别小的视觉任务,可真把它当成一个正经项目来做的时候,坑比想象中深得多。我们这次在某交通枢纽做的智能识别方案,后端就是用 YOLO11-C3k2-MambaOut-SFSC 这套结构组合打的底子。核心目标只有一个:让摄像头在复杂光照、反光、倾斜、遮挡的现场条件下,实时把楼层牌从画面里找出来,并正确识别出它到底是 F1、F2、B1 还是别的什么层。这篇文章把我们从选型、改造、训练到部署、踩坑的全过程记录下来,适合正在做小目标检测、导视识别或者想了解 YOLO11 结构魔改思路的同行参考。

1. 车站楼层标识:一个看着简单、做着麻烦的视觉任务

1.1 真实场景里会遇到什么

先别急着谈模型。任何一个在真实车站环境里跑过的检测项目,都会告诉你同样的道理:数据现场比论文里的标准数据集残酷得多,楼层标识在现实里长什么样,远比想象中丰富。

我列一下实际采集时最常见的几种情况:

  • 材质和反光:绝大多数楼层牌是不锈钢、亚克力板或者覆膜铝板,表面光滑,在射灯、自然光、屏幕光照下会产生大面积镜面反射。反光一旦盖住数字,人眼都可能认错,更别说模型。
  • 视角与倾斜:摄像头安装高度通常在 2.5 米到 4 米之间,俯拍、侧拍、斜前方拍都有。楼层牌的实际形状从正面矩形到严重透视变形,跨度极大。
  • 尺度差异:车站有扶梯口、直梯口、墙上指示、悬挂式指示牌等多个位置。有的楼层牌在画面里占比很大,有的则只是远处墙上一个面积不到几十像素的小目标。
  • 类间相似:F1 和 1F 写法不同但含义相同,B1 和一层容易混淆,部分建筑用 G 表示地面层,部分用 LG,还有无障碍坡道旁的“无障碍楼层”标识也和普通楼层牌长得接近。
  • 遮挡与干扰:行人经过、行李阻挡、检修围挡,甚至保洁人员的工具车都可能临时盖住标识。除此之外,车站里大量商业广告牌、安全出口指示牌、超市促销海报里的数字信息,都会对识别产生干扰。

所以这个任务并不是“找一个矩形框,读一个数字”这么简单。它本质上是复杂场景下的小目标检测 + 细粒度分类问题。

1.2 底层选 YOLO11 的原因与边界

我们一开始就排除了纯 OCR 路线,比如传统文本检测加文本识别的两段式方案。原因很直接:楼层标识不是一个标准的“文本行”,它可能是“3F”这样的组合,也可能是单独的“B1”加一个小图标,还可能是竖排的“R层”。与其做检测再加 OCR 识别,不如让一个检测器直接输出“目标类别 + 位置”,把检测和分类合一。这样在推理链路上更短,也更容易控制误检。

当时考虑过的方案有三类:

  • DETR 系列检测器:精度上限高,但训练收敛慢,在算力紧张的边缘设备上部署成本偏高,而且我们对推理延迟的要求比较苛刻。
  • RT-DETR 这类实时端到端模型:速度不错,但生态和部署工具链相对没那么顺手,换到嵌入式环境时需要做更多适配。
  • YOLO11:工程生态成熟,导出 ONNX、量化、TensorRT 加速的路径都很清晰,训练技巧开源充分,社区踩坑记录多。对我们这种需要快速落地、快速迭代的项目来说,YOLO11 是最稳妥的起点。

但 YOLO11 默认结构也不是完全适合这个场景。默认的骨架在全局上下文建模上偏弱,对远处小目标和强反光区域的判别力不够。所以我们在 YOLO11 的骨架上做了局部手术:保留 C3k2 做基础特征提取,再引入 MambaOut 模块补全局依赖,用 SFSC 做多尺度特征选择和校准。这几个模块的组合,就是我们项目里最终部署的 YOLO11-C3k2-MambaOut-SFSC 方案。

提示:选择模型的第一原则不是“哪个最新”,而是“出了问题你能不能最快定位并解决”。对我们来说,YOLO11 的社区热度和工具链成熟度就是最大的底气。

2. 网络结构怎么拼:MambaOut 补全局、SFSC 补尺度

2.1 C3k2 只是起步:局部建模的局限

YOLO11 默认使用的 C3k2,可以理解为 CSP 瓶颈结构的一种轻量化变体。它把输入特征沿通道分成两路,一路经过若干 3x3 卷积和 bottleneck 堆叠,另一路做快捷连接,最后拼接并 shuffle 通道。这种设计的优点是计算量小、梯度传播路径短,在常规目标检测任务上表现很好。

可它的本质还是局部卷积堆叠,每一层只能看到周围有限区域。楼层标识检测有两个特点,让这个“局部性”成了短板:

一是远处的楼层牌在特征图里可能只剩下很小的纹路,局部卷积感受野不够,容易把周围墙面纹理混进来;二是反光区域的亮度异常会形成局部高响应,如果没有全局上下文,模型很容易被一小块高光带着走,误以为那就是数字笔画。

所以 C3k2 是很好的“地基”,但我们需要在地基之上加两根柱子:一根负责全局上下文,一根负责多尺度选择。

2.2 MambaOut 模块:用线性复杂度换全局上下文

很多同行第一次看到“MambaOut”这个名字都会以为是一个现成的开源模型。其实在我们项目里的理解是:把 Mamba 这类状态空间模型的思路,作为视觉特征提取的辅助分支融合进检测器,而不是把整个 backbone 换成 Mamba 结构。

Mamba 的核心思想可以类比成“按顺序扫读”的长序列建模:它把二维特征图展开成一维序列,然后沿着扫描方向做状态更新,每一步的输出都同时依赖当前位置和之前积累的状态信息。这样做的好处是,模型能在不大幅增加计算量的前提下,捕捉比较远的依赖关系。

我们把它落地的做法是:

  1. 从 C3k2 的输出特征图中取一层,展平成序列;
  2. 经过选择性扫描(selective scan)分支,得到带有全局上下文的序列表示;
  3. 恢复成原来的空间形状;
  4. 将全局分支与原有局部分支做通道加权融合。

用生活化的比喻来说,局部卷积像做菜时只盯着手边洗好的那几根菜,而 MambaOut 是让你能随时扫一眼冰箱,知道其他食材还存在。它在模型里的作用不是替代 C3k2,而是让特征图在局部细节之外,还能感知“这个楼层牌周围是玻璃幕墙还是墙面”,从而减少反光区域的误判。

注意:MambaOut 这类模块插的位置很关键。我们实际实验下来,把它插入 neck 中间层比插入 backbone 底层效果好很多。太靠前会带来过多全局信息干扰局部纹理,太靠后则对浅层小目标帮助有限。

2.3 SFSC 模块:多尺度特征的选择与校准

SFSC 在我们这里指的是 Scale-aware Feature Selection and Calibration,尺度感知的特征选择与校准。它解决的是楼层标识尺度差异过大的问题。

一张 640x640 的输入图里,近处扶梯口的楼层牌能占 80 个像素以上,远处墙上的楼层牌可能只有 16x16 像素。如果所有尺度的特征都被同等对待,模型很难同时稳住两头。SFSC 的处理方式比较直白:

  • 对不同尺度的特征图分别计算通道注意力权重,让每个尺度上的特征自己决定“哪些通道更值得信任”;
  • 再引入一条跨尺度的校准路径,把高层语义信息往浅层特征里“灌”,帮助小目标借用到全局语义;
  • 最后把校准后的多尺度特征重新融合,供检测头使用。

这种选择与校准的组合,很大程度上缓解了小目标漏检和大目标误检的矛盾。从实测数据看,加入 SFSC 之后,弱小目标的那一类召回率提升最明显,尤其是在反光玻璃背景下的远距离楼层牌。

2.4 结构补丁策略:为什么不动整个骨架

规划网络结构时,我们也有过“要不要直接把 backbone 换成 Mamba 架构”的想法。讨论后还是放弃了,原因有三:

  • 改动和收益不成正比。完整替换骨架意味着要重新验证所有 stage 的尺寸和通道匹配,训练时间成本高,而实际需求只集中在全局依赖和多尺度两点;
  • 生产环境可维护性差。全量换架构后,代码仓库里出现一堆自定义算子,后续同学接手成本和出问题风险都会上升;
  • 增量式魔改可以在每个模块上单独做消融,能够清楚知道每个改动的作用,出了问题也多了一个回退点。

所以最终的结构策略就是:以 YOLO11 和 C3k2 为不变基线,在 neck 中插入 MambaOut,在 head 前接入 SFSC,形成一个“局部为主、全局辅助、尺度自适应”的组合。

3. 数据与标注:先于模型的天花板

3.1 采集方案:覆盖多少个维度的变化

网络结构再漂亮,数据不扎实也一样白搭。我们的采集思路不是简单找几个楼层的照片就完了,而是提前把“变量”列出来,尽量打满整个空间:

变量维度覆盖范围
光照条件白天自然光、夜间灯光、射灯直射、屏幕光源补充光
拍摄角度正面、30度侧拍、俯拍、仰拍
目标大小近景大目标、中景、远景小目标
材质类型哑光喷涂、不锈钢、亚克力背发光、玻璃贴字
干扰情况行人遮挡、行李遮挡、保洁工具遮挡、临时围挡
背景复杂度大白墙、玻璃幕墙、商业广告背景、扶梯背景

每个维度至少补拍 3 组以上,同一个点位尽量在不同时段重复采集。最终我们积累了近万张车站实拍图,其中约 30% 是有明显反光或遮挡的困难样本。

3.2 标签体系:检测与分类怎么拆

标注体系是另一个容易踩坑的地方。我们最后采用的是“两级标签”思路:

  • 第一级是目标类别,也就是“楼层标识”这一个类,检测网络负责找到所有楼层牌的位置;
  • 第二级是语义类别,具体是这个标识代表的楼层值,比如 F1、F2、F3、B1、B2、B3、G、R。

检测和分类拆开的好处是灵活。现场如果出现临时标识、手写楼层号、施工围挡上的楼层提示,只要第一级检测框能框住,第二级分类就算分不准也不会导致全盘崩溃。后续如果想扩展楼层种类,只需要修改二级分类的标签体系,不需要重新训练整个检测网络。

标注规则上,我们特别立了一条标准:只要人眼能认出来,就算标注目标;如果人眼都因为反光或遮挡认不出来的,宁可不标,也不强制标。这样能保证正样本的纯净度。

3.3 负样本与合成:反光不是玄学

很多项目会忽略负样本,但楼层标识识别里最关键的恰恰是负样本。车站里到处都是“数字 + 字母”组合的牌子:安全出口指示灯、商铺编号、票务窗口编号、自助机屏幕上的楼层信息。这些和楼层牌在形状上高度相似,如果不喂足够多的负样本,模型会在部署时把广告牌上的“1F 特惠”当成楼层标识。

我们处理反光问题的办法是“采集 + 合成”双管齐下。实拍阶段专门挑太阳直射时段去拍反光严重的标识牌;合成阶段则通过渲染手段,在正常楼层牌图片上叠加随机的高光渐变、镜面倒影和光斑遮挡。这样的合成样本虽然和真实物理反光不完全一样,但足够让模型学到“别被一片亮区域带偏”的鲁棒性。

提示:合成样本的比例不宜超过数据总量的 20%,否则模型容易在某类特定光班上过拟合。我们用下来比较舒服的比例是实拍 85% + 合成 15%。

4. 训练调参与消融:每个模块的真实贡献

4.1 从 COCO 预训练开始:训练策略细节

训练细节决定了结构改进到底能发挥几成功力。我们的完整训练策略如下:

  • 输入分辨率:640x640,训练中期使用多尺度采样,尺度范围 480 到 800;
  • 预训练权重:加载 COCO 数据集的公开预训练权重,而不是随机初始化;
  • 优化器与学习率:SGD,初始学习率 0.01,warmup 3 个 epoch,使用余弦退火衰减;
  • 训练轮数:总共 200 epoch;
  • 数据增强:Mosaic 增强在前 150 个 epoch 开启,最后 50 个 epoch 关闭,转为细调阶段;Mixup 概率 0.1;此外叠加了随机亮度对比度扰动、随机透视变换和翻转;
  • 类别不均衡:语义类别里 F1、B1 的样本量明显大于 R 和 B3,所以对低频类别按照样本数量做了反向加权。

冻结预训练骨干的前 10 个 epoch,我们让 head 和新增模块先收敛,之后再解冻全部层。这样做的好处是避免训练初期新增模块的随机初始化参数把预训练特征冲乱。

4.2 消融实验:表格里的信息量

结构改动到底有没有用,得用消融说话。我们在一批固定验证集上做了完整对照实验,验证集包含约 2000 张困难样本,内容覆盖夜间灯光、反光、小目标和遮挡:

配置mAP50mAP50-95参数量单帧耗时(相对)
YOLO11 基线88.4%72.6%9.4M1.0x
+ 替换 C3k2 调整89.1%73.8%9.6M1.02x
+ MambaOut90.3%75.2%10.4M1.08x
+ SFSC91.5%77.0%11.3M1.13x
完整方案92.8%79.1%11.7M1.18x

从结果可以看出两件事:

一是每个模块单独都有正向收益,不是无效堆叠;二是 SFSC 带来的 mAP50-95 提升最明显,说明多尺度特征校准在这个场景里比全局建模更关键。

这里想特别提醒一句:消融实验的验证集必须固定,且要多做几次随机种子实验取平均。我们早期就吃过一次亏,某个模块单独跑一次看起来提升很大,换了个随机种子后提升直接减半。后来所有结论都基于三个随机种子的平均值。

4.3 参数与速度的取舍

完整方案比基线增加了约 2.3M 参数量,单帧耗时慢约 18%。这在边缘设备上是一个需要掂量的成本。我们权衡后的结论是:在楼层识别这个任务里,误判的代价远高于十几毫秒的延迟,所以最终选了完整方案。

如果现场对实时性要求极高,也可以把 SFSC 的通道注意力部分砍掉一半,只保留跨尺度校准路径,耗时增加能压到 8% 以内,mAP50-95 大约下降 1.1 个百分点。这是一种合理的“线上降级”思路,可以根据业务实时性要求灵活切换。

5. 推理部署与业务联动:从模型到可用

5.1 导出与量化:FP16 下精度对齐

训练完的模型先导出为 ONNX,再转成 GPU 推理加速框架下常用的 FP16 精度模型。导出过程主要注意三点:

  • 输入输出的命名和动态维度要显式指定,方便后续业务代码调用;
  • MambaOut 里的扫描操作如果是自定义实现的,导出前要确保算子能映射到 ONNX 的标准算子集,否则需要在部署框架里补充自定义插件;
  • 转 FP16 后要在验证集上重新跑一遍指标,确认精度没有明显回退。我们实测 FP16 相比 FP32 只掉了 0.3 个百分点左右的 mAP50,完全可以接受。

5.2 时序后处理:连续帧怎么投票

单帧检测会有偶发抖动,所以部署端加了时序后处理逻辑:

  • 维护一个最近 5 帧的检测结果队列;
  • 对同一个物理位置的楼层牌,如果 5 帧里有至少 3 帧输出一致,就确认这个结果;
  • 如果连续帧结果不一致,继续保持上一稳定状态,不立刻跳变。

这种做法在人流密集的场景下特别有用。行人遮挡可能让楼层牌短暂消失一两帧,等行人过去后模型又能重新抓到,中间不会产生错误输出。

5.3 业务降级:遇到不认识的东西怎么办

任何模型都有不认识的东西。我们在业务层预留了降级策略:

  • 如果检测框置信度低于阈值但分类头给出结果,则输出“疑似楼层标识”,交由后端人工复核;
  • 如果连续一段时间在同一点位出现大量低置信度框,则触发设备巡检,提示摄像头角度可能被遮挡或移动。

这套降级逻辑是项目落地后使用方反馈最好的一部分。大家一开始都在问“模型准不准”,跑一段时间后真正关心的其实是“不准的时候系统能不能让我知道”。

6. 踩坑实录:一次高置信度误检的完整排查

6.1 现象:误检集中出现在反光区域

模型上线两周后,部署现场的同事反映一个情况:在某个换乘通道的固定摄像头画面里,系统经常会把一家商店门头的亚克力灯箱识别成楼层牌,置信度还很高,达到 0.9 以上。按我们当时的后处理规则,这样的置信度会直接进入确认状态,所以每次识别出来都会触发错误的业务联动。

我们首先把错误样本全部导出做切片。从几百张错误截图中发现一个规律:误检位置都集中在灯箱上部的斜向高光区域,那里正好有一个“1”形的亮斑,配上灯箱边缘的“F”形胶痕,恰好构成了一个极像“1F”的条件反射组合。

6.2 排查链路:从错误样本到特征响应

定位思路分三步走:

第一步查数据分布。统计所有训练集样本里有没有同类型的“亚克力灯箱 + 高光 + 字母残留”组合,结果显示这一组合在训练样本里的占比不到 0.5%,近乎不存在。模型在这个场景下等于没有见过负例,自然会把它当成正例。

第二步看类别激活。把误检样本输入到训练好的模型里,取出中间特征图做响应可视化,发现高响应区域集中在高光边缘和字母残留处。这说明模型确实是从这些局部纹理上做判断,而不是理解了“楼层标识”的整体语义。

第三步查后处理。当时后处理只做了置信度阈值和 NMS,没有对目标的长宽比、面积比例做约束。而真实楼层牌的宽高比相对稳定,商店灯箱的宽高比则明显偏离,这个特征其实不需要模型就能判掉。

6.3 修复与验证

修复方案分三层:

  • 数据层:额外采集了 3000 张带有各种灯箱、广告牌、玻璃反光的负样本,并把这些样本在不包含楼层标识的区域进行“背景增强”式训练;
  • 结构层:在 SFSC 的跨尺度校准模块中增加一层空间注意力,让模型对“高光噪声区域”有更强的抑制能力;
  • 后处理层:增加目标的宽高比先验过滤,偏离合理范围的检测结果直接丢弃。

验证结果:误检率从每千帧约 30 次,下降到每千帧不超过 5 次;高置信度误检基本清零。整体 mAP50 没有明显下降,反而因为负样本更多,难例上的表现略有好转。

6.4 给同行的排查清单

这类“高置信度误检”在工业视觉项目里非常常见,总体上可以沉淀成一份排查清单:

  1. 先导错误样本,按时间、地点、场景聚类分析,不是看单张而是看分布;
  2. 对比训练数据分布,确认模型是否见过同类负样本;
  3. 做特征响应可视化,判断模型是在看“整体目标”还是在看“局部噪声”;
  4. 检查后处理是否有额外可用的先验约束,比如目标尺寸、宽高比、运动规律;
  5. 针对场景补充负样本重训一次,比上来就调网络结构优先级更高。

反光、高光、字母残留这类干扰,在车站环境里防不胜防。一次踩坑之后我们形成了一个习惯:每个新点位摄像头接入时,先在现场采集一批连续帧跑一遍旁路测试,确认没有明显误报再切换到正式链路。

这几年做视觉落地的体会是:模型结构只决定精度上限的起点,数据、后处理和部署侧的细节才是真正拉开差距的地方。YOLO11-C3k2-MambaOut-SFSC 这套组合本身是一种可行的结构方案,但如果没有足够扎实的数据采集和一套能自我纠错的后处理流程,任何结构都不会自动变成可靠的产品。如果让我重新做一次,我会在开工第一天就先带上相机去车站里蹲一周,把各个时段、各种角度的楼层标识拍到足够多,再谈网络结构怎么改。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询