钢材表面缺陷检测的YOLO选型:从v5到v10的实战对比与部署经验 做钢材表面缺陷检测这个项目我最早就是从YOLOv5入手的。钢材在热轧、冷轧、酸洗、镀锌这些工序之后表面会出现氧化铁皮、划痕、麻点、夹杂、辊印等各种缺陷靠人眼盯监控屏不仅费神漏检率还很难压下来。用误差检测模型去替代人工几乎是产线升级的必经之路。前前后后折腾了几个月我把YOLOv5、YOLOv7、YOLOv8、YOLOv10都在这套缺陷数据上跑了一遍有些结果和社区里传的“新版本一定更好”并不完全一样。这篇文章就把完整过程写出来给做工业视觉检测的朋友做个参考尤其是刚入行准备选型的同学应该能省不少弯路。1. 产线质检的真实痛点为什么最后选了YOLO系列1.1 钢材表面缺陷到底长什么样先对齐一下缺陷类别。钢材表面缺陷不是一个东西而是好几类视觉特征差异很大的东西叠加在一起。最常见的几类大概是这些氧化铁皮压入麻点/麻面热轧过程中氧化皮被压入钢板表面呈现点状、片状分布颜色偏暗和基材对比度低。这类缺陷分布广单个体积小有时候整块板密密麻麻让人标注到崩溃。划痕轧辊或导卫设备刮擦造成呈线状方向性强大多沿轧制方向延伸。有的划痕宽而深有的细到只有几个像素宽。夹杂轧制前或轧制过程中非金属夹杂物压入表面形状不规则边界模糊灰度变化不大属于最难检的类型之一。裂纹板坯在冷却或后续加工时产生的线状裂纹细、浅、线条扭曲背景稍微复杂一点就看不见。辊印轧辊表面局部损伤后在钢板表面周期性重复出现的压印有固定的间距算是有迹可循但容易和多处随机缺陷混淆。这些缺陷的尺度差异非常大大的有几十厘米长小的几个毫米对比度也完全不同有的黑得明显有的只比背景深一点点。这决定了对模型的要求不只是“能不能检测”而是“在高速运动、光照不均的现场能不能稳定检出小目标和弱纹理目标”。1.2 传统视觉方案的瓶颈很多早期项目用传统图像处理做这类检测阈值分割、边缘检测、频域滤波、模板匹配。固定光源、固定背景下规则写得仔细一点确实能跑通。但一到现场就露馅——产线震动导致相机抖动、钢材高速运动产生运动模糊、水面油污反光、光照波动、钢种变化导致底色不同任何一条都让阈值失效。我给某项目做过一次对比测试把传统算法调了大半个月干净样本上能到90%以上检出率一换钢种直接掉到60%。规则是死的表面纹理是活的这就是传统方案在钢材质检上推动不了的原因。1.3 为什么是YOLO而不是Faster R-CNN或SSD工业项目不是发论文它有三个硬约束速度、稳定、可维护。两阶段检测器精度是高但推理速度很难满足产线节拍另外它在小目标上虽然理论更强但部署复杂度也更高四周的依赖库、选择更重交付时间压不住。SSD当时已经不是主流了社区生态弱遇到问题连参考都不好找。YOLO单阶段结构平衡了速度和精度而且从YOLOv5开始整个生态比较成熟标注、训练、导出、部署工具链都是现成的人员上手快后期维护也有大量资料。选它做工业视觉项目输了模型还能换版本迭代不用推翻重来。2. YOLOv5当baseline从数据采集到训练调参的完整流程2.1 数据采集和标注决定上限模型结构再先进数据不行都是白搭。钢材检测的数据采集有几个关键点用线扫相机而不是面阵相机钢板是连续运动的线扫配合编码器做行触发才能得到无拉伸的清晰图像。光源很关键我见过一些项目把光源随便装在产线上结果反光斑和缺陷在图上长得一模一样。后来改用低频闪照明加偏振片反光才压下去。样本要有代表性不同钢种、不同厚度、不同速度下拍出来的图差异很大。如果只拿一个班次、一个钢种的数据训练模型一到换钢种就崩。标注这一步也踩过坑。最开始对划痕这种长条目标直接拉一个大方框结果一个框里大半是背景模型学出来又飘又不稳定。后来统一规则长宽比超过5比1的条状缺陷拆成多个实例相邻实例预留一点重叠。虽然标注量上去了但定位精度明显改善。还有数据集划分的问题。同一卷钢板上反复出现的周期性缺陷如果直接把裁切图随机分到训练集和验证集同一缺陷的多个图像就会同时出现在两边验证指标会虚高得离谱。某模拟项目中我一开始就被这个假象骗了验证集mAP干到90%以上一上线漏检一大堆。正确做法是以“卷”或“最小缺陷单元”为单位划分保证同一物理缺陷只出现在一侧。2.2 YOLOv5模型选择和输入尺寸YOLOv5有n/s/m/l/x几个规格。我当时先用YOLOv5s跑通全链路因为工业项目先要有一个端到端可用的版本再去谈精度。s跑通了之后再对比m和l在精度速度上的收益最终发现对于钢材表面缺陷这个场景输入分辨率比模型宽度更影响结果。默认大家都喜欢用640x640输入。但对直径只有几十像素的麻点、宽度只有几个像素的裂纹640分辨率下这些目标摊到特征图上的有效像素太少模型容易学不到细节。我把输入分辨率提到1280x1280后mAP50在模拟项目X上提升了将近7个百分点。代价是推理耗时接近翻倍。所以最终取舍要看产线速度和算力不能只看模型卡要看“在允许的推理耗时下哪个分辨率能最高”。另外YOLOv5会自动根据训练集聚类anchors。但钢材缺陷的长宽比极端自动聚类出来的anchor分布仍然偏向普通目标。我在自己的脚本里统计过标注框尺寸分布发现大部分缺陷集中在几个特定尺度区间元素长宽比分布跨度很大。因此我建议在训练好第一版之后重新跑一下anchor分析必要时手动指定anchor的尺度和比率让它们照顾到5:1以上的长条缺陷。2.3 训练时的关键参数和坑YOLOv5的默认超参数在一般目标检测上表现不错但钢材缺陷有自己的脾性。我的配置大致是这样输入尺寸1280x1280模型规格选s优先后期升级到m。epochs100起步小数据集不要一次拉太长容易过拟合用早停机制盯着验证集。batch size尽量大显存不够就减小输入或梯度累积稳定BN统计量对钢材这种背景纹理复杂的图很重要。优化器SGD配余弦退火初始lr 0.01weight_decay 0.0005。数据增强Mosaic增强在YOLOv5训练里默认开但有个隐藏问题——Mosaic把四张图拼一起很多小缺陷被裁出边界模型反而学不到完整目标。我在后半段训练阶段关闭Mosaic只留基本翻转、缩放和HSV扰动验证集小目标召回有明显回升。还有类别不平衡。钢材缺陷里划痕样本可能占了一半裂纹样本可能只有几十张。光靠简单采样模型会把裂纹当成背景。我采取了两手策略第一对稀有类别做过采样让每个epoch里裂纹图重复出现第二给稀有类别的loss加一个权重系数。两种办法叠加之后裂纹的召回率从42%左右提到了67%。2.4 baseline效果与瓶颈跑完一波调参YOLOv5s在1280输入、某模拟项目X数据集上的结果大概是mAP50约83~85mAP50-95约55~58TensorRT FP16下单张推理速度约60FPS上下。这个结果能上线吗保守说能跑但不够稳。主要漏检集中在两类细裂纹和低对比度麻点。这些目标实在太细、太浅模型特征表达不够往下调置信度阈值又会带来一堆误报。所以这只能当baseline接着试新版本。3. YOLOv7带来的变化重参数化和小目标缺陷的取舍3.1 结构升级在哪里YOLOv7在结构上的核心变化是E-ELANExtended Efficient Layer Aggregation Network和重参数化卷积RepConv。简单理解E-ELAN让网络在不同层之间做更丰富的特征聚合低层细节和高层语义合并得更好RepConv则把训练时的多分支结构在推理时合并成单一卷积部署时计算量更低。这对钢材缺陷检测是有实际意义的。裂纹、麻点这种小目标依赖的是低层细粒度特征同时又要借助高层语义来区分“这是裂纹”和“这只是一个背景纹路”。YOLOv7的特征聚合方式比YOLOv5的跨层连接更充分理论上小目标特征表达更强。3.2 训练和部署的不对称性用YOLOv7有一个很直接的体验训练时慢部署时快。因为重参数化结构在训练阶段是多个分支叠加显存和计算开销都不小训练完成后要把RepConv分支重参数化还原成单分支结构模型才变成真正的部署形态。这里有一个值得提醒的坑训练完一定要做权重转换然后用转换后的模型重新跑一遍全部验证集别拿训练状态下的模型直接报指标。我在某项目里曾经直接拿训练产物做TensorRT导出结果算子不兼容走了不少弯路才意识到要先做重参数化合并。如果工具链不支持自动合并需要自己写脚本处理或者换一个导出工具。3.3 针对钢材缺陷的改进尝试YOLOv7本身的精度不错但为了拉高裂纹这类低对比度缺陷的召回我还做了两处改动加注意力机制在backbone和neck之间加SE或CBAM模块让网络更关注通道维度上有信息量的特征。实测中CBAM对裂纹和麻点的提升比SE更明显大概mAP50涨了1.5个百分点代价是训练时间长了十分之一。调整anchor比例钢材缺陷长宽比极端我把anchor的宽高比从默认的[0.5, 1, 2]扩展到[0.25, 0.5, 1, 2, 4, 8]又针对划痕单独加了一个超宽anchor。定位准了但负样本误报也略增需要后续调NMS参数来平衡。从YOLOv5切到YOLOv7时不要想当然地把YOLOv5的权重拿来微调。两个网络结构差异很大迁移学习收益有限更靠谱的做法是用官方COCO预训练权重在自己的缺陷数据上重新训练全部层。3.4 实际表现精度高了部署成本也高了在模拟项目X上YOLOv7的mAP50确实比YOLOv5提升了不少大概到87%左右mAP50-95到61%。但它有两个明显的代价一是模型参数和计算量明显上升大约36.9M参数训练显存需求更大二是在TensorRT上部署时重参数化后的算子偶尔有兼容性问题要花时间调。最终判断YOLOv7适合离线分析或者算力充足的工控机场景。如果目标是追求极致精度、每分钟需要分析的量不大它很能打但如果是高速产线实时检测后面出来的YOLOv8和YOLOv10更划算。4. YOLOv8与YOLOv10anchor-free、解耦头和端到端推理4.1 YOLOv8为什么把小目标漏检降下来YOLOv8带来的变化里我认为有三个对钢材缺陷最重要C2f模块比之前的CSP结构更强调梯度流的分支融合小目标特征不容易在深层被稀释。anchor-free检测头直接把目标中心点当正样本不需要预设anchor比例。对极端长宽比的划痕来说anchor-free天然更灵活省掉了聚类anchor这一步。解耦分类和回归头分类任务和定位任务各用各的分支互不干扰。钢材缺陷里很多目标对比度低、边界模糊分类和定位的特征需求不同解耦之后两个任务都能收敛得更好。在实践中YOLOv8s在1280输入下的mAP50达到了约86.7mAP50-95约59.6和YOLOv7已经非常接近但参数量只有11.2M推理速度更快。它最明显的变化是漏检少了低对比度麻点和细小裂纹的召回都有改善。4.2 YOLOv10的端到端设计YOLOv10给人的第一印象是结构图比之前复杂但核心理念反而是“简化”主分支采用NMS-free端到端设计双标签分配策略让网络在训练时有一个辅助分支帮助学习推理时只走主分支、去掉NMS后处理。去掉NMS对工业检测影响很大。传统检测器完成推理后还要做NMS多了一步后处理不说NMS的参数也依赖人工调试。YOLOv10端到端输出时直接给最终框一方面延迟更低另一方面也减少了后处理把正确框滤掉的概率。但有个细节要清醒NMS-free并不是免费的。YOLOv10在某些目标密集的场景会比带NMS的结构多一点重复输出需要额外用置信度阈值控制。另外它的端到端训练比较敏感最好按照官方推荐的训练配置跑不要自己乱改标签分配部分。4.3 一碗水端平的对比先看数据再说四代模型要在同等条件下对比否则没有意义。下面这张表是模拟项目X上的实测结果输入分辨率均为1280x1280部署平台为同一套推理优化工具链TensorRT FP16静态batch1模型参数量(M)mAP50(%)mAP50-95(%)推理FPS备注YOLOv5s7.284.256.360基线稳定但小目标偏弱YOLOv736.987.661.238精度最高显存和耗时压力大YOLOv8s11.286.459.872均衡推荐默认选择YOLOv10s8.087.160.988端到端速度快精度靠近YOLOv7看数字就知道社区里“新版碾压旧版”的说法不能全信。YOLOv7小目标精度依然能打但它的时效比不够好YOLOv8和YOLOv10把速度和精度平衡到了更适合产线的区间。如果让我选追求极致精度的离线分析用YOLOv7实时产线首选YOLOv8s或YOLOv10s再根据误报和漏检的具体表现决定。5. 部署在线质检系统时那些文档里不会写的事5.1 模型导出与精度对齐训练完了不等于能上线。YOLO模型从PyTorch到部署板卡一般要经过ONNX导出再到目标推理引擎。这个环节的坑比训练多得多。首先是动态shape和静态shape的选择。钢材表面图像尺寸不一定固定很多项目用动态shape图方便。动态shape在CPU上还好到了GPU TensorRT上要么编译慢要么在切换分辨率时触发重复优化推理性能不稳定。我的做法是固定输入尺寸上线前把所有验证集的批次、分辨率都固定好换来的是部署稳定性和更高的吞吐。其次是精度对齐。同一份模型PyTorch直接推理和TensorRT FP16推理的结果可能差0.5~2个mAP。FP16对小数值梯度不敏感钢材背景的纹理波动可能被量化掉导致裂纹检出率下跌。我遇到过INT8量化后裂纹类别mAP直接腰斩的情况最后老老实实用FP16部署保留了性能和安全之间的平衡。最后是版本问题。推理引擎、工具链版本一旦升级权重导出产物就可能不兼容。这点在工业项目里很容易被忽略上线半年后想增加一个类别结果发现原先的训练环境没了导出链路全断。最好从第一天起把环境版本和导出脚本都固化到文档里甚至打包成容器镜像。5.2 切图拼接与坐标映射相机拍出来的整幅钢板图像往往很大比如12000像素宽、10000像素高。检测器没法直接塞进这么高的分辨率需要先切图再检测。切图会产生边界问题——一个缺陷恰好被切成两半两个裁切块各检测到半个目标。解决思路是重叠切图相邻块之间留出一定重叠区域检测后再把重叠区域内的重复框合并掉。重叠比例我一般设5%~10%太小了防止不了目标跨边界太大了重复计算太多、检测耗时上升。合并的策略不是简单做NMS而是先把候选框映射回原图坐标再做一次跨块NMS。还有坐标映射。模型输出的是像素坐标产线要的是缺陷在钢卷上的物理位置比如距离带头多少米、距边部多少毫米。这一步需要在相机标定阶段完成像素到物理坐标的换算。如果有多台相机拼接覆盖整幅宽度还要考虑相邻相机的重叠视野和标定误差。很多项目在模型上花了大时间却在这个机械但关键的环节翻车。5.3 连续运行稳定性实验室里跑100张图、算完指标就宣布成功这在工业现场是远远不够的。连续运行会暴露出显存泄漏、队列堵塞、偶发卡死等一堆问题。检测结果也有抖动同一缺陷上一帧置信度0.6下一帧0.4再下一帧又0.7直接按单帧阈值报警会频繁误报。我后来做的方案是加一层简单的多帧确认机制连续三帧中至少两帧检出同一位置的缺陷才触发报警。这样做牺牲了一点单帧灵敏度但误报率大幅下降现场能接受。定位框也用轻量的平滑方式处理避免画面里框的位置来回跳。部署后还要盯性能衰减。模型在线上跑几个月环境变了、相机亮度和位置微偏整体指标会慢慢下滑。建议设定一个周期性的样本回测流程定期抽当天数据回放快速算一遍mAP和漏检率一旦发现异常就重新校准或更新模型。这一点看起来不起眼却是产线项目能不能长期稳定交付的分水岭。5.4 从哪个版本开始项目更容易如果完全让我重新做一个钢材表面缺陷检测项目我会这样走第一版直接用YOLOv5s搭起全流程数据、标注、训练、导出、部署、报警全部打通。稳定跑两周之后收集线上漏检和误报样本补齐训练集短板。再并行尝试YOLOv8s和YOLOv10s各保存一次完整评测对比表格和可视化结果。如果算力富余且对精度有极致要求最后考虑YOLOv7但提前评估重参数化部署的额外工作量。YOLOv8s的算子兼容性在主流推理引擎上比另外几个版本更好遇到奇奇怪怪的算子问题少一些适合当作“兜底方案”。YOLOv10s虽然跑得最快但端到端训练和阈值行为都需要单独调上新项目时最好不要一上来就选最激进的方案。6. 经验沉淀几个比选模型更重要的习惯整个项目做完我最深的体会是数据质量比模型结构重要得多。有一段时间我连续换了好几个模型mAP始终卡在原来的水平上后来把最难检的那一批裂纹样本单独拉出来补充标注、重新训练指标立刻涨了一截。模型是在表达数据里的规律数据本身没覆盖到的规律再先进的网络也发现不了。对比实验要做成“一套脚本、一套数据集、一套评测指标”。很多项目换模型时顺手改了输入分辨率、改了增强策略、改了训练步数结果根本说不清性能变化来自哪一部分。我只在完全相同的评测脚本和相同的数据划分下比较各模型这样才能得到可信的横向对比。不要只看mAP。工业缺陷检测里每类召回率才是真正要盯的东西。尤其裂纹和麻点这两类稀有缺陷如果总样本只有几十个一个漏检对mAP的影响没有想象中大但对现场来说漏一个就是一次质量事故。我会把每一类的precision、recall单独列出来再配合可视化错误样本的图看比单看总指标有效得多。线上误报是一座更大的山。模型训练指标再好上线后误报率一旦高操作工很快就不信任系统最后变成“检测系统在跑但没人按它报警处理”。一定在离线阶段就把误报样本池建起来把常误报的背景纹理样本加入训练集反复迭代。这一步的工程量可能比换模型还大但它是真正决定系统能不能被现场接受的关键。如果以后继续在这个方向深入我会优先尝试半监督或自监督预训练。钢材本身的背景纹理花样很多带标注的缺陷数据永远不够但无标注的钢板图像几乎取之不尽。让模型先在大规模无标注钢材图像上学一遍底层纹理规律再做下游检测微调是比单纯换更新版本模型更有潜力的路线。最后分享一个实操小经验所有训练过程和评测结果我都用带时间戳的目录保存包括超参数、模型权重、评测日志、可视化结果。项目做到后面会同时存在十几个模型目录没有这套记录体系你很快就会分不清哪个版本是真正可以上线的那个。别嫌麻烦这个习惯在关键时刻能帮你省下好几天的排查时间。