简介:面向道路缺陷检测场景的大型目标检测数据集,包含约一万四千张训练图像、二百六十张验证图像和一千张测试图像,标签已转为YOLO格式,覆盖四类常见道路缺陷,可直接用于YOLO全系列网络训练。压缩包采用7z格式,共两千个文件,其中一千九百九十九个txt为YOLO格式标签文件,另附show.py脚本,可将检测框绘制到原图,方便直观核验标注质量与模型预测效果。整个资源约九百二十点六八MB,并提供class类别文件,明确各类缺陷定义。目前已有三百七十三人学习下载。适合道路养护、自动驾驶感知及目标检测研究者将其作为训练集或评测基准,省去格式转换与数据整理环节,快速开展模型迭代实验;同时该数据集包含明确的训练、验证、测试划分,适合作为算法效果对比的公共基准。
1. 道路缺陷检测数据集:一万多张 YOLO 标注图,拿到先别急着训练
真正让道路缺陷检测项目翻车的,很少是模型结构选得不对,而是第一批训练数据本身就不干净。裂缝、坑槽、修补带这些目标,在强光、阴影、潮湿路面下的形态差异极大,几百张手工标注图喂进去,模型一到真实路段就露馅。这份目标检测数据集把路面图片、标签、可视化和类别文件全部打包好,训练集约 1.4 万张、验证集 260 张、测试集约 1000 张,统一导出成 YOLO 格式,共 4 个类别。做公路养护检测、毕设验证和算法选型的人,可以直接拿它跑通一整套数据到训练的链路,省掉最耗时的标注环节。
2. 数据集结构与 YOLO 标签格式:训练前两小时先做四件事
很多人拿到这种打包数据后直接解压就敲训练命令,结果要么图片和标签对不上,要么类别索引全错,白白烧掉一晚上。我的习惯是训练前先花两小时熟悉资源结构,不做任何训练,只做四件事:核对目录、解析标签、确认类别映射、统计数量分布。
2.1 顶层目录结构:images/labels 一一对应,注意 UUID 后缀
从解压结果看,这份资源沿用了标准导出布局:train、valid、test 三个目录,每个下面带 images 和 labels 子目录,另外根目录有 classes.txt 和 show.py。整理后的目录结构大致如下:
road_defect/ ├── train/ │ ├── images/ │ │ ├── img_007600_jpg.rf.e3ea45e961a5f445fd838593c1abaa18.jpg │ │ └── img_003245_jpg.rf.a0ce0b5daba90c9e176ce66a24217b51.jpg │ └── labels/ │ ├── img_007600_jpg.rf.e3ea45e961a5f445fd838593c1abaa18.txt │ └── img_003245_jpg.rf.a0ce0b5daba90c9e176ce66a24217b51.txt ├── valid/ │ ├── images/ │ └── labels/ ├── test/ │ ├── images/ │ └── labels/ ├── classes.txt └── show.py两个识别要点。第一,同一张图的图片文件和标签文件必须同名,图片是 .jpg,标签是 .txt;文件名里那一长串十六进制字符串是标注平台导出时生成的去重 ID,作用就是保证导出文件路径不冲突,不要手动改它。第二,判断某张图属于训练、验证还是测试,以顶层目录为准,不要只凭文件名猜。
收到数据第一步,我会先跑一条命令检查同名配对,把“有图无标签”的情况直接揪出来:
for f in train/images/*.jpg valid/images/*.jpg test/images/*.jpg; do dir=$(dirname "$f") lbl="${dir%images}labels/$(basename "$f" .jpg).txt" if [ ! -f "$lbl" ]; then echo "missing label: $f" fi done逻辑说明:对每个 jpg 文件,用 dirname 拿到图片所在目录,再把路径里的 images 替换为 labels,得到预期标签路径;if 判断标签文件不存在就打印。参数说明:如果解压后的顶层目录不叫 road_defect,把 for 后面三个路径改成实际路径;如果图片后缀是 .png,把 .jpg 全部替换成 .png 即可。
实操里这条脚本大概率输出为空,空输出说明配对完整。如果输出一大片 missing,常见原因有两种:一类是某些 txt 文件是 0 字节占位符,表示该图没有目标;另一类是原始采集时部分图片漏标。前者属于负样本,可以保留,后者建议直接删除对应图片,否则训练时 YOLO 会持续刷警告。
2.2 标签文件内部五个数字:归一化边界框的含义
打开任意一个 txt,每行是一条检测目标记录,标准 YOLO 格式是一行五个数:
类别id 中心点x 中心点y 宽度 高度类别 id 从 0 开始计数,后面四个坐标全部做了归一化,数值范围应处于 0~1 之间。以下面这行为例:
0 0.823 0.654 0.214 0.108含义是:类别 0 的缺陷目标,框中心位于图像横向 82.3%、纵向 65.4%,框宽度占整张图宽度的 21.4%,高度占整张图高度的 10.8%。
为什么要用归一化而不是像素坐标?因为相机拍出来的道路照片分辨率并不统一,同一批数据里既有 1920×1080,也可能有 4032×3024。YOLO 训练时会在前处理阶段做 letterbox 等比缩放,如果标签写死像素坐标,图像一缩放,框的位置和大小就全部错位;归一化坐标只描述相对比例,缩放前后天然不变。这也是后续所有 YOLO 系列模型都沿用这套格式的根本原因,别试图把标签私自改成像素格式。
把归一化坐标转回像素坐标的公式,可视化脚本里一定会用到:
x1 = int((cx - w / 2) * image_width) y1 = int((cy - h / 2) * image_height) x2 = int((cx + w / 2) * image_width) y2 = int((cy + h / 2) * image_height)这里 cx 和 cy 是归一化中心点,w 和 h 是归一化宽度和高度,乘以实际宽高后得到框的左上角 (x1, y1) 和右下角 (x2, y2)。注意横向坐标乘图像宽度,纵向坐标乘图像高度,颠倒了画出来的框会完全扭曲。
2.3 classes.txt 与类别映射:顺序比名字重要
资源里明确带了 class 文件,classes.txt 的每一行是一个类别名,行号减一就是类别 id,从 0 开始计数。4 个类别在道路缺陷场景里通常对应裂缝、坑槽、修补带、碎裂区域中的几种,但具体叫什么、顺序如何,以随包的 classes.txt 为准,不要凭想象把类别名写进配置文件。
先执行这样一条命令检查行号和类名的对应关系:
cat -n classes.txtcat -n 会输出行号和内容,行号减一就是类别 id。如果看到的结果和预期不一致,不要直接改 classes.txt,而是记住“原文件顺序”才是训练时的唯一事实。后续写 data.yaml 时,names 列表必须按 classes.txt 顺序一字不差地复制,否则会出现类别名字错位。这类错误在可视化阶段还能看出文字对不上,但框本身并没乱,容易疏忽。
YOLO 训练需要一份数据配置文件,统称 data.yaml。如果压缩包里没有现成的,可以按下面模板在根目录新建:
path: ./road_defect train: train/images val: valid/images test: test/images nc: 4 names: 0: cls0_name_from_classes_txt 1: cls1_name_from_classes_txt 2: cls2_name_from_classes_txt 3: cls3_name_from_classes_txt参数说明:path 是数据集根目录相对路径,train/val/test 都写相对于根目录的 images 目录位置,不要写成 labels。nc 必须和 classes.txt 行数一致,names 的索引和顺序也必须和 classes.txt 对齐。上面代码里我保留了占位符,实际使用时要替换成 classes.txt 中的真实名称,否则唯一影响是可视化和报表上类别名显示错位,训练数值不会崩。很多标注平台导出时 jpg、png 混存,YOLO 会自动扫描 images 目录,不用手动指定后缀。
2.4 数量分布统计:验证集很小,测试集要单独留着
资源在摘要中标注了三段规模:训练约 1.4 万张、验证 260 张、测试约 1000 张。建议亲手统计一遍,顺手看标签里的目标数分布。
echo "train images: $(find train/images -type f | wc -l)" echo "train labels: $(find train/labels -type f | wc -l)" echo "valid images: $(find valid/images -type f | wc -l)" echo "test images: $(find test/images -type f | wc -l)"find 把目录下所有普通文件路径列出来,wc -l 统计行数,-type f 确保只统计文件,避免子目录干扰。再抽查标签看看目标数量分布:
for f in train/labels/*.txt; do wc -l "$f"; done | sort -rn | head -20head -20 显示目标最多的 20 个文件。如果这些文件里动辄十几个目标,说明一张图里塞了大量缺陷,这类图常出现在裂缝密集路段,训练时会被当作难例;如果大量 txt 文件是 0 行,说明这些图确实没有缺陷,属于正常负样本。
这里最需要留意的是验证集只有 260 张。260 除以 1.4 万,约等于 1.8%,远低于常见的 10% 验证比例。验证集太小,直接后果是 mAP 指标起伏很大。所以建议不要在验证集上反复调早停,把 1000 张测试集留到最终统一评估。验证集用来挑权重,测试集才是最终裁判。
3. 用 show.py 可视化验证数据:训练前的质量闸门
训练前我必做的一件事是可视化抽查。模型不认文字说明,它只会学你给的框对不对、边界贴不贴。标注质量不过关时,训练出来的权重就是垃圾进垃圾出,看一遍坏框比看十篇教程都有用。
3.1 show.py 的典型工作方式
这份资源自带 show.py 可视化脚本。常见实现是读取图片和对应 txt,把边界框和类别文本画在图上,再保存成新图片。命令行调用时一般可以带三组参数:图片路径、标签路径、类别文件路径,部分版本还会提供一个 --out 参数用于指定输出目录。运行前先确认 Python 环境里装好了 OpenCV。
我拿到压缩包之后的运行命令通常是:
python show.py --img train/images/img_003245_jpg.rf.a0ce0b5daba90c9e176ce66a24217b51.jpg \ --label train/labels/img_003245_jpg.rf.a0ce0b5daba90c9e176ce66a24217b51.txt \ --classes classes.txt参数说明:--img 指定要绘制的原图;--label 指定同名标签;--classes 给类别名文件,脚本读它之后能在框上方显示类名。如果脚本支持目录遍历,也可以只传 --images 目录和 --labels 目录,批量生成整组可视化结果。
考虑到不同打包脚本的参数名有差异,比如有的用 --image,有的用 --img_path,第一次运行时先执行 python show.py --help 看一眼参数定义。脚本是哪个平台导出的通用版不重要,重要的是可视化结果能让你看见框是否精准贴合目标。
3.2 自己写一套不依赖封装的可视化检查代码
如果 show.py 执行报错,或者只想抽查一张图,我会直接写一个十几行的独立脚本。这段代码不依赖数据集自带封装,标签格式是标准 YOLO 五元组就能用:
import cv2 image_path = "train/images/img_003245_jpg.rf.a0ce0b5daba90c9e176ce66a24217b51.jpg" label_path = image_path.replace("/images/", "/labels/").replace(".jpg", ".txt") img = cv2.imread(image_path) if img is None: raise FileNotFoundError(f"无法读取图片: {image_path}") h, w = img.shape[:2] colors = [(0, 0, 255), (0, 180, 255), (255, 0, 0), (128, 0, 128)] with open(label_path, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue parts = line.split() if len(parts) != 5: print(f"跳过非法行: {line}") continue cls_id, cx, cy, bw, bh = map(float, parts) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) color = colors[int(cls_id) % len(colors)] cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, str(int(cls_id)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imwrite("vis_check.jpg", img) print("可视化结果已保存到 vis_check.jpg")逻辑说明:先用 replace 把图片路径中的 /images/ 改成 /labels/,把 .jpg 改成 .txt,从而定位同名标签;逐行读取标签,空行和格式不对的行直接跳过,这是最稳妥的容错方式。参数说明:colors 定义每种类别的颜色,cls_id 超出颜色列表长度时取模,避免越界;x1/y1/x2/y2 的计算就是前面提到的归一化转像素公式,OpenCV 的 rectangle 接受左上和右下两个点。
这段代码的好处是,无论文件来自哪个标注平台,标签还是标准 YOLO 格式就能复用。如果可视化某张图完全没框,不止可能是标签为空,也可能是我这里 replace 路径写错,或者 txt 读取编码异常。第一次跑通后,建议把它留成固定工具,换任何 YOLO 数据集都能用。
3.3 用可视化结果排除三类标注缺陷
批量可视化的核心目的是发现标注问题,不是看效果。我一般会在训练集里随机抽 20 到 30 张不同类型的图:光线亮的、阴影重的、裂缝密集的、表面干净的,然后按下面三项筛查。
第一,边界框覆盖是否准确。框应该贴合目标边缘,如果框明显把一半路面也包进去,说明标注员把目标画大了;如果目标有一半露在框外,说明框偏小。这两类标注误差会直接传导给损失函数,导致收敛后预测框系统性偏大或偏小。
第二,坐标是否落在图像范围内。标准 YOLO 坐标理论上不会大于 1,但如果标注工具导出异常,可能出现 x 大于 1、w 加 h 大于 1 的情况。可视化阶段框画出图外的表现就是矩形边缘被裁剪,这类标签要尽早修正。
第三,小目标占比是否极端。道路缺陷里裂缝往往呈细长形状,转成归一化坐标后宽度会非常小,训练时是典型的小目标。如果可视化发现大量框宽不到图像宽度的 5%,后面要认真考虑把输入分辨率从 640 提高到 1280,这个决定在可视化阶段做出,比训练中再调整省时间。
| 检查项 | 可视化表现 | 建议处理 |
|---|---|---|
| 框偏大或偏小 | 框与目标边缘有明显间隙 | 判断是否系统化标注误差,占比高则重新标注 |
| 坐标越界 | 框被图像边缘截断 | 修正对应 txt 数值,限制到 0 到 1 之间 |
| 小目标过多 | 大量框宽高小于图像宽高 5% | 默认 imgsz 从 640 提高到 1280 |
做完这一步,训练时才不会被隐藏的标注错误带偏。可视化抽查的意义不是能预判模型将来有多准,而是能阻止明显不合理的标签进训练器。有异常要及时处理,没异常就放心进入下一步。
4. YOLO 训练配置:data.yaml、模型选型与关键超参数
数据集本身不会选模型,但这份资源的体量和 4 类目标数决定了怎么配置最合理。训练集约 1.4 万张,对目标检测来说属于中小规模,用轻量级模型加合理的迁移学习,就能在有限算力下拿到稳定结果。真正需要先定下来的三件事:权重初始化、训练分辨率、早停策略。
4.1 用脚本从 classes.txt 生成 data.yaml
为了避免手写 names 时和 classes.txt 顺序不一致,我会用一个小脚本直接生成 data.yaml:
with open("classes.txt", "r", encoding="utf-8") as f: names = [line.strip() for line in f if line.strip()] with open("data.yaml", "w", encoding="utf-8") as f: f.write("path: ./road_defect\n") f.write("train: train/images\n") f.write("val: valid/images\n") f.write("test: test/images\n") f.write("nc: {}\n".format(len(names))) f.write("names:\n") for i, name in enumerate(names): f.write(" {}: {}\n".format(i, name))逻辑说明:把 classes.txt 的每一行读成一个类名,再按 YOLO 需要的 data.yaml 结构写出去。类名里有空格也可以,冒号后的字符串会被当作完整名字;中文类名在某些 YOLO 版本里偶尔有编码问题,表现是可视化报表里显示乱码,但不影响训练。参数说明:path 那行如果在服务器上训练,建议改成绝对路径,或者直接用命令行参数覆盖,避免笔记本路径和服务器路径不一致。
跑完脚本后执行 cat data.yaml,人工确认 nc 确实是 4。验证集只有 260 张,不需要再切分,直接指向 valid/images 即可。
4.2 模型选型:为什么从轻量级基线起步而不是直接上大模型
对 1.4 万张图、4 类缺陷,我建议用轻量级模型或中等模型作为基线。轻量级模型推理快、显存占用小,便于快速迭代超参数;中等模型效果更好,但训练时间大约多出六成,在数据规模不算大的情况下,两者的差距不会像在 COCO 80 类上那么显著。
我踩过直接上最重模型的坑:训练时间拉长好几倍,最终 mAP 只比轻量模型高零点几个点,反而没有时间去调输入分辨率。对这类资源,先用预训练权重做迁移学习是性价比最高的起点。预训练权重在公开场景上提供的通用特征已经足够,后面几层会很快适应道路缺陷的分布。
如果显存只有 6G 左右,建议轻量模型加 640 分辨率加 batch 16;如果显存有 12G 以上,可以尝试中等模型加 640 分辨率,或者在同样 batch 下把分辨率提到 1280。
4.3 训练命令与参数解读
以常见的 YOLO 命令行训练模式为例,一条典型命令如下:
yolo detect train \ --model yolov8s.pt \ --data road_defect.yaml \ --epochs 150 \ --imgsz 640 \ --batch 16 \ --patience 30 \ --project runs/road_defect \ --name exp1参数说明:--model 指定预训练权重,框架会自动下载;如果网络环境访问不了权重仓库,需要手动把权重文件放到对应目录。--imgsz 是训练输入分辨率,640 是默认值,用在道路缺陷数据上速度与精度平衡较好;遇到小目标漏检严重再提到 1280。--batch 受显存制约,16 大约对应 8G 显存的安全值,显存不够可以先降到 8 试跑一个 step。--patience 30 表示连续 30 轮验证 mAP 不提升就提前停止,能省很多时间;早期迭代里别舍不得设它,没人会一直盯着监控面板。
还有 --cache 参数值得注意。第一次训练时,YOLO 会把图片缓存到显存或内存,加速数据读取;磁盘或显存紧张就别开。我训练第一版通常不开 cache,等后面反复复跑相同数据时再开,把卡人的时间省下来。
4.4 训练曲线怎么读:避免在错误方向上浪费算力
训练的前 20 个 epoch,loss 下降明显,mAP 可能在 epoch 30 之后才出现爬升,这属于正常现象。真正要盯的是三个信号。
第一,box 回归 loss 不再下降,但验证 loss 稳步上升,这是过拟合信号。1.4 万张对 4 类的小模型不太容易过拟合,但如果某个类别样本特别集中,也会有局部过拟合。此时优先加数据增强,而不是立刻换大模型。
第二,验证 mAP50 在某个区间稳定后开始剧烈抖动。前面说过验证集只有 260 张,抖动很可能来自样本量太小。不要因为一波抖动就反向调低学习率,先看后续 10 个 epoch 的趋势再决定。
第三,某个类别 mAP 始终为 0。这经常是类别样本数量太少。先统计每个类别的目标数,如果某类不足 200 个目标,要考虑放弃该类,或者对该类做复制增强。这里注意,k 折交叉验证在这个数据集上并不划算,验证集本来就小,折数切小反而加剧方差。
提示:类别名错位和标签越界在训练阶段都不会报错,属于典型的黑匣子故障,靠看 loss 曲线发现不了,只能靠可视化抽查和标签扫描防守。
5. 常见问题与避坑:五个高频翻车点的排查记录
每次让新人跑这份数据,几乎都会在同样的地方摔跟头。下面五条是最常遇到的问题,按现象、原因、解决三段记录。
5.1 现象:训练开始后大量警告缺失标签
现象:启动训练后,控制台不断刷出类似标签文件为空的警告,loss 异常,训练跑不动。
原因:labels 目录里文件都在,但不少 txt 文件内容是 0 行。标注流程把“无缺陷正常路面”和“漏标的缺陷图”混在一起,导出时统一写成空 txt。解决:先把空文件数量统计出来,再结合可视化判断。无缺陷的样本是有价值的负样本,清点后保留,不需要强迫它们带框;明显有缺陷但 txt 为空的图,要么补标,要么直接删除。判断依据是抽看原图,如果原图路边有一条明显裂缝而标签为空,就是漏标,建议删除,否则模型会学到“这种裂缝不该检测”。
5.2 现象:坐标出现负数或超过 1
现象:可视化脚本画出的框跑到了图像外边,或者有的框直接把整条路面盖住。
原因:标签文件里并不是每行都符合 YOLO 规范。标注平台转格式时,个别边界框归一化计算没做好,出现 x_center 加 width 的一半大于 1,或者 y 坐标出现负数。解决:先用扫描脚本把非法文件和非法行找出来,再修正。扫描脚本可以直接复用这段:
import glob bad = [] for txt in glob.glob("**/labels/**/*.txt", recursive=True): with open(txt) as f: for i, line in enumerate(f, 1): p = line.strip().split() if len(p) != 5: bad.append((txt, i, "列数错误")) continue c, x, y, w, h = map(float, p) if not (0 <= x <= 1 and 0 <= y <= 1 and 0 <= w <= 1 and 0 <= h <= 1): bad.append((txt, i, f"越界: {p}")) for item in bad: print(item)逻辑说明:glob 递归扫描所有 labels 下的 txt,逐行解析;列数不等于 5,或任一坐标不在 0 到 1 区间,就记录文件路径、行号和具体内容。参数说明:glob 路径要匹配实际目录,如果标签目录不叫 labels,按实际情况修改。拿到非法列表后,我会把越界框裁剪回图像边界,而不是整行删除,因为删除会让目标直接丢失。
5.3 现象:训练正常,但 mAP 一直在低位徘徊
现象:损失曲线看着正常,训练 100 轮下来 mAP 始终提不上去,怎么调超参都没改善。
原因:通常是类别索引错位。classes.txt 的行顺序和 data.yaml 中 names 不一致,训练时的监督信号整体偏移。有人习惯在 data.yaml 里写自己推测的类名,而不是读 classes.txt,结果每个类都在学错误的目标。解决:做一次类目顺序一致性检查,把两个文件逐行对齐:
cat -n classes.txt cat -n data.yaml | sed -n '/^names:/,$p'越早发现越好,因为这种错位在训练指标上不会有任何报错,是最典型的黑匣子故障。好在修正成本低,改完 yaml 重新跑一次对比实验就行。从那以后我换数据集必做这步检查,宁可多花两分钟,也不再赌手气。
5.4 现象:验证集 260 张导致不同实验间得分忽高忽低
现象:同一套代码跑两次,一次 mAP50 是 0.75,一次是 0.71,无法判断改动是否真的有效。
原因:验证集只有 260 张,代表性不足,每次验证时随机采样带来的波动远超超参改动带来的影响。解决:用测试集 1000 张做最终 A/B 对比,而不是在验证集上做决断。操作是在验证时把数据配置指向 test 集:
yolo detect val \ --weights runs/road_defect/exp1/weights/best.pt \ --data road_defect.yaml \ --split test \ --conf 0.001这里 conf 设得很低,是为了统计所有检测结果,而不是只挑高置信度的框。不同模型之间对比时,关键是保证同一张测试图、同一个 conf、同一个 iou,只有这样才能相信测试集上的差异确实来自模型改动。
5.5 现象:裂缝漏检,小目标成了重灾区
现象:整体 mAP 尚可,但抽查时发现细长裂缝大量漏检,很多框只框住局部。
原因:裂缝宽度极细,在 640 分辨率下只占几个像素,属于典型的小目标和极端长宽比目标。YOLO 处理这类目标时,深层特征图分辨率不够,浅层特征又容易被高层语义覆盖。解决有三条路,按成本从低到高。第一,把 imgsz 从 640 提到 1280,让目标像素面积变大。第二,开启更强的 mosaic 和 copy-paste 增强,让模型在训练时更频繁看到小尺度样本。第三,针对该类单独收集补充样本做重采样,平衡类别占比。如果是交付阶段,还可以用滑窗切图方式推理,把大图切成小块,对重叠结果做 NMS 融合。切图会增加推理耗时,但往往是裂缝类缺陷最有效的救急方案。
6. 测试集验证与阈值调优:交付前最后一公里
训练曲线的 mAP 只能说明学习过程没崩,真正拍板能否交付,还得回到那 1000 张没参与训练的测试图上。两个技巧比较实用。
6.1 统一在测试集上打标点
把测试集路径加进 road_defect.yaml 之后,用和训练时同一套参数跑一次验证,命令就是第 5.4 节那条。结果中有三项必看:mAP50、mAP50-95 和每个类别的 mAP 列表。mAP50 用于和外部论文对标,mAP50-95 更能反映框的贴合度。道路缺陷这种对定位精度要求高的场景,两者都要记录。
再把 1000 张测试图按类别分组看各类 mAP。如果有一个类别比别人低一截,优先怀疑标注质量,而不是模型能力。这时候调回可视化脚本,抽看该类别的 30 张测试图,对着真实标注核对预测框的位置和大小,不要在一堆指标里空猜。
6.2 用置信度阈值压住误报
测试图上得到的结果是一堆带置信度的框。道路巡检场景下,误报成本很高,空旷路面上一块阴影被识别成坑槽,就会造成一次无效出勤。我的习惯是先打印各类别在测试集上的精度-召回曲线,选一个精度不再明显上升的置信度点作为发布阈值,比如 0.35。实现很容易,但注意不要每次换模型都重选阈值,那样会把阈值学进模型导致过拟合,先固定一个值,模型迭代完再做一次微调。
做好阈值之后,我会做最后一遍交付核查:从测试集随机挑 50 张图,用最终权重画预测结果,亲自翻一遍预测框有没有大面积偏移、有没有把水渍阴影错判成缺陷。这个动作没有技术含量,但它能救回前面所有看不见的细节事故。
从那以后,我每次换数据集都会强制走一遍流程:先检查图片标签完整性,再随机可视化 20 张,最后才允许触发训练。当年跳过这些步骤直接训练,浪费了一整晚算力才回头找原因的教训,至今印象深刻。希望这套流程对你也有用,拿这份资源时少走几步弯路。
本文还有配套的精品资源,点击获取