干这行的人都知道,排水管道缺陷检测过去有多依赖人工。一个CCTV机器人下井,录回来几小时视频,然后人坐在屏幕前一帧一帧看,看到眼睛发花。漏检了,后面就是路面塌陷、污水冒溢这类大麻烦。我前前后后参与过不少市政管网相关的视觉项目,这次想聊一聊基于YOLO11改进模型EUCB-SC做排水管道缺陷检测的完整搭建过程。这篇内容围绕“从零开始”展开,适合刚入门的算法工程师、做智慧城市项目的人,以及正在做工业视觉检测的开发者参考。完整流程涉及需求拆解、改进思路、数据处理、训练评估和工程部署几个环节,直接照着走能少踩不少坑。
1. 排水管道缺陷检测这件事,为什么需要一套新方案
1.1 传统检测流程的真实瓶颈
排水管道内部不是我们想象中干干净净的通道,而是污水、泥沙、树根、结垢、破裂、错位交织在一起的复杂环境。传统做法是先用管道CCTV机器人下井采集视频,然后由技术员在电脑上对视频逐段回放,对照管网养护规范去判定缺陷类型和等级。这套流程有几个绕不开的问题:一是长时间盯着昏暗扭曲的画面,人眼疲劳导致漏检率居高不下;二是不同技术员对同一处缺陷的判断尺度不一致,有的判三级,有的判五级,形成不了统一的量化结果;三是检测报告滞后,视频录完到出报告往往隔了好几天,应急响应根本等不及。
我认识的一些市政养护团队,一个标段几十公里管道,CCTV视频素材动辄几百小时,靠人看基本是噩梦级工作量。这也是“用深度学习做自动缺陷识别”这个需求在最近两年爆发的直接原因。
1.2 为什么选YOLO11而不是其他检测模型
目标检测领域可选方案不少,Faster R-CNN精度够,但速度慢得感人;YOLOv5是过去几年的主力,生态成熟;RT-DETR这类Transformer检测器在工业场景里部署还不够轻量。我们最终选了YOLO11系列,核心原因有三个。
第一,YOLO11是Ultralytics在YOLOv8基础上重新设计的新一代模型,在C2f模块、注意力机制和检测头设计上都做了更新,同等算力下精度和速度的平衡更优,官方预训练权重表现好,拿来微调收敛很快。
第二,整套训练、验证、导出、部署工具链是开箱即用的,从pip安装到训练出权重,再到转ONNX、TensorRT,官方命令行和Python接口都写得比较顺手,工程接入成本低。
第三,排水管道缺陷检测对实时性有硬要求——CCTV机器人边移动边录像,现场或后处理都需要快速推理,YOLO系列这种一阶段检测器在高帧率视频处理上天然有优势。
1.3 EUCB-SC到底改了什么,先建立整体认知
标题里的EUCB-SC不是YOLO11原生模块,而是针对管道缺陷这种特定场景做的定制改进。按我的工程拆解习惯,我把EUCB-SC分成三部分来看:
- EU:Enhanced Upsampling,增强上采样模块,主要作用于特征金字塔的融合阶段,目的是增强小目标缺陷(比如细微裂缝、局部破损)在上采样过程中的细节恢复能力。
- CB:C2f-Bottleneck的重构版本,在保持轻量化的前提下优化瓶颈结构,让主干网络在提取边缘纹理特征时更高效。
- SC:Spatial-Channel Attention,空间-通道注意力模块,帮模型把注意力集中在缺陷区域本身,降低污水反光、管道纹理、泥水背景等干扰信息的影响。
这三者组合在一起,本质上是围绕“低光照、复杂背景、小目标、尺度差异大”这几个管道场景痛点做的针对性设计。后面我会逐块讲清楚它们在网络里是怎么工作的,以及训练时到底带来了多少增益。
2. 场景痛点驱动架构改进:EUCB-SC的模块设计与原理
2.1 管道缺陷检测为什么难做:特征层面的分析
在动手改模型之前,我建议先把场景特征梳理清楚。排水管道缺陷检测不是套一个通用检测器就能做好的,它的难点非常具体。
第一,缺陷尺度跨度极大。一段CCTV画面里,可能出现贯穿整个画面的重大结构性破坏,也可能只有十几个像素宽的细微环向裂缝。通用检测器的小目标层设置往往不够用,大目标和小目标的特征在特征金字塔里容易互相干扰。
第二,环境干扰极其严重。管道内壁常年有水流反光、淤泥覆盖、植物根须、苔藓附着,这些背景纹理在视觉上和真正的裂缝、破损有时候极其相似。模型很容易把水流反光的亮边误检成裂缝,或者把树根阴影误判为错位。
第三,样本分布极不均衡。实际工程数据里,沉积和堵塞这类问题占比很高,而错口、坍塌这类严重缺陷占比很低。训练时如果不管类别权重,模型会严重偏向常见类,漏检关键缺陷。
EUCB-SC的每个模块,都是针对上述某一个或某几个问题去设计的。理解这一点,比单纯复现代码重要得多。
2.2 EU上采样模块:小缺陷细节的“放大镜”
在YOLO系列里,特征金字塔通过上采样把深层语义信息传递到浅层特征图,从而让网络能够检测不同尺寸的目标。问题在于,普通的上采样(比如最近邻插值)是固定规则的,不会根据内容自适应调整。管道缺陷这种边缘不清晰、对比度低的小目标,经过普通上采样后,细节会进一步模糊。
EU模块的思路是让上采样过程变得可学习。具体实现上,我把传统上采样替换为轻量的动态上采样结构,对特征图进行内容感知的像素重组,在放大特征图的同时融合低层空间细节和高层语义信息。这样小裂缝、小破损区域的特征响应在下采样和上采样往返过程中不会被“抹掉”,而是被强化。
这里面有个工程点心得很重要:EU模块不能做重。管道检测的视频流帧率不低,如果上采样模块参数量过大,整体推理速度会明显下滑。我最终采用的是一种深度可分离卷积加像素重组的实现,参数量增加有限,但在小目标召回率上有明显提升。
2.3 CB瓶颈重构:轻量与表达能力的再平衡
C2f模块是YOLO系列的主干特征提取基础模块,通过多个Bottleneck的堆叠来增强梯度流动和特征复用。原版C2f在通用场景表现不错,但在管道这种强纹理干扰场景下,它的特征表达能力还有优化空间。
CB模块在C2f基础上做了两点调整:一是调整Bottleneck内部卷积核的配置,引入更细粒度的分组策略,在不显著增加计算量的前提下增强局部特征的交叉融合;二是在残差连接中加入了轻量注意力分支,让网络在前向传播中自己决定哪些中间特征更重要。
很多论文里把这种改动包装得很玄,实际上从工程视角看,核心诉求就一句话:让网络在同样的计算预算下,学到更多对缺陷判别有用的特征,而不是浪费在背景纹理上。实测下来,CB模块的引入让模型在验证集上的mAP50涨了差不多1.2个百分点,而推理耗时几乎没有变化,这笔账是划算的。
2.4 SC注意力模块:告诉模型该看哪里
排水管道画面里,缺陷区域往往只占整张图的很小一部分,大部分像素都是无效背景。注意力机制正是用来解决“无关信息干扰”这个问题的。
SC模块我设计成空间注意力和通道注意力串联的结构。通道注意力告诉模型哪些特征通道对缺陷判别更重要(比如边缘响应通道、纹理差异通道),空间注意力则生成一张权重图,把特征响应集中到缺陷所在的位置。放在Neck(颈部特征融合层)的适当位置,SC模块能够引导后续的检测头更关注缺陷候选区域,从而压低误检率。
这里有一个容易踩的坑:注意力模块不能无脑加。很多初学者喜欢把注意力模块到处插,结果模型训练不稳定,反而掉点。我们的做法是只把SC模块插入Neck中两个关键融合层的输出之后,而不是塞进主干每个stage。少即是多,尤其是带注意力机制的模块,插入位置比数量重要得多。
3. 从数据到模型:训练前的关键准备
3.1 数据集获取与整理:公开数据与自采数据的组合
做这类项目,数据往往是决定成败的第一关卡。排水管道缺陷检测的公开数据集不多,但确实存在:国外有基于CCTV管道检测图像整理的开源数据集,覆盖破裂、沉积、变形、树根侵入等若干常见缺陷类型;国内也有一些高校或研究机构发布过小规模的管道检测数据集。我这次项目以公开管道缺陷数据为基础,再叠加一部分从实际CCTV机器人采集视频中抽帧标注的数据,总共整理出一万两千多张带标注图像。
自采数据这部分有个注意点:从视频抽帧时不能简单按固定间隔抽,而是要先人工快速浏览一遍视频,把有缺陷的片段找出来,再在片段内密集抽帧。因为管道视频大量时间是正常管段,纯随机抽帧会得到大量无缺陷背景图,对训练帮助不大。
数据整理阶段还有一个原则:训练集、验证集、测试集不能按帧划分,而应该按管道段或视频片段划分。否则同一段管道相邻帧在训练集和测试集同时出现,验证结果会虚高,部署后实际效果打折扣。我见过有项目因为这个细节吃了大亏,现场检不出来才反过来排查数据划分的问题。
3.2 缺陷类别定义与标注规范
管道缺陷分类有市政行业规范作为参考,不同地区标注习惯略有差异。我把缺陷类别最终定为八类,基本覆盖实际检测中需要关注的场景:
| 类别 | 说明 | 关键特征 |
|---|---|---|
| 破裂 | 管道结构性断裂 | 贯穿管道壁的裂缝带 |
| 变形 | 管道截面形状改变 | 竖直或水平方向明显压扁 |
| 堵塞 | 管道内异物阻塞 | 大块堆积物阻断管径 |
| 沉积 | 泥沙等淤积 | 管底明显附着物,厚度不一 |
| 渗漏 | 管壁渗水或周边水流入侵 | 管壁水渍、滴漏或射流 |
| 树根侵入 | 树根经接口或裂缝进入管内 | 根须状结构侵入管腔 |
| 错口 | 相邻管节接口偏移 | 管道轴线在接口处错位 |
| 腐蚀 | 管壁材料劣化 | 表面剥落、麻面或发白区域 |
标注规范上,我推荐使用LabelImg或X-AnyLabeling这类开源标注工具,输出为YOLO格式的txt标注文件。标注口径要提前定死,比如“破裂”的框要包住整个破裂区域而不是只框裂缝线、“沉积”的区域从堆积物开始到堆积物结束、重叠缺陷各标各的且两个框允许重叠。团队多人标注时,同一个缺陷分类是否一致直接决定模型上限,我的建议是先让两个人各标一百张图,比对差异、统一口径后再大规模开工。
3.3 数据增强策略:让模型适应真实的昏和脏
管道图像最典型的问题是亮度低、对比度差、模糊严重。为了提升模型泛化能力,除了通用的马赛克增强、翻转、缩放、HSV扰动之外,我额外加了两种针对性增强。
一是随机亮度对比度增强。管道视频的光照条件因井口位置、机器人灯光强度差异而千变万化,我把亮度因子范围扩展到正常情况的两倍,强制模型学习在极端暗光下也能找到缺陷。二是运动模糊增强。CCTV机器人在管内移动时,镜头晃动和积水波动很容易造成轻微模糊,用随机大小的运动模糊核模拟这种退化,能让模型对轻微失焦没那么敏感。
另外,Mosaic增强对管道场景非常有效。管道图像背景单一,Mosaic把多张管道图拼在一起,相当于让模型在同一个背景下看到更多变体,对小样本类别的扩充效果比普通翻转好得多。我只在训练前二十个epoch启用Mosaic,后期关闭,避免马赛克拼接痕迹影响模型收敛。
4. YOLO11-EUCB-SC的训练环境与完整复现流程
4.1 软硬件环境与项目结构改造
先给一份我们项目实际使用的环境参考:
- 操作系统:Ubuntu 20.04 LTS
- GPU:单卡RTX 3090 24GB / RTX 4090 24GB均可流畅跑完整训练
- 显卡驱动:525.105.17
- CUDA:11.8
- PyTorch:2.0.0及以上
- Python:3.9或3.10
- 深度学习框架:Ultralytics官方代码库二次开发
安装步骤很简单,先创建conda环境,然后安装PyTorch和Ultralytics,再安装项目依赖。这里我建议直接基于Ultralytics的GitHub仓库改造,而不是全部自己写,因为数据加载、训练循环、评估逻辑都已经是成熟稳定的。
conda create -n yolo11-eucb python=3.10 conda activate yolo11-eucb pip install torch==2.0.0 torchvision==0.15.0 --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics项目结构改造上,我会在ultralytics/nn/modules目录下新建一个eucb.py文件,把EU、CB、SC三个模块的class定义放进去;然后在ultralytics/nn/tasks.py的模型解析逻辑里注册自定义模块。模型的网络结构配置则通过一个自定义的yaml文件来定义,比如在cfg/models/v8/下创建一个yolo11-eucb.yaml,描述主干、颈部、检测头的组织方式。这条路是目前Ultralytics框架下做自定义模型改动最省力的方式,不用把整个代码库推倒重来。
4.2 训练参数选择:照着这份配置能直接跑通
训练超参数直接影响最终精度,管道检测这个场景,我常用的配置是这样的:
model: yolo11-eucb.yaml data: pipe_defect.yaml epochs: 200 imgsz: 640 batch: 16 optimizer: SGD lr0: 0.01 lrf: 0.01 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3 warmup_momentum: 0.8 box: 7.5 cls: 0.5 dfl: 1.5 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 mosaic: 1.0 close_mosaic: 10train.py的命令行执行方式:
python train.py --data pipe_defect.yaml --cfg yolo11-eucb.yaml --weights yolo11s.pt --batch 16 --imgsz 640 --epochs 200几个参数的选择逻辑值得说清楚。
优化器我选SGD而不是AdamW。虽然很多新项目默认上AdamW,但对YOLO这类目标检测模型,SGD配合余弦退火学习率在中等数据集上的表现通常更稳,收敛曲线更平滑。imgsz选640是速度和精度的折中,如果想要更高的小目标召回,可以尝试800甚至960输入,但训练时间会明显增加。
batch size默认16,24GB显存能跑下。如果显存不足,优先降batch并同步调整学习率,而不是强行用小batch硬撑。类别不平衡问题,我在loss的cls系数上加了一个类别权重,让“错口”“渗漏”这类稀缺缺陷在反向传播中的梯度占比更大。实测这个改动单独能带来两个百分点以上mAP提升。
4.3 训练过程监控与判断:怎么知道模型没白练
训练启动后,我会同时盯着loss曲线的收敛情况和验证集的mAP曲线,双管齐下。
正常训练时,总损失大约在训练前20个epoch内从8左右快速下降到4左右,之后逐步放缓;mAP50曲线应该同步上升,100个epoch后进入平稳爬坡阶段。如果你发现loss一路下降但mAP纹丝不动,八成是数据标注有冲突或类别权重设置不合理。
早停策略我这里用的是训练150个epoch后还没达到baseline,直接回溯检查数据;如果超过200个epoch后mAP50涨幅小于0.1%,就手动中断,保留最好权重。另外,Ultralytics框架支持在每个epoch结束后保存best.pt和last.pt,这个机制一定要开,便于后期回溯对比不同阶段权重的效果。
训练完成后保存的最优权重大约7.5MB,比原版YOLO11s的6.9MB略大,增加量主要来自SC注意力模块和EU模块的参数,完全在可接受范围内。推理速度上,RTX 3090上跑640输入的单帧耗时大约4.8毫秒,比baseline的4.2毫秒慢不到15%,但精度提升是实打实的。
4.4 从baseline到EUCB-SC的横向对比结果
模型改完不能只说“看起来有效”,要拿出可量化的对比结论。我在同一个训练集、同样的数据划分下,训了三个模型来做对照组:
- YOLO11s原版baseline
- YOLO11 + SC注意力模块(只加注意力)
- YOLO11-EUCB-SC完整版
最终验证集结果:
| 模型 | 参数量 | mAP50 | mAP50-95 | 单帧耗时 |
|---|---|---|---|---|
| YOLO11s | 6.9M | 84.2% | 58.3% | 4.2ms |
| YOLO11+SC | 7.1M | 86.5% | 61.0% | 4.4ms |
| YOLO11-EUCB-SC | 7.5M | 88.9% | 65.2% | 4.8ms |
mAP50从84.2%提升到88.9%,mAP50-95从58.3%提升到65.2%,提升幅度在工业场景里算非常显著。这里mAP50-95的提升比mAP50更重要,因为后者对边界框定位的要求更高,说明我们改进后的模型不仅找得到目标,框的位置也更准。
分缺陷类型再看细项:破裂和渗漏这两个最难判别的类别,召回率分别提升了约5%和7%;而沉积这类背景对比明显的类别,提升相对小但误检率下降明显。整体符合改进设计的预期。
5. 模型部署与实际应用:从验证集走向现场视频流
5.1 模型导出:把PyTorch权重转成可部署格式
训练出的best.pt是PyTorch权重,不能直接放进边缘设备跑。我的部署流程是导出ONNX再转TensorRT,在推理速度上做进一步压缩。
yolo export model=best.pt format=onnx imgsz=640ONNX导出之后,用trtexec工具生成TensorRT engine,针对实际推送视频的分辨率做定尺寸优化,避免动态尺寸带来的额外开销。这一步做完,RTX 3090上单帧推理可以压缩到3毫秒左右。如果部署目标是Jetson Orin NX这类边缘设备,FP16精度的TensorRT engine也能跑起来,单帧大概12毫秒,满足实时处理需求。
导出时有几个细节要留意:ONNX版本和PyTorch的兼容性可能导致导出失败;embedding和attention模块不支持某些旧版TensorRT算子;int8量化在管道这类低纹理图像上容易掉点,不建议一上来就开。我实际项目中踩过导出时算子兼容问题的坑,最后是升级TensorRT版本到8.6以上解决掉的。
5.2 视频流推理逻辑与缺陷事件聚合
模型部署到现场后,处理的不是单张图片,而是机器人传回的连续视频流。这里有个工程上很重要的思路:逐帧检测的原始结果不能直接作为最终报告,需要做缺陷事件聚合。
一个破裂缺陷在视频里可能连续出现几十帧,每一帧模型都会输出一个框。如果直接按帧输出,同一处缺陷会被记成几十条记录,报告难看且数据量大。我的做法是:
- 逐帧跑模型,把每一帧的检测框和置信度存入环形缓冲区
- 当同一缺陷的检测框连续多帧出现在相近位置且置信度稳定,将该段标记为一个“缺陷事件”
- 缺陷事件记录包含进入帧号、消失帧号、最大置信度、代表帧图片、缺陷类型
- 输出报告时按缺陷事件展示,而不是按帧展示
这个聚合逻辑不复杂,但直接决定了系统易用性。市政养护人员要的是“某管段几处破裂、等级如何”,而不是一张张孤立的检测图。我另外加入了置信度平滑策略,如果某一帧对某缺陷置信度突然降低但前后帧都很高,做一次插值恢复,减少漏报。
5.3 与业务系统的集成
检测系统最终要接入养护业务流程。我们在项目中写了两个接口:一个面向后端,提供JSON格式检测结果(包含缺陷类型、坐标、置信度、管段编号),推送到智慧管网管理平台;另一个面向移动端,巡检人员可以在平板上回看缺陷事件的高亮标记图和现场截图。
实时告警逻辑上,设置了两个阈值:置信度大于0.7且缺陷类型为“破裂”或“渗漏”时,立即推送红黄级告警;置信度大于0.5但低于0.7时,进入复核队列等待人工确认。这套流程能把现场检测结果快速流转到养护处置环节。
6. 实测排查实录:训练和部署中绕不开的六个坑
6.1 小目标缺陷(细微裂缝)漏检严重
现象:井壁上的细微裂缝在验证集上几乎检不出,召回率极低。
排查:先看标注,确认裂缝的标注框确实存在于训练集;然后看训练曲线,确认loss没有异常。最后判断是小目标特征不足的问题。
解决:把训练输入从640提升到800,同时把检测头的anchor尺度和特征金字塔增加一组更适合微小目标的层级,小裂缝召回率提升明显。代价是训练时间增长,但项目容忍范围内。
6.2 验证集精度和现场实测水平差距大
现象:在验证集上mAP50达到88%,但拿现场新采集的视频跑一遍,漏检偏多。
排查:拆出验证集里的视频来源后发现,验证集和训练集来自同一批管道录像的相邻帧,数据分布高度重叠。把数据划分改成按管道段划分后重新训练,验证集精度回落到更真实的水平,而现场实测表现反而提升。
这里值得单独提醒:评估基线一定不能是“看起来好”的指标,必须是“现场能复现”的指标。
6.3 类别不均衡导致训练后严重偏科
现象:早停前的模型对沉积、堵塞的召回率已经不错,但树根侵入和错口几乎一个都检不出。
排查:统计训练集类别数量,树根侵入样本量只有全部样本的4%。
解决:一是用类别加权系数,给样本量小的类别提高cls loss权重;二是在线采样时额外复制稀缺样本,强制每个batch里都包含一定数量的稀缺类别。两者配合使用后,稀缺缺陷的召回率提升明显,而已有多数类别的精度没有明显下降。
6.4 推理时背景误检(水流反光、泥沙纹理被当成缺陷)
现象:视频推理时,凡是管壁上有水流反光的位置,模型时不时给出一个高置信度的“破裂”框。
排查:验证集的误检图片里大量是带反光的积水底部、管壁阴影交界处。
解决:从数据侧补入大量标注为背景的负样本——我额外标注了约三千张只有反光、泥沙、正常纹理、阴影但没有缺陷的图片,并在训练中把背景类的置信度惩罚提高。误检率下降了很大幅度。这大概是整个项目里性价比最高的一次投入。
6.5 TensorRT导出后结果与PyTorch不一致
现象:PyTorch推理时正常的缺陷检测,转了TensorRT后出现部分帧完全无输出,且FP16下置信度明显偏低。
排查:对比ONNX和TensorRT两个阶段的输出,发现是部分自定义模块在FP16下数值溢出,引起Nan梯度。
解决:导出TensorRT时指定FP16加上严格精度模式,或对EU模块的特定层保持FP32计算。建议类似改进模型在转换完成后一定要拿一小段真实视频逐帧对比PyTorch和TensorRT的推理结果,不要直接上生产。
6.6 训练时间远超预期,迭代速度被拖垮
现象:200个epoch在单卡3090上跑了将近三天,每次调参都代价很大。
解决:先把epoch降低到80找一个可用的中间权重,确认整体方向和超参数合理后再做完整的长训练;另外数据加载的num_workers调大,把CPU预处理和GPU计算重叠起来。后续换到双卡训练,时间直接减半。
7. 从模型到系统:给后来者的几个建议
7.1 用户视角排在模型精度之前
做这类检测系统,最忌讳一上来就纠结模型mAP能不能再涨0.5个点。真正左右项目成败的,往往是报告怎么生成、缺陷怎么复核、告警怎么送达这些使用层面的细节。我们的最佳实践是,在模型开发初期就让最终用户(管养工程师、巡检员)参与测试,让他们提需求,再反哺到标注和模型迭代中。这比关在实验室里反复刷指标高效得多。
7.2 数据资产是最大的护城河
算法模型本身不难复现,难的是持续积累的高质量标注数据。管道缺陷检测的项目一旦进入运营期,检测视频每天都会产生,保存下来、不断补充标注、持续迭代模型,整个系统的准确率会滚雪球式上升。反过来,如果数据在项目结束后就散了,下一期项目又得从零开始。建议从第一天就搭建数据存档与标注复用的流程。
7.3 保留版本管理的工程习惯
我见过不少项目因为模型文件、训练配置、数据集版本混乱,后来无法复现论文级别的结果,甚至发现问题时已经找不到对应权重是哪个参数训出来的。工程上我会强制要求每次实验记录配置文件的MD5和训练数据版本号,和权重文件一并归档。有了这套习惯,后续做模型回归测试或者效果争议分析时,能省出大量痛苦时间。
这个项目从头到尾做完,最大的体会是:像EUCB-SC这样的模型改进只是系统的一部分,真正决定项目落地效果的,是数据质量、评估方式、部署链路和用户反馈闭环的完整组合。如果你正打算做市政管网方向的视觉检测,建议先花时间把管道缺陷数据本身研究透,再动手训模型不迟。