改进YOLOv5实现裂缝检测:SE注意力融合BiFPN与TensorRT部署
简介一份基于改进YOLOv5模型的高速道路裂缝检测本科毕业论文面向计算机视觉、目标检测方向的毕业设计学生用于参考完整论文结构、研究思路与实验设计。文档以YOLOv5为基础围绕模型改进、数据集构建、预处理、训练与结果对比展开涵盖引言、技术综述、数据集与实验、模型设计、实验分析、结论展望等章节能够帮助读者梳理裂缝检测选题的论文写作脉络。资源为单个docx文档包体大小约30KB内容包含目录与正文核心章节较适合需要快速获取论文框架和行文范式的读者。目前已有433人学习浏览属于轻量级选题参考资料。文档中不仅介绍了YOLOv5模型原理与传统检测方法还提出了优化网络结构、损失函数或训练策略的思路在实验部分给出数据集介绍、实验设置、mAP/召回率等评估指标并与现有方法对比讨论。阅读后可以了解从模型改进到实验验证的完整闭环为撰写同类型毕业论文提供可复用的章节组织方式和专业表述。1. 为什么裂缝检测要选YOLOv5并做结构改进高速公路路面裂缝往往只有 2 到 4 像素宽在 1280×720 的巡检图像上占比极小却要让模型把它和车道线、伸缩缝、轮胎印、水渍区分开。直接跑一版 YOLOv5s 会发现裂缝的 recall 能到 90%但误检率也很高沥青路面的随机纹理被当成裂缝真正细长的龟裂还经常被拆成好几段。这个现象的本质是通用目标检测的默认配置并不适配线状小目标。YOLOv5 的 CSPDarknet 主干在高层特征里保存了太多语义信息而裂缝依赖的是中低层的边缘和连续性响应锚点预设也偏向宽高比接近 1 的物体。所谓“改进YOLOv5”要做的事情第一步不是换更重的模型而是把注意力机制放在浅层特征、把特征融合改成适合长条形目标的形式再针对裂缝噪声调训练策略。这篇文章面向做过目标检测但没真正碰过道路病害的工程师我把数据准备、结构改法、训练参数和部署验证串成一条可复现的路线。2. 基于YOLOv5的裂缝检测数据格式与环境配置2.1 裂缝数据集按YOLOv5格式组织的最小目录结构YOLOv5 训练接口对数据目录的约束很固定不按它的规则来train.py会在读取 labels 时报 index 越界或空样本错误。最常见做法是把裂缝数据集整理成下面这样的镜像结构crack_dataset/ ├── images/ │ ├── train/ │ │ ├── crack_train_0001.jpg │ │ └── ... │ └── val/ │ ├── crack_val_0001.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── crack_train_0001.txt │ │ └── ... │ └── val/ │ ├── crack_val_0001.txt │ └── ... └── data.yamlimages 目录的命名为什么必须和 labels 一致因为train.py内部是拿图片路径去替换images为labels、替换.jpg为.txt来定位标注文件。如果改过目录层级就破坏了这层隐式映射。我一般会把原始无人机巡检影像按路段先切成 640×640 的瓦片再放入 train 和 val切片能让高分辨率原图里的细小裂缝在输入尺度上更容易被识别。2.2 data.yaml 的编写要点与标注字段含义标注用常见的 LabelImg 或 X-AnyLabeling 导出成 YOLO 格式保存的 txt 内容表现形式是class x_center y_center width height坐标全部归一化到 0 到 1 之间。裂缝框宽高比通常非常大标注时不要紧贴裂缝边缘画框留出几个像素的外边距反而更能稳定训练。data.yaml最精简版本train: crack_dataset/images/train val: crack_dataset/images/val nc: 1 names: [crack]上面的nc是指类别数这里只有裂缝一类names的顺序要和你标注文件里的 class id 对得上否则训练时类别标签错位损失曲线看起来正常但预测结果完全混乱。我一般还会加入test字段指向独立的抽检目录用来跑最终验证。2.3 环境配置与首次训练的最小命令YOLOv5 官方仓对环境的要求是 Python 3.8 和 PyTorch 1.8。裂缝检测训练不需要太新的显卡显存 8GB 以上即可跑 640 输入、batch 16 的 s 模型。配置环境的常见做法git clone 可用的YOLOv5仓库地址 # 源码获取 cd 仓库目录 pip install -r requirements.txt python train.py \ --img 640 \ --batch 16 \ --epochs 200 \ --data crack_dataset/data.yaml \ --weights yolov5s.pt--img 640是输入图像边长原始 2048 分辨率切片后直接用 640 训练能保留裂缝拓扑细节并控制显存成本--weights yolov5s.pt指定加载预训练权重官方权重在 COCO 上训过能提供底层纹理特征迁移到裂缝域之后收敛时间会明显缩短。首次训练只需要确认 loss 曲线掉到 0.05 以下且 val 集 mAP 不变差就说明环境与数据链路是通的。3. 改进YOLOv5的注意力机制与多尺度特征融合3.1 在 C3 模块中嵌入 SE 注意力yolov5s_cse.yaml标准 YOLOv5s 的主干由多个 C3 模块串联特征提取能力没问题但各通道权重是均等的。裂缝在颜色上和沥青背景几乎一致信息只存在于边缘与纹理灰度梯度里默认模型会被大量平坦路面干扰。给 C3 模块内部加一个 SESqueeze-and-Excitation分支是改进 YOLOv5 最温和、也最容易回退的结构调整。SE 先对空间维度做全局平均池化压缩成通道描述再用两个全连接层重新标定各通道权重等于告诉网络哪些特征通道对裂缝更敏感。修改models/common.py加入一个C3SE类import torch import torch.nn as nn class SEBlock(nn.Module): def __init__(self, c, r8): super().__init__() self.squeeze nn.AdaptiveAvgPool2d(1) self.excitation nn.Sequential( nn.Linear(c, c // r), # 压缩比例 r8降低参数量 nn.ReLU(inplaceTrue), nn.Linear(c // r, c), # 还原到原通道数 nn.Sigmoid() ) def forward(self, x): b, c, _, _ x.size() y self.squeeze(x).view(b, c) y self.excitation(y).view(b, c, 1, 1) return x * y.expand_as(x) class C3SE(nn.Module): def __init__(self, c1, c2, n1, shortcutTrue, e0.5): super().__init__() c_ int(c2 * e) self.cv1 Conv(c1, c_, 1, 1) self.cv2 Conv(c1, c_, 1, 1) self.cv3 Conv(2 * c_, c2, 1) self.m nn.Sequential(*(Bottleneck(c_, c_) for _ in range(n))) self.se SEBlock(c2) def forward(self, x): return self.se(self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)))上面的r8控制压缩比例值越小保留的通道信息越多但参数量和计算量随之上升。实际测试中裂缝检测常用 r4 到 r16 之间我建议从 r8 起步调参。shortcut参数在原 C3 里用来控制残差连接改造时要注意保持结构一致性否则加载预训练权重会出现 shape 不匹配。随后在models/yolov5s_cse.yaml中把backbone末尾两个 C3 替换成 C3SEbackbone: - [-1, 1, Conv, [64, 6, 2, 2]] - [-1, 1, Conv, [128, 3, 2]] - [-1, 3, C3, [128]] - [-1, 1, Conv, [256, 3, 2]] - [-1, 6, C3, [256]] - [-1, 1, Conv, [512, 3, 2]] - [-1, 9, C3SE, [512]] - [-1, 1, Conv, [1024, 3, 2]] - [-1, 3, C3SE, [1024]] - [-1, 1, SPPF, [1024, 5]]注意 yaml 中C3SE的写法必须和 common.py 里的类名完全一致YOLOv5 的模型解析器会以这个字符串去globals()里查找类。替换深层的 C3 而不是浅层是因为裂缝的细长线条在底层已经由小感受野捕获高层通道更需要重新标定来抑制背景响应。3.2 BiFPN 替换 PANet加权特征融合对裂缝分割的影响标准 YOLOv5 neck 用 PANet 做自上而下和自下而上的双向融合对不同尺度特征直接相加。问题是浅层特征图分辨率高但不含语义信息高层特征图有语义但裂缝位置已经模糊简单相加会稀释目标响应。BiFPN 的做法是给每个输入特征学一个可训练的权重让网络自己判断在不同路面环境下应该信任哪一层。修改 neck 部分为加权融合结构最实用的改法是把models/yolov5s_cse.yaml中 head 部的 Concat 换成 WeightedConcathead: - [-1, 1, Conv, [512, 1, 1]] - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 6], 1, WeightedConcat, [512]] - [-1, 3, C3, [512]] - [-1, 1, Conv, [256, 1, 1]] - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 4], 1, WeightedConcat, [256]] - [-1, 3, C3, [256]]WeightedConcat 的核心是一个可学习的 softmax 权重数组前向时对输入特征图逐元素加权相加。相对于直接 sum 的不可解释性这个模块让调试更有方向训练完成后打印权重能看出网络更依赖 P3 还是 P4 的输出。如果 P4 权重占比过低说明裂缝目标在中等尺度上的语义信息不足可以考虑增加一层 C3 的深度。BiFPN 的完整版本还包括跨尺度连接和跳层但工程上引入过多额外算子会拖慢边缘设备推理速度我通常只做加权 Concat 这一步。3.3 改进结构的参数量与感受野边界改完结构不代表一定变好必须量化收益。YOLOv5 的yolov5s_cse.yaml在训练时可以通过--verbose参数打印模型的参数量。SE 模块增加的全连接层对整体参数量的影响很小s 模型从 7.2M 会增加到 7.6M 左右推理延迟在 GPU 上几乎可以忽略。真正要关注的是感受野匹配裂缝的宽度决定了有效感受野不需要太大而裂缝的连续长度要求感受野在长轴方向延伸。为什么标准卷积难以做到因为正方形卷积核覆盖的区域对细长目标来说大部分是背景这也是直接加大输入分辨率不总是有效的原因之一。改进 YOLOv5 的更进一步的思路是仿照可变形卷积的思想让卷积核采样点沿裂缝方向偏移但这部分通常只能通过修改 C3 中的 Bottleneck 实现普通用户可以先从 SE BiFPN 组合开始满足多数高速公路沥青路面的裂缝检测需求。4. 改进YOLOv5裂缝检测的训练超参数与损失函数调试4.1 裂缝场景的标注策略与数据增强裂缝检测问题最典型的表现是前景占比极低一张 640×640 的图里裂缝像素占比往往不到 0.5%这会导致模型从一开始就偏向背景。标注策略上长裂缝一段一段标成多个框比整条标成一个框更能提升 recall因为一个框内包含的非裂缝背景少特征更好学。数据增强方面YOLOv5 内置的 mosaic 和 mixup 对裂缝效果反而偏激默认 1.0 的 mixup 会把两张图透明叠加裂缝灰度信息被摊薄。修改data/hyps/crack_hyp.yamlhsv_h: 0.0 hsv_s: 0.0 hsv_v: 0.2 degrees: 10.0 translate: 0.1 scale: 0.3 shear: 5.0 perspective: 0.0 flipud: 0.5 fliplr: 0.5 mosaic: 0.8 mixup: 0.2hsv_h和hsv_s设为 0.0 是因为沥青路面的色彩信息几乎不参与裂缝辨识调色相只会增加无意义的数据多样性mosaic降到 0.8太高会让裂缝截断严重。flipud保留是因为裂缝在垂直方向的形态也多样别只做水平翻转。4.2 训练命令、batch 与学习率的配合改进后的模型训练命令与官方基线并无太大差异关键是学习率参数要和 batch size 联动。官方推荐lr00.01对应 batch 16如果显卡显存不足把 batch 降到 8学习率也应该同步下调到 0.005 左右否则早期梯度更新步子太大权重容易发散。推荐的一组稳定超参数参数值说明img640输入尺寸显存充足可试 768batch16与 lr0 联动调整lr00.005初始学习率cosine 调度会逐步衰减lrf0.01最终学习率相对比例warmup_epochs3.0预热轮数稳定收敛weight_decay0.0005正则强度防止裂缝噪声过拟合训练时用python train.py \ --data crack_dataset/data.yaml \ --cfg models/yolov5s_cse.yaml \ --weights yolov5s.pt \ --hyp data/hyps/crack_hyp.yaml \ --epochs 300 \ --batch-size 16 \ --img 640 \ --patience 30--patience 30是验证集 mAP 连续 30 轮没有提升就提前终止能省下不必要的算力。yolov5s.pt 原本的类别输出有 80 维改成单类别后模型的检测头会自动重置这里很容易忽略其实不用手改权重文件的类别维度训练代码会重新初始化对应层。4.3 前景损失不平衡与类别权重调优单类裂缝的核心矛盾不是类别间不平衡而是前景与背景的极端失衡。YOLOv5 的 box 损失采用 CIoU它对小目标的梯度贡献天然弱于大目标。一个常见的改法是调整loss.py里类别损失和框损失的系数或者直接对置信度损失做 focal loss 处理。最直接的变化在热词“yolov5超参数”里就能体现训练阶段检查train_batch0.jpg这张可视化图就能知道增强是不是把裂缝切成了无法辨认的碎片。# 在 utils/loss.py 的 ComputeLoss.__init__ 中找到置信度损失权重 self.balance {3: [4.0, 1.0, 0.4]} self.cp, self.cn 1.0, 0.0 # 正样本权重 1.0负样本权重 0 # 将上面改为 self.cp, self.cn 1.5, 0.0这里的cp调高代表让模型更关注正样本的预测置信度代价是可能把非裂缝物体误报成裂缝。我的经验是cp1.5配合边框回归的 IoU 阈值从 0.2 调到 0.3能同时缓解低置信度误检又不会丢失真正细小的裂缝。如果训练后训练集 loss 与验证集 loss 之间的 gap 持续增大优先看增强参数里的scale裂缝标注框被等比放大或缩小后目标本身的宽高比会在 neck 特征层发生偏移。5. 裂缝检测改进模型的验证指标与TensorRT部署5.1 mAP、裂缝级recall与F1的对比口径常规 mAP0.5 对裂缝检测不够严格因为一个连续裂缝被拆成两段识别IoU 照样能过 0.5。我会建议额外统计以目标为单位的 recall将一张图上所有预测框合并成连通域只要这个连通域与任意标注框的交集大于标注框面积的 30%就计为一次命中。改进 YOLOv5 后应在 Head 输出的特征层的 P3浅层上算一次小目标漏检率。训练结束后的验证命令python val.py \ --data crack_dataset/data.yaml \ --weights runs/train/exp/weights/best.pt \ --img 640 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --task val--conf-thres 0.25意味着置信度低于 0.25 的框被过滤道路巡检场景建议只在最终部署时提高这个值评估阶段降到 0.1 能更真实反映模型能力。--iou-thres是 NMS 的 IoU 阈值裂缝框往往狭长过低的阈值会把相邻裂缝段合并从而拉低 recall 评估的准确性。5.2 ONNX 导出与 TensorRT 推理的最小流程改进后的模型如果包含自定义C3SE算子直接导出 ONNX 通常没问题SE 里全是标准卷积和全连接层。但如果在第 3 章引入了可变形卷积这类自定义算子导出时要专门处理算子映射。目前最稳妥的部署方式是先转 ONNX 再转 TensorRTpython export.py \ --weights runs/train/exp/weights/best.pt \ --include onnx \ --img 640 \ --opset 12 trtexec \ --onnxbest.onnx \ --saveEnginebest.engine \ --fp16 \ --minShapesimages:1x3x640x640 \ --optShapesimages:4x3x640x640 \ --maxShapesimages:8x3x640x640--opset 12是兼容性和表达能力平衡比较好的版本trtexec的动态 batch 配置要注意 Jetson 平台上的显存限制。FP16 精度在裂缝检测里损失很小因为裂缝的边缘响应是强梯度信号量化误差不容易淹没。得到 engine 文件后实际推理时输入要做 letterbox 预处理并同步记录缩放比例和 padding 偏移否则框坐标回原图时整体错位最常见的错误就是推理代码忘了把框按ratio还原缩小。5.3 断缝修补与连续帧去抖高速巡检车连续拍摄的视频流里同一裂缝在相邻几帧会被检测框反复横跳。此时把检测结果输入一个轻量级跟踪池按框中心距离与长宽比做最近邻匹配能显著提升有效告警。先在单帧上做形态学闭运算核宽度 3、长度 15再对连续 5 帧的命中结果做投票这种做法是业内成熟的降噪技巧。如果 TensorRT 部署的 batch 固定为 4不建议把跟踪逻辑放进引擎内部图像预处理和跟踪都放在外部 C 或 Python 包装层便于后续替换改进完的模型检测算法。本文还有配套的精品资源点击获取