ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YOLOv8-seg改进的轮胎损伤分割系统:从训练到部署全解析

YOLOv8-seg改进的轮胎损伤分割系统:从训练到部署全解析

1. 项目全貌:这套轮胎损伤分割系统到底解决什么问题

1.1 轮胎质检里的真实痛点

做视觉这行的人,应该都接过类似需求:“能不能把轮胎上的裂纹数出来,鼓包圈出来”。我理解完现场情况后发现,这已经不是简单检测框能解决的事。裂纹、磨损、割伤、嵌杂质,这些损伤在图像里形状不规则,尤其是细裂纹,可能只有几个像素宽,检测框很容易丢失边缘信息。轮胎损伤分割系统就是做像素级判断,把损伤区域完整抠出来,输出轮廓,业务方可以直接拿到面积、周长、位置数据。

传统轮胎质检场景多数靠人工目检。工人盯着传送带上的轮胎,长时间重复劳动,眼睛很容易疲劳。细小裂纹在人眼疲劳期非常容易漏检,而且不同检验员的标准很难完全统一。换成深度学习实例分割之后,至少可以得到一个相对稳定、可量化的结果。分割和普通目标检测还有个很大的区别:检测框只告诉你“这里有伤”,分割Mask能告诉你“伤有多大、什么形状”,这部分信息对后续缺陷等级判定和自动剔除非常有用。

所以这套系统的定位很明确:给工业视觉项目、算法课程设计、论文实验提供一套开箱即用的基础。整个项目围绕YOLOv8-seg展开,并加入seg-aux、C2f-Faster等多个改进点,同时整理了标注好的数据集、一键训练脚本和Web前端展示界面。整个过程不需要从零写网络结构。

1.2 项目的整体构成与使用场景

再具体说一下交付内容。源码部分包含完整的自定义模型定义、训练脚本、评估脚本、推理封装。数据集部分包含整理好的轮胎损伤图片以及对应的分割标注,覆盖了常见损伤类型,比如磨损、裂纹、鼓包、割伤、金属异物嵌入。部署教程部分包含从环境安装到服务化部署的完整步骤。Web前端展示部分让你可以上传一张轮胎照片,直接在浏览器里看到分割出来的Mask叠加在原始图上。

适合谁来参考?第一,工业视觉工程师,想把深度学习算法落地到质检设备上;第二,做机器视觉相关毕业设计或论文实验的学生,这里面的改进点和实验对照可以直接作为研究素材;第三,刚接触实例分割的初学者,可以通过这套完整链路理解数据、训练、部署的流程,不用陷在环境配置里出不来。我建议你把这份内容当成一个项目模板,而不是固定成品,具体图像数据、类别、网络结构都可以按自己的场景替换。

2. 模型选型与改进点拆解:为什么是YOLOv8-seg

2.1 实例分割方案怎么选

工业实例分割能选的方案不少。老牌的是Mask R-CNN,两阶段方法精度有保障,速度就比较吃亏,产线要求高帧率时很难撑住。SOLO系列不依赖检测框,直接分割,但通用场景下边缘质量需要仔细调参。相比之下,YOLOv8-seg是平衡得最好的那一档:它复用YOLOv8检测框架的特征提取能力,在C2f模块之后接了一个分割头,同时输出目标框和Mask,训练和部署都有成熟生态支撑。

轮胎损伤场景还有一个特殊性:大量损伤是细小目标、低对比度目标。比如轮胎侧面的细裂纹,背景复杂、边缘模糊,如果网络只在常规尺度上做特征融合,这类目标很容易被忽略。YOLOv8-seg使用了多尺度特征金字塔,配合改进点里的辅助分割头、注意力模块,可以从不同层面强化小目标特征。这也是整套系统的基础架构选择没有采用复杂二阶段模型的原因:要落地,速度、精度、部署便捷度必须一起考虑。

当然,任何选型都有取舍。如果项目不要求实时性,Mask R-CNN仍然可以参考,这在对比实验里也有价值。但从产线部署角度看,YOLOv8-seg的显存占用、推理时延、ONNX/TensorRT导出顺畅度,都更适合工程化。所以我把主线放在了YOLOv8-seg,而不是一个封闭的自研模型。

2.2 关键改进点原理拆解

先讲seg-aux。这个名字简单理解就是“辅助分割头”。主分割头用深层特征输出最终Mask,辅助分割头用浅层特征计算一份额外的损失。浅层特征保留了更多空间细节,对裂纹这种边缘精细的目标很有帮助。训练时主头和辅助头一起参与损失计算,推理由主头完成,所以不会增加线上推理负担。类似做法在姿态估计、深度估计里很常见,本质上是给学生网络加了一个“老师”。

