NEU-DET数据集这几年在工业视觉圈子里几乎成了“入门必刷”的基准,我做表面缺陷检测项目这两三年,前前后后在它上面折腾了不少时间,从最早拿YOLOv5跑着玩,到后来做数据增强对比实验,再到给产线项目做可行性预研,都离不开这1800张图。今天就把我对这个数据集的理解、踩过的坑以及一套比较稳妥的实操流程整理出来,给准备入坑或者正在调参的朋友做个参考。
先说这个数据集是什么。NEU-DET是某高校金属材料实验室公开的钢材表面缺陷检测数据集,全称是NEU surface defect database,收录的是热轧带钢表面的六类典型缺陷图像,一共1800张,每类300张,图像尺寸统一为200乘200像素,灰度图。它同时提供分类标注和物体检测用的边界框标注,后者就是大家常说的NEU-DET版本。由于发布于2013年前后,它成了目标检测算法在工业质检场景下最常用的公共测试集之一,但凡研究钢材表面缺陷的论文,十有八九都会在自己的方法对比表里带上它的mAP数字。
这个数据集最吸引人的地方在于“真实”。它不是合成图,也不是实验室里摆拍出来的,而是从实际热轧产线上采集的样本,缺陷形态带着产线上真实存在的噪声、纹理和光照变化。对于做工业视觉的朋友来说,这比在CIFAR或者ImageNet上刷精度有价值得多——你面对的是真正在产线上会出现的东西。
1. 数据集整体设计与思路拆解
1.1 为什么是六类缺陷、每类300张
先聊一个很多人会忽略的问题:为什么NEU-DET长这样?200乘200的分辨率、1800张总量、六类缺陷的设定,其实都是照着钢材质检的实际需求来设计的。
热轧带钢表面的缺陷类型非常多,但真正影响下游客户使用的、频率又比较高的就那么几类:裂纹、夹杂、斑块、凹坑、氧化铁皮压入、划伤。这六类在国标和行业标准里都有对应的描述,选它们做分类,意味着模型学出来的结果能直接对应到质检术语上,方便跟工艺工程师沟通。
每类300张、图像尺寸只有200乘200,则是当年采集和标注成本约束下的产物。热轧产线上能拿到的缺陷样本本来就少,要凑够每类300张已经不容易了。分辨率定在200乘200,是因为这个尺寸足够看清缺陷的纹理和边缘特征,又能让早期基于传统特征加分类器的方案跑得动。放到现在看,200乘200确实偏小,很多缺陷在图像里只占十几个像素,但对当年的硬件和算法水平来说,这是一个兼顾可行性和实用性的选择。
1.2 分类任务与检测任务的关系
NEU-DET经常被当成“一个数据集”,实际上它有两套标注:一套是每张图一个类别标签,用于图像分类;另一套是为检测任务准备的边界框标注,每张图里可能有多个目标框。这两套标注的价值不同。
分类标注适合快速验证骨干网络和预训练权重的好坏。检测标注才是真正贴近产线的标注方式,因为一块带钢表面的缺陷不会只出现一处,有的图里同时存在四五个凹坑和划伤,分类任务只能告诉你“这张图有凹坑”,检测任务能告诉你“凹坑在哪儿、有几个”。做产线质检的人要的是后者。
我个人的建议是,如果你目标是发论文或者做方法对比,分类和检测都可以玩;如果目标是复现一个能用的质检模型,直接上检测标注,别在分类上浪费时间。
2. 六类缺陷的形态特征与检测难点
2.1 每一类缺陷到底长什么样
把六类缺陷的形态搞清楚,比调参重要得多。我刚开始训练的时候,模型在mAP上总是上不去,后来一帧一帧翻测试集才发现,问题是把“裂纹”和“划伤”当成一回事了,原因是我根本没仔细看它们的形态区别。
裂纹(Crazing):表现为表面呈网状或龟裂状的细纹,形态像干裂的泥地,方向杂乱,深浅不一。这类缺陷在200乘200的图像里通常占据比较大面积,但纹理细碎,跟背景的灰度差不明显,尤其跟氧化铁皮压入混在一起时,肉眼都容易看错。检测难度高。
夹杂(Inclusion):这是我最喜欢的一类,因为特征最“硬”。它是轧制过程中夹杂物被压入表面形成的,表现为颜色较深(或较亮)的点状、条状区域,边缘清晰,对比度高。在灰度图上通常是一块明显的暗斑,周围纹理变化不大。检测难度低,学起来最快。
斑块(Patches):表现为大面积的不规则灰色区域,灰度值与周围背景有差异但边界模糊,形状像水墨晕开的感觉。有些斑块非常淡,跟背景几乎融为一体。检测难度中等偏高,主要难在边界定位不准。
凹坑(Pitted Surface):表面出现离散的圆形或不规则形凹陷,表现为一个个深色小点或小坑,有的带明显的边缘阴影。单看一张图很直观,但难点在于数量多少不一,有的图里只有一两个,有的图里密密麻麻一大片。检测难度中等,难在每个坑都要定位。
氧化铁皮压入(Rolled-in Scale):这是热轧产线的“老朋友”,高温轧制时氧化铁皮被压入表面形成的片状或条状缺陷,肉眼呈灰黑色、形态不规则,表面粗糙,通常会有明显的灰度跃变。跟夹杂有点相似,但氧化铁皮的边缘更毛糙、内部灰度更不均匀。检测难度中等。
划伤(Scratches):细长线条状缺陷,方向通常跟轧制方向一致,灰度可能比背景暗也可能更亮,线条有连续也有断续。难点在于细长目标在检测框里占的面积很小,而且容易跟裂纹混淆。检测难度偏高。
2.2 混淆矩阵背后的视觉相似性
如果你训练完模型后打印出混淆矩阵,会发现最常见的错误基本集中在两对组合上:裂纹与划伤、斑块与氧化铁皮压入。这不是算法的锅,是视觉特征本身就接近。
裂纹是网状分散的细纹,划伤是连续方向性的线条,但分辨率只有200乘200时,细裂纹看起来就像几条方向杂乱的短划伤。斑块是灰度渐变的区域,氧化铁皮压入则是灰度跳变剧烈的片状区域,当氧化铁皮的边缘被压缩或者模糊后,两者的边界就变得难以区分。做数据增强或者挑选验证集的时候,要有意识地把这两对作为“易混类”单独观察误差,而不是只看整体mAP。
3. 标注格式、数据切分与统计细节
3.1 检测标注是什么格式
NEU-DET的检测标注是PASCAL VOC风格的XML文件,每张图对应一个同名XML,里面记录了图像尺寸和目标边界框。一个标准的XML大致长这样:
<annotation> <folder>NEU-DET</folder> <filename>0c4b19f8.jpg</filename> <size> <width>200</width> <height>200</height> <depth>3</depth> </size> <object> <name>inclusion</name> <bndbox> <xmin>68</xmin> <ymin>66</ymin> <xmax>172</xmax> <ymax>178</ymax> </bndbox> </object> </annotation>需要注意的是,虽然原始图像是灰度图,但XML里记录的depth是3,读取的时候很多框架会按三通道处理,这本身没有影响,但如果你在预处理里做了通道归一化,别被这个字段带偏了。
3.2 类别实例数量并不均衡
这是很多人没注意的“隐藏问题”。NEU-DET虽然每类有300张图,但每张图里的目标数量不一样,导致各类别的边界框总数差异很大。有些类的实例数量接近甚至超过1000,有些类不到500。举个实际的数据,根据公开统计,凹坑和斑块的实例框比较多,裂纹和划伤相对少一些。这种天然的不平衡会直接影响训练时的正样本数量,如果你用的是Faster R-CNN这类两阶段检测器,在图像数量少且实例不均衡的情况下,少数类很容易欠拟合。
处理办法有两个方向:一是做类别层面的过采样,让包含裂纹和划伤的图像在每轮训练里被抽到的概率更高;二是用带类别权重的损失函数,给数量少的类别更高权重。我实测下来,过采样操作简单、效果更直接,尤其在小数据集上,权重损失容易出现训练震荡。
3.3 官方没有标准切分,自己动手要有约定
NEU-DET官方没有提供标准的train、val、test划分文件,这就引出两个问题:第一,不同论文用的数据切分不一样,mAP数字没法直接横比;第二,很多人随手train_test_split,不做分层采样,结果某一类在测试集里几乎缺席。
我给的建议是,第一次实验就锁定一个固定的划分方案。一种通用的做法是:按6:2:2做分层随机切分,保证每类缺陷在训练集、验证集、测试集中的图像数量比例保持一致,并固定随机种子。如果用YOLO系列,我习惯先按比例生成一个包含六个类别、每类180张训练图、60张验证图、60张测试图的切分,然后固定它,后续所有实验都不再变动。
4. 实操:从数据预处理到模型训练全流程
4.1 数据下载与目录组织
这一节直接给一份可复现的流程。数据集的下载地址这里不方便贴,搜索NEU-DET或者NEU surface defect database就能找到,网上也有很多镜像。下载完你会得到一个压缩包,解压后大致包含images目录和annotations目录,分别存放200乘200的灰度图和对应的XML文件。
我建议拿到手先做三件事:第一,统一文件命名检查,确认图像和XML一一对应;第二,把XML里的类别名统一成小写字母,有的版本里类名首字母大写,后续脚本处理容易出问题;第三,把所有图像统一转成三通道RGB的jpg再喂给模型。虽然灰度图本身可以按单通道读入,但很多预训练模型的输入是三通道,转成RGB后可以直接复用ImageNet预训练权重。
目录结构可以参考下面这个:
NEU-DET/ ├── images/ │ ├── 0c4b19f8.jpg │ └── ... ├── annotations/ │ ├── 0c4b19f8.xml │ └── ... ├── ImageSets/ │ ├── train.txt │ ├── val.txt │ └── test.txt └── label_map.json4.2 数据增强策略怎么搭配才有效
200乘200的图像是真小,物体检测模型下采样几次之后,特征图上的目标就只剩几个像素了,直接训练效果很差。所以数据增强不是可选项,是必需品。
我实测下来,第一优先级的增强是几何类:随机水平翻转、随机旋转正负30度、随机缩放。这些操作不改变缺陷的本质特征,能有效提升模型对位置和方向的鲁棒性。
第二优先级是像素级增强:随机亮度和对比度调整、高斯模糊、随机噪声。热轧产线采集的图像受光照和氧化皮厚度影响,灰度变化明显,让模型见过更多灰度分布是必要的。
第三优先级是针对性的:Cutout或者RandomErase,随机遮挡一小块区域,强迫模型不要只依赖局部强特征。对于凹坑这类多个小目标的情况,这个增强对提升召回率有明显帮助。
有一个坑要提醒:不要用太大的旋转角度。划伤是有方向性的(通常沿轧制方向),旋转90度或更大角度会让语义发生偏移,学出来的特征在真实产线上反而不可靠。我没限旋转角度之前,模型在验证集上表现不错,但拿到产线拍的图片上测试时,对水平方向的划伤识别能力明显差,后来把旋转限制在正负45度以内才改善。
4.3 用YOLO系列训练的具体配置参考
以YOLOv8为例,配置里我用过一组比较稳定的参数,直接给出来供参考:
# neu_det.yaml path: ./NEU-DET train: ImageSets/train.txt val: ImageSets/val.txt test: ImageSets/test.txt nc: 6 names: 0: crazing 1: inclusion 2: patches 3: pitted_surface 4: rolled_in_scale 5: scratches训练命令:
yolo detect train \ data=neu_det.yaml \ model=yolov8s.pt \ epochs=200 \ imgsz=640 \ batch=16 \ lr0=0.01 \ mosaic=1.0 \ close_mosaic=10 \ augment=True这里有几个参数需要解释一下。imgsz设成640是因为虽然原始图像是200乘200,但YOLO会把图像resize到640,小目标反而能获得更多的有效像素。mosaic增强对NEU-DET这种小图数据集效果很好,但我习惯在最后10个epoch关掉mosaic(close_mosaic=10),因为mosaic合成的图像跟真实单图分布差异很大,关闭后能让模型适应真实的图像分布,收敛更稳定。
我在这个配置下的实验结果是:验证集mAP50能到0.72到0.78之间浮动,mAP50-95大约0.48到0.52。具体数字跟数据切分和随机种子相关系数很大,不同论文报的数字可比性不强,所以别太纠结小数点后第二位。
4.4 用Faster R-CNN做对比实验时的注意事项
如果你想用两阶段检测器做对比,我的经验是注意候选框生成的质量。Faster R-CNN在小数据集上比YOLO更容易过拟合,尤其是RPN部分,因为候选框提案网络需要足够的正样本才能学到“哪儿可能有缺陷”。建议在使用Faster R-CNN时做这几件事:用ImageNet预训练权重而不是随机初始化;把所有类别都框进去的标注直接参与训练,不要因为框太小而过滤掉(默认配置里有些实现会忽略面积小于某个阈值的框,这对小目标数据是致命的);降低NMS的IoU阈值到0.4左右,保住密集小目标的候选框。
5. 常见问题与排查技巧实录
5.1 训练loss正常下降但mAP不涨
这个现象我在NEU-DET上遇到过好几次。loss曲线看起来很正常,但验证集的mAP停留在0.5上下不动。排查方向有两个。
第一个方向是检查目标框的可视化结果。把验证集图像连同预测框画出来,看看漏检的到底是什么。我在实际排查中发现,漏检最严重的是凹坑这种密集小目标,一张图上几十个坑,模型只检出三五个。这说明不是模型没学会,而是正样本数量在NMS阶段被压制了。解决办法是降低置信度阈值,或者针对性地提高小目标的损失权重。
第二个方向是检查augmentation是否过度。mosaic和旋转叠加时,目标框容易扭曲失真,导致训练数据里有不少“假标注”。我的处理经验是,mosaic比例从1.0降到0.5,旋转角度再收紧点,mAP往往能回升几个点。
5.2 训练集精度高,产线图片上完全不能用
这是一个“学术模型落地”的典型问题。NEU-DET的训练集和测试集分布一致,都是实验室环境下采集的清晰灰度图,但产线上相机拍出来的图片可能偏亮、偏暗、有镜头畸变、有粉尘遮挡,分布差异非常大。在我参与的一个模拟项目里,模型在NEU-DET测试集上mAP50达到0.75,迁移到产线采集的样张上时,直接掉到0.4以下。
这不是模型参数的问题,是数据分布的问题。应对思路有两个:一是先用少量产线真实图片对模型做微调,哪怕只有几百张,效果提升也会非常明显;二是做风格迁移或者灰度归一化,把NEU-DET图像和产线图像的灰度直方图对齐后再训练。后者操作起来比较复杂,优先考虑前者。
5.3 六类缺陷数量少怎么扩充
我知道很多朋友想在NEU-DET基础上扩充数据,比如生成更多缺陷样本。我的建议是谨慎使用过采样和基础增强就够了,不要轻易尝试用生成模型造数据。我用过扩散模型生成缺陷图像,结果生成的图像人眼看起来很像,但模型训练后mAP反而下降了。原因很可能是生成的图像在高频纹理细节上和真实图像存在系统性偏差,模型学到了这些偏差,在真实测试集上的泛化反而变差。
如果一定要扩充,优先考虑用真实产线数据,哪怕分辨率不同、光照不同,只要标注准确,都比生成的假数据有价值。
6. 从NEU-DET走向产线部署的差距分析
6.1 数据集评测与真实质检需求的三个差异
第一个差异是评价指标不一样。论文里看mAP,产线上更关注的是每类缺陷的召回率和误报率。一块带钢上如果有一个凹坑漏掉了,客户退货的概率就很高;反过来,误报太多,工人天天处理假警报,系统也部署不下去。
第二个差异是图像来源不一样。NEU-DET每张图是独立采集的一个视野区域,产线上是连续扫描形成的长条图像,需要切割成子图再送检,切割尺寸和重叠率都会影响检测效果。
第三个差异是实时性要求不一样。学术实验里单张图推理速度慢一点没关系,产线上如果带钢速度是每秒几米,留给算法的处理时间可能只有几十毫秒。这时候就需要做模型量化、剪枝或者用轻量级骨干网络,这些在NEU-DET上做评测的意义不大,因为评测关注的是精度而不是速度。
6.2 以NEU-DET为起点做项目预研的正确姿势
如果你跟我一样,是用NEU-DET做产线项目的可行性预研,我的建议是:第一,先用NEU-DET搞清楚六类缺陷的区分边界在哪里,哪些类好分、哪些类难分,这直接影响后续标注规范的设计;第二,拿产线实拍的少量数据做一次“冷启动测试”,看看领域差异到底有多大,这个数据比mAP数字有用得多;第三,用NEU-DET训练出的模型作为基线,产线数据微调后,记录每类缺陷的召回率变化,确定哪些类必须增加数据。
7. 个人实操中的一些体会
最后分享一点我在多次实验里沉淀下来的经验。
NEU-DET这个数据集的价值不在于“刷高分”,而在于它是一面镜子,照出的是你在真实工业场景中会遇到的问题:类别不平衡、小目标检测、易混类别、数据分布迁移、标注噪声。这些问题的处理思路,比模型本身的精度更有复用价值。
我现在的做法是,每次新项目启动时,先花一两天时间把NEU-DET的训练流程完整跑一遍,把它当成“基线体检”。如果YOLOv8在NEU-DET上mAP50连0.7都到不了,那说明环境配置、数据处理流程或者训练参数有基础性问题,先解决这个问题,再去看产线数据。反过来,如果NEU-DET跑得很顺,产线数据效果仍然差,那基本可以断定是领域差异问题,下一步重心就转到采数据和标注上。
另外,保存实验记录的习惯值得养成。我会把每次实验的数据切分文件、增强参数、训练命令、mAP曲线和可视化结果全部归档,这样复现实验结果或者排查问题的时候就不用重新折腾。NEU-DET的体验让我深刻理解了一个道理:在小数据集上做实验,实验管理的重要性甚至超过模型结构的选择。