干建筑结构检测这行的人应该都有同感:墙体损伤巡检这事,过去靠人眼爬脚手架、拿望远镜、对着图纸圈圈画画,效率低不说,结果还高度依赖个人经验。如今越来越多的项目用无人机挂载相机或者巡检机器人自动采集墙体图像,再交给视觉模型自动找裂缝、剥落、渗水,YOLOv8几乎成了这个场景的默认选择——检测精度和推理速度的平衡好,框架自带训练、导出、部署一条龙,社区资料也多,踩坑容易自救。但这个标题里其实藏着两个特别容易被低估的坎:一个是模型压缩,一个是精准分级。单纯跑出一个能用的YOLOv8模型不难,难的是把它塞进边缘设备、在几十毫秒内出结果,同时还能把损伤等级分准,让维护团队拿到结果后真的知道该派几个人、带什么材料去修。
这篇文章就把我实际做过的墙体损伤检测项目思路完整梳理一遍,覆盖方案选型、数据标注、分级策略、剪枝量化蒸馏、部署实测和问题排查。你要是正准备做类似的东西,或者已经在用YOLOv8做巡检但总觉得哪里不对劲,这篇应该能帮你少走不少弯路。
1. 方案选型:为什么是YOLOv8,压缩和分级为何要绑在一起做
1.1 YOLOv8的优势不是“能力最强”,而是“工程坑最少”
墙体损伤检测这个任务,目标物体天然就分两类。一类是裂缝这种细长条,长宽比可能到几十比一;另一类是剥落、渗水、空鼓这种块状区域。这种目标形态差异很大的场景,在目标检测里其实不太讨喜,因为传统基于anchor的方法得人工设计一堆不同长宽比的锚框。YOLOv8改成了anchor-free结构,省掉了这层麻烦。它对细长目标的贴合度更好,少了很多“锚框怎么配都不合适”的调参痛苦。
另一个让我选它的理由是解耦检测头和C2f模块。解耦头把分类和回归分开,对精度提升有帮助,尤其在小目标上比老版YOLO稳。再加上ultralytics库把训练、验证、导出、部署的路径都打通了,一个CLI命令就能完成大部分环节,省下不少工程时间。真遇到需要精细轮廓的情况,还能直接切到YOLOv8-seg。相比Faster R-CNN精度可以但推理慢,相比SSD速度快但小目标敏感度差,YOLOv8基本是综合成本和精度的最优解。
1.2 模型压缩是部署的硬门槛,不是锦上添花
很多同行第一次跑通模型时都很兴奋,觉得检测效果不错,但一到部署就傻眼了。巡检机器人、无人机机载盒子这类设备,算力跟实验室的GPU完全不是一个量级。一个YOLOv8m的模型,参数量二十多兆,FP32权重五十多兆,一张图跑下来几十毫秒,在边缘设备上可能直接翻倍。现场还要处理视频流、跟踪、拍照控制、数据回传,计算资源根本分不过来。
所以模型压缩在墙体损伤检测里不是“优化项”,而是“必选项”。我一般把压缩分成三条线:结构化剪枝减少通道数、量化把权重从FP32降到INT8、知识蒸馏用大模型带小模型。三者的目标一致——把模型变小、推理变快,同时尽量保住精度。但顺序和力度要控制好,后面第四章我会展开说。
1.3 分级才是真正解决业务问题的环节
检测模型告诉你“这面墙有裂缝”,但现场维修人员真正想知道的是“这条裂缝要不要马上修、是派两个人带砂浆去还是直接上报请检测机构来评估”。这就是分级的意义。
纯检测不加分级的时候,项目交付容易卡在最后一公里。负责维护的人拿着一张画满框的图,还是得自己去看框里的损伤严不严重,等于把专业判断的活又交回给人。而且人工分级的主观性很强,同一条裂缝,不同的人可能判出不同等级。如果能用算法把分级标准化,维护排期、预算分配、安全风险评估都有据可依。
这里有个非常关键的认知:分级必须在数据标注阶段就参与进来,不能等模型训好了才想“要不我加个后处理做分级”。因为分级直接影响标签设计,标签定了再改,等于整个模型重来一次。
2. 数据与标注:分级模型的命根子
2.1 先定义好“损伤类别+等级维度”
我看过不少项目一上来就标“裂缝”、“剥落”两类,训完才发现完全没法用。实际墙体检修中,损伤类型至少要分成:横向裂缝、纵向裂缝、网状裂缝、剥落起皮、渗水、空鼓、钢筋外露锈蚀这几类。再往上加分级维度,每个类别最好配“轻度、中度、重度”三档。
等级判定标准绝对不能靠个人感觉写死,必须量化。我给过一个裂缝的参考口径:轻度指裂缝宽度小于0.2毫米且长度小于0.5米,中度指宽度介于0.2到0.5毫米或长度超过0.5米,重度指宽度大于0.5毫米、或长度超过1米、或出现贯通性裂缝。剥落类按面积比例:轻度是单块面积小于0.01平方米,中度是介于0.01到0.05平方米之间,重度是超过0.05平方米或出现钢筋外露。这些数字不要抄我这里的,一定要根据项目当地的工程规范去定,但思路是通用的。
还要特别提醒:裂缝宽度和深度这些参数,单纯从图像上是测不出来的,图像只能估算像素尺度,需要配合现场实测数据做标定。所以项目启动时就要跟结构工程师敲定标准,并且收集对应的现场量测记录,不然模型训练完才发现分级标准和工程要求对不上,返工成本极高。
2.2 采集与标注的实操规范
采集图像时,设备尽量保持在正射角度拍摄,倾斜角度会让裂缝宽度和面积在画面里产生形变,直接影响等级判读。无人机拍摄时要固定飞行高度和镜头焦距,巡检机器人的摄像头也要固定安装角度。这个细节看起来不起眼,但后面做“宽度估算”后处理时,角度不一致的图会带来巨大误差。
标注规范上,我的经验是检测框要把损伤区域完整包住,宁可比实际范围稍微大一点,也不要切成两半,尤其裂缝这种细长目标,框切半了模型非常容易学坏。等级标签的判定口径按“框内最严重区域”执行,因为维修决策看的是最坏情况,不是平均情况。
多标注人员一起干活时,最常见的矛盾发生在“轻度vs中度”的边界。我建议制作一本《参考图集》,把每个等级对应的典型图像打印出来或放进在线标注工具里,让大家有据可查。标注完必须做一致性校验,算Kappa系数,低于0.8就说明标准没对齐,要回头重新培训标注员。另外数据集划分要按建筑或楼栋去分,不要按单张图随机分,否则同一条裂缝的相邻图会同时混进训练集和测试集,指标虚高得厉害,到现场一测就原形毕露。
2.3 数据增强怎么用才不帮倒忙
YOLOv8训练默认会开Mosaic和MixUp,这对小目标和背景干扰强的场景很有效,但用在墙体损伤上要留个心眼。Mosaic把四张图拼在一起再随机裁剪,如果裂缝纹理被切碎重拼,损伤本身的连续性和形态特征会被破坏,模型反而容易学歪。我的做法是Mosaic开启但概率调低到0.5左右,MixUp干脆关掉或者只用在前期。
真正有用的是光度扰动和几何变换。墙体图像在不同天气、不同时段下色温差异很大,做色彩抖动和亮度扰动可以提升泛化能力。多尺度训练也非常关键,因为无人机在不同高度拍到的裂缝尺度完全不同,模型需要能应对这种尺度变化。再就是高分辨率输入,细长裂缝本身占的像素就少,输入分辨率太低等于把特征抹掉了。
合成数据可以作为冷启动的手段,在干净的墙体背景上粘贴程序生成的裂纹纹理,能补一点样本量。但掺入比例一定要控制,我一般控制在总数据量的20%以内,而且每个epoch都做人工抽检,防止模型学到合成纹理的特征伪影。
3. 训练与分级策略:两条路线怎么选
3.1 目标函数和超参数怎么定
训练配置建议从小模型开始。别一上来就用YOLOv8m或x,损伤数据量一般不会特别大,先用YOLOv8s把数据流程和分级规则跑通,再考虑上大模型提升精度上限。输入尺寸默认640起步,如果主要目标是细长裂缝,可以上960,代价是显存和训练时间都涨,实测对裂缝召回率帮助明显。
数据配置文件很简单,核心就是指定路径和类别名:
path: ./wall_damage_data train: images/train val: images/val nc: 4 names: ["horizontal_crack", "vertical_crack", "spalling", "efflorescence"]训练命令:
yolo train model=yolov8s.pt data=wall_damage.yaml epochs=150 imgsz=640 batch=16 patience=20损失函数这块,YOLOv8自带分类加回归加DFL的loss组合,整体比较均衡。如果存在类别不均衡,比如轻度样本远比重度多,可以在训练时给类别加权重,或者后期用focal loss替换默认分类损失。batch size建议16起步,太小的话BN层统计数据不稳定,对大分辨率训练更明显。
3.2 分级方案对比:端到端分类 vs 检测后几何分级
分级有两条技术路线,我反复对比过,各有适用场景。
方案A是把等级直接放进类别标签里,比如“裂缝_轻”“裂缝_中”“裂缝_重”“剥落_轻”等等。好处是训练简单,一个模型同时输出位置和等级,推理链路短。坏处是类别数量膨胀,样本均衡更难做,而且模型对“轻”和“中”的边界判断是纯黑盒的,出了问题不好解释,也不好调试。
方案B是先检测损伤类型,再用后处理根据几何特征分级。裂缝就计算宽度和长度,剥落就统计框内损伤像素占比。好处是分级规则透明可控、抗数据不均衡能力强,逻辑跟工程规范直接对应;坏处是需要相机标定或比例尺换算,才能把像素尺寸变成物理尺寸。
我的实际选择是优先方案B。因为结构工程师最后需要的是明确的分级依据,比如“这条裂缝宽度0.4毫米,属于中度”,而不是模型给一个没有解释的标签。但纯方案B在实时性要求高的场景可能有点吃力,所以也有折中做法:让模型先输出一个粗分级(比如轻/重二分类),再用几何特征细化。这个混合思路在原型验证阶段表现很好,建议你也试试。
3.3 评价指标要分等级看
很多项目汇报时只看mAP,这是个大坑。mAP是整体指标,它不会告诉你重度裂缝的召回率到底是99%还是60%。在墙体损伤场景里,漏掉一个重度裂缝的代价远大于误报十个轻度裂缝。所以我的评估流程是分等级的:
- 计算每个等级类别的AP,比如AP_light、AP_medium、AP_severe,对比看短板在哪。
- 漏检率和误检率单独统计,检测命中按IoU>=0.5为准。
- 分级效果用混淆矩阵加加权Kappa系数,单纯看准确率会被样本不均衡骗过去。
- 工程验收指标我建议直接用“严重损伤漏检率”。这个指标可以直接换算成安全风险,比mAP好沟通太多。
这类项目的甲方往往不是算法工程师,你拿mAP聊他无感,但“重度损伤漏检率控制在5%以内”他能立刻知道价值。
4. 模型压缩实操:剪枝、量化、蒸馏怎么落地
4.1 剪枝:先让模型学会“躺平”再动刀
剪枝是结构化压缩里收益和风险都最大的一步。很多人直接加载预训练权重,用工具按通道重要度一刀剪下去,结果精度崩得惨不忍睹。正确做法是先做一个稀疏化训练,通过L1正则或BN层的缩放因子正则,让一部分通道的贡献趋近于零。这个阶段模型相当于学会了“哪些通道可以不要”,然后再动刀裁剪。
工具方面,如果是基于ultralytics训练出来的模型,可以写一个自定义训练循环加入稀疏正则,再用torch_pruning这类库做通道剪枝。剪枝比例一定要渐进式调整,我习惯从20%开始,每剪10%就重新微调几十个epoch,不要想着一口气剪到50%。对于YOLOv8m来说,保留40%到50%的通道通常还能维持可接受的精度,但具体要看任务难度。
这里有个非常关键的经验:剪枝要优先剪backbone,检测头尽量保守。检测头的输出通道跟类别数和回归分支直接相关,粗暴裁剪极易造成定位和分类能力断崖式下跌。剪完之后做结构重参数化,把BN层和卷积层合并,才能真正减少计算量,否则只是参数变少但推理速度没快多少。
4.2 量化:从FP32到INT8,精度掉点往往在小目标上
量化是把模型权重和激活从32位浮点压缩到8位整数。INT8的模型体积大约是FP32的四分之一,推理速度在支持硬件上能提升两到三倍,但对墙体损伤这种大量细纹理和小目标的场景,直接做PTQ(训练后量化)容易掉点,因为裂缝边缘的梯度信息对数值精度敏感。
如果PTQ掉点严重,就上QAT(量化感知训练)。QAT是在训练阶段模拟量化误差,让模型学会适应低精度表示,效果通常比PTQ好不少,代价是要额外训练几天。我的经验是:先试PTQ,看整体mAP和各等级AP,如果轻度裂缝的AP掉得超过2个百分点,就换QAT。
量化时的校准集选择也很讲究。校准集要能覆盖不同光照条件、不同墙面材质、不同拍摄距离的图像,数量500到1000张就够,不需要全量训练集。另外,不是所有层都适合INT8。第一层卷积和检测头的敏感度很高,有些推理引擎允许对特定层保留FP16精度,这个“混合精度”操作往往能在精度和速度之间找到最佳平衡点。
4.3 知识蒸馏:用更大的老师教出更稳的学生
剪枝和量化都在做减法,都会有精度损失,而知识蒸馏是做“加法”,用一个能力更强的模型当老师,把小模型教得更接近大模型的效果。我一般在剪枝之后再接蒸馏来弥补精度损失。
具体操作上,老师模型用未压缩的YOLOv8m或x,学生模型用剪枝后的小模型或者YOLOv8n。训练时先正常监督训练学生模型若干epoch,让它具备基本检测能力,再开启蒸馏,否则容易出现训练不稳定的情况。损失函数一般包含三块:学生对老师分类logits的KL散度、回归头的L1距离或DFL距离、特征图层面的蒸馏损失。特征图蒸馏可以简单用attention map对齐,也可以直接用L2拉近特征距离。
蒸馏的收益在墙体损伤场景中很稳定。实测下来,蒸馏能追回剪枝损失的三分之一到二分之一。组合方案顺序是:剪枝压体积、蒸馏回精度、量化再压缩,最终模型体积和推理速度都好看,精度也够用。
5. 部署与实测:压缩后的模型在真实场景的表现
5.1 部署链路怎么搭
部署链路我一般走ONNX中转。先用ultralytics导出ONNX:
yolo export model=best_compressed.pt format=onnx opset=12然后使用onnx-simplifier对计算图做简化,去掉冗余节点。如果目标设备是CPU,可以考虑直接用ONNX Runtime或者OpenVINO;如果是带GPU或NPU的边缘设备,再转成对应推理引擎的格式。转格式时我建议固定输入分辨率,动态shape虽然灵活,但在很多推理引擎里会引发额外显存分配和性能损耗,部署现场调试起来也麻烦。
预处理和后处理逻辑一定要跟训练时保持一致。很多团队在电脑上测试没问题,一到设备上就结果对不上,十有八九是resize方式、归一化参数或NMS阈值不一致。建议把预处理、模型推理、后处理封装成统一接口,代码只维护一份。视频流方面也要考虑抽帧策略,全帧推理会把设备拖成PPT,实际往往是按秒抽帧或当检测到运动目标时才触发。
5.2 一组实测数据的参考
我在一个模拟墙体检测项目里的实测数据大概是这样,不同场景会有波动,但量级可以参考:
| 模型方案 | 参数规模 | FP32体积 | 推理耗时 | mAP50 | 重度损伤召回率 |
|---|---|---|---|---|---|
| YOLOv8m baseline | 25.9M | 50MB | 32ms | 0.79 | 0.86 |
| 剪枝保留45%通道 | 11.8M | 23MB | 19ms | 0.77 | 0.84 |
| 剪枝+INT8量化 | 11.8M | 8MB | 9ms | 0.75 | 0.79 |
| 蒸馏学生模型+INT8 | 4.8M | 7MB | 7ms | 0.75 | 0.82 |
推理耗时是边缘盒子上单张640x640图的平均耗时,FP32为基准。可以看出整个流程下来,mAP50只掉了大约4个百分点,但重度损伤召回率从0.86掉到了0.79,这就是需要重点盯防的地方。如果重度召回率跌破0.75,说明压缩力度过猛,应该回调剪枝比例或给敏感层保留FP16。
5.3 部署现场的坑要早踩
现场部署跟实验室最大的区别在于环境不可控。我最深的体会是:不同建筑、不同墙面的材质差异,可能比模型算法本身更影响效果。清水混凝土、瓷砖面、抹灰墙、旧涂料墙,模型在A现场表现很好,换到B现场就漏检率飙升。这不是算法玄学,而是训练数据没覆盖到这种墙面纹理。所以部署阶段一定预留现场增量采集和自训练的时间,哪怕只是小规模微调,也能把“掉点”救回来不少。
光照问题也很头疼。逆光、阴影、墙面反光都会让裂缝在图像里若隐若现,这类情况误检和漏检同时发生。无人机巡检尽量规划飞行时段,避免大角度斜射阳光;使用补光灯或HDR模式能缓解一部分。再就是飞行高度控制,无人机飞太高,裂缝在画面里只有几个像素,神仙模型也难救。固定的拍摄距离和重叠率,远比后期换模型参数效果明显。
6. 常见问题与排查技巧实录
6.1 裂缝小目标漏检怎么办
细长裂缝在很多图中只占几十个像素,这是漏检的根源。我常用的手段有三个。
第一是切片推理,把大图切成有重叠的patch分别推理,再用NMS合并结果,网上很多工具可以做这事,效果立竿见影。第二是多尺度训练,直接加大输入分辨率到960甚至1280,配合尺度扰动提升模型对尺度变化的适应能力。第三是数据层面,把含小裂缝的图片局部裁剪出来做成额外样本,相当于给模型开小灶专门练“找细裂缝”的注意力。
切片推理的缺点是推理次数变多,耗时上升,部署时要跟设备算力做平衡。
6.2 类别严重不平衡,重度样本太少
实际数据里轻度损伤永远远多于重度,刚开始训练时重度类别的AP可能低得没法看。解决思路分两头。数据层面做重采样,让每个batch里各等级都有一定比例,再用Copy-Paste增强把重度样本“贴”到不同背景中,扩充多样性。损失函数层面给重度类别更大的分类权重,或者在评估时自定义代价矩阵,对“重判轻、轻判重”这种错误加权,迫使训练过程更关注高等级损伤。
6.3 压缩后精度掉了怎么补
压缩后精度掉是必然事件,关键是别盲试。先按类别和等级拆开看AP,定位掉点集中在哪。如果只有轻度裂缝掉,说明量化对细小纹理不友好,考虑对第一层卷积或检测头保留FP16。如果所有类别一起掉,先怀疑剪枝比例过大,回调到80%通道再重新微调。如果剪枝没动、量化也没动就掉,大概率是模型导出和部署端的算子在某个环节没有对齐,用相同输入的输出对比定位差异。
我的经验是,压缩后的精度调试不能只盯着总mAP,板块化验收很重要。每做一个压缩操作,就在“总精度、重度损伤召回率、小目标AP、推理耗时、模型体积”这几个维度上过一遍表,找到短板再针对性处理。
6.4 误检太多,污渍阴影全被当成损伤
数据量少的时候,模型特别容易把“墙面纹理变化”误判成“损伤”,污渍、阴影、苔藓、接缝都对模型是巨大的诱惑。针对这个问题,硬负样本挖掘最有效——专门收集大量带污渍、阴影、粗糙纹理但没有损伤的照片,标注成背景类放进训练集。初始版本训练完会漏一堆误检,把这些误检区域裁出来当作负样本再次迭代训练,效果立刻改善。
形态学后处理也能过滤一部分误检:真实裂缝通常有方向性、连续的长条形特征,用骨架提取加长宽比过滤,能滤掉不少圆滚滚的污渍。高等级损伤判断在现场最好加一道人工复核,让检测结果作为辅助,而不是直接替代专业判断。
最后几点经验
这套项目做下来,我最大的体会是:真正难的从来不是把YOLOv8跑起来,而是把分级标准变成可计算的规则,再把模型压到设备里还能维持可用精度。我给自己定了一个顺序:先定分级规则,再跑小模型baseline,然后集中精力采集补充数据,精度达到要求后再去做剪枝、蒸馏、量化。压缩永远放在最后一步,不要一上来就追求小模型。
还有一个经验是部署前一定要预留现场自训练的时间窗。墙体损伤检测跟通用目标检测不一样,墙面材质和光照环境的分布变化太剧烈了,在实验室测一万遍都不如去现场采集几百张真实照片再微调一轮来得有效。批次性地补充新鲜现场数据,是这个项目最终能落地的最大杠杆。