☰
Yolov8道路病害检测实战:源码部署、模型训练与评估指标全解析
2026/10/1 16:26:12 网站建设 项目流程

简介:这是一份基于YOLOv8实现的道路病害检测平台项目资源,集成前端源码、部署教程、训练好的模型和各类评估指标曲线,适合软件工程、计算机、人工智能等专业学生用于毕业设计、课程设计、项目初期演示,也可作为深度学习目标检测任务的入门实践。包内共有29个文件,包括17个jsx前端页面组件、svg/css样式文件、js/json路由与工程配置、README部署说明,以及独立打包的模型zip,整体体积仅159KB,目录按功能模块组织,便于对照阅读和修改。训练好的模型与损失曲线、精度曲线等评估结果均随资源交付,配合部署教程可快速还原道路病害检测流程,也能从曲线趋势判断模型收敛情况,为答辩讲解和文档撰写提供直接素材。已有208人学习下载,项目经导师指导通过、代码测试正常,适合作为课设或毕设的高分参考项目。

1. 道路病害检测为什么绕不开Yolov8:这个压缩包到底能帮你什么

公路养护里,路面裂缝、坑槽、修补区这些病害的巡检,过去靠人眼或者半自动的取芯,一天下来几公里路,眼睛都看花了。现在普遍的做法是拿车载相机或者无人机拍图像,再用目标检测模型一帧帧框出来。Yolov8 是当下做这个事最顺手的一套检测框架,它自带训练、验证、导出和部署的完整链路,而且社区里公开的道路病害数据集很多,踩坑记录也多,适合做专项优化。这个标题给出的项目包,正好是把「源码 + 部署教程 + 训练好的模型 + 评估指标曲线」捆在一起的高分交付物,针对的就是想快速跑通并在此基础上做二次开发的从业者。

它解决的直接问题有三个:一是你不用从零搭环境、写训练脚本,解压后按部署教程把依赖装好,就能先用现成的权重在图片 / 视频上看到检测效果;二是训练好的模型不是黑匣子,压缩包里给了各项评估指标曲线,你可以判断它到底在裂缝、坑槽哪一类上靠谱,哪一类是凑数的;三是源码本身可改,不管是换数据集、调 anchor、加注意力机制,还是往边缘设备上迁移,都有现成的起点。

适合的人群比较明确:做道路养护信息化、智慧公路项目的工程师,做毕业设计 / 课程设计的学生,以及想把 Yolov8 快速迁移到工业视觉检测方向的算法工程师。如果你只是好奇目标检测是什么,想看看 demo,这个包对你来说偏重;但如果你手头有公路图像数据,想在一到两周内做出一版能演示、能出指标的检测模型,这个方向值得投入。

2. Yolov8检测道路病害的原理与选型:从Backbone到损失函数

2.1 Yolov8的网络结构:C2f模块与解耦检测头

Yolov8 的 backbone 沿用了 CSPDarknet 的思路,但把 Yolov5 里的 C3 模块换成了 C2f 模块。C2f 的特别之处是它把输入在 Bottleneck 之间做了更密集的跨层连接,梯度可以更直接地回流到浅层,同时感受野没有因为网络加深而丢失全局上下文。对道路图像来说,裂缝是细长目标,坑槽是块状目标,C2f 这种多分支结构能在同一个特征层上兼顾两种不同尺度的语义,漏检率会比老模型低一截。

检测头是 Yolov8 最大的变化:从耦合检测头改成了解耦检测头。具体说就是分类分支和回归分支各自走一组卷积,不再共享输出通道,最后分别输出类别概率和边界框坐标。为什么这对病害检测重要?因为路面图像里裂缝和坑槽的背景都很复杂——有车道线、影子、水渍、油污,分类难度和定位难度不同,耦合头容易被背景带偏,解耦之后两个任务互相不干扰,训练收敛过程更平滑。

下面这段是 Yolov8 官方配置里用于小模型的 yolov8n.yaml 的关键片段,几乎每个自称 Yolov8 道路病害检测的项目都会从这里改起:

