简介:基于YOLOv5的布匹缺陷检测项目,面向工业质检、计算机视觉学习者与算法竞赛选手,提供了从官方数据集格式转换、滑动窗口切图到模型训练与检测推理的完整Python实现。压缩包内包含8个文件,以6个Python脚本为主,覆盖数据预处理、YOLO格式标注转换、训练与测试流程;另有项目说明Markdown和任务示例Notebook,便于理解源码结构和快速运行。包体仅25KB,轻量精炼,适合已有一定深度学习基础、希望参考工业检测落地思路的用户。当前已有363人学习浏览,资源将官方广东赛题数据组织为code、train_data、models、weights等清晰目录,并给出convertTrainLabel.py、process_data_yolo.py等关键脚本,可直接复现布匹缺陷标注与训练流程,帮助读者掌握YOLOv5在细粒度瑕疵识别中的工程化方法。
1. 布匹缺陷检测难点与yolov5的选型理由
产线上布匹以每分钟几十米的速度通过相机视野,检测装置能在每个缺陷上停留的时间往往只有零点几秒。人工目检在这个节奏下漏检率超过 10% 并不罕见,而布匹表面纹理的周期性又让传统视觉方案吃尽苦头——阈值分割会把纬线交织误判成污渍,边缘检测面对褶皱和阴影时噪声大得没法看。这也是为什么基于深度学习的布匹缺陷检测算法能在近两年快速替换掉老一代机器视觉方案:它不再靠人工设计特征,而是直接从图像里学出“哪些纹理异常属于缺陷”。
yolov5 在这个场景里是个务实的选择。它不像两阶段检测器那样慢,精度又比早期单阶段模型稳,部署生态在工控机和 Jetson 这类设备上已经非常成熟。拿到一份“python源码+项目说明+数据集.zip”的项目包,实际上就是在围绕这四块工作:环境搭建、数据准备、模型训练、验证部署。这篇文章就按这条路径把每一段会踩的坑和能用上的参数讲透,新手能照步骤跑通,熟手也能找到锚框设置、超参数调优和部署细节上的增量信息。
2. 布匹缺陷检测为什么先跑通yolov5环境
2.1 小目标与纹理背景决定了yolov5而不是yolov8
布匹缺陷检测的难点不在“有没有缺陷”,而在“缺陷太小且和背景太像”。一根断掉的纬纱在 640x640 的输入图上可能只占 10 个像素宽、几十个像素长,和正常织纹混在一起。yolov5 的 PANet 结构对这类小目标比早期 YOLOv3 友好得多,它把高层语义信息和底层纹理细节反复融合,缺陷即使只占几个像素也能在特征图里留下响应。另一个关键机制是自适应锚框:训练时 yolov5 会根据你的数据集自动重新聚类锚框尺寸,而不是死守 COCO 的默认值。
至于为什么不直接上 yolov8,核心原因是部署半径。布匹缺陷检测的落地端通常是工控机甚至边缘盒子,yolov5 的 ONNX 导出、TensorRT 加速、C++ 推理示例在社区里积累得最多,遇到问题搜得到答案;yolov8 某些新模块在这些老设备上的算子支持反而没那么全。模型大小对比上也说明问题,s 版本只有 14 MB 左右,在产线要求的实时性下性价比最高。
在布匹数据上,不同缺陷的长宽比差异很大,锚框设置直接决定小目标召回率。做数据准备时可以先粗略统计一下:
| 缺陷类型 | 典型长宽比 | 对锚框的要求 |
|---|---|---|
| 破洞 | 接近 1:1 | 小方形锚框 |
| 污渍 | 1:1 到 2:1 | 中小尺寸锚框 |
| 缺纬 | 1:5 以上 | 极扁长锚框 |
| 褶皱 | 3:1 到 5:1 | 长条锚框 |
如果某个类别的长宽比统计结果突变,比如油渍全是圆形而缺纬全是细长条,就把这些极端形状的量级信息记下来,后面训练时关闭自动锚框或手动指定范围,防止 autoanchor 把所有锚框都拉到中性尺寸。
2.2 yolov5环境配置的最小命令与显卡选择
拿到源码包后第一步不是改代码,而是把依赖环境装到和作者一致的状态。yolov5 官方推荐 Python 3.8 到 3.10,PyTorch 1.8 以上即可,但不同版本之间算子实现有差异,建议先按源码里的 requirements.txt 安装而不是自己拼版本。环境配置的完整流程通常是:
conda create -n fabric python=3.8 -y conda activate fabric cd yolov5-master pip install -r requirements.txtrequirements.txt 里的核心依赖大致包括 torch、torchvision、opencv-python、numpy、matplotlib、pyyaml、tqdm、seaborn 等。安装时有一点容易忽略:如果机器有 NVIDIA 显卡,要在安装 torch 之前先确认 CUDA 版本,用nvidia-smi看驱动支持的 CUDA 版本,再到 PyTorch 官网选对应的安装命令;否则 pip 默认装 CPU 版 torch,训练速度差几十倍。没有独显的环境也能跑,但 batch size 要压到 4 以下,且一定要开--cache缓存数据,否则 CPU 和磁盘会成为瓶颈。
装完后用一条推理命令验证环境是否通:
python detect.py --weights yolov5s.pt --source ./test.jpg --conf-thres 0.25yolov5s.pt 如果本地没有会自动从 GitHub 下载,跑通后会在runs/detect/exp下生成标注了检测框的结果图。这一步能确认 torch 版本、CUDA 可用性和 opencv 读取路径都没问题。如果报 CUDA 不可用,检查torch.cuda.is_available()返回值,而不是盲目重装整个环境。
2.3 用预训练权重先看单张布匹图的检测效果
很多人习惯直接拿自己的数据集开始训练,但我建议先用 COCO 预训练权重跑几张布匹图,哪怕检测结果全是错的也无所谓。目的有三个:确认推理管线完整;观察模型在纹理背景上会产生什么类型的误检;为后面判断训练是否收敛留一个“差基线”。执行时注意--conf-thres不要设太高,布匹缺陷普遍对比度低,预训练模型给的置信度本来就不会高。
python detect.py --weights yolov5s.pt --source ./fabric_samples/ --conf-thres 0.1 --save-txt加--save-txt后,每张图的检测结果会以小写类别代号和归一化坐标写到runs/detect/exp/labels目录下。如果预训练模型在布匹图上除了误检什么都没有,甚至误检框都没有,属于正常现象——COCO 的类别里没有“破洞”和“缺纬”,模型只能提取一些底层纹理特征。观察的是它把背景召回的程度:误检框特别密集说明特征提取在周期性纹理上不稳定,这对后续布匹缺陷检测算法调参有参考价值,训练时数据增强就要侧重打破纹理周期。
提示:跑推理时如果 GPU 显存占用很高但帧率极低,多半是显存里同时加载了多个 batch 或开了
--augment,调试阶段默认参数即可。
3. 布匹缺陷数据集的标注、格式转换与增强
3.1 缺陷类别划分与样本量策略
布匹缺陷检测算法里数据准备比模型结构更决定上限。先定义类别,常见的工业缺陷分类包括破洞、污渍、褶皱、缺纬、跳花、油渍等,具体以项目说明文档里的标注规范为准。分类粒度会影响训练难度:把“油渍”和“水渍”并成一类“污渍”,模型更容易学;分成多类则每类样本量被摊薄,小样本类别容易欠拟合。我的建议是第一版训练控制在 4 到 8 类,先保证每类的可区分性,再考虑细分。
样本量上有一个经验线:每个类别至少 500 个标注实例,且小目标(相对原图面积小于 1%)的占比不能太低。如果实际收集到的画面里大面积缺陷占多数,训练出来的模型会对小缺陷不敏感。观察布匹数据集的常见做法是跑一轮统计脚本,打印所有标注框的宽高分布和面积分布,如果发现宽度小于 32 像素的框占比过低,说明数据集存在明显的尺度偏差,需要在增强阶段有意补充。
import os import cv2 label_dir = "datasets/fabric/labels" stats = {"small": 0, "total": 0} for f in os.listdir(label_dir): if not f.endswith(".txt"): continue img_path = os.path.join("datasets/fabric/images", f.replace(".txt", ".jpg")) h, w = cv2.imread(img_path).shape[:2] with open(os.path.join(label_dir, f), "r") as fp: for line in fp: _, cx, cy, bw, bh = map(float, line.split()) box_w, box_h = bw * w, bh * h stats["total"] += 1 if box_w * box_h < w * h * 0.01: stats["small"] += 1 print("small ratio:", stats["small"] / stats["total"])这段脚本从 YOLO 格式的标签文件里读归一化坐标,乘回原图宽高后计算标注框面积占比。小于 1% 的框计入小目标统计。如果 ratio 低于 0.3,后面训练时要重点依赖 mosaic 和 copy-paste 增强来补偿小缺陷样本不足的问题。
3.2 标注工具选型与XML转YOLO格式的Python转换脚本
布匹图像标注最常见的工具是 LabelImg,但它默认输出 PASCAL VOC 格式的 XML 文件,而 yolov5 训练需要 YOLO 格式的 txt。虽然新版 LabelImg 可以直接切到 YOLO 模式,但对小缺陷标注来说,XML 格式更方便做跨工具迁移和后续检查,代码里做一次统一转换也更可控。转换脚本是必须的工具链一部分:
import xml.etree.ElementTree as ET import os classes = ["hole", "stain", "fold", "missing_weft"] def convert(xml_path, out_dir): tree = ET.parse(xml_path) root = tree.getroot() img_w = int(root.find("size/width").text) img_h = int(root.find("size/height").text) lines = [] for obj in root.iter("object"): cls = obj.find("name").text if cls not in classes: continue box = obj.find("bndbox") xmin = float(box.find("xmin").text) ymin = float(box.find("ymin").text) xmax = float(box.find("xmax").text) ymax = float(box.find("ymax").text) cx = (xmin + xmax) / 2 / img_w cy = (ymin + ymax) / 2 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{classes.index(cls)} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") out_name = os.path.splitext(os.path.basename(xml_path))[0] + ".txt" with open(os.path.join(out_dir, out_name), "w") as fp: fp.write("\n".join(lines)) for f in os.listdir("annotations"): if f.endswith(".xml"): convert(os.path.join("annotations", f), "labels")坐标必须除以整张图的宽高归一化,而不是缩放到 640x640——yolov5 训练时内部会做 letterbox 缩放,标签如果基于固定尺寸归一化会错位。保留 6 位小数是为了在 4000x3000 的大图上也不丢亚像素精度。转换完成后抽样打印几个 txt 文件,检查坐标是否落在 0 到 1 区间,小于 0 大于 1 一定是标注框越界或写错了分母。
3.3 从自定义数据集到注册机制的data.yaml配置
yolov5 使用 data.yaml 描述数据集路径和类别映射,这个文件虽然短,但路径写错是训练失败最常见的原因。一个可用的配置模板如下:
train: /data/fabric/train/images val: /data/fabric/val/images nc: 4 names: ["hole", "stain", "fold", "missing_weft"]train 和 val 指向存放图片的目录,yolov5 会自动在同级 paths 下找 labels 目录。所有训练图片和标注文件的文件名要一一对应且都在对应子目录里,否则报 “image not found” 或标签缺失。names 的索引顺序必须和转换脚本里 classes 列表完全一致,这一步错了模型会拿“破洞”的标签去学“污渍”的特征,训练曲线还看不出异常。
数据划分上按 9:1 切训练集和验证集,并且要保证划分是按“布匹卷”而不是按“单张图”做的。同一卷布相邻位置的图像纹理高度相似,如果它们同时出现在训练集和验证集里,验证指标会虚高,部署到新布种上立刻露馅。切分时直接按目录或文件名前缀分组。
3.4 针对布匹纹理的增强组合:亮度抖动、mosaic与小目标复制粘贴
布匹检测场景里,数据增强的核心目标是打破纹理周期性和模拟现场光照波动。yolov5 内置的 hyp 配置文件里默认开了 mosaic、flipr、hsv_h、hsv_s、hsv_v 等增强,但对布匹来说默认亮度抖动幅度不够。现场产线的光源会因为电压波动和灯管老化出现缓慢变化,建议把 hsv_v 从默认 0.4 往 0.5 到 0.6 调,让模型见过更多明暗变化。
yolov5超参数中的 mosaic 对布匹缺陷尤其重要。一个 batch 里拼接 4 张图,等于把 4 个不同纹理区域的缺陷组合进同一张训练图,模型被迫学会在纹理变化的背景下找缺陷,而不是记住某块背景。对小目标,可以再配合 copy-paste 增强:从其他图里把标注好的缺陷裁剪下来,随机贴到当前图上并同步生成新标签。这种方法对布匹缺陷检测算法特别有效,因为织物纹理相对均匀,贴入的缺陷在视觉上不突兀,且能把稀缺的小缺陷样本复用几十次。
hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.5 mosaic: 1.0 copy_paste: 0.3 fliplr: 0.5copy_paste 开启后训练时间会变长,因为每次迭代都要做随机裁剪和粘贴的额外计算。显存紧张时优先保证 batch size 而不是增强强度,batch 小到 4 以下时增强带来的随机性反而会把梯度方向搅乱。
4. yolov5训练布匹缺陷模型的参数设置与调优
4.1 模型配置文件里修改nc与depth_multiple
训练自己的数据集时,第一步要改的是models/yolov5s.yaml里的类别数。yolov5 6.0 之后把类别数从 data.yaml 挪到了模型文件里,网上大量旧教程还停留在改 data.yaml 的 nc 字段,照做会导致模型输出维度和标签维度对不上,训练直接报维度错误。修改要点如下:
nc: 4 depth_multiple: 0.33 width_multiple: 0.50nc 改成自己的类别数。depth_multiple 和 width_multiple 控制网络深度和宽度,0.33 和 0.50 对应的是 s 版本。如果显卡显存不紧张,可以换models/yolov5m.yaml提高精度,布匹缺陷检测里 m 版本比 s 版本通常能多出 2 到 3 个点的 mAP,代价是推理时间增加约 40%。工控机上如果 deadline 紧,优先考虑 s 版本加更好的数据增强来补精度。
4.2 训练命令与关键参数说明
配置完成后启动训练,用下面这条命令作为起点:
python train.py --img 640 --batch 16 --epochs 200 --data fabric.yaml --weights yolov5s.pt --hyp hyp.scratch-low.yaml --cache-ram参数含义逐一说明:--img 640是输入分辨率。布匹缺陷小,理论上 1280 能保留更多细节,但显存占用是平方级增长、推理速度也显著下降。我先用 640 训练一版看小目标表现,如果缺纬这类细长缺陷召回不够,再单独用 1280 微调,而不是全程跑大图。--batch 16取决于显存,8 GB 显存跑 s 版本 640 分辨率大约能支撑 16 到 24,显存溢出时优先减 batch 而不是减分辨率。--epochs 200对缺陷检测足够,数据量大或类别多就加到 300。--weights yolov5s.pt加载 COCO 预训练权重做迁移学习,是收敛速度的关键;除非要做对比实验,否则不要用--weights ''从头训练。--cache-ram把数据集一次性读入内存,能极大减少磁盘 I/O 等待。
训练日志里重点观察两个指标:box_loss和cls_loss。如果 box_loss 持续下降但 cls_loss 在某个点后不再变化,说明缺陷类别之间的可区分性不够,可能是标注类别定义模糊或者背景干扰太强,这时候加更多数据比加大模型更有效。
4.3 hyp.scratch-low.yaml里值得手动改的超参数
yolov5 的超参数配置里,不是所有参数都需要动,但有几个对布匹缺陷检测影响明显。打开data/hyps/hyp.scratch-low.yaml,关注这几项:
| 参数 | 作用 | 布匹场景建议 |
|---|---|---|
| lr0 | 初始学习率 | 默认 0.01,数据量少时降到 0.005 |
| lrf | 最终学习率系数 | 保持默认 0.01 |
| warmup_epochs | 预热轮数 | 3 到 5,batch 小的时候用更大值 |
| mosaic | mosaic 增强概率 | 布匹纹理复杂或样本少时保持 1.0 |
| fliplr | 水平翻转 | 左右镜像对大多数缺陷有效,保持 0.5 |
warmup 机制值得多说一句:训练初期模型权重是随机的,直接上大学习率会让梯度方向剧烈震荡,前几个 epoch 先用小学习率“预热”,等 loss 从初始值降下来再切到正常学习率。布匹数据集如果只有几百张图,warmup_epochs 调到 5 以上能明显减少前 20 轮训练曲线的大幅抖动。
4.4 autoanchor重算与训练中断恢复
yolov5 会在训练开始时自动对数据集做 k-means 锚框聚类,日志里会打印 "AutoAnchor" 相关的提示。内置的锚框面积是一组 9 个不同尺度的框,如果聚类结果和默认值差异过大,训练早期阶段的定位损失会偏高。我的做法是先跑 20 个 epoch,从runs/train/exp下的anchors.png查看聚类分布,如果大部分缺陷的长宽比集中在图的一角,说明 anchor 初始化偏移了,需要把自动计算出来的新锚框填入模型 yaml 并关闭 autoanchor 重训。转移学习时不要手动修改锚框,让预训练阶段给够时间,通常 100 轮后模型自己会适应。
中断恢复用--resume runs/train/exp,可以接着上次的权重和优化器状态继续训练,epoch、学习率调度都会自动接上。布匹缺陷训练动辄十几个小时,跑了一半断电是常事,建议训练命令写进 shell 脚本里,配合 nohup 或 tmux 运行,避免终端意外关闭导致进程被杀。
5. 布匹缺陷检测的mAP验证与部署技巧
5.1 val.py验证与per-class AP分析
训练结束后第一件事不是急着部署,而是跑验证:
python val.py --weights runs/train/exp/weights/best.pt --data fabric.yaml --img 640 --conf-thres 0.001 --iou-thres 0.6验证集上输出的 mAP 指标里,mAP@0.5和mAP@0.5:0.95的差距在布匹场景通常比通用目标检测大,因为小缺陷在 IoU 阈值提高后边界稍微偏一点就判负。产线验收时如果允许单帧漏检再由后续帧补回,我通常更看重 mAP@0.5 和召回率而不是死磕 0.95。建议把验证输出里 per-class 的 AP 表拉出来看,破洞 AP 低而污渍 AP 高时,大概率是破洞样本尺度太小,优化方向是提高输入分辨率或在增强阶段做针对性过采样,而不是统一调置信度阈值。
5.2 导出ONNX并搭一个最小Python推理接口
部署第一步是导出与训练框架解耦的模型格式,yolov5 对 ONNX 支持成熟:
python export.py --weights runs/train/exp/weights/best.pt --include onnx --opset 11用 ONNX Runtime 的好处是不依赖 PyTorch 环境,现场只需要安装 onnxruntime 和 opencv。一个最小可用的推理脚本结构如下:
import cv2 import numpy as np import onnxruntime as ort session = ort.InferenceSession("best.onnx") input_name = session.get_inputs()[0].name def letterbox(img, size=640): h, w = img.shape[:2] r = min(size / h, size / w) new_w, new_h = int(w * r), int(h * r) resized = cv2.resize(img, (new_w, new_h)) canvas = np.full((size, size, 3), 114, dtype=np.uint8) x, y = (size - new_w) // 2, (size - new_h) // 2 canvas[y:y+new_h, x:x+new_w] = resized return canvas, r, x, y img = cv2.imread("test.jpg") padded, r, x, y = letterbox(img) blob = padded[:, :, ::-1].transpose(2, 0, 1)[None].astype(np.float32) / 255.0 outputs = session.run(None, {input_name: blob})[0]letterbox 预处理保持原始宽高比缩放,多余部分用灰色填充,这一步必须和训练时一致,否则坐标映射会错位。yolov5 的 ONNX 输出形状是(1, 25200, 5+nc),25200 是三个尺度特征图所有候选框的总数,5 对应 cx、cy、w、h 和 objectness。后处理要做置信度阈值过滤和 NMS,置信度可以按类别分别设置:破洞这类小缺陷的分数普遍偏低,conf_thres 给 0.15;污渍相对好检测,给 0.3,统一阈值会漏掉前者或放大后者的误检。
5.3 产线上值得用的三个部署技巧
布匹检测部署和普通目标检测有个典型差异:输入不是独立图片,而是连续运行的视频流。利用这个时间连续性可以做帧间轨迹叠加——同一缺陷在连续多帧里位置连续变化,单帧置信度略低于阈值的候选框,如果前后帧在同一位置都出现了,就认为它是真实缺陷;反之单帧高置信度但前后帧消失的,大概率是飞花或者反光噪声。这个策略能把漏检率再降一个档次,比盲目调低阈值安全得多。
第二个技巧是光照自适应。现场灯管老化、电压波动都会改变布面亮度,训练时虽然做了亮度增强,但极端情况下照度变化超过模型见过的范围。部署端可以在相机前加平场校正,或按区域统计灰度均值并做线性调整,把输入图的亮度分布拉回训练集的分布区间。第三个技巧是部署后用一段带标注的新产线数据做在线验证,把不同时段的模型预测结果存成日志,定期统计误检和漏检属于哪一类缺陷——决策要跟着数据走,不要凭感觉调超参数。
本文还有配套的精品资源,点击获取