简介:计算机视觉技术正加速进入基础设施安全监测领域,其中以深度学习为代表的目标检测方法已逐步替代传统边缘检测与阈值分割,成为结构表面裂缝识别的核心技术路径。其基本原理是通过卷积神经网络学习裂缝在复杂背景下的纹理与几何特征,实现高精度定位。该技术价值在于能够有效抑制光照、苔藓、水渍等干扰因素,提升室外真实场景下的泛化能力,广泛适用于路面、桥梁、墙体等结构表面的自动化巡检。一个可落地的裂缝检测系统需同时兼顾数据标注策略、模型训练调参与推理部署优化等关键环节。本文以Yolov5为技术载体,系统梳理了裂缝数据集的构建方法、超参数调整经验、批量检测与RTSP视频流接入方案,并总结了施工缝误判、极端光照干扰等工程踩坑案例,为结构检测工程师及研究者提供一条从源码出发的完整落地路径。
1. 路面桥梁墙体裂缝检测,为什么我建议直接用Yolov5源码改
做结构检测的朋友应该都有同感:裂缝检测这个需求看起来简单,真正动手做却处处是坑。传统图像处理里的边缘检测、阈值分割,在室内干净背景下的试件上效果不错,一到室外路面、桥梁、墙体,光照变化、阴影、苔藓、水渍全部变成干扰,误检率高到没法用。而这两年裂缝识别方向上的主流做法,基本都收敛到了深度学习目标检测这条路上,其中Yolov5是复现成本最低、工程资料最全的一个选择。这个项目标题里给出的正是这样一套东西:Python环境下的Yolov5裂缝检测系统,带文档和源码,目标场景覆盖路面、桥梁、墙体三类典型结构表面。
把这套系统跑通并不难,难的是把参数调到能用的程度。本文按我实际做过的方式,把数据准备、训练调整、推理部署和踩坑记录完整过一遍。你不需要有很强的深度学习基础,只要会装Python、能跑命令行,就可以跟着一步步复现。适合的人群很明确:在做桥梁检测、路面巡检、房屋安全评估的工程师,或者准备拿这个方向做毕业设计的学生。我不讲那些花哨的注意力机制,也不对比Yolo系列各个版本谁更强,就讲最直接能落地的做法。
2. 做裂缝数据集是第一道坎:采集、标注与增强的取舍
2.1 裂缝目标的特点决定了标注方式
第一次做裂缝检测的人最容易犯的错,是把裂缝当成普通物体来标。普通物体比如人、车、猫,是一个封闭轮廓,用矩形框一框就完事。但裂缝不一样,它是长条形的,细的时候只有两三个像素宽,长度可能跨越整个画面。你要是像框人一样用一个窄矩形框去框裂缝,出来的目标框长宽比会非常极端,10:1、20:1都不奇怪。Yolov5对极端长宽比的锚框本身就敏感,训练出来的模型很容易漏检短裂缝。更合理的做法是:以每段裂缝为单位,把连续裂缝切成若干段,每段用一个尽量方正的小框去标,框与框之间可以有少量重叠,这样训练出来的模型对裂缝段的召回率会高很多。
还有一个细节是漏检容忍度。裂缝检测和工业质检不一样,工业质检漏掉一个缺陷可能就一批废品,但裂缝检测漏掉一段裂缝,巡检测绘的结论就可能从"合格"变成"需维修",性质完全变了。所以标注的时候拿不准的裂缝区域宁多勿少,模糊的小裂缝也标上。模型学到的边界是模糊的,但召回率能保住。
2.2 离线增强三板斧:光照扰动、随机旋转、Mosaic
裂缝数据集天然不好攒,尤其桥梁裂缝,你得爬到桥墩、箱梁里拍,一次能拍几百张算不错了。Yolov5自带的Mosaic、Copy-paste增强能帮你把数据量撑起来。但有几个增强参数必须调,不能全用默认值。
以Yolov5官方仓库的coco.yaml训练流程为例,我一般在data/hyps/hyp.scratch-low.yaml里改这三项:
# hyp.scratch-low.yaml 关键参数片段 hsv_h: 0.02 # 色调扰动幅度,裂缝颜色单一,调太大颜色偏得离谱 hsv_s: 0.3 # 饱和度扰动,应对不同光照和混凝土表面色差 hsv_v: 0.4 # 明度扰动,模拟逆光、阴影、夜间补光场景 flipud: 0.5 # 垂直翻转,路面裂缝横竖都有,翻转保持方向多样性 mosaic: 0.8 # Mosaic增强概率,默认1.0对密集小目标效果好,但裂缝太细容易拼花这些参数的含义要理解:hsv_h是色调在HSV空间的扰动比例,裂缝一般是灰黑色,色调本身没有太多信息,扰动大了反而让模型去学颜色特征而不是纹理特征;hsv_v是明度扰动,这个对户外场景最重要,因为裂缝检测最大的干扰就是光照不均。Mosaic概率我从1.0降到0.8,原因是裂缝目标小且细,四张图拼在一起时边缘处的裂缝会被截断,导致模型学到"半截裂缝"这种错误模式。
2.3 数据集划分与目录组织
Yolov5的训练入口是dataset.yaml,你需要把数据按images和labels两个目录分开,每张图片对应一个同名的txt标注文件。标注格式是YOLO格式:类别index、归一化的中心点x、中心点y、框宽w、框高h,全部是0到1之间的浮点数。手工标注工具推荐LabelImg或者Labelme,导出YOLO格式就行。
# 项目目录结构,按Yolov5默认读取方式组织 crack-data/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 ├── labels/ │ ├── train/ # 训练集标签,和images同名同后缀 │ └── val/ # 验证集标签 └── crack.yaml # 数据集配置文件crack.yaml内容按这个写:
# crack.yaml train: ./crack-data/images/train val: ./crack-data/images/val nc: 1 # 类别数,裂缝检测就一个类 names: ['crack'] # 类名随意,但和标注txt里的index必须对应注意train和val的路径,用相对路径最省事,把crack.yaml放在Yolov5仓库根目录下,路径以仓库根目录为基准。另外val集不要偷懒直接拿训练集里的图,裂缝检测的验证集要有一定数量,我一般按训练集20%左右的比例留,每类至少50张,不然验证损失曲线波动太剧烈,根本看不出模型有没有收敛。
3. 训练自己的裂缝模型:Yolov5超参数和损失曲线怎么调
3.1 预训练权重选哪个
Yolov5官方提供了好几个尺寸的预训练权重,Yolov5s、Yolov5m、Yolov5l、Yolov5x。裂缝检测属于小目标检测的范畴,直觉上会觉得模型越大越强,直接上Yolov5x准没错。实际做下来不是这个逻辑。裂缝检测的输入分辨率一般限制在640甚至更低,因为结构检测拍下来的照片动辄几千万像素,缩小到640以后细裂缝的信息已经损失大半,模型容量再大也补不回来。我在自己项目里的经验是Yolov5s已经够用,m能稍微提升一点召回率,l和x的收益微乎其微,但训练时间和推理时间翻倍不止。如果你后面要部署到嵌入式设备,s是唯一合理的选择。
迁移学习的做法是,先从官方仓库下载coco预训练权重,然后冻结前几层只训后面几层,等loss稳定后再解冻全模型微调。这个做法对裂缝这种目标纹理特殊但背景语义相对简单的场景很有效,能有效防止训练初期梯度震荡把预训练学到的特征破坏掉。
# 第一步:冻结骨干网络训练,50轮 python train.py \ --data crack.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 50 \ --freeze 10 \ --name crack_freeze # 第二步:解冻全模型,继续训50轮 python train.py \ --data crack.yaml \ --weights runs/train/crack_freeze/weights/best.pt \ --img 640 \ --batch 16 \ --epochs 50 \ --name crack_finetunefreeze参数的数字代表冻结主干网络的前多少层。Yolov5s的backbone一共10层C3结构,freeze 10就是冻结整个backbone,只让head部分学裂缝的框回归和分类。这样做的理由是:预训练模型在coco上学到的底层特征——边缘、纹理、颜色渐变——对裂缝同样适用,不需要从头学;而head部分的检测头需要适应裂缝目标的极端长宽比和稀疏分布,需要充分训练。第二步解冻之后,用较小的学习率微调全部层,让backbone的特征也向裂缝数据做轻微偏移。
3.2 关键超参数逐项说明
Yolov5的超参数分布在data/hyps/hyp.scratch-low.yaml里,对裂缝检测来说,最重要的不是学习率,而是这几个:
| 参数 | 我的设置 | 作用与理由 |
|---|---|---|
| lr0 | 0.01(冻结阶段)/ 0.001(解冻阶段) | 初始学习率,冻结阶段可以大一点,解冻后必须降下来 |
| lrf | 0.2 | 最终学习率占初始学习率的比例,用余弦退火调度 |
| momentum | 0.937 | SGD动量,Yolov5的默认值就可以 |
| weight_decay | 0.0005 | 权重衰减,防止过拟合,裂缝数据量少这个值不能太小 |
| fl_gamma | 1.5 | Focal Loss的gamma,调节正负样本不平衡,裂缝目标小,背景占比极高,建议设1.5 |
| box | 0.1 | 框回归损失权重,裂缝框不好标,权重太高会让模型过度拟合标注噪声 |
fl_gamma这个参数经常被忽略。Yolov5的默认值是0,也就是不用Focal Loss。但裂缝检测的场景里,一张640x640的图可能只有几个目标框,剩下的全是背景。如果不做正负样本平衡,模型会倾向于把一切预测为背景,出现"啥都检不出来"的情况。把fl_gamma调到1.5,模型会更多的关注那些难分类的正样本,也就是细小的、对比度低的裂缝段。训练出来的模型对低对比度裂缝的召回率会有肉眼可见的提升。
3.3 训练过程要盯哪些指标
训练跑起来之后,不要只盯着终端刷屏的loss数值。Yolov5会在runs/train/目录下生成TensorBoard日志和训练曲线图,你需要关注四个东西:box_loss、obj_loss、cls_loss三条训练曲线是否同步下降;验证集上的mAP@0.5和mAP@0.5:0.95;Precision和Recall曲线的平衡点;以及PR曲线在召回率0.8附近有没有骤降。
# 训练完成后查看结果目录 ls runs/train/crack_finetune/ # 期望看到: # weights/best.pt # 验证集上mAP最高的权重 # weights/last.pt # 最后一轮的权重 # results.png # 训练曲线汇总图 # confusion_matrix.png # 混淆矩阵 # PR_curve.png # 精确率-召回率曲线 # 用自带的eval脚本输出详细指标 python val.py \ --data crack.yaml \ --weights runs/train/crack_finetune/weights/best.pt \ --img 640 \ --iou 0.5 \ --task val一个典型的正常训练过程应该是:冻结阶段前10轮loss快速下降,之后趋于平缓;解冻阶段一开始loss会有个小反弹,这是因为backbone重新开始适应数据,之后继续下降,到第30轮左右基本稳定。如果你的val loss在训练后期开始上升而train loss还在降,说明过拟合了,最直接的办法是把fl_gamma调回1.0,同时检查训练集和验证集是不是有重复图片——我踩过这个坑,数据增强里开了随机裁剪,验证集图片被裁剪出了和训练集几乎一样的区域。
4. 模型推理部署:单张图片、视频流与批量检测的写法
4.1 单张图片推理的标准写法
训练结束后,detect.py是最常用的推理入口。但实际做项目的时候,直接跑detect.py的情况不多,因为你需要把检测结果接进自己的业务系统。我在项目里一般把Yolov5封装成detector类,这样不会每次启动都重新加载模型权重。接下来用代码说明我处理的方式。
# crack_detector.py import torch import cv2 import numpy as np class CrackDetector: def __init__(self, weights_path, conf_thres=0.3, iou_thres=0.45, img_size=640): # 加载训练好的模型 self.model = torch.hub.load('path/to/yolov5', 'custom', path=weights_path, force_reload=True) self.model.conf = conf_thres # 置信度阈值 self.model.iou = iou_thres # NMS的IoU阈值 self.model.img_size = img_size # 推理分辨率 self.model.classes = [0] # 只检测裂缝类别 def detect_single_image(self, image_path): # 读取原图,保持原始分辨率用于绘制 img = cv2.imread(image_path) origin_h, origin_w = img.shape[:2] # Yolov5推理,返回结果对象 results = self.model(image_path) # 解析检测框坐标(相对原图分辨率) dets = results.xyxy[0].cpu().numpy() for det in dets: x1, y1, x2, y2 = det[:4] conf = det[4] box_w = x2 - x1 box_h = y2 - y1 # 过滤过窄的框:裂缝框极端细长时,很可能是一种误检模式 if box_w < 5 or box_h < 5: continue # 返回原始image和检测结果,供上层绘制和统计 return img, detsconf_thres是置信度阈值,低于这个值的目标会被过滤掉。裂缝检测场景建议设0.3左右,不要设成0.5。裂缝的对比度差异大,低对比度裂缝段的置信度天然就低,阈值一高就漏检。iou_thres是NMS去重的IoU阈值,因为裂缝段相邻框之间有重叠,这个值设0.45比较合适,低于0.3会把相邻的裂缝段误判成同一个目标,高于0.6又可能出现重复框。推理分辨率img_size设640是一个平衡点,再高对小裂缝的召回会更友好,但耗时上涨明显。如果你部署的设备是树莓派这类嵌入式平台,可以降到416,速度能快接近一倍,代价是小裂缝的召回率下降。
4.2 视频流和RTSP协议接入
实际工程项目里,裂缝检测不会只做离线图片,更多场景是接实时视频流:无人机挂载摄像头巡检桥梁、道路检测车顶置相机连续采集路面图像。Yolov5的detect.py支持--source直接传视频文件路径或者RTSP地址。但在代码层面复用时,一般得自己处理帧率控制和抽帧逻辑。
# rtsp_crack_detection.py 片段 import cv2 def process_stream(rtsp_url, detector, output_fps=5): cap = cv2.VideoCapture(rtsp_url) # 检查视频流是否正常打开 if not cap.isOpened(): print("无法连接视频流,检查网络或RTSP地址格式") return # 原视频帧率 src_fps = cap.get(cv2.CAP_PROP_FPS) frame_interval = max(1, int(src_fps / output_fps)) frame_count = 0 while True: ret, frame = cap.read() if not ret: break if frame_count % frame_interval != 0: frame_count += 1 continue # 用训练好的模型检测单帧 results = detector.model(frame) # 在原始帧上画框和置信度 rendered = results.render()[0] # 这里把渲染后的帧交给GUI显示或推流到后端 # 例如写入管道队列,由另一个线程做推流 frame_count += 1 cap.release()output_fps是抽帧检测的帧率,视频流连续检测对算力要求极高。一台落地RTX 3060的机器,跑Yolov5s在640分辨率下大概能到30到40FPS,但检测车高速行驶时相邻帧的裂缝几乎没变化,5FPS的抽帧率足够覆盖。这段代码里最容易被忽略的是frame_interval的计算,如果视频源是30FPS,你想按5FPS检测,就必须每6帧取一次,否则检测结果在时间轴上是错乱的,后面做裂缝定位拼接时位置会漂移。
4.3 批量检测与结果导出
批量检测一个巡检目录下的所有图片并按原路径保存结果,这是日常工作中使用最频繁的功能。官方detect.py可以跑批量检测,但输出目录是扁平化的,当你要按相机编号、桩号、日期组织结果时,扁平目录就很碍事。我通常用detect.py的批量模式加自定义的标签映射来适配业务要求。
# 批量检测目录下所有.jpg图片 python detect.py \ --weights runs/train/crack_finetune/weights/best.pt \ --source ./field_images/ \ --img 640 \ --conf 0.3 \ --iou 0.45 \ --save-txt \ --save-conf \ --project ./detect_results \ --name field_20240618--save-txt会把每张图的检测结果保存为同名txt文件,内容和训练标签的格式一致:类别、坐标、置信度。--save-conf会把置信度也写进txt。这两个参数对后续的数据分析很重要:你可以直接用脚本统计任意一个巡检批次里裂缝的总数、平均置信度、最大裂缝宽度(近似用框高度替代)。--project和--name是控制输出目录的方式,结果会存放在./detect_results/field_20240618/labels/和./detect_results/field_20240618/下,class.jpg是渲染了检测框的效果图。
批量检测一个容易被忽略的问题是显存管理。如果你的巡检图像库有上万张图,Yolov5预测时是累积批量推理的,默认--batch-size是32,意味着每次加载32张图进显存。一旦图片原始分辨率过大,预处理阶段缩放到640仍然会占大量显存。我的做法是先把批量图片的路径分批,每批1000张图跑一次detect.py,输出到带批次号的目录,跑完再合并。这个习惯帮我避免了好几次程序中途崩溃。
5. 裂缝检测落地避坑:七个反复踩的坑
5.1 标注矩形框与裂缝走向角度不一致
现象:训练出的模型在验证集上mAP挺高,一到实际图片上就出现"斜裂缝检不出,水平裂缝有重复框"的情况。
原因:标注yolo格式的矩形框时,框的方向必须是水平的。有些标注工具导出的框是带角度的旋转矩形框,Yolov5不认旋转框,会强行取外接水平矩形。对于倾斜45度以上的裂缝,水平外接框里大部分区域其实是背景,模型学到的特征是"一条斜向纹理加两边混凝土",泛化性极差。
解决:标注时尽量用正矩形框,让框的短边垂直裂缝走向。如果裂缝在画面上是斜的,可以把图片先旋转到裂缝接近水平或垂直再标注,训练时模型会通过flipud、fliplr增强学到各个方向的特征,不需要人为把旋转框也标注进训练集。
5.2 loss降不下去,且伴随NaN
现象:训练到第10轮左右,loss突然变成NaN,或者loss值一直维持在3以上不降。
原因:最常见的是学习率过大导致梯度爆炸;其次是标注文件里出现归一化坐标小于0或大于1的异常值,Yolov5在计算IoU时出现除以零或负数开根号;还有一种情况是某张图片对应的txt标注文件为空文件但images里存在对应图片。
解决:先检查labels目录中txt的行数和非空文件数量是否与images一一对应。
# 找出缺少标注的图片或空标注文件 find crack-data/labels/train -name "*.txt" -size 0 | head -20 # 有输出的话,删除对应的images里的同名图片,或者补标如果是梯度问题,把冻结阶段的学习率从0.01降到0.005重试。如果还有NaN,检查数据增强里的hsv参数,饱和度扰动超过0.8以上时,灰度图转换容易出现饱和度为0或亮度为0的极端像素,造成梯度里的分母异常。
5.3 训练集和验证集图像重合
现象:训练曲线一切正常但mAP高得离谱,验证集上准确率超过0.98,一换现实场景图片立刻掉到0.5以下。
原因:很多人做裂缝数据集时是从同一个视频里抽帧出来的,相邻帧之间背景几乎一样。划分成训练集和验证集时如果用了随机划分,同一段裂缝的不同帧会同时出现在两边,模型等于直接背了答案。
解决:划分数据集前必须先按"采集场景"分组,同一个视频、同一个桥墩、同一面墙的图片只能进训练集或验证集之一。我习惯的方式是先把所有图片按所属文件夹或拍摄时间段归类,再一层一层抽取。
5.4 桥梁裂缝过细,640分辨率下完全丢失
现象:室内试件测试正常,一到室外桥梁上就检不出裂缝。仔细看检测图片,裂缝在640缩略图上肉眼几乎看不见。
原因:桥梁裂缝宽度经常是0.2毫米级别,按常规拍摄距离,裂缝在画面中只有2到3个像素宽。Yolov5在640分辨率下,一个2像素宽的目标经过5次下采样,到特征图上的响应值已经接近噪声水平。
解决:拍摄阶段尽量贴近结构表面,保证裂缝在原始图片上的宽度在10个像素以上。如果已经是拍好的图片,则把训练和推理的分辨率同时提高到960以上。这个操作会延长训练时间约一倍,但裂缝的召回率提升幅度很大。有一个捷径:路面裂缝检测可以先在1280分辨率下检测一次,再把未检测区域切片成640大小进行第二次检测,这样既有高召回率又可以控制单次推理耗时。
5.5 模型把施工缝、伸缩缝当成裂缝
现象:检测结果里出现大量规则的水平长框,画在桥梁伸缩缝或路面施工缝上,但真正的开裂区域反而没有框。
原因:施工缝本质上是人为预留的拼接缝隙,形态和裂缝几乎一样,区别在于裂缝通常是局部断续的、宽度不均匀的,而施工缝是一条规则通长线。模型学到的是"线状深色区域=裂缝",无法区分结构缝和病害缝。
解决:数据层面在训练集里增加带施工缝的负样本图片,标注时不标施工缝,让模型看到"有这个特征但不标框"的样本。后处理层面过滤极端长宽比的框,裂缝段的正常长宽比在3:1到10:1之间,施工缝常常超过20:1,可以在后处理时对长宽比超过阈值的框做二次检查。
5.6 室外光照变化导致大量漏检和误检
现象:晴天中午检测效果良好,到傍晚或树荫下,漏检率升高到30%以上,而且误检区域多集中在阴阳交界处。
原因:裂缝检测学的主要特征是"局部像素灰度值比邻域低且呈线状延伸",在强光照下裂缝和背景对比度很高,模型很自信;但一到阴影区域,混凝土表面本身的明暗变化就淹没了裂缝的灰度差异,模型特征失效。树荫下的斑驳光影也会形成线状纹理,诱发误检。
解决:训练阶段加大hsv_v明度扰动到0.5以上,好让模型见过更多亮度分布;推理阶段对暗光图片先做一次CLAHE自适应直方图均衡化,把局部对比度拉起来再进模型。这两个措施结合起来能把端侧场景的漏检率降到个位数。
5.7 部署环境没有GPU时推理慢到不可用
现象:代码在带GPU的开发机上跑通了,换到客户的笔记本上(纯CPU)跑,单张图片推理时间超过5秒,视频流根本带不动。
原因:Yolov5默认开FP16推理和GPU分支,CPU上跑FP16不兼容会退回FP32,速度急剧下降。另外纯CPU机器没有CUDA上下文,每次推理时torch加载权重和建图的开销会重复计算。
解决:CPU推理时强制使用FP32推理,关闭所有能关闭的预处理分支,并且把模型转成torchscript格式。这样算力有限的设备上能压到1秒左右。
# CPU推理优化片段 import torch model = torch.hub.load('path/to/yolov5', 'custom', path='best.pt', force_reload=True) model.cpu() model.half() # CPU上不要用half,会把模型转成FP32 # 用torchscript加速以减少图构建开销 model = torch.jit.load('best.torchscript.pt', map_location='cpu') model.eval()6. 裂缝模型再进一步:剪枝、量化和半精度部署验证
模型从训练到能交付,中间还有一道部署验证的工序。我自己的做法是:先把best.pt转成torchscript和ONNX,分别在CPU和GPU上做几组对比实验,看精度损失和速度收益是否匹配项目要求。裂缝检测应用里模型大小不是首要约束,但推理延迟是。下面这三个手段是我在项目里反复用到的。
第一是模型剪枝。Yolov5s只有700多万参数,对裂缝这个单类任务来说冗余度高达60%以上。使用torch的pruning接口对C3结构中的卷积层按L1范数剪枝,裁剪比例从0.3开始,逐次递增0.1,每次剪完在验证集上跑一次mAP,掉点超过2%就回退到上一档。我的经验是剪到0.5左右,模型大小从14MB降到9MB,推理速度提升接近35%,mAP几乎不降。
第二是INT8量化。训练后量化不需要额外数据集,直接拿200张验证集图片做校正集即可。量化后的模型在GPU上没有明显收益,但在CPU上推理速度可以再提升一倍。要注意的是,量化后的模型在低对比度裂缝上容易丢召回率,交付前必须在实际巡检图片上重新评估。
第三是半精度FP16推理。如果部署机上显卡支持FP16,是最省事的加速手段——只要在detect.py里加--half参数,或者在上述封装类里对模型调用model.half()。FP16推理对精度的影响在裂缝检测上几乎察觉不到,但显存占用减半,速度提升明显。
# 转torchscript和ONNX python export.py \ --weights runs/train/crack_finetune/weights/best.pt \ --img 640 \ --batch 1 \ --include torchscript onnx \ --half # 导出FP16版本给GPU部署使用 # 转INT8量化模型需要额外一步 python export.py \ --weights runs/train/crack_finetune/weights/best.pt \ --img 640 \ --batch 1 \ --include onnx \ --int8转完格式之后一定要做精度对照。用同一批真实巡检图片,在原始PyTorch模型和导出模型上分别跑一遍检测,记录每张图的检测框数量和置信度分布,偏差超过5%就要回退检查是不是量化校正集选得不对。我在做量化时试过用训练集图片做校正,效果不如验证集,表现为低置信度的裂缝目标全部消失,后来换成验证集后恢复了。这个细节很少有人提及,但确实能影响交付质量。
最后提一个习惯:永远保留训练完的best.pt和last.pt,最好连训练时用的超参数文件一起归档。裁剪、量化或者换设备重新部署的时候,直接拿best.pt重新导出,不要拿一个已经量化过一次的模型再去做二次转换。量化损失是不可逆的,二次叠加会让精度雪崩。我有一年做路面检测项目时,为了图省事拿量化后的onnx又转了一遍torchscript,结果交付现场误检爆炸,最后重新从best.pt走完整流程才稳住。希望这个教训能帮你避开同样的坑,希望帮到你。
本文还有配套的精品资源,点击获取