# Parameters nc: 2 # number of classes 这里改成你的病害类别数 scales: # model compound scaling constants n: [0.33, 0.25, 1024] # depth, width, max_channels s: [0.33, 0.50, 1024] m: [0.67, 0.75, 768] l: [1.00, 1.00, 512] x: [1.00, 1.25, 512] # YOLOv8.0n backbone backbone: - [-1, 1, Conv, [64, 3, 2]] - [-1, 1, Conv, [128, 3, 2]] - [-1, 3, C2f, [128, True]] - [-1, 1, Conv, [256, 3, 2]] - [-1, 6, C2f, [256, True]] - [-1, 1, Conv, [512, 3, 2]] - [-1, 6, C2f, [512, True]] - [-1, 1, Conv, [1024, 3, 2]] - [-1, 3, C2f, [1024, True]] - [-1, 1, SPPF, [1024, 5]]

这段配置的关键在于nc参数,它直接决定了检测头输出的类别通道数。如果你只检测裂缝(crack)和坑槽(pothole)两类,nc就填 2;如果还要加修补(repair)和网状裂缝(alligator_crack),就改成 4。后面的scales控制模型宽深,n是最小版本,适合车载嵌入式平台;s和m是我们在服务器上训练时常用的折中选择。改nc时注意训练数据的标签文件里类别索引必须从 0 开始连续编号,否则检测头输出的维度会对不上,训练时会直接报错。

2.2 道路病害检测的标签体系与损失函数设计

道路病害检测本质上是一个目标检测任务,标签体系一般按病害类型划分。常见公开数据集如 RDD2020 和 Crack500 里面,类别通常包括横向裂缝、纵向裂缝、网状裂缝、坑槽、修补等。但也有人为了省事只分两类:完好和病害,实际落地时这样并不可取,因为养护部门需要区分裂缝长度和坑槽面积,它们对应的修补成本完全不同。

训练时 Yolov8 默认使用 TAL(Task-Aligned Assigner)作为正负样本分配策略,损失由分类损失(BCEWithLogitsLoss)和回归损失(CIoU Loss)两部分组成。TAL 的思路是让分类分数高、预测框与真值框重合度高的样本优先作为正样本,其他样本忽略或者作为负样本。这个策略对细长裂缝很友好,因为裂缝的 GT 框通常很长很扁,早期的 Anchor-based 方法很容易把它误当成背景,而 TAL 会综合考虑分类和定位匹配度,能保住这类难样本。

CIoU 损失除了考虑框的重叠面积,还惩罚了中心点距离和长宽比差异。对坑槽检测来说,坑槽形状不规则,人工标注的框偏大偏小都会影响长宽比,CIoU 会比 IoU 损失更耐噪声。需要留意的是,Yolov8 的回归损失默认对每个预测框用的是 Distribution Focal Loss(DFL)加 CIoU 的组合,DFL 会把边界框坐标回归建模成离散分布,这对裂缝边缘的精细定位有帮助,但也会让模型对标注框的边界噪声更敏感,所以标注时尽量让框紧贴病害边缘,不要留太多背景。

2.3 为什么不用Yolov5、Yolov7而选Yolov8

这个问题几乎每个做公路检测项目的人都会问。从精度上看,Yolov8 在 COCO 上的 AP 比 Yolov5 同尺寸模型高 2-3 个点,在病害这种小目标多的场景里,高出来的点主要来自小目标召回率的提升,原因是解耦头加 TAL 的组合对小目标更友好。从部署上看,Yolov8 官方仓库原生支持 ONNX、TensorRT、CoreML、TFLite 导出,而且导出的 ONNX 算子更规范,用 TensorRT 构建 engine 时很少碰到自定义算子,这一点我们在 RK3588、Jetson 上踩过不少坑,Yolov5 的某些旧版本导出后会带Focus算子,必须手动拆层。从训练体验上看,Yolov8 把训练、验证、预测、导出都收进了同一个 CLI,一个参数切换任务模式,写脚本的负担小很多。

当然 Yolov8 也不是没有缺点。它在小目标密集场景下偶尔会漏检,模型体积因为解耦头比 Yolov5 大一点,训练显存占用略高。如果你的硬件实在紧张,Yolov8n 在 1080Ti 上训练 640 分辨率也要 4-6G 显存,Yolov5n 会少 1G 左右。我的建议是:有 GTX1660Ti 以上显卡就无脑 Yolov8,只有 CPU 或者 4G 以下显存时,先用 Yolov8n 跑通,再考虑切 Yolov5 保底。

3. 本地部署与源码运行:从零把平台跑起来

3.1 环境准备:CUDA、PyTorch与Yolov8的版本匹配

拿到这个压缩包后第一步不是直接运行,而是确认环境。Yolov8 官方要求 Python 3.8+,PyTorch 1.8+,实际上我们推荐 PyTorch 2.0 以上,因为 2.0 的编译优化对卷积加速明显。GPU 环境里 CUDA 版本最好与 PyTorch 的 wheel 对应,比如 PyTorch 2.0 默认对应 CUDA 11.7 和 12.1,你可以用nvidia-smi看驱动支持的最高 CUDA 版本,只要驱动版本够新,PyTorch 的 CUDA 运行库可以比驱动低,但不能高。很多人装了 CUDA 12.0 的驱动,却去下了 CUDA 11.7 的 PyTorch,这没问题;反过来就会提示找不到 libcudart。

如果你只有 CPU 且系统是 Ubuntu20.04,也能跑,但推理速度会很感人——640 分辨率的图片用 yolov8n 在 i5 上大约 300-500ms 一次。这种情况下建议至少用mkl版 PyTorch,并在推理时开torch.set_num_threads()。部署教程里如果给了 CPU 版环境配置,照做即可,但不要指望实时视频,离线图片分析没问题。

检查环境的命令如下:

# 查看显卡驱动支持的 CUDA 版本 nvidia-smi # 查看当前 Python 与 PyTorch 版本 python -c "import torch; print(torch.__version__, torch.cuda.is_available())"

第一段命令的作用是确认驱动侧的天花板,第二段是确认 PyTorch 是否真的能看到 GPU。如果torch.cuda.is_available()输出False,说明 PyTorch 安装成了 CPU 版,或者 CUDA 版本不搭,直接卸载重装比排查半天更省事。命令行里不用担心版本号完全一致,只要驱动版本号精简后不低于 PyTorch 要求的 CUDA 版本号即可。

3.2 下载源码与安装依赖:pip install 那一步

常见做法是直接把 ultralytics 仓库 clone 到本地,或者用 pip 安装 ultralytics 包。标题里的源码包一般已经内置了 ultralytics 的改动版,所以更常见的做法是解压后进入项目根目录,先创建一个虚拟环境再装依赖。

# 创建虚拟环境,避免污染系统 Python python -m venv .venv source .venv/bin/activate # 升级 pip 并安装 PyTorch(GPU 版以 CUDA 12.1 为例) pip install --upgrade pip pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 安装项目依赖 pip install -r requirements.txt

这里用虚拟环境是必须的,因为道路病害项目通常依赖特定版本的 opencv-python、numpy、pandas,而系统 Python 环境往往被其他项目占用。requirements.txt 里一般会有 ultralytics、opencv-python、matplotlib、scikit-learn 等,安装时如果提示numpy版本冲突,多数是 opencv-python-headless 和 opencv-python 同时存在导致的,先卸掉其中一个再装。

安装完成后验证一下模型是否能正常加载:

# 用官方预训练权重快速验证环境 yolo predict model=yolov8n.pt source=https://ultralytics.com/images/bus.jpg

如果这条命令能输出一张带检测框的图,说明你的环境没问题。之后再用项目自带的训练好的模型替换这个yolov8n.pt。这一步能帮你把「环境问题」和「项目代码问题」分开,避免一上来就甩一个ModuleNotFoundError。

3.3 用训练好的模型做推理:CLI命令与Python脚本

部署教程一般会教你两种推理方式。第一种是命令行,适合快速测试:

# 单张图片推理 yolo predict model=runs/train/exp/weights/best.pt source=data/test/0001.jpg conf=0.25 # 批量图片推理,结果保存到 runs/predict yolo predict model=runs/train/exp/weights/best.pt source=data/test/ save_txt=True save_conf=True

conf是置信度阈值,道路病害场景里我习惯设 0.25,因为裂缝这类小目标模型置信度普遍不高,设 0.5 会漏掉一半。save_txt=True会把每个框的类别、坐标、置信度写到同名 txt 里,后续做 GIS 统计分析时非常有用。

第二种是 Python API,适合集成到平台或者做二次开发:

from ultralytics import YOLO # 加载训练好的模型,这里用压缩包内的 best.pt 作为示例 model = YOLO("runs/train/exp/weights/best.pt") # 推理单张图片 results = model.predict( source="data/test/0001.jpg", conf=0.25, iou=0.5, device="cuda:0" ) # 提取结果:类别、框坐标、置信度 for r in results: for box in r.boxes: cls = int(box.cls[0]) # 类别编号 conf = float(box.conf[0]) # 置信度 xyxy = box.xyxy[0].tolist() # [x1, y1, x2, y2] print(f"class={cls}, conf={conf:.3f}, box={xyxy}")

这个脚本的关键在于读懂results对象:r.boxes是一个列表,每个元素对应一个检测框,.cls是类别索引,.conf是置信度,.xyxy是左上角和右下角坐标,单位是像素。如果你要把检测结果叠加到原图上,可以用r.plot(),它会返回一张 RGB 数组,配合cv2.imwrite就能直接存图。很多部署教程会漏掉device参数,导致 CPU 上跑半天,这行参数指定推理设备,GPU 训练完的模型直接用cuda:0能快 20 倍以上。

3.4 部署教程里常见的目录结构与权重文件说明

标题里的源码包解压后,目录结构通常是这样:

路径作用
runs/train/exp/weights/best.pt训练好的模型,验证集上指标最好的一版
runs/train/exp/weights/last.pt最后一次迭代的模型,可用于断点续训
runs/train/exp/results.csv每次迭代的 loss、P、R、mAP 等指标
runs/train/exp/PR_curve.pngP-R 曲线,评估模型在不同置信度下的表现
data/数据集目录,包含 images 和 labels
deploy/ONNX/TensorRT 导出脚本或推理脚本

best.pt和last.pt的区别要搞清楚:best 是验证集表现最好的,last 是训练结束时的状态。如果训练后期过拟合,best 会显著优于 last;如果两个文件几乎一样,说明训练还没到极限,可以加大 epochs。

使用模型时优先用best.pt。但如果发现 best 在某个病害类别上 mAP 很低,而 last 反而更高,可能是验证集划分不合理,rare 类别样本太少导致 best 在验证集上的波动大。这时建议重新划分数据集,而不是纠结用哪个权重。

4. 训练自己的道路病害数据集与评估指标曲线

4.1 数据标注与目录组织:从Labelme到YOLO格式

道路病害检测一般不会直接用 COCO 数据,而是用你自己的路面图像。常见的数据来源有三个:车载相机俯拍、手持相机近拍、无人机航拍。俯拍和航拍视角差异很大,如果混在一起训练,模型很容易懵,建议按场景分开建模。

标注工具用 Labelme 或 X-AnyLabeling 都可以。Labelme 默认生成的是 JSON 多边形,Yolov8 训练需要的是 YOLO 格式的 txt。转换脚本是每个项目必须有的,常见做法是读 JSON 里的shapes,把多边形的外接矩形转成 Yolo 格式的归一化坐标:

import json import os def labelme_to_yolo(json_path, out_path, classes): with open(json_path, encoding="utf-8") as f: data = json.load(f) img_w, img_h = data["imageWidth"], data["imageHeight"] lines = [] # 遍历每个标注多边形 for shape in data["shapes"]: label = shape["label"] if label not in classes: continue cls_id = classes[label] points = shape["points"] # [[x1,y1], [x2,y2], ...] xs = [p[0] for p in points] ys = [p[1] for p in points] # 计算外接矩形并归一化 x_min, x_max = min(xs), max(xs) y_min, y_max = min(ys), max(ys) box_w = (x_max - x_min) / img_w box_h = (y_max - y_min) / img_h c_x = (x_min + x_max) / 2 / img_w c_y = (y_min + y_max) / 2 / img_h lines.append(f"{cls_id} {c_x:.6f} {c_y:.6f} {box_w:.6f} {box_h:.6f}") out_txt = os.path.join(out_path, os.path.basename(json_path).replace(".json", ".txt")) with open(out_txt, "w") as f: f.write("\n".join(lines)) classes = {"crack": 0, "pothole": 1, "repair": 2} labelme_to_yolo("data/label/0001.json", "data/labels/train", classes)

这段脚本的核心是按imageWidth和imageHeight归一化,YOLO 格式要求中心点坐标和宽高都是 0-1 之间的小数。要注意:直接对多边形取外接矩形会把裂缝两端的背景也包进来,标注得越贴合,bounding box 越准。坑槽这类不规则形状,建议用矩形标注而不是多边形,多边形转矩形会损失一部分真值信息,矩形标注反而更直接。

目录组织也很重要,一个标准的 Yolov8 数据集目录长这样:

data/ images/ train/ road001.jpg val/ road100.jpg labels/ train/ road001.txt val/ road100.txt

训练时只需要提供data.yaml,里面指定train和val的路径。一个容易翻车的点是:images 和 labels 必须保持相同的相对目录结构,且文件名完全对应(允许后缀不同),否则训练时会报找不到标签文件。

4.2 训练命令与关键参数:img、batch、epochs、patience

训练命令很简单,但参数需要仔细调。以这个项目里的yolov8s为例:

yolo train \ model=yolov8s.pt \ data=data.yaml \ imgsz=640 \ batch=16 \ epochs=100 \ patience=15 \ device=0 \ workers=4

imgsz是训练分辨率,病害检测里 640 是性价比最高的选择。提升到 1280 对小裂缝有微弱提升,但显存占用翻 4 倍,训练时间也翻倍。batch越大,模型收敛效果越一致,但受显存限制;如果显存 8G,640 分辨率下 yolov8s 的 batch 建议不超过 16。patience是早停参数,验证集 mAP 连续 15 个 epoch 不提升就自动停止,道路病害数据集通常 50-80 epoch 就能收敛,不用傻傻跑满 100。

训练时还要注意权重的初始化方式。如果直接用model=yolov8s.pt,会用 COCO 预训练权重做迁移学习,这是首选。如果你已经有一个道路病害最佳模型,可以用它接着训练:

yolo train model=runs/train/exp/weights/best.pt data=data.yaml imgsz=640 batch=16 epochs=50

这种做法叫增量训练,适合新增一类病害或者用新数据扩充旧模型。但增量训练会在一定程度上改变原有类别上的性能,如果旧模型已经很好,新数据只是加了少量样本,建议把旧权重作为参数初始化而不要冻结 backbone,或者直接做数据融合训练。这个尺度需要多试几次,没有统一答案。

4.3 评估指标曲线:P-R曲线、F1曲线、混淆矩阵怎么生成

标题里说的「各项评估指标曲线」是判断模型能不能用的关键。训练结束后,Yolov8 会在验证集上自动生成PR_curve.png、F1_curve.png、P_curve.png、R_curve.png和confusion_matrix.png,这些图都在runs/train/exp/下。另外results.png会画训练和验证的 loss 曲线,以及 P、R、mAP50、mAP50-95 的逐 epoch 变化,一眼能看出模型有没有过拟合。

P-R 曲线最值得看。它的横轴是召回率,纵轴是精确率,曲线下的面积就是 AP。AP 越接近 1,说明模型在保持高精确率的同时还能召回大部分目标。道路病害场景里,裂缝的 AP 通常在 0.6-0.85 之间,坑槽的 AP 高一些,因为目标大。如果曲线在某个置信度阈值附近突然断崖下跌,说明模型对该类别的置信度分布不合理,需要调整置信度阈值或者补充难例样本。

你也可以用脚本手动绘制,Yolov8 的results.curves_results可以直接拿到各阈值下的 P、R 数据:

from ultralytics import YOLO model = YOLO("runs/train/exp/weights/best.pt") metrics = model.val(data="data.yaml", split="val") # 各类别的 mAP print(metrics.box.map) # mAP@0.5:0.95 print(metrics.box.map50) # mAP@0.5 for cls_name, ap50, ap in zip(metrics.names.values(), metrics.box.ap50, metrics.box.ap): print(f"{cls_name}: AP50={ap50:.3f}, AP={ap:.3f}")

这段代码的输出结果比 curve 图更直接。如果某个类别的 AP50 低于 0.5,说明模型基本没学会这个类,先查数据量是不是太少,再看标注框是否太松。metrics.box.map是 COCO 风格的 mAP@0.5:0.95,道路病害评估报告里通常用 mAP50,因为病害的边界模糊,iou 阈值太高会让人工标注误差被放大。

4.4 用训练好的模型做验证:val模式与测试集

训练时 Yolov8 会在每个 epoch 结束后对验证集做一次评估,但我们需要对独立测试集(训练中没见过的图像)再做一次验证,得到最终的评估指标。这一步直接用 val 命令:

yolo val model=runs/train/exp/weights/best.pt data=data.yaml split=test

注意split=test要求data.yaml里配置了test路径。如果你只配置了 train 和 val,Yolov8 会默认用 val 做测试,指标会比真实场景略好。在道路病害项目里,测试集最好是另一段路的图像,哪怕相机参数相同,不同路面的纹理也有差异,这才能真正反映模型的泛化能力。

如果 val 结果与训练时结果差异很大,先确认测试集图像是否经过预处理。Yolov8 内部会自动做 resize、归一化,但你如果测试的是视频帧,别忘了帧率导致的运动模糊也会影响检测效果。建议在 val 前人工抽看一下测试集的标注,排除错标和漏标样本——指标曲线不会告诉你是标注错了还是模型错了,这一步只能自己排查。

5. 部署与训练中的常见问题排查:5个踩坑记录

5.1 现象:Ubuntu20.04 CPU版环境跑起来特别慢

第一次在这个项目里运行预测时,一张 640×640 的路面图片在 i5-9400F 上跑了快 1 秒,视频流直接掉到不到 1 FPS。一开始以为是模型太大,后来发现是 PyTorch 装成了 OpenBLAS 版本,没有使用 Intel 的 MKL 加速。

原因是 CPU 版 PyTorch 在 Ubuntu 上的默认矩阵运算库不一定是 MKL,OpenBLAS 在多线程调度上效率低。解决方法是安装 MKL 版 PyTorch,或者改用官方 Intel CPU 轮子:pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu,并在推理前设置torch.set_num_threads(8)。设置后单张推理降到 200ms 左右,虽然仍然不能实时,但批量处理图片已经可以接受。另外把imgsz降到 416,速度还能再快一半。

5.2 现象:训练时显存溢出(OOM)

在 8G 显存的 GTX1070 上用 yolov8m 训练,batch 设 32,刚开始 200 步就报 CUDA out of memory。原因是imgsz=640且 workers=8 时,数据加载器也会占用一部分显存,另外 Yolov8 在训练时会额外保留两倍的梯度用于自动混合精度。

解决方法是先开 AMP 混合精度,Yolov8 默认开着但老版本可能没开;然后把 batch 降为 8,workers改为 4,如果还不够,换模型版本,yolov8s 比 m 省 30% 显存。还有一招是把cache=True关掉,因为缓存数据集到显存/内存会瞬间抬高占用。最实用的排查命令是nvidia-smi,看到其他进程占显存时用fuser -v /dev/nvidia*找出并杀掉残留的训练进程,这个坑很多人忽略。

5.3 现象:模型把路面裂缝识别成车道线

在验收时发现模型把新旧沥青接缝、白色车道线都框成了裂缝,精确率直线下滑。原因是训练集里全是干净路面上的裂缝,没有加入带车道线、接缝、阴影的负样本,模型没有见过「看起来像裂缝但其实不是」的干扰项。

解决方法是收集足够多的 hard negative 样本,单独建一个文件夹,把它们的标签文件留空(txt 只有 0 字节),放进训练数据里。Yolov8 会把这些图片作为背景类参与训练,从而抑制误检。另外,数据增强里的hsv_h、hsv_s等参数会让颜色扰动过大,把路面颜色搅乱,导致模型依赖纹理忽视频色特征,建议在道路病害数据上把颜色增强幅度调低,比如hsv_h=0.01。

5.4 现象:P-R曲线极其反常(AP为0或恒定)

训练结束后查看PR_curve.png,发现某一类别的 PR 曲线是一条水平线,AP 为 0。排查后发现这个类别在训练集中只有 20 张图,而且全部集中在验证集划分后的一小部分,训练时几乎没有收敛到该类。

原因是样本不平衡和划分不均匀。解决方法是先用train/val/test = 7/2/1按文件夹分层采样,而不是随机划分;对小类别做增强复制,或者用class_weight调高损失权重。另外,如果某个类别在验证集里只有 1-2 个目标,AP 波动会非常大,建议每类至少 50 个检测目标再评估,否则那根曲线只能说明数据划分有问题,不代表模型能力。

5.5 现象:导出ONNX后推理结果与PyTorch不一致

把best.pt导出成 ONNX 再部署到 RK3588 上,发现同一个置信度阈值下,ONNX 的检测框比 PyTorch 少了一半。用 ONNX Runtime 仔细对比后发现,输出张量里的坐标值和小目标置信度都有细微差异,原因是导出时没有固定输入尺寸。

Yolov8 的export默认支持动态尺寸,ONNX 里的 NMS 算子与 ultralytics 处理逻辑不一致也会造成差异。解决方法是导出时固定尺寸并关闭推理模式以外的附加输出:

yolo export model=best.pt format=onnx imgsz=640 dynamic=False opset=12

导出后用onnxruntime跑一遍相同的图片,对比输出的检测数量,确认差异可接受。如果差异大,检查是否用torch.no_grad()导出,以及模型是否在 eval 模式。还有一个常见坑是导出前忘了把权重切到float16,Pytorch 上没问题,但板端推理时半精度会丢掉小目标,建议导出后先量化校准再部署。

6. 进阶:用 RK3588 部署道路病害模型的完整思路

如果你的项目不是演示完就结束,而是想装在巡检车上,那绕不开边缘部署。RK3588 是目前国产边缘板里性价比很能打的选择,8 核 CPU + 6 TOPS NPU,能跑 Yolov8s 量化的模型。部署的核心思路不是把 PyTorch 搬到板子上,而是转成 RKNN 格式。

6.1 模型导出与量化

先在 PC 上用 ONNX 做中间格式,再用 RKNN-Toolkit2 转成 RKNN。导出命令保持一致:

yolo export model=best.pt format=onnx imgsz=640 opset=12 dynamic=False

然后在 PC 上的 rknn-toolkit2 环境里执行转换,关键参数是量化类型和数据集。

from rknn.api import RKNN rknn = RKNN() # 配置 NPU 核心数、量化精度 rknn.config(target_platform="rk3588", quantized_dtype="w8a8", batch_size=1) # 加载 ONNX 模型 rknn.load_onnx(model="best.onnx") # 使用 100 张训练集图片做量化校准 rknn.build(do_quantization=True, dataset="quant_dataset.txt") rknn.export_rknn("best.rknn")

量化数据集quant_dataset.txt里每一行是图片路径,文件内容就是待导入的图片列表。这里用训练集而不是验证集,因为量化校准只需要表征数据分布,训练集量大更有代表性。rknn 转换后建议在 PC 上先做板端仿真推理,预览误检情况,再上板。

6.2 板端推理验证与性能对比

在 RK3588 上用 Python 的 RKNN Toolkit 或 C API 跑推理,测量精度和延迟。通常 w8a8 量化后,mAP50 会下降 2-5 个百分点,这个幅度对道路病害可接受,因为裂缝本身边界模糊。如果下降超过 10 个点,优先检查量化是否忽略了hsv增强导致的颜色分布偏移,或者尝试改成 w8a16。

我的经验是:先跑 100 张现场图片对比原版 best.pt 和量化后模型的检测框,确认没有大面积漏检再上实车。部署完成后要保留原始 ONNX 和量化脚本,方便复现,不要只留一个.rknn文件,否则后续调优还得重新摸索。

最后说句实在话,道路病害检测这个方向,模型只是起点,真正决定项目能不能交付的是数据质量和部署时的边界情况。我自己的习惯是每次接到新路段的图像,先拿旧模型跑一遍,把漏检和误检图挑出来,补进训练集里做一轮增量训练,再更新部署模型。这个流程看起来笨,但效果比换任何新模型都稳。希望帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询