再说C2f-Faster。YOLOv8里C2f模块是基础组成,C2f-Faster把它替换成轻量化卷积组合,典型思路是引入部分卷积,只对部分通道做卷积,其余通道直接短路,减少冗余计算,同时保持感受野。轮胎表面纹理相对固定,不像开放世界图像那么复杂,轻量化带来的精度损失很小,但推理速度提升明显,对边缘设备部署很划算。

剩下的改进点大致可以分几类:注意力类、检测头类、分割头类、训练策略类。注意力类的EMA、CBAM、SE等,作用是引导网络把权重集中在损伤区域;检测头类包括增加小目标检测层,或者将检测头解耦;训练策略类包括自动锚框、EMA、混合精度、EMA权重平均。你不能把几十个改进点一次性全堆进去,因为能登上期刊的改进模型通常是“主模块改造+辅助模块增强”的组合,而不是模块接龙。针对轮胎损伤,我实测下来稳定性比较好的组合是:C2f-Faster做骨干轻量化,seg-aux做分割监督,外加一个注意力模块提升小目标响应。

2.3 改进点的模块化管理方式

50多个改进点如果都平铺在代码里,后续维护会非常煎熬。我设计了一套模块化逻辑:每个改进点独立成文件,模型配置用字符串指定。比如在yaml里写backbone模块名或者head模块名,训练脚本加载配置后动态组装网络。

一份示意模型配置大概是下面这个路子,实际字段以源码为准,但核心思想是配置驱动:

# 示意:yolov8-seg-c2ffaster.yaml(具体结构字段需对应源码实现) backbone: - [-1, 1, Conv, [64, 3, 2]] - [-1, 1, C2f_Faster, [128, True]] - [-1, 1, Conv, [256, 3, 2]] - [-1, 1, C2f_Faster, [256, True]] head: - [-1, 1, SegAux, [nc]] - [-1, 1, Detect, [nc]]

这样做的好处非常明显:做消融实验时,不再需要复制一整个模型文件,只需在配置里换模块名。想验证EMA注意力模块的效果,把backbone里的某个C2f替换成带注意力变体,训练一次对比mAP即可。对发论文来说,模块化能保证实验结果可复现,不会出现“明明改了一行,训练结果解释不了”的尴尬。

3. 数据集准备:从采图到标注,最花时间的环节

3.1 轮胎损伤数据怎么收集和整理

做工业视觉项目,数据问题永远比模型问题更让人头疼。轮胎损伤形态差异很大,有的裂纹细得像头发丝,有的鼓包轮廓很大,有的割伤边缘是撕裂状。即使是有公开数据集,也很难完全匹配实际产线上看到的情况,所以我一向建议以自采数据为主,公开数据为辅。

采集的时候要注意光照和角度。轮胎表面是曲面加纹理,反光严重,同一个伤在不同光源下表现完全不一样。实际项目里,如果只开顶光,某些低洼裂纹会因为阴影被误判成损伤边缘。我建议至少覆盖两种光照:环形光拍常规胎面,侧光拍侧面细小裂纹。图像分辨率也不能一刀切,胎面可以用较高分辨率,胎侧受相机安装角度限制,常常需要覆盖更大视野。尽量在采集时记录损伤类型和等级,后续标注会轻松很多。

数据量方面,常用的原则是每个类别至少300张以上带标注样本,类别越多,数据量越要加大。如果损伤样本本身很少,先用数据增强扩充,再考虑合成样本。基础增强我一般用翻转、旋转、HSV扰动、随机缩放和Cutout。需要提醒的是,方向性很强的损伤(比如沿胎纹方向的裂纹)不能随意旋转90度或180度,容易扭曲语义,建议做小范围角度扰动,比如±15度。

3.2 标注格式、工具和目录结构

分割标注我推荐先用labelme这类工具画多边形,然后转成YOLO-seg格式。YOLO-seg的标签是一行表示一个目标:类别编号加一组归一化坐标点,按顺序连起来就是多边形轮廓。目录结构如下:

dataset/ images/ train/ val/ labels/ train/ val/

标签示例,一行代表轮胎裂纹的一个实例:

0 0.112 0.247 0.135 0.281 0.176 0.293 0.204 0.269

坐标都归一化到0到1之间,解析时乘以图像宽高就是像素坐标。标注过程里最重要的是统一标准。裂纹边缘模糊,两个人画的轮廓可能差几个像素,对模型训练的干扰不大,但如果一类目标时有时无、边界随意,模型就会学得很混乱。我一般会让参与标注的人先看一遍标准图例,再抽20%的可视化复核,把误标、漏标的图像重新返工。

类别不平衡也是轮胎项目的常见问题。磨损样本可能很多,鼓包样本很少。训练时如果直接跑,模型会对高频类别过拟合,低频类别AP值很难看。处理办法有几种:少样本类别过采样、复制增强、使用带权重的损失函数。我实际中最常用的是先统计类别分布,再给少样本类别适当增加增强倍数,比如鼓包图像旋转、缩放多做几份。

4. 训练链路与一键训练脚本

4.1 环境准备

训练环境不用太复杂,Python 3.9以上,PyTorch 2.0以上,ultralytics库,外加labelme做标注、opencv做图像处理。建议用conda建独立环境,避免项目之间依赖打架。

装好之后要确认CUDA是否可用,否则训练速度会慢到让人怀疑人生。可以用:

python -c "import torch; print(torch.cuda.is_available())"

输出True再继续。图像分辨率太低或GPU显存不够时,可以先小分辨率跑通流程,再提高精度。

4.2 数据配置和模型配置

数据配置是一个yaml文件,核心内容是数据目录和类别名。拿这个轮胎项目举例:

path: dataset/ train: images/train val: images/val names: 0: wear 1: crack 2: bulge 3: cut

模型配置则决定你训练哪个改进结构。为了避免每次改模型都去翻源码,我把改进点都做成了配置字符串,训练脚本通过解析yaml来组装网络。在前面2.3小节已经给过示意,实际操作时只需要保证对应模块已经注册进源码的模型定义里。

4.3 一键训练脚本怎么设计

“一键训练”听起来高大上,其实就是把容易出错的流程固定下来。我习惯写一个train.py,把数据路径、模型配置、超参数都暴露成命令行参数,内部再做检查:数据目录存在吗?类别数和模型输出层匹配吗?GPU能分配吗?检查通过后调用训练入口。

python train.py \ --data wheels.yaml \ --model yolov8-seg-c2ffaster.yaml \ --batch 8 \ --epochs 200 \ --imgsz 640 \ --optimizer AdamW

这里讲一下参数怎么选。训练轮数常规是100到300,数据量少时轮数太少了学不到位,太多了容易过拟合,建议先跑100轮看loss曲线走势。图像尺寸默认640,但轮胎图像里小裂纹非常多,把imgsz提高到960往往能明显提升小目标召回,代价是显存占用和训练时间上升。

显存不足是新手最常见的坎。实测下来,8G显存跑YOLOv8-seg,imgsz取640时batch设成4比较稳;12G显存可以跑到8;24G显存能跑到16左右。如果显存实在不够,又不改分辨率,可以用梯度累积来模拟大batch,比如实际batch为4、累积4步,等效batch就是16。注意要在脚本里区分清楚,否则学习率的设置会按等效batch和你实际batch不一致导致收敛异常。

训练过程中的监控也很关键。只看总loss不够,要分别看box_loss、seg_loss、cls_loss。如果seg_loss降不下去,大概率是数据标注或辅助头设计的问题;如果cls_loss异常,可能类别标签写错了。断点续训用resume参数,它会自动加载上一次的权重和优化器状态,不用每次从头开始。

4.4 训练结果与模型保存

训练结束后,ultralytics会输出best.pt和last.pt。best.pt按验证集指标保存,是部署首选;last.pt保留最后一轮状态,适合继续训练。我习惯把每次实验的训练参数、数据版本、mAP结果记录到一个实验表里,这样多个改进点之间对比时才不会混乱。对论文实验来说,固定随机种子尤其重要,否则模块改进带来的精度提升会被随机性掩盖。

5. 评估、推理与Web前端展示

5.1 分割效果怎么评估

训练完的第一步,不是急着部署,而是先看数字指标。实例分割领域最常看mAP50、mAP50-95、mask-mAP、precision、recall。mAP50衡量的是预测Mask和真实Mask在IoU阈值0.5时的平均精度,工业项目里比较看中这个数;mAP50-95更严苛,论文里一般都会报。轮胎缺陷里,漏检比误检更危险,所以我会额外看recall,尤其是细小裂纹类别的recall。

只看指标还不够,随机抽一批图像,把标签和预测Mask叠加显示,人眼过一遍。裂纹类目标常出现的现象是:Mask预测比标注更大,把正常胎纹纹理也算进去了。这种边界膨胀问题,指标上可能只差1-2个点,但在业务方看来完全不能接受。解决办法是检查seg-aux辅助头权重、调整Mask后处理阈值,或者增加边界感知损失。

5.2 模型导出与推理封装

训练好的模型要部署,一般先导出成ONNX,或者进一步转TensorRT。ONNX的好处是跨平台,TensorRT是针对NVIDIA显卡的加速方案。导出命令:

yolo export model=best.pt format=onnx dynamic=True yolo export model=best.pt format=engine device=0

导出之后,建议先在本地跑一遍推理,确认输出结果一致。很多项目在PyTorch里精度不错,一转ONNX就有算子兼容问题,尤其一些自定义模块比如C2f-Faster里的部分卷积结构,导出时需要注意算子版本。遇到问题优先升级ONNX和onnxruntime,再检查自定义算子。

推理封装不要把所有逻辑堆在脚本里。我习惯封装成一个Detector类,里面有load_model、preprocess、inference、postprocess几个方法。preprocess负责letterbox padding,postprocess负责把Mask坐标映射回原图。这样做的好处,后续接Web后端或边缘设备都很方便。

5.3 Web前端展示:让业务方看得见效果

算法工程师很容易忽视前端展示,但很多项目能被推进下去,靠的就是“看得见的效果”。给业务方展示的时候,一张带分割Mask叠画的轮胎图,比几十个mAP数字更有说服力。

我用FastAPI写了一个轻量后端,核心思路是接收前端传过来的图片,调用Detector推理,再把结果返回成JSON。前端用简单的HTML+JavaScript+Canvas实现,不依赖重型前端框架。流程是:用户上传图片,Canvas画原图;拿到后端返回的mask多边形坐标;逐类别用不同颜色填充透明度,把轮廓画在原图上。

下面是一个刻意简化的后端接口示意:

from fastapi import FastAPI, File, UploadFile import cv2, numpy as np from detector import TireSegmentDetector app = FastAPI() detector = TireSegmentDetector("best.pt") @app.post("/detect") async def detect(file: UploadFile = File(...)): img = cv2.imdecode(np.frombuffer(await file.read(), np.uint8), cv2.IMREAD_COLOR) masks, boxes, classes, scores = detector.infer(img) return { "classes": classes, "scores": scores, "masks": masks # 每张mask转为多边形坐标 }

前端绘制部分,核心就是根据返回坐标画路径,并给不同的类别映射不同的颜色:

function drawMask(ctx, maskPoints, color) { ctx.beginPath(); ctx.moveTo(maskPoints[0][0], maskPoints[0][1]); for (let i = 1; i < maskPoints.length; i++) { ctx.lineTo(maskPoints[i][0], maskPoints[i][1]); } ctx.closePath(); ctx.fillStyle = color; ctx.globalAlpha = 0.4; ctx.fill(); }

要处理几个细节:后端返回的坐标必须是原图坐标,不能是letterbox之后的坐标;多类别时颜色不能冲突;大图在前端缩放后坐标变换要做等比换算。这些细节做好了,演示才不容易翻车。

6. 部署落地与常见问题速查

6.1 部署路径怎么选

部署形态取决于现场。最轻量的方式,是在一台带GPU的服务器上直接启动FastAPI服务,产线计算机通过HTTP调用。这种方式开发和迭代速度快,适合小批量图片质检。如果产线要求实时视频流处理,就需要解析RTSP流,逐帧推理,或者用边缘设备加速。边缘设备上优先用TensorRT,模型先用onnx导出再转engine,推理时间通常能比PyTorch原生快一倍以上。

部署的时候要重新检查输入源分辨率。很多工业相机分辨率远高于训练图像的640或960,如果直接resize到640,细小裂纹可能直接消失。我建议要么提高训练分辨率,要么在推理时保留原尺寸并用滑动窗口分割,后者复杂度高一点,但对裂纹这类小目标比较友好。这个权衡要按现场算力来定,没有标准答案。

6.2 常见问题排查速查表

做这个项目过程中,我沉淀了一个问题排查表。很多问题不是模型不够强,而是训练或部署环节的小坑。

现象可能原因处理方式
Loss始终不降学习率不合理、数据标签严重错乱检查dataloader可视化,调低学习率
训练很快但val mAP低过拟合,增强不足增加数据增强、提高正则、早停
小裂纹全部漏检分辨率不够、小目标层缺失提高imgsz,增加小目标检测层
Mask边界粗糙分割头监督信息不足启用seg-aux,提高分辨率
显存溢出批大小过大减小batch,开梯度累积
导出ONNX报错自定义算子不兼容升级onnxruntime,检查算子
推理结果不稳定前后处理不一致统一letterbox和坐标映射方式

这个表不是万能药,但覆盖了我近期被问得最多的问题。遇到问题先别怀疑模型,把原始图像、标签、预测结果放在一起可视化,比看十个小时代码更有效。

6.3 后续扩展与实际体会

这套体系做完之后,我最大的体会是:工业视觉项目的复杂度不在算法,而在数据、部署、展示这些“边缘环节”。数据标注标准不统一,再好的改进点也会被浪费;部署链路不顺畅,演示现场就容易翻车。用YOLOv8-seg作为基座,恰恰能把大多数精力留给真正要研究的改进点。

后续如果继续做,我会优先尝试半监督标注和主动学习。轮胎损伤样本在某些类别上很难采集,人工筛选成本很高,让模型先预测一批候选,人工只修正置信度低的部分,能进一步降低标注成本。如果有3D线扫相机条件,还可以把深度信息与2D图像融合,对鼓包这类立体形变损伤应该会有明显增益。这套模块化代码结构,也为这些扩展留了入口。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进