ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

布匹瑕疵检测实战:从数据预处理到YOLOv5训练全流程

布匹瑕疵检测实战:从数据预处理到YOLOv5训练全流程 简介这份数据集源自2019年天池布匹瑕疵检测赛题覆盖32种布匹表面缺陷类别面向计算机视觉学习者、算法工程师及工业质检相关团队可用于目标检测、图像分类等模型的训练与验证。压缩包共935个文件包含689张JPG原图、245个XML标注文件及1个TXT说明文件XML中保存了缺陷边界框便于直接接入VOC格式检测流程。整个资源包约927MB图片以缺陷类别和拍摄时间命名组织便于按需筛选。目前已有2914人浏览学习。客观来看各缺陷类别样本数量不均部分类别图片较少标注质量也非完美建议使用前进行数据清洗或扩展增强。该数据集仍有助于初学者理解工业布料瑕疵的视觉特征与标注方式也可作为算法效果对比的基准资料。 2019年天池上有一个后来被很多人拿来练手的工业视觉赛题广东工业智造大数据创新大赛·布匹瑕疵检测。这个比赛配套开放的布匹瑕疵数据集几乎成了缺陷检测方向绕不开的入门资料。我一直想把这套数据上踩过的坑和跑通的经验完整梳理一遍包括数据格式、模型思路、训练细节和各类排查技巧。如果你正准备复现这个比赛、做毕业设计或者公司里正好有布料、纺织类的质检项目需求这套方法论基本可以无缝迁移过去。1. 布匹瑕疵数据集到底长什么样1.1 来自真实生产线的图像数据先说背景。这个比赛聚焦的是纺织行业的质检环节数据来自真实生产线上的工业相机拍摄不是实验室里摆拍出来的“干净样本”。所以图像里有大量现实世界的复杂情况布料褶皱、纹理差异、光照不均、飞絮灰尘等等。这一点非常关键因为真实数据和学术数据集最大的区别就是噪声无处不在你的模型最终要面对的也是这种脏数据。公开的布匹瑕疵数据集一般会分成训练集、验证集和测试集。训练集量级大概在五千到九千张不等不同比赛阶段会有调整。单张图片的分辨率特别高常见尺寸接近4000×1696甚至更高。为什么这么高因为工业相机视野要尽量覆盖整匹布的宽度为了看清细微瑕疵就必须保留高分辨率。但这对算法工程师来说就是个麻烦后面我会专门讲怎么处理。1.2 标注格式与六类瑕疵这个数据集里标注格式在不同版本里略有差异但社区里流传的版本大多是PASCAL VOC风格的XML或者是JSON转成的VOC格式。每一张图对应一个标注文件里面用矩形框标出瑕疵的位置和类别。瑕疵类别主流是六类下面我用表格直接列出瑕疵类型直观表现检测难点破洞布料出现孔洞边缘不规则容易和深色纹理混淆水渍水痕浸染区域边界模糊对比度极低油渍反光的油污区域颜色与布匹底色接近反光不稳定三丝细线状异物目标极细、长条形、长宽比夸张结头纱线接头或小坨尺寸小还可能密集出现网纹编织异常形成网纹状缺陷面积大但轮廓模糊视觉上很不“框”记得我刚开始做的时候以为瑕疵检测就是普通目标检测拿过来就跑YOLO结果被“三丝”这类目标折磨得不轻。一条丝可能只有几个像素宽横跨大半张图普通anchor根本框不准。1.3 和常见缺陷检测数据集有什么区别很多人之前可能接触过NEU-DET那是热轧钢带表面缺陷数据集六类缺陷共1800张图目标相对居中且大小适中。但布匹瑕疵数据集完全不是这个难度它的核心区别有三个。第一图像尺寸大了一个数量级切片几乎是必须的。第二瑕疵目标尺度极不均匀既有大范围的网纹也有几个像素的三丝。第三类别分布严重不均衡破洞、水渍这类样本很多网纹、结头这类样本可能只有几十个。这些特性决定了你不能把一个常规目标检测pipeline原封不动搬过来必须做针对性调整。2. 为什么这批数据这么难搞2.1 小目标、低对比度与长尾分布很多人第一次跑这个数据集都会困惑明明在COCO或者VOC上效果很好的模型为什么到这里mAP直接崩盘答案就藏在这三个难点里。小目标问题最直接。以4000×1696的图为例一个50×50像素的破洞占整张图面积的比例不到万分之四。常规检测网络下采样32倍后这个目标在特征图里只有不到2个像素基本不可能被检测到。低对比度问题更隐蔽。水渍这种瑕疵在布面上只是一块颜色稍微深一点的区域人眼都得凑近了才看得清模型提取特征就更是难上加难。处理这类目标时光照归一化和对比度增强往往是提升效果的关键。长尾分布则是数据层面的坑。我自己统计过一次六类瑕疵里样本数最多的一类和最少的可能差几十倍。模型训练时会被多数类主导少数类几乎学不到有效特征推理时自然漏检严重。2.2 检测框架选型的思路框架选择没必要盲目追新。我在这个数据集上试过Faster R-CNN、YOLOv5和mmdetection系列最后稳定使用的还是YOLOv5原因有三个。第一YOLOv5对滑窗切片训练的兼容性非常好。切片之后每张小图相当于普通的自然图像完全可以直接喂进去不需要额外改网络结构。第二社区生态成熟遇到问题随便一搜就有答案放工业项目里意味着迭代效率高。第三YOLOv5的推理速度足够快高分辨率图切片后虽然数量多但整体吞吐量还是能满足产线需求。如果你更习惯mmdetection也可以用它跑通只是配置和调参成本会高一些。Transformer系列检测器如DINO或CO-DETR我也试过精度确实能涨一点但对显存和训练时间要求更高想要快速出结果的话还是先别碰。2.3 不要直接拿整图训练这是新手最容易犯的错误。把4000×1696的整图resize到640×640再去训练结果就是所有目标都被压缩成了几个像素模型能学到的东西非常有限。直接拿整图训练还有三个实际问题显存压力大单张图可能就要占据几个G的显存batch size根本提不上去小目标经过多次下采样后完全丢失正负样本比例极端失衡背景占比太大模型偏向于把所有区域都预测成背景。所以业界通用的做法是“切块训练切块推理”。简单说就是把大图切成若干个小块比如1280×1280或者1024×1024切成的小图作为训练样本。推理的时候也用同样的方式切分最后把检测框映射回大图坐标再做去重合并。这个思路我下面会展开讲细节。3. 从数据到模型完整实操流程3.1 先把标注转成模型能吃的格式我习惯把数据集先整理成YOLO格式也就是每张图对应一个txt文件每一行是“类别 cx cy w h”其中cx、cy是归一化后的中心点坐标w、h是归一化后的宽高。下面是VOC XML转YOLO txt的参考代码import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_txt_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] class_map { hole: 0, water_stain: 1, oil_stain: 2, three_silk: 3, knot: 4, mesh: 5 } for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 注意有些版本的标注坐标从1开始建议统一减1 x1, y1 max(x1 - 1, 0), max(y1 - 1, 0) x2, y2 min(x2 - 1, img_w - 1), min(y2 - 1, img_h - 1) cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{class_map[name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines))这里有两个坑必须提醒。一个是坐标偏移问题。PASCAL VOC的坐标是从1开始的而像素坐标通常从0开始如果不统一减1所有框会系统性偏移一个像素。虽然单个框偏移一像素看起来不严重但在细长目标上可能直接影响IoU计算。另一个是类别映射表一定要固定。训练和推理阶段必须使用完全相同的类别ID顺序否则模型输出和真实标签对不上结果全部作废。3.2 滑窗切片与坐标映射切块这件事听起来简单做起来有不少细节。我常用的参数是切片大小1280×1280重叠率0.25。为什么不直接用640×640因为切片尺寸越小目标被切断的概率越高而且每个切块里包含的上下文信息越少模型识别大范围瑕疵时会吃亏。但切片尺寸太大又会增加显存压力所以1280和三倍下采样后的中间特征图尺寸相对平衡。重叠率的选择也很关键。重叠率太低目标被切成两半的概率增加重叠率太高训练样本膨胀严重。0.2到0.3之间是比较常见的区间我习惯用0.25也就是步长取切片尺寸的75%。切片后必须做一件事把原始标注的绝对坐标转换成切块内部的相对坐标。这里最容易出错因为一张大图切成多个切片后如果坐标转换的偏移量算错模型训练出来的框就会整体偏移。建议在代码里写一个调试函数把切块图片和转换后的标注框画在一起人工抽样检查几轮确认无误再开始训练。推理阶段同样用滑窗切块得到所有检测框后映射回原图坐标然后做NMS合并。跨切片重复检测是必然的因为重叠区域的同一个目标可能被两个相邻切片都检测到NMS可以很好地解决这个问题。如果你用了不同切片尺寸得到的多组结果还可以尝试WBF加权框融合效果往往比单纯NMS更好。3.3 训练配置、数据增强与评估基础配置方面我建议先用YOLOv5s跑通整个流程确认没有数据格式问题后再换YOLOv5m或YOLOv5l提升精度。输入分辨率设成640×640起步如果显存允许再调到1280×1280。一开始就上大分辨率的话训练速度和调试成本都会高很多不利于快速定位问题。数据增强方面YOLOv5自带的mosaic增强我建议保留它对提升小目标的鲁棒性很有帮助。HSV颜色增强也建议开但强度不要拉满因为工业场景下颜色变化没有那么多过度增强反而会让模型学到错误的颜色不变性。我还额外加了随机光照扰动模拟生产线上不同时段的光照变化这个操作在真实场景下涨点明显。评估指标主要看mAP0.5和mAP0.5:0.95。但我要特别强调一句工业项目里mAP0.5通常更重要。瑕疵检测不需要非常精确的像素级框框的位置差不多命中就够用了mAP0.5反而更贴近实际业务需求。另外每训练完一个阶段一定要把badcase可视化图保存下来盯着看一遍比只看数字有用得多。3.4 尾部类别的处理针对网纹、结头这类样本数特别少的类别我试过几种方法效果排序大概是复制粘贴增强大于重采样大于单纯调整损失权重。复制粘贴增强的做法很简单从训练集里找出包含目标类别的区域把它们裁剪下来粘贴到其他正常布匹图像的随机位置同时生成对应的新标注。这个操作对“三丝”这类细长目标尤其有效因为三丝本身占的面积小粘贴进去不会太违和。但要注意粘贴位置尽量落在纹理均匀的区域不要贴在已有的明显瑕疵上否则标注会混乱。重采样就是让模型每个batch里都能看到足够多的尾部类别样本实现上可以在自定义Dataset里对样本数少的类别做上采样。这个方法逻辑最简单但对训练速度有一定影响。损失权重调整我放在最后尝试因为这需要比较多轮的实验来确定权重系数投入产出比一般。4. 训练和推理阶段的常见问题排查4.1 mAP不涨先怀疑标签而不是模型我在这个数据集上最大的教训就是模型效果差大概率不是模型的问题而是标签和预处理流程出了问题。最常见的情况是坐标转换错误。XML转YOLO的时候如果你忘了把坐标从1改为0或者切片时偏移量算错模型训练出来的框就会全部偏移。这类问题在loss曲线上往往看不出来loss可能正常下降但mAP就是上不去。我自己的排查流程是训练前随机抽取200张带标注的图片把标签画回去一张一张过目。不要嫌麻烦这一步能省掉后面无数个小时的无效训练。只要看到框的位置和实际瑕疵对不上立刻停下修代码千万不要带着错误标签继续跑。还有一个隐蔽问题是类别ID顺序。YOLO格式的txt文件里类别是用数字表示的如果你训练和验证阶段用的类别映射表不一致验证结果会乱成一锅粥。建议把class_map写成一个固定文件所有脚本都从同一份文件读取避免手动复制粘贴导致不一致。4.2 漏检、误检和跨切片重复框漏检的主要原因有两个目标太小和训练样本不足。目标太小靠提高输入分辨率解决。我测试过640和1280两种输入下的小目标AP后者的mAP0.5有明显提升。如果你的服务器显存不够可以先在切块层面降低切片尺寸比如从1280降到1024这样至少能在batch size上保持可用。样本不足靠增强和重采样上一节已经提过这里不重复。误检则往往是因为背景太复杂。布料上的纹理、褶皱很容易被模型当成瑕疵。我的做法是增加一个后处理步骤对每个检测框计算“瑕疵区域内部对比度”之类的特征如果特征值太低就认为是背景误检。这个方法比较粗暴但在某些类别上效果显著。跨切片重复框是切块推理特有的问题解决思路是在NMS之前把所有检测框统一映射到原图坐标再做一次全局NMS。阈值可以适当调高比如0.45到0.5左右否则重叠区域的目标可能被保留多个框。4.3 显存不足与训练时间失控这套数据下显存不足太常见了。一块16G的V100如果用1280×1280输入batch size可能只能设到4甚至2训练速度非常感人。三个可行办法开启AMP混合精度训练显存能省接近一半使用梯度累积相当于用时间换显存实在不行就降低输入分辨率先跑通流程再优化精度。另外提一句如果训练时间实在不可控优先检查数据加载是不是成了瓶颈。滑窗切片之后样本数量会膨胀很多我的建议是提前把所有切片结果缓存成离线文件而不是每次训练时实时切图。这样GUP利用率能明显提高训练时间可以缩短一半以上。我整理了一个高频问题速查表方便你排查时参考现象检查方向解决办法loss不降或震荡学习率、标签调低学习率检查坐标转换是否正确mAP0.5低但loss正常数据、输入分辨率检查badcase图提高切片分辨率某个类别几乎不检出样本量、增强重采样、复制粘贴增强、降低该类置信度阈值推理框明显偏移坐标映射检查切片到原图的坐标恢复逻辑大量重复框NMS策略映射到原图后统一NMS尝试WBF训练集acc高验证低过拟合增大切片数量加强增强加早停4.4 预处理一致性这类隐性坑还有一个非常容易出现但经常被忽略的问题训练和推理阶段的预处理必须完全一致。比如我在训练时加了对比度增强和随机光照扰动推理阶段如果不加模型看到的图像分布和训练时不一致效果自然会下降。尤其对水渍这种本来就低对比度的目标预处理差异会直接导致漏检翻倍。实际操作上建议把预处理函数单独封装训练脚本和推理脚本共用同一个函数。不要在两份代码里各写一份哪怕复制粘贴都要避免因为一旦改了其中一个忘了另一个结果就是玄学。5. 个人经验与后续扩展5.1 一套可以直接复用的通用管线做完整个比赛我沉淀下来的通用管线其实很简洁高分辨率滑窗切块、通用目标检测器训练、跨块结果合并。这套流程不仅适用于布匹瑕疵数据集迁移到皮革表面缺陷、钢板表面缺陷、薄膜表面缺陷等场景只需要改标注类别和切片参数。建议你拿到一个新数据集后先用最小的代价跑通一个baseline把数据加载、训练、评估、可视化的完整链路确认没问题再开始优化精度。我见过太多人一上来就堆Swin Transformer、各种trick最后发现数据标签有问题浪费了几天时间。5.2 这个数据集还能怎么玩如果你把检测做完了这个数据集还有很多可扩展的方向。一个方向是把检测框转成分割mask做像素级的瑕疵分割。因为矩形框对长条形的三丝和大范围的网纹表达不够精细分割模型往往能拿到更好的业务效果。另一个方向是无监督异常检测。只用正常布匹图像训练PatchCore这类模型让模型学习“正常长什么样”新样本只要偏离正常分布就视为瑕疵。这个思路对工业场景很有吸引力因为实际产线上经常会出现数据集里没有的新瑕疵类型监督学习模型对未知类别无能为力无监督方案反而更灵活。最后说一句我的真实体会在这个数据集上刷分很容易让人上头但真正有用的能力是能快速定位模型哪里不行、为什么不行。每跑完一轮实验把预测错误的框画到图上盯着看十分钟比盲目调参有用得多。这也是我在布匹瑕疵数据集上最大的收获。本文还有配套的精品资源点击获取
返回列表