路面病害检测这两年找我咨询的人明显变多了,而且需求高度一致:过去靠人工或者传统图像处理做的路面裂缝识别,误报率居高不下、泛化能力差,换个光照换个路面材质就崩。大家真正想要的是一套能落地、能训练、能部署的完整方案,而不是几个Demo截图。这篇文章我就把自己用YOLOv8做道路缺陷检测的完整经验拿出来,从选型理由、数据集怎么从零构建、训练参数怎么调,到部署阶段踩过的坑,一次讲清楚。
先说结论:用YOLOv8做路面裂缝和损伤识别,在工程落地角度上是目前性价比最高的路线。原因不复杂,你需要检测的目标(裂缝、坑槽、龟裂、修补区域)本质上都是形状不规则的物体,对实时性要求又高,巡检车跑起来不可能慢慢磨叽。YOLO系列这种单阶段的检测范式天然适合这个场景,v8版本在精度、训练便利性和部署生态上的平衡做得尤其好。下面我会拆开讲。
1. 为什么项目最终选择了YOLO路线,而不是传统图像处理或者更强的分割模型
1.1 传统人工巡检和图像处理方案各自卡在了哪里
路面缺陷检测不是新需求,很多养护单位过去一直靠人工目测或者车载摄像头录回去慢慢看。人工方式的问题肉眼可见:效率低是一方面,更麻烦的是标准不统一,同一段路面,两个技术人员看出来的病害类型和严重程度可能都不一样,甚至同一个人上午和下午的判断都会有偏差。这直接导致养护决策难以量化,因为连"这段路有多少裂缝"这种基础数据都不可靠。
传统图像处理方案我早期也尝试过,基于边缘检测、形态学操作的思路,对理想光照下、背景干净的裂缝确实有效果。但一放到真实道路上就崩了:路面有新旧标线、有修补痕迹、有油渍、有轮胎摩擦黑印,这些纹理和裂缝在灰度特征上非常接近,阈值怎么调都会两头错。你只要经历过一次"晴天下午三点拍出来的裂缝检测精度很高,阴天早上九点就变成灾难现场",就会明白传统的特征工程方案在开放场景下撑不了多久。
1.2 深度学习检测范式解决的问题本质
把裂缝检测当成目标检测问题来处理,本质上是把"手工设计特征"变成了"让模型自己学习特征"。裂缝、坑槽、龟裂这些目标,虽然在传统算子看来和路面背景难以区分,但深度卷积网络能够整合多尺度的纹理、上下文和形状信息,对光照和材质变化的鲁棒性比人工特征强一个量级。
为什么具体选择单阶段检测器而不是双阶段的Faster R-CNN这类方案?检测速度是决定性因素。道路检测常常是车载连续采集,每秒要处理好几帧画面,双阶段模型的两级结构天然慢一些,而且训练和部署也更重。单阶段模型把分类和定位放在同一个网络里一次输出,在同等硬件条件下能换来的帧率优势非常明显。YOLO系列又是单阶段里生态最成熟、社区迭代最快的一支,遇到问题能找到的参考资料最多,这点对做工程的人来说很实际。
1.3 YOLOv8在这个场景里到底扮演什么角色
YOLOv8在项目里的定位就是"检测主干",它负责从输入图像中找出每个缺陷目标的边界框。项目里我做了两件事:第一,用YOLOv8的检测能力直接输出裂缝或损伤的位置;第二,在检出位置的基础上,后期再加一个小判别逻辑来降低误报。整个系统里算法主干是YOLOv8,但真正让它符合实际业务要求的,是围绕它构建的数据集、训练策略和后处理逻辑。
所以你千万不要以为"套个YOLOv8模型就完了",那只是把枪拿到手,真正要花功夫的是怎么给这把枪准备合适的弹药,也就是数据集,以及怎么根据实际情况调整射击姿势,也就是训练和部署策略。
2. 模型选型深度拆解:YOLOv8相对v5和v7的核心差异与工程收益
2.1 网络结构上的关键变化
YOLOv8相比v5、v7最有感知度的变化有四处:
第一,C2f模块替代了v5的C3结构。C2f在梯度流上做了更细的拆分,能在增加极少计算量的前提下提升特征提取能力。直观感受是训练过程中loss下降更平稳,收敛后的精度上限略高。
第二,Anchor-Free的检测头。v5还是Anchor-Based,需要在训练前计算先验框大小;v8直接改成Anchor-Free,把目标检测转化为中心点加边框回归的问题。这对新手极其友好,省掉了聚类锚框的步骤,也减少了训练时的调参项。
第三,解耦分类头和回归头。分类和定位两个任务从共享一个特征输出改成各自独立分支,收敛速度和最终精度都有改善。裂缝检测这种场景里,很多误检来自"位置对了但类别置信度乱跳",解耦头能缓解这个问题。
第四,正负样本分配策略换成了动态匹配。简单说就是训练初期和训练后期使用不同的匹配逻辑,让模型在不同阶段都有合适的样本信号,训练过程更稳。
2.2 为什么没有选择实例分割模型
可能有人会问:裂缝是不规则长条,用分割模型不是更精确吗?我确实试过。当时用了基于实例分割的框架,分割出来的裂缝轮廓确实比边界框更漂亮,展示效果也好。但落地时发现两个问题:
一是标注成本直接翻倍。检测框只要一个矩形框,分割模型要精确勾勒裂缝边缘,一张图的人工标注时间要乘三倍以上。对一个少说几千张的数据集来说,这个成本差距是巨大的。
二是下游决策用不上那么细的轮廓。养护部门需要的核心指标是"哪里有病害、属于什么类型、大概占多大面积",检测框完全能换算出面积占比,不需要像素级的轮廓。多出来的精度在业务上是无效成本。
所以,训练速度更快、推理更快、标注更便宜的检测方案,就是工程上的正确选择。
2.3 部署约束和生态考量
当时项目场景里还有一条硬约束:部署的机器不一定带高性能GPU。巡检车辆上可能只有一台低功耗工控机,或者用云端处理但带宽有限。YOLOv8s或者YOLOv8n这种体量在CPU上也能勉强跑起来,配合TensorRT或者ONNX优化在GPU上能达到非常可观的帧率。
综合考虑精度、速度、标注成本、部署灵活度和社区资料丰富度之后,YOLOv8在这个项目里就是最均衡解。这里也给出一个参考结论供选型时对比:
| 对比维度 | YOLOv8 | YOLOv5 | Faster R-CNN | 实例分割模型 |
|---|---|---|---|---|
| 训练便利度 | 高 | 高 | 中 | 中低 |
| 推理速度 | 快 | 快 | 慢 | 慢 |
| 标注成本 | 低 | 低 | 低 | 高 |
| 裂缝轮廓精度 | 框级 | 框级 | 框级 | 像素级 |
| 工程生态 | 极活跃 | 极活跃 | 较成熟 | 较弱 |
裂缝检测业务其实不需要像素级轮廓,这决定了YOLOv8是"够用且最顺手"的方案。
3. 数据集构建:决定工程成败的70%工作都在这
3.1 采集环节的实操规范
很多人忽略采集环节,直接去网上扒现成的道路缺陷数据集。这能用来跑通流程,但你要真部署到具体路网上,性能往往不达标。原因很简单:不同地区的路面材质、标线风格、养护习惯差异很大,通用数据集覆盖不了你实际要检测的道路特征。
我当时采集的思路是这样的:
采集设备用一部中等价位的运动相机,固定在车后方支架上,镜头朝下,拍摄距离地面大约1到1.2米,保证裂缝在画面里占到足够像素。车速控制在每小时30公里以内,因为速度太快会让运动模糊严重,小裂缝直接就糊掉了。拍摄时段覆盖上午、中午、下午、阴天、晴天这几个条件,特别要注意逆光和阴影这种容易让模型学歪的场景。
如果你没有车载条件,手持设备沿路走也是可行的,但要注意保持拍摄高度一致,并且尽量让裂缝在画面中处于不同位置、不同方向,不要总是正中央横着一条。
还有一个很多项目吃亏的地方:采集的原始视频里大量连续帧高度相似,如果不做抽帧去重,直接拿来做训练,会导致数据高度冗余,模型过拟合到某一段路的特有纹理上。我一般每隔10到15帧抽一帧,且对连续相似帧计算感知哈希相似度,相似度超过90%的只保留一帧。
3.2 裂缝和损伤类型的标注逻辑
标注是数据集环节里最磨人但也最关键的一步。我结合项目实际,把路面缺陷划分成五类:
- 横向裂缝:大体上和道路走向垂直的裂缝,通常因温度应力或者反射裂缝引起
- 纵向裂缝:顺着行车方向的裂缝,和路基不均匀沉降关系大
- 龟裂:网状、块状分布的细小裂纹群,往往是路面老化信号
- 坑槽:路面材料脱落形成的凹陷,这是最危险的一类,直接影响行车安全
- 修补区域:沥青填补过的位置,之所以也做出来,是因为修补区和周边路面的纹理差异明显,容易导致误检
标注规范上有几个细节必须强调:
第一,框一定要紧贴目标。很多标注者习惯性地把框画松一点,觉得把整条裂缝包进去就行。这在训练里会造成严重问题,因为边界框里混入了大量背景像素,模型学到的特征会被背景干扰。裂缝检测对边框紧致度的敏感度比车辆检测高很多。规则应该是:框恰好包含裂缝像素,能不包背景就不包背景。
第二,对长裂缝遮挡、延伸出画面边缘的情况,我的做法是只要裂缝在画面内长度超过30个像素,就标注完整可见部分。未入镜的部分不强行延伸,因为标注不完整的目标强标反而会毁掉标签质量。
第三,标注工具建议使用开源工具,比如LabelImg或者X-AnyLabeling都可以,导出格式统一用YOLO格式的txt文件,每行五个值:类别id、归一化中心x、归一化中心y、归一化框宽、归一化框高。这样的格式后续训练时快乐很多。
标注之后一定要做质量复核,最好是多人独立标注同一批图然后计算标注一致性,不一致的地方逐张讨论修正。这一步虽然费时间,但对最终模型精度的提升远超你后面怎么调训练参数。
3.3 数据增强:哪些有效,哪些是白费力气
数据增强我直接把Ultralytics内置的参数用了一部分,同时按场景需求加了个性化处理。
我个人推荐开启的增强项:
- Mosaic:把四张图拼接成一张训练,显著提升模型对小目标、遮挡目标的适应能力,对裂缝这种细长目标尤其有用
- 随机翻转和旋转:注意旋转角度不要太大,路面裂缝有横纵语义,转90度以上会让方向信息失真
- HSV扰动:轻微改变亮度、饱和度、色相,增强对光照变化的鲁棒性
- 随机擦除:模拟裂缝被阴影局部遮挡的情况
不推荐的项目是大幅度的缩放加裁切。裂缝本来就很细,过度缩放到小尺寸会让裂缝变成只有一两个像素宽的短线,模型基本学不到有效特征。
给出一组我实测下来稳定靠谱的增强配置参考:
augment: true hsv_h: 0.015 hsv_s: 0.5 hsv_v: 0.3 degrees: 10 translate: 0.1 scale: 0.3 mosaic: 1.0 mixup: 0.05 fliplr: 0.5注意这里的mixup我只开了很小的值。路面缺陷类别之间边界不算清晰,mixup比例太大会让龟裂和坑槽这类目标互相糊在一起。
3.4 数据划分与清洗的隐藏天坑
数据划分上,我最想提醒的一个坑是:千万不要把所有图片打乱后简单随机划分。这是因为采集得到的连续帧即使做了抽帧,仍然存在相似性,如果同一路段的前后帧同时出现在训练集和验证集里,验证集就成了"开卷考试",评估分数虚高。
正确做法是按路段划分。先把所有图片按所属路段分组,然后以路段为单位划分训练集、验证集和测试集。比如当时项目里就按7:2:1的比例,但随机分组对象是路段,而不是单张图片。这样验证集检测到的才是模型没见过的物理路段,评估才可信。
数据清洗同样重要。训练前要对全量数据集做了一次人工遍历,删掉三类数据:严重模糊的、目标占比过小的(裂缝在800万像素图里只占不到50像素)、标注框明显错误的大难图。质量优先于数量,不是图越多越好,脏数据会拖垮训练。
4. 从零到能跑:YOLOv8道路缺陷检测模型训练全流程
4.1 环境准备与目录结构
先说环境。我用的是Python 3.9配合PyTorch 2.x,CUDA版本根据GPU驱动来选。如果你没有现成的深度学习环境,最稳妥的做法是创建一个干净的虚拟环境,然后安装Ultralytics库:
python -m venv road_env source road_env/bin/activate pip install ultralytics这一条命令会带起依赖的PyTorch等核心库。有GPU就把CUDA版PyTorch提前装好,没有GPU纯CPU训练不是不行,但一张1000张图的训练集在CPU上要跑好几个小时,有条件的强烈建议用GPU。
数据目录按YOLO官方习惯组织:
road_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── road.yaml其中road.yaml的内容是关键:
path: /your_path/road_dataset train: images/train val: images/val names: 0: horizontal_crack 1: longitudinal_crack 2: alligator_crack 3: pothole 4: repair_area这里有个细节:names顺序必须和标注txt里的类别id完全一致,否则训练会出现张冠李戴的灾难。建议训练前写个小脚本检查每个txt标签文件里出现的类别id是否都在配置范围内。
4.2 训练命令与关键参数通俗解读
训练命令本身不复杂:
yolo detect train model=yolov8s.pt data=road.yaml epochs=150 imgsz=640 batch=16 device=0六个核心参数建议逐个理解,不要照抄:
第一,model权重文件的选择。首次训练用yolov8s.pt做预训练权重比从随机初始化开始好很多,迁移学习能让模型快速理解基础视觉特征。v8n速度最快但精度偏低,v8m精度再高一点但推理变慢,s是中间档,裂缝检测场景下我用s居多。
第二,imgsz训练尺寸。官方默认640,但裂缝是细长小目标,分辨率太低细节会丢。我建议项目针对裂缝至少设到960,这个选项对裂缝检测的影响非常大。代价是显存占用增加,batch要相应调小。如果你的GPU显存只有8G左右,batch设成4或8就好。
第三,epochs训练轮数。表面看150轮很常规,但裂缝检测数据集往往只有几千张,过拟合风险高,后面我会讲具体对策。数值本身不重要,关键是看训练曲线来判断。
第四,batch大小。这个参数和GPU显存直接挂钩,训练时如果报显存溢出,优先把batch调小,其次是降低imgsz。
第五,device指定GPU编号。多卡训练可以写成device=0,1,但数据量不大的时候单卡训练更省心,不用担心卡间同步问题。
第六,patience参数建议设置。它是早停机制,如果验证集指标连续多少轮不下降就提前结束训练。我一般设patience=30,既不至于浪费太多时间,又给模型足够空间去突破瓶颈。
4.3 训练过程的监控:到底该看哪些指标而不是只盯mAP
训练过程中你会看到终端持续打印指标,很多人只盯着最后的mAP,中间过程完全不看。这是不够的。
重点看两个指标的变化趋势:
一是Box Loss和Cls Loss是不是同步下降。正常情况两者都稳定缓降。如果Cls Loss下降很快但Box Loss始终下不去,问题大概率在标注质量上,尤其可能是标注框不紧贴目标。
二是验证集上的Precision和Recall曲线的相对关系。裂缝检测场景更偏重Recall还是Precision,取决于业务用途。如果这套系统是用来自动筛选可疑路段的,宁可多报一点,后面人工二次确认,那么Recall优先,通过降低置信度阈值来提升;如果系统直接驱动自动养护决策,那么Precision优先,误报的代价更高。
训练结束不要只用最后一个epoch的权重。Ultralytics会自动保留best.pt和last.pt,一般best.pt是验证集上综合指标最好的权重,默认用它做后续推理。但如果验证集指标和实际场景差异较大,还是要回到实际图片上去检验。
4.4 显存不够和训练中断的处理经验
训练过程中最常见的现实问题是显存溢出,尤其是imgsz提到960之后。我遇到显存不足时的优先处理顺序:
先缩小batch到2或者1,不行再把imgsz降至800或736,最后再考虑用梯度累积替代大batch的效果。注意Ultralytics的batch参数直接控制单次前向的图片量,很多人误以为它可以像Gradient Accumulation那样隐性扩大规模,其实改动它只影响显存占用和BN统计批量大小。数据量小的时候batch小一点影响没那么大,可以接受。
训练中途意外中断时,不用从头开始。Ultralytics支持断点续训,在训练命令里加上resume=True,它会自动从项目run目录下的last.pt继续。这个习惯一定要有,不然一次断电可能白跑十几个小时。
5. 训练过程中的实战调优:loss不降、小目标漏检、误报三大难题逐个击破
5.1 训练初始阶段loss居高不下的排查链路
有段时间训练出来的模型几乎什么都不检测,loss曲线在训练初期就高得离谱而且下不来。排掉数据格式和yaml配置这些问题后,我发现了一个容易被忽略的坑:标签文件里存在大量空标签图。
因为我们采集的图片并不是每一帧都有缺陷,抽帧后没有缺陷的图片如果不删除也不标注,在YOLO格式里就是空的txt文件。Ultralytics默认会用这些图参与训练,让模型不断学习"这张图里什么都没有",但它同时也还有其他没有缺陷的正样本图,两类样本互相干扰,导致loss波动剧烈且不下降。
排查办法是在训练前统计一下标签文件的情况:
import os label_dir = "road_dataset/labels/train" empty_count = 0 for f in os.listdir(label_dir): file_path = os.path.join(label_dir, f) if os.path.getsize(file_path) == 0: empty_count += 1 print(f"空标签文件数量:{empty_count}")发现大量空标签后,我的处理方法是:不直接删除这些图片,而是把这些负样本单独放一个目录,训练时通过数据目录配置把它们以适当比例混合进来,模拟真实道路巡检中"大部分画面没有缺陷"的分布。因为真实应用场景里,巡检画面绝大多数都是路面背景,完全没有裂缝,模型必须见过足够的负样本才不会把普通路面误检成裂缝。但负样本比例也不能太高,否则模型会偏向保守,漏检严重。我试下来负样本占20%到30%是比较稳的值。
5.2 细长裂缝和小目标漏检问题的根因与解决
裂缝的最大特点就是"细长",框面积占比可能只有整张图的千分之几。模型在高层特征图上的语义信息强但分辨率低,到了这个尺度,几条像素宽的裂缝信息早就被池化操作弄丢了。这就是裂缝检测经常漏检的根因。
针对这个问题,我按以下路径逐个排查:
第一步,把imgsz从640提到960或者1024。这一步通常能直接让mAP上涨四到五个点,因为目标在输入分辨率下的像素数增加了不少。
第二步,调整anchor相关参数。虽然v8是Anchor-Free,但对目标尺度仍然敏感,同一张图内裂缝长度差异太大,有几十像素的细线,也有贯穿画面的长裂缝。可以考虑使用多尺度训练,Ultralytics里开启multi-scale训练时每轮的输入尺寸在一定范围内随机变化,模型对不同尺度目标的适应会好很多,代价是训练时间变长。
第三步,分析漏检的分布。我写过一个推理脚本,把所有验证集图片跑一遍,把漏检的图片单独收集起来人工查看。结果发现漏检集中出现在两类图上:一是逆光条件下裂缝和阴影混淆;二是裂缝太过密集,龟裂区域里模型只检出一部分。这种针对性的错误分析比盲目调参有效率得多。
5.3 数据量不足导致的过拟合识别与应对
道路缺陷数据集做起来非常费人力,很多个人开发者能收集到的也就是几百来张图。几百张数据去训练一个深度神经网络,过拟合几乎是必然的,区别只在于什么时候开始过拟合。
判断过拟合的关键是关注验证集指标和训练集指标之间的gap。训练集mAP已经到0.95甚至0.98,但验证集只有0.6上不去,且训练过程中的val loss从某个epoch之后持续上升,训练loss还在继续下降,这就是标准过拟合信号。
应对手段优先级我认为是:
先加大数据增强强度,尤其把mosaic、随机翻转、HSV扰动的幅度都往上调。这个手段成本最低,也不用动模型。
然后尝试换更小的模型。我自己遇到过不少次用yolov8s过拟合严重,换yolov8n反而验证指标更好。模型容量小,正则化效果天然更强。
再考虑冻结骨干网络。在数据量小时,前若干epoch用model冻结backbone层参数训练,相当于把底层特征提取交给预训练权重,只让高层适应道路缺陷的分布,能有效降低过拟合速度。后续再解冻全模型精调。
最后才是考虑补充更多数据。如果真是数据量太少,以上手段只是缓解,最终要么继续采集,要么用更大规模增强来硬顶。没有捷径。
5.4 误报问题:把阴影、油渍、标线当成缺陷的治理思路
误报是路面检测系统最头疼的问题。模型很容易把以下三类东西误判为裂缝:轮胎刹车留下的黑色痕迹、路面标线边缘、树影或者绿化带投影的细长阴影。它们共同的特点是和裂缝一样呈细长条状,颜色也和沥青裂缝接近。
治理思路分两路。
一路是数据层面。我在标注时引入了一个关键措施:专程采集了大量带阴影、带油渍、带标线的路面图片,把它们作为负样本加入训练数据。注意这些图里可能有真实的裂缝也要标注,此时就是正负样本同图共存。负样本的作用是让模型学会区分"裂缝纹理"和"伪裂缝纹理",提升判别力。
另一路是后处理层面。训练完成后,分析误检框的位置和置信度分布。发现大量误检框的置信度集中在0.25到0.45之间,而真正的裂缝大多高置信度。于是我在推理时把置信度阈值从默认0.25调到0.4左右,误报率立刻显著下降。如果业务上更侧重查全率,阈值可以保留低一点,但配合一个尺寸过滤规则:过滤掉面积过小、长宽比异常离谱的框。对龟裂这类块状目标和纵横向裂缝的目标形态差异,还可以尝试按类别单独设置阈值。
6. 部署与推理:模型从训练环境搬到实际检测场景的全流程
6.1 模型导出与推理接入方式
训练完的best.pt是PyTorch权重,直接在生产环境里跑需要安装全套深度学习框架,既不高效也不灵活。我一般将模型导出成ONNX格式,在需要更高帧率的场景再配合TensorRT做进一步优化。
导出命令:
yolo export model=best.pt format=onnx imgsz=960 opset=12 simplify=True导出ONNX时有两个参数要注意:imgsz必须和训练尺寸保持一致,否则在导出阶段模型会重新调整输入维度,可能导致精度损失;simplify开启后能对计算图做简化消除冗余节点,推理会更快。
导出后的推理可以直接用Ultralytics的YOLO类:
from ultralytics import YOLO model = YOLO("best.onnx") results = model.predict( source="input_image.jpg", conf=0.4, imgsz=960, device="cpu" ) boxes = results[0].boxes.xyxy.cpu().numpy() scores = results[0].boxes.conf.cpu().numpy() classes = results[0].boxes.cls.cpu().numpy()部署阶段的IO细节经常被忽略,比如输入图像颜色通道顺序。YOLO系训练时用的是RGB,而OpenCV读取图像默认是BGR,如果不做转换直接送进ONNX推理,检出的目标颜色特征会错乱,效果暴跌。Ultralytics的predict接口内部已经帮你处理了这个问题,但如果你自己写ONNX Runtime推理脚本,一定要记得做通道顺序转换。
6.2 连续视频帧的稳定性处理
道路巡检多数是处理视频流,单帧推理常见的问题是目标闪烁:同一段裂缝在这一帧检出了,下一帧没了,再下一帧又出现。这会导致统计出来的裂缝数量非常不稳定。
我采用的方案是轻量级的帧间投票。取连续五帧检测结果,当某个位置的检测框在多帧中被重复检出且中心点漂移不大,就认为它是一个稳定裂缝,否则认为是抖动误检。实现不复杂,就是做检测框匹配:
def match_boxes(boxes1, boxes2, iou_threshold=0.3): matched = [] for b1 in boxes1: best_iou = 0 best_b2 = None for b2 in boxes2: iou = compute_iou(b1, b2) if iou > best_iou: best_iou = iou best_b2 = b2 if best_iou >= iou_threshold: matched.append((b1, best_b2)) return matched连续帧帧率在30帧时,相邻帧间同一目标的中心点移动很小,IOU阈值0.3就够用。通过投票之后,检测结果的稳定性明显提高,业务统计也更可信。这是很多教程不会讲,但实际工程里非常重要的一步。
6.3 边缘设备上的推理性能优化
我在低成本部署环境(无GPU,只用CPU)上做的优化路径是这样的:
第一,模型量化。训练完的模型是FP32精度,用ONNX Runtime的量化工具把权重从FP32压到INT8,但要注意对细长裂缝目标,直接量化可能造成精度掉点。保守做法是只量化到FP16,精度损失小很多。第二,把推理批次设为1,开启线程数优化,在CPU场景下有时可以提升20%到30%的吞吐。第三,对输入图像做预处理裁切,只保留路面主体区域,加快网络推理。
这些优化里最实在的还是把模型尺寸降下来,对部署环境压力大时,训练阶段就选择yolov8n,并用蒸馏思路用一个更强的教师模型辅助训练,能在较少的参数量下保留大部分精度。
7. 项目复盘:那些常规文档不会告诉你的经验细节
最后分享几个在做这个项目时沉淀下来的实操细节。你把这些细节自己验证一遍,就能感觉到明显差别。
第一个经验,杜绝标注风格漂移。数据是多人流水线标注的话,标注风格不一致迟早会在模型中体现出来。项目里定下"框紧贴目标,误差不超过两个像素"的硬标准,每两天随机抽五十张已标注图做交叉复核,发现漏标和松框立刻返工。标准的稳定程度直接决定了训练结果的上限。
第二个经验,不要迷信统一的置信度阈值。我之前习惯全局用0.25的阈值,排查后发现横纵裂缝的置信度普遍比龟裂和坑槽高。原因是龟裂区域特征更复杂,网络对其判别难度更大。针对不同的类别设置不同的置信度阈值,整体F1分数能再拔高。这个活儿不复杂,就是拿验证集跑一遍,按类别统计置信度分布,再找合理的切分点。
第三个经验,善用预训练权重。有人为了"纯粹"从随机初始化开始训练道路缺陷模型,我劝你不要这么做。用yolov8s.pt这种在大型数据集上预训练过的权重做起点,即便道路场景和预训练数据差异极大,迁移学习依然显著优于从零开始。本质上是让模型复用基础纹理和边缘特征。想要完全从头训练,等你有几万张数据再说。
最后一个建议,上手道路缺陷检测不要一上来就想刷SOTA,把基准流程完整跑通最重要。先用几百张公开数据把训练、验证、导出的链路跑顺,再逐步扩数据、调结构、做优化。我见过很多人在环境配置和消融实验上卡了太久,反而是从简单流程开始的人更早做出可展示的结果。先完成,再完美,这句话放在这个项目里非常合适。