尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

PCD表面元器件缺陷检测:YOLO数据集与训练实践

PCD表面元器件缺陷检测:YOLO数据集与训练实践 简介一份面向目标检测与缺陷识别场景的PCD表面元器件缺陷检测数据集适用于YOLO系列网络训练也适合PCB质检、电子制造自动化等方向的研究者与工程师。数据集包含608张标注图像及对应609个txt标签文件另附class类别文件和可视化脚本共1219个文件压缩包57.41MB已按训练集、验证集划分并经数据增广处理可直接用于模型训练与验证。缺陷类别共7种涵盖Miss、mask defect、defect等类型覆盖电路板表面常见元器件异常。配套的show脚本可将标注框绘制到图像上便于直观检查标注质量与模型预测效果。目前已有383人学习适合需要快速获得带标签数据集、开展YOLO系列缺陷检测实验的开发者。1. 从“能用”到“好用”PCD表面元器件缺陷检测数据集为什么值得拆开看PCB板上的表面元器件PCD缺陷检测和常见的PCBA整板缺陷检测完全是两回事。整板检测关注的是焊点少锡、桥连、元件偏移而PCD级检测要把视角拉近到单个电容、电阻、排阻的表面miss漏贴、mask defect掩膜缺陷、本体缺损、划痕等。这类缺陷在整板标注里往往只占几个像素模型很难学到区分性特征。这个数据集专门拿超过600张近景图像做标注7个缺陷类别全部转成YOLO格式并已经划分好训练集、验证集还做了数据增广。对真正要落地表面元器件质检的团队来说600张图听起来少但配合已有的YOLOv8预训练权重足以在几天内训练出一个能跑在产线工控机上的检测模型。下面把目录结构、标签格式、可视化脚本和训练参数一条条拆开方便你直接复现。2. 目录结构、class文件与YOLO标签格式一套可直接送入训练管线的最小闭环先讲清楚这个数据集交付了什么。除了超过600张JPG/PNG图像每张图都对应一个同名txt标签文件标签采用YOLO标准格式类别ID加归一化的中心点坐标和宽高。数据集中附带class文件列出全部7个类别顺序决定标签文件里的ID编号训练时classes列表必须和这个文件保持一致。另外数据集还做了data增广意味着train目录里的图片可能是原始图、旋转、亮度变化、马赛克增强等副本但标签文件会同步变换过可以直接训练不需要再做对齐。2.1 典型的YOLO数据集目录结构拿到资源后解压完一般是下面这种组织方式pcd_defect_dataset/ ├── train/ │ ├── images/ │ │ ├── 6_PNG_jpg.rf.e9eafa26558f3ce2defce65e40498238.jpg │ │ └── ... │ └── labels/ │ ├── 6_PNG_jpg.rf.e9eafa26558f3ce2defce65e40498238.txt │ └── ... ├── valid/ │ ├── images/ │ └── labels/ ├── classes.txt └── show_annotations.py部分打包版本会把可视化脚本放在根目录需要说明的是不同发布者会把数据yaml配置放在不同位置常见做法是在根目录放一个data.yaml内容指向train和valid的图片目录。如果收到的手动包里没有data.yaml自己新建一个即可路径用绝对路径或者相对你执行命令的目录来写。2.2 标签文件与class文件的对应关系每个txt文件里每行代表一个目标框格式为0 0.5123 0.4788 0.1234 0.0867从左到右依次是类别ID、x中心归一化到0-1、y中心、宽度、高度。注意这里中心点和宽高都是相对图片宽高的比例值不是像素坐标。类别ID是从0开始的不是1。所以classes.txt里的第一个类对应ID 0第二个对应ID 1以此类推。拿这个数据集的类别来说7个缺陷类型可能包括Miss、mask defect、defect等实际名称以classes.txt为准。如果names列表写错顺序训练时loss照常下降但推理时标签显示会错位所以先打开class文件检查一下。下面是一个读取yaml配置的示例代码训练前把names顺序和txt里的ID对齐from pathlib import Path def load_class_names(class_txt_path): names [] with open(class_txt_path, r) as f: for line in f: line line.strip() if line: names.append(line) return names classes load_class_names(classes.txt) print(f类别总数: {len(classes)}) for idx, name in enumerate(classes): print(fID {idx}: {name})这段代码会把classes.txt里的每一行读取为一个类别名并输出对应的ID。训练脚本需要同时引用类别数和类别名列表确保和标签文件使用相同顺序。如果你的数据里有新的缺陷类型需要加入必须修改class文件并在所有对应标签上新增或修改ID否则模型输出的置信度会错配。2.3 检查标签边界是否越界从Roboflow导出的数据通常不会越界但如果是手工整理的YOLO标签常常出现宽度或高度大于1、中心点负数这类问题。下面这个脚本可以快速统计越界框import glob label_files glob.glob(train/labels/*.txt) bad_count 0 for label_file in label_files: with open(label_file, r) as f: for line_num, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: print(f{label_file}:{line_num} 非5段格式: {line}) bad_count 1 continue _, x, y, w, h map(float, parts) if x 0 or y 0 or w 1 or h 1 or x 1 or y 1: print(f{label_file}:{line_num} 越界: {line}) bad_count 1 print(f异常标签数量: {bad_count})参数说明这里假设标签文件都在train/labels目录下glob匹配所有txt。x、y、w、h都是0到1的归一化值如果w或h大于1说明标注框比整张图还大需要回看原图。对于越界的框推荐在训练前用脚本裁剪到[0,1]区间而不是直接删除因为删除会让那张图少一个真实目标削弱对缺陷的召回能力。异常类型判断条件处理方式中心点越界x或y小于0或大于1裁剪到0-1区间宽高越界w或h大于1检查标注框是否跨图类别ID越界类别ID大于等于nc检查classes顺序2.4 数据增广后的训练注意事项这个数据集已经做了data增广很多旋转、平移后的图片特征与原图有较大差异。YOLO训练时如果继续使用默认的在线Mosaic增强相当于在增广过的图片上再做一次组合有几率把缺陷纹理变成完全不真实的伪影。常见做法是关闭或降低Mosaic强度例如设置mosaic0.0只保留hsv扰动和水平翻转。同时增广后的标签文件里坐标可能已经出界使用上一节的越界检查脚本跑一遍确保所有框都在有效范围内。3. show脚本可视化边界框先确认标签可靠再谈模型训练模型训练前的数据验证环节很多人会直接跳过直接开训。但如果标签有错后面所有调试都会回头查数据。这个数据集自带show脚本作用是把box绘制回图像上便于确认每个目标的类别和位置是否符合直觉。下面给一个类似的脚本实现基于OpenCV可以批量化生成带标注框的预览图。3.1 单张图片的标注绘制函数import cv2 from pathlib import Path def draw_yolo_boxes(image_path, label_path, class_names): img cv2.imread(str(image_path)) if img is None: print(f读取失败: {image_path}) return None height, width img.shape[:2] with open(label_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) x_center float(parts[1]) * width y_center float(parts[2]) * height box_w float(parts[3]) * width box_h float(parts[4]) * height x1 int(x_center - box_w / 2) y1 int(y_center - box_h / 2) x2 int(x_center box_w / 2) y2 int(y_center box_h / 2) x1 max(0, x1) y1 max(0, y1) x2 min(width - 1, x2) y2 min(height - 1, y2) color (0, 255, 0) if cls_id 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) label f{cls_id}:{class_names[cls_id]} if cls_id len(class_names) else str(cls_id) cv2.putText(img, label, (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) return img这里的坐标转换逻辑是YOLO标签里存储的是相对比例训练时网络也按比例回归但绘制到图像上时必须乘以图像的宽和高才能得到像素坐标。画框前做了越界裁剪避免矩形画出边界时OpenCV报错或显示异常。color变量在示例里简单区分了第一类与其他类实际使用时建议根据类别ID生成固定颜色确保同一类在所有图像里颜色一致。3.2 批量生成预览图from pathlib import Path def batch_visualize(data_root, output_root): data_root Path(data_root) output_root Path(output_root) output_root.mkdir(parentsTrue, exist_okTrue) class_names load_class_names(data_root / classes.txt) for label_file in (data_root / train/labels).glob(*.txt): image_file data_root / train/images / (label_file.stem .jpg) if not image_file.exists(): image_file data_root / train/images / (label_file.stem .png) if not image_file.exists(): print(f图片不存在: {label_file.stem}) continue img draw_yolo_boxes(image_file, label_file, class_names) if img is not None: output_path output_root / (label_file.stem .jpg) cv2.imwrite(str(output_path), img) print(f可视化结果保存在 {output_root})注意这里图片后缀同时判断了jpg和png因为原始数据里两种格式都存在文件名有_jpg和_png后缀但实际文件可能是jpg扩展名需要现场确认。另外show脚本往往还会把检测框的面积和类别名打印在终端方便快速统计类别分布。提示如果可视化出来的标注框整体偏向某一边或者框没有贴合器件轮廓大概率是标签归一化时用的width/height顺序反了。建议从图中心到像素坐标的换算逻辑里重新检查一下。可视化现象数据问题处理建议框整体偏移归一化坐标以错误尺寸计算重新读取图片宽高修正坐标多个框重叠在同一区域标注重复保留置信度高的标注删除重复框框内明显没有缺陷类别误标回看原图修正类别ID框太小且集中在一角目标被截断考虑裁剪或调整原图预处理3.3 可视化结果如何指导训练策略批量生成预览图后建议按类别归类单独创建一个目录把每个类别出现的图像副本放进去用图片浏览器快速浏览。这一步能帮助确定两件事第一类别是否平衡某些缺陷如果只有几十个框训练时要考虑类别权重第二目标尺度分布如果大部分框的宽高小于图片尺寸的10%说明这是典型的小目标检测场景训练时imgsz需要适当调大或者使用多尺度训练。4. YOLOv8训练PCD缺陷检测数据划分、超参与收敛排查数据集已经准备好接下来进入训练环节。以YOLOv8为例因为官方对自定义数据集支持最省事只需要一个yaml和一个train命令。4.1 创建数据集配置文件# pcd_yolov8.yaml path: ./pcd_defect_dataset train: train/images val: valid/images nc: 7 names: 0: Miss 1: mask_defect 2: defect 3: other_class_3 4: other_class_4 5: other_class_5 6: other_class_6这里的names列表里的顺序必须和class文件一致。如果你不知道具体类名可以先运行前面的load_class_names脚本把输出复制到这里。path字段可以是绝对路径也可以是相对当前终端的路径建议用绝对路径避免在不同目录下执行命令时路径解析错误。4.2 训练命令与参数选择yolo detect train datapcd_yolov8.yaml modelyolov8s.pt \ epochs120 imgsz640 batch16 device0 \ patience15 lr00.01 augmentTrue参数说明data指向yaml配置文件的路径。model使用yolov8s.pt预训练权重相比nano版本对缺陷的细节特征捕捉更好又不会像large那样明显拖慢训练速度。imgsz设为640输入分辨率。若PCD缺陷框面积占比很小可以提高到768或1024但训练和推理耗时也会上涨。batch根据显卡显存调整16G显存可以用168G建议降到8。patience15表示验证集指标连续15轮不提升就早停避免无效空转。augmentTrue启用内置的Mosaic、MixUp等增强。这个数据集已经做过离线增强所以在线增强强度可以适当降低比如设置hsv_h0.01防止过拟合到增广后的伪纹理。训练启动后重点关注两个输出一个是loss曲线另一个是验证阶段的mAP50和mAP50-95。如果mAP50在20轮后仍然低于0.6通常是数据侧问题回到第2章检查标签格式和类别分布。参数推荐值说明imgsz640或768小目标缺陷建议768epochs120配合patience早停batch8-16显存小时降到8lr00.01发散时降到0.001augmentTrue过拟合时降低增强强度4.3 常见坑训练发散与类别误检现象可能原因处理方法loss变成nan学习率过大或标签中有非法字符调低lr0到0.001检查txt编码mAP50-95很低类别ID与names错位打印验证集预测结果核对类名验证集AP/AR为0标签文件为空确认valid/labels下是否有对应txt训练速度很慢在线增强计算量大降低augment相关参数或关闭Mosaic表格里的四个现象基本覆盖了初次训练PCD数据集时最容易遇到的问题。特别提醒这个数据集里的图片文件名带_jpg、_png后缀Roboflow格式下图片和标签都保留了这个后缀但两个文件的basename是一致的。如果遇到某些图片没有对应标签不要直接删图而是检查是不是标签文件后缀写错了例如.txt被命名成.png.txt。4.4 验证与导出模型训练结束后用best.pt做一次验证yolo detect val datapcd_yolov8.yaml modelruns/detect/train/weights/best.pt验证过程会生成每类别的precision、recall和mAP。对表面元器件缺陷检测recall往往比precision更重要因为漏检的缺陷板如果流到下一道工序返工成本远高于误检产生的复检。如果recall低优先检查miss类和mask defect类的样本量并考虑使用第5章的技巧。4.5 训练结果如何筛选当best.pt验证完毕后打开验证生成的混淆矩阵和预测样本图观察哪些类别容易被相互混淆。PCD缺陷中mask defect与defect经常看起来相似如果mAP差异较大可以把这两个类别合并或为低AP类别增加单独的训练图像。一般我会先跑一个baseline记录mAP50再修改类别权重重新训练对比两者的混淆矩阵差异。不要只看总mAP要逐类看AP50否则少数类的召回问题会被多数类掩盖。5. 类别不平衡与小目标漏检用类别权重和滑窗推理把漏检压下来PCD表面元器件缺陷数据集的7个类别里miss漏贴和mask defect这类异常的出现频率通常远低于普通defect。直接用默认损失函数训练模型会倾向把少数类预测为多数类表现为recall偏低。这时可以采用两种不改变网络结构的做法。5.1 类别权重调整在YOLOv8中可以通过设置分类损失权重来缓解不平衡。常见做法是在训练命令中加入与类别名对应的损失权重列表把少数类的权重调到1.52.0多数类保持1.0。注意权重不要超过2.5否则训练初期loss震荡严重模型反而学不到稳定特征。每次调整权重后重新训练前先重置学习率并观察前20轮的mAP曲线如果轻微抖动但整体上升属于正常现象。5.2 滑窗推理sliding window用于小目标对于在640分辨率下缺陷框小于二十像素的情况另一种有效手段是把原图分成重叠的滑窗对每个窗口独立推理再将结果映射回原图坐标。常见做法是窗口大小320×320步长160重叠率50%。推理时把每个窗口的检测框坐标加上窗口左上角的偏移量最后用NMS合并重叠框。import cv2 from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) def sliding_window_detect(image_path, win_size320, stride160, conf0.25): img cv2.imread(image_path) h, w img.shape[:2] all_boxes [] for y in range(0, h - win_size 1, stride): for x in range(0, w - win_size 1, stride): crop img[y:y win_size, x:x win_size] results model.predict(crop, imgszwin_size, confconf, verboseFalse) for box in results[0].boxes: x1, y1, x2, y2 map(int, box.xyxy[0]) all_boxes.append((x x1, y y1, x x2, y y2, float(box.conf), int(box.cls))) return all_boxes这段代码的sliding_window_detect函数会遍历整张图对每个窗口独立跑模型。注意窗口尺寸需要和训练时的imgsz保持一致否则特征尺度会漂移。stride越小重叠越多检测率越高但耗时翻倍。实际项目中先在全图上跑一次统计漏检区域的位置再针对漏检区域做局部滑窗这样能把推理耗时控制在可接受范围。把滑窗步长设为0.5倍窗口尺寸通常能在召回率不下降的前提下把误检率控制住。本文还有配套的精品资源点击获取
返回列表