简介:这份资源是2019年天池布匹瑕疵检测赛题相关的图像数据集,面向从事工业质检、缺陷检测算法实践的开发者与学习者,可用于分类、检测等视觉任务的训练与验证。压缩包共935个文件,以689张jpg瑕疵图像和245个xml标注文件为主,另附1个txt说明文件,整体约927.26MB,图像与标注基本配套,便于直接构建监督学习数据管线。数据集覆盖32种布匹表面瑕疵类别,各类别样本数量差异较大,部分类别图片偏少,作者也坦言整体质量不算高,更适合作为练手或补充数据使用。目前已有2919人学习下载,读者可从中获得多类别瑕疵的原始图像与对应标注,用于熟悉工业缺陷数据的组织方式、验证模型在小样本与类别不均衡条件下的表现,并据此设计数据清洗与增强策略。
1. 布匹瑕疵数据集-2019天池:一张图里藏着多少种“织错”的方式
第一次拿到布匹瑕疵数据的人,多半会低估它。以为就是“有瑕疵/没瑕疵”的二分类,跑个 CNN 就完事。真正打开标注文件才会发现,同一匹布上,断经是细长竖线,破洞是局部空洞,油污是低对比度色斑,三者的形态差异比猫和狗还大,而它们又常常同时出现在一张图里。这就是布匹瑕疵数据集-2019天池这类工业质检数据集的核心难点:它不是单标签分类,而是多标签、小目标、类别极不均衡的检测任务。
这个数据集面向的是纺织面料表面缺陷检测,典型场景是验布机上的工业相机在线拍摄,需要模型在高速产线上把断经、断纬、破洞、油污、污渍、三丝等缺陷框出来并分类。适合谁?做工业视觉落地的算法工程师、想把检测模型从公开数据集迁移到真实产线的团队,以及需要一套“脏但真实”的数据来验证小目标检测方案的人。它解决的不是“能不能识别”,而是“在类别长尾、标注粒度粗、背景纹理强干扰的条件下,怎么把召回率做上去”。
2. 先看清数据长什么样:标注格式、类别分布与图像特性
动手写模型之前,必须先把数据集翻一遍。工业质检数据集和 COCO 那类自然图像数据集的气质完全不同,直接套通用检测流程,十有八九会在验证集上看到“mAP 还行但漏检严重”的玄学现象。这一章先把数据的三个关键面拆开:标注结构、类别长尾、图像纹理。
2.1 标注文件的结构与字段含义
这类比赛数据集常见做法是给一个 CSV 或 JSON 标注表,每行对应一个缺陷框,字段大致是图像名、类别、左上角坐标、宽高。不同年份、不同赛题的具体字段名会有差异,但结构逻辑一致。拿到手第一件事不是训练,是写脚本统计:每类多少个框、每张图平均几个框、框的宽高分布。
import pandas as pd # 假设标注表为 train.csv,字段名按常见命名 df = pd.read_csv("train.csv") # 1. 类别分布:看长尾有多长 cls_count = df["category"].value_counts() print(cls_count) # 2. 每图框数分布:判断是单目标还是密集多目标 per_img = df.groupby("image_id").size() print(per_img.describe()) # 3. 框尺寸分布:小目标占比决定要不要改 anchor / 特征层 df["w"] = df["xmax"] - df["xmin"] df["h"] = df["ymax"] - df["ymin"] df["area"] = df["w"] * df["h"] print(df["area"].describe(percentiles=[0.1, 0.5, 0.9]))这段脚本的价值在于把“感觉”变成数字。类别分布如果头尾差几十倍,就不能用普通交叉熵硬训,得考虑重采样或类别加权;每图框数如果集中在 1 到 2 个,说明大部分图是稀疏标注,密集场景少,评估时按图算指标会更贴近产线;框面积的中位数如果很小,说明小目标占主导,特征金字塔的高层分辨率不够用,得往上加 P2 层或者提高输入分辨率。
参数上要特别注意坐标是绝对像素还是归一化值。有些标注表混用两种,训练前必须统一。我一般会在统计脚本里顺手加一句断言,检查xmax > xmin且坐标不超过图像宽高,先把脏标注筛出来。
2.2 类别长尾与“标注粒度”陷阱
工业瑕疵数据集的类别不均衡不是简单的 1:10,常见是 1:50 甚至更极端。断经、破洞这类显眼缺陷样本多,油污、三丝这类细微缺陷样本少。更麻烦的是标注粒度不统一:有的图把一片连续污渍标成一个大框,有的图把它拆成几个小框。模型学到的“目标尺寸”概念就被搅乱了。
处理长尾,常见做法有三条路。第一条是损失层面,用 Focal Loss 或类别加权 CE,把稀有类的梯度放大。第二条是采样层面,对稀有类做 oversampling,但要注意同一张图里有多个类时不能简单复制,否则会重复计算常见类。第三条是评估层面,别只看 mAP,要按类看 AP,稀有类 AP 掉到 0.1 以下就说明模型根本没学会。
我一般会先跑一版不加权的 baseline,拿到每类 AP 的表格,再决定加权系数。加权系数不是拍脑袋,通常取sqrt(N_max / N_c)这种温和形式,太激进会让模型在稀有类上过拟合到几个样本。
2.3 强纹理背景下的图像特性
布匹图像的背景是规则织物纹理,经纬线重复、对比度低,缺陷往往“嵌”在纹理里。这带来两个直接后果:一是通用数据增强里的随机裁剪、旋转会破坏纹理方向性,可能让模型学到错误的纹理先验;二是颜色归一化很关键,不同批次布料的底色差异大,模型容易把“底色深”误判成“油污”。
实际处理时,我会保留水平翻转和轻度亮度扰动,慎用大角度旋转和强色彩抖动。归一化用数据集自身的均值和方差,而不是 ImageNet 的,因为工业图像的色彩分布和自然图像差得远。输入分辨率上,如果小目标多,640 起步,条件允许上到 1024,配合多尺度训练。
提示:先把标注统计和几十张可视化图看完再写模型。工业数据集里“标注错误”和“标注粒度不一致”的比例,往往比想象中高,早发现能省掉后面几天的调参。
3. 检测方案怎么选:从 YOLO 系到两阶段的取舍
数据看清了,接下来是选型。布匹瑕疵检测在工业界主流还是单阶段检测器为主,原因是产线要速度,两阶段在精度上的优势在这个场景不一定兑现,因为缺陷形态太不规则,RPN 的候选框质量未必比密集 anchor 好。这一章讲清楚选型逻辑,再给一套能跑通的最小训练流程。
3.1 单阶段与两阶段在这个场景的真实差异
单阶段(YOLO 系、RetinaNet 系)的优势是推理快、部署简单,对小目标靠特征金字塔补。两阶段(Faster R-CNN 系)的优势是候选框经过 RoI Align 后分类更准,适合形态复杂的目标。但在布匹瑕疵上,缺陷边界往往模糊,标注框本身就有几个像素的抖动,两阶段精细的框回归优势被抵消了一部分。
我的经验是:如果缺陷以细长条(断经、断纬)和局部斑块(油污)为主,单阶段配合可变形卷积或注意力模块,性价比更高;如果缺陷类别多且形态差异极大,两阶段在稀有类上的召回可能更稳。实际项目里我会先跑 YOLO 系做 baseline,因为它迭代快,一天能出结果,再决定要不要上两阶段做对比。
选型还要看部署端。产线边缘设备算力有限,单阶段量化后更容易压到实时。这一点在方案初期就要确认,别训完发现部署不上去。
3.2 用 YOLO 格式转换标注并跑通最小训练
大多数检测框架吃的是 YOLO 格式(每张图一个 txt,每行class cx cy w h,全部归一化)。从原始 CSV 转过去是最容易翻车的一步,坐标归一化、类别映射、空标注图处理都要小心。
import os import pandas as pd from PIL import Image df = pd.read_csv("train.csv") # 类别名到 id 的映射,务必固定顺序,训练和推理要一致 classes = sorted(df["category"].unique()) cls2id = {c: i for i, c in enumerate(classes)} out_dir = "labels" os.makedirs(out_dir, exist_ok=True) for img_id, group in df.groupby("image_id"): img_path = os.path.join("images", img_id) W, H = Image.open(img_path).size lines = [] for _, r in group.iterrows(): # 归一化并裁剪到 [0,1],防止脏标注越界 cx = max(0, min(1, (r["xmin"] + r["xmax"]) / 2 / W)) cy = max(0, min(1, (r["ymin"] + r["ymax"]) / 2 / H)) w = max(0, min(1, (r["xmax"] - r["xmin"]) / W)) h = max(0, min(1, (r["ymax"] - r["ymin"]) / H)) if w <= 0 or h <= 0: continue # 丢弃退化框 lines.append(f"{cls2id[r['category']]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") # 空标注图也要生成空文件,否则训练时会被当成无标签跳过 with open(os.path.join(out_dir, img_id.replace(".jpg", ".txt")), "w") as f: f.write("\n".join(lines))逻辑说明:按图像分组遍历,保证一张图的所有框写进同一个 txt;坐标先算中心点和宽高再归一化,顺序不能错;越界坐标做裁剪而不是直接丢,因为轻微越界是标注抖动,丢掉会损失样本;退化框(宽或高为 0)必须丢,否则训练时算 IoU 会出 NaN。空标注图生成空文件这一步很多人漏掉,导致背景图没参与训练,模型在纯纹理区域误检率偏高。
转换完用框架自带的数据集检查脚本过一遍,确认类别 id 连续、没有越界、没有空文件缺失。然后跑最小训练:
# 以常见 YOLO 系框架的命令行为例,具体参数名以所用框架为准 python train.py \ --data fabric.yaml \ --img 640 \ --batch 16 \ --epochs 100 \ --weights pretrained.pt \ --hyp hyp.fabric.yamlfabric.yaml里写训练/验证路径和类别数,hyp.fabric.yaml是超参文件。第一版不要改太多超参,先用默认跑通,看 loss 曲线和验证集每类 AP。batch 根据显存调,640 输入下 16 是常见起点。epochs 先 100 看收敛趋势,别一上来就 300,浪费时间。
3.3 输入分辨率与 anchor 的联动调整
小目标多的时候,光调 anchor 不够,得先看特征图分辨率。640 输入下,P3 层是 80×80,一个 8 像素宽的断经在 P3 上只占 1 个格子,几乎学不到。两个办法:上到 1024 输入,或者加 P2 层(160×160)。前者显存翻倍,后者增加计算量但更划算。
anchor 方面,先用 k-means 在训练集框上聚类出 9 个尺寸,替换默认 anchor。聚类时用 IoU 距离而不是欧氏距离,因为框的匹配看的是重叠度。聚类完检查最小 anchor 是否覆盖了 10% 分位的小框,覆盖不到就手动加一组更小的。
注意:改输入分辨率后,anchor 必须重新聚类,否则匹配策略失效,表现为 loss 不降或召回上不去。这是血泪经验,别问怎么知道的。
4. 训练调优与评估:让稀有类不再“隐身”
baseline 跑通只是起点。布匹瑕疵数据集的真实挑战在训练中后段:常见类 AP 很快到 0.8,稀有类卡在 0.2 不动,整体 mAP 被平均得好看,但产线上漏检的全是稀有类。这一章讲三件事:损失与采样怎么配、数据增强的边界在哪、评估指标怎么按类拆开看。
4.1 类别加权与 Focal Loss 的实操参数
Focal Loss 的两个参数 α 和 γ,γ 控制难易样本的聚焦程度,常用 1.5 到 2.0;α 控制类别平衡,多类场景一般按类别频率设。但工业瑕疵里我不建议直接用标准 Focal Loss,因为稀有类样本太少,γ 太大会把仅有的正样本梯度也压掉。
更稳的做法是类别加权 CE 加适度的 Focal。加权系数用w_c = (N_total / N_c)^0.5,再归一化到均值 1。这样稀有类权重是常见类的几倍,但不至于几十倍导致过拟合。训练时监控每类的正样本平均 loss,如果稀有类 loss 一直不降,说明权重还不够或者样本本身标注有问题。
另一个常被忽略的点是负样本挖掘。布匹背景纹理强,容易产生大量假阳性。OHEM(在线难例挖掘)在这个场景有效,但要注意只对背景类做挖掘,别把稀有正样本当难例压掉。
4.2 数据增强的边界:哪些增强会帮倒忙
前面提过,大角度旋转和强色彩抖动会破坏纹理先验。具体边界我一般这样定:水平翻转必开,垂直翻转看缺陷是否有方向性(断经有,破洞没有),旋转限制在 ±10 度以内,色彩抖动只调亮度和轻微对比度,饱和度不动,因为布料颜色是判断油污的重要线索。
Mosaic 增强对小目标有帮助,因为它把多张图拼一起,变相增加了小目标密度。但 Mosaic 会让框的绝对尺寸变小,如果原图小目标已经很多,Mosaic 后可能小到无法识别。我的做法是训练前期开 Mosaic,后期关掉,让模型在真实分布上收尾。
还有一个容易翻车的增强是随机裁剪。裁剪可能把缺陷裁掉一半,标注框却还在,模型学到的是“半个缺陷也是缺陷”,推理时对完整缺陷反而不敏感。如果要用,裁剪后必须重新计算框的可见比例,低于 0.3 的直接丢。
4.3 按类 AP 与混淆矩阵定位问题
整体 mAP 是给汇报看的,调优要看每类 AP 和混淆矩阵。混淆矩阵能告诉你稀有类是被漏检(预测为背景)还是被误分类(预测成别的缺陷)。漏检多说明召回不足,查 anchor 匹配和正样本分配;误分类多说明特征区分度不够,查类别间的视觉相似性。
# 用 sklearn 快速看分类头的混淆情况(以检测框匹配后的类别为例) from sklearn.metrics import confusion_matrix, classification_report # y_true, y_pred 为匹配后的类别 id 列表,-1 表示背景 cm = confusion_matrix(y_true, y_pred, labels=list(range(num_classes)) + [-1]) print(classification_report(y_true, y_pred, zero_division=0))看报告时重点盯稀有类的 recall 和 precision。recall 低优先补召回,precision 低优先查假阳性来源。如果某两类互相混淆严重,考虑在特征层加类别间的对比损失,或者干脆合并成一个大类再细分,产线上有时“先检出再细分”比“一步到位”更稳。
5. 避坑与排查:那些让 mAP 虚高、产线翻车的细节
这一章是踩坑记录,每条都按现象、原因、解决写。这些问题在公开数据集上不一定暴露,但迁移到真实产线就会集中爆发。
5.1 验证集 mAP 很高,产线漏检严重
现象:离线评估 mAP 0.85,上线后稀有类漏检率超过 40%。原因通常是验证集和训练集同分布,而产线图像的光照、布料批次、相机参数都变了,模型过拟合到训练集的纹理和色彩先验。解决:划分验证集时按批次或按时间段切分,不要随机切;上线前用一批未参与训练的新批次图做一次盲测;色彩归一化用在线统计的均值和方差,而不是固定训练集的值。
5.2 loss 正常下降但验证集 AP 不动
现象:训练 loss 一路降,验证集每类 AP 从第 20 轮开始横盘。原因多半是标注粒度不一致导致模型学到的框回归目标自相矛盾,或者数据增强过强让验证分布和训练分布偏离。解决:先关掉 Mosaic 和随机裁剪跑一版,看 AP 是否恢复;再抽查验证集的预测可视化,看框是偏大偏小还是位置漂移;如果是粒度问题,考虑把评估改成按缺陷面积分桶看 AP,而不是整体平均。
5.3 小目标召回始终上不去
现象:面积小于 32×32 的框 recall 低于 0.3,调 anchor 无效。原因是特征图分辨率不够,小目标在高层特征上已经消失。解决:加 P2 检测层,或者把输入分辨率从 640 提到 1024;同时检查正样本分配策略,小目标容易被 IoU 阈值筛掉,可以降低小目标的正样本 IoU 门槛,或用中心点采样代替 IoU 采样。
5.4 背景纹理被大量误检为油污
现象:纯纹理区域出现大量低置信度油污框,precision 被拉低。原因是油污和深色纹理在低分辨率下特征相似,且负样本挖掘不足。解决:加入纯背景图作为负样本参与训练;提高分类头的背景类权重;推理时对低置信度框做基于纹理特征的二次过滤,比如计算框内梯度方向一致性,纹理规则的区域直接压掉。
5.5 多标签图里常见类“吃掉”稀有类
现象:一张图同时有断经和油污时,模型只检出断经,油污框消失。原因是 NMS 阶段不同类之间虽然不互相抑制,但正样本分配时常见类占据了主要梯度,稀有类学习不足。解决:检查正样本分配是否按类独立进行;训练时对同图多类样本做类别平衡采样;推理阶段对稀有类适当放低置信度阈值,再统一做后处理。
6. 从数据集到产线:蒸馏、量化与一套可复用的验证习惯
数据集训到 mAP 满意,只是走完一半。真正决定这个方向值不值得投入的,是模型能不能在产线算力上跑起来、能不能在批次切换时稳住。我一般会做两件事:先把大模型的知识蒸馏到小模型,再做量化,最后用一套固定的盲测流程验收。
蒸馏的做法是拿训好的大模型当教师,小模型当学生,损失由检测损失加蒸馏损失组成。蒸馏损失作用在分类头的 logits 和特征图上,温度 T 取 2 到 4,权重从 0.5 开始试。工业场景里教师模型不必太大,关键是教师在新批次上的泛化要稳,否则蒸馏会把过拟合也传下去。
# 蒸馏损失的核心形式(分类头部分),T 为温度,alpha 为权重 import torch.nn.functional as F def distill_loss(student_logits, teacher_logits, labels, T=3.0, alpha=0.5): # 硬标签损失 hard = F.cross_entropy(student_logits, labels) # 软标签蒸馏损失,教师梯度不回传 soft = F.kl_div( F.log_softmax(student_logits / T, dim=1), F.softmax(teacher_logits / T, dim=1), reduction="batchmean", ) * (T * T) return (1 - alpha) * hard + alpha * soft参数说明:T 越大软标签越平滑,稀有类的类间关系信息传得越多,但太大(超过 5)会让学生学不到尖锐边界;alpha 控制蒸馏强度,小模型容量有限时 alpha 别超过 0.7,否则硬标签学不扎实。蒸馏后必须重新在验证集上按类看 AP,确认稀有类没掉。
量化方面,训练后静态量化对小模型友好,但检测头的框回归对量化误差敏感,建议只量化 backbone,检测头保留浮点,或者用量化感知训练。量化后一定要用同一批盲测图对比浮点模型和量化模型的每类 AP,掉超过 3 个点就要回退检查敏感层。
验收习惯上,我固定用三组数据:训练同批次、跨批次、极端光照。每组至少 200 张,人工复核漏检和误检。三组都过才认为可以上线。这个习惯比任何单次 mAP 都可靠,因为产线不看你验证集多漂亮,只看漏没漏。
说到底,布匹瑕疵数据集-2019天池这类数据的价值不在刷分,而在逼你把小目标、长尾、纹理干扰这几个工业视觉的老问题一次性面对。我自己的教训是:每次想跳过数据统计直接训模型,最后都会在排查阶段加倍还回来。先把标注翻烂,再谈模型。希望帮到你。
本文还有配套的精品资源,点击获取