利用 YOLOX 网络检测印刷电路板上的缺陷
本示例演示了如何使用 YOLOX 目标检测器检测、定位和分类印刷电路板 (PCB) 中的缺陷。
印刷电路板 (PCB) 包含各个电子元件及其连接。PCB 中的缺陷可能会导致性能不佳或产品故障。通过检测印刷电路板 (PCB) 中的缺陷,生产线可以剔除有缺陷的 PCB,从而确保电子设备的高质量。
下载预训练的 YOLOX 检测器
默认情况下,本示例使用 downloadTrainedNetwork 辅助函数下载 YOLOX 目标检测器的预训练版本 [1]。该辅助函数作为辅助文件附于本示例之后。您可以使用预训练网络直接运行整个示例,无需等待训练完成。
trainedPCBDefectDetectorNet_url = "https://ssd.mathworks.com/supportfiles/"+ ... "vision/data/trainedPCBDefectDetectorYOLOX.zip"; downloadTrainedNetwork(trainedPCBDefectDetectorNet_url,pwd); load("trainedPCBDefectDetectorYOLOX.mat");
下载 PCB 缺陷数据集
本示例使用了 PCB 缺陷数据集 [2] [3]。该数据集包含 1,386 张带有合成缺陷的 PCB 元素图像。该数据包含六种缺陷类型:缺孔、鼠咬、开路、短路、刺状缺陷和异常铜。每个图像中都包含多个位于不同位置的同类缺陷。该数据集包含了每个图像中每个缺陷的边界框和坐标信息。该数据集的大小为 1.87 GB。
请将数据集的位置指定为 dataDir。使用 downloadPCBDefectData 辅助函数下载数据集。此函数作为支持文件包含在本示例中。
dataDir = fullfile(tempdir,"PCBDefects");
downloadPCBDefectData(dataDir)执行目标检测
从数据集中读取一张示例图像。
sampleImage = imread(fullfile(dataDir,"PCB-DATASET-master","images", ... "Missing_hole","01_missing_hole_01.jpg"));
Warning: Division by zero when processing CompressedBitsPerPixel. The value has been set to NaN.
使用 detect 函数预测每个边界框的边界框、标签以及特定类别的置信度得分。
[bboxes,scores,labels] = detect(detector,sampleImage);
显示结果。
imshow(sampleImage) showShape("rectangle",bboxes,Label=labels); title("Predicted Defects")

准备要训练的数据
创建一个用于读取和管理镜像数据的镜像数据存储。
imageDir = fullfile(dataDir,"PCB-DATASET-master","images"); imds = imageDatastore(imageDir,FileExtensions=".jpg",IncludeSubfolders=true);
创建一个数据存储文件,用于从 XML 文件中读取注解数据。指定一个自定义读取函数,用于解析 XML 文件并提取边界框信息。自定义读取函数 readPCBDefectAnnotations 作为辅助文件附在示例中。
annoDir = fullfile(dataDir,"PCB-DATASET-master","Annotations"); fds = fileDatastore(annoDir,ReadFcn=@readPCBDefectAnnotations, ... FileExtensions=".xml",IncludeSubfolders=true);
将标注的边界框数据保存为边界框标签数据存储。
annotations = readall(fds);
tbl = struct2table(vertcat(annotations{:}));
blds = boxLabelDatastore(tbl);将目标类的名称作为分类向量获取。
classNames = categories(blds.LabelData{1,2})classNames = 6×1 cell array
"'missing_hole'"
"'mouse_bite'"
"'open_circuit'"
"'short'"
"'spur'"
"'spurious_copper'"
将图像和框标注数据存储合并。
ds = combine(imds,blds);
分析目标类的分布情况
使用 countEachLabel 函数测量数据集中类标签的分布情况。该数据集中的类分布是均衡的。
countEachLabel(blds)
ans=6×3 table
missing_hole 497 115
mouse_bite 492 115
open_circuit 482 116
short 491 116
spur 488 115
spurious_copper 503 116
分区数据
在对数据进行分区之前,请将全局随机状态设置为默认状态,以确保结果具有更高的可重复性。
rng("default");将数据集分成训练集、验证集和测试集。由于图像总数相对较少,因此将相对较大的比例 (70%) 的数据分配给训练。将 15% 的资源用于验证,其余部分用于测试。
numImages = ds.numpartitions; numTrain = floor(0.7*numImages); numVal = floor(0.15*numImages); shuffledIndices = randperm(numImages); dsTrain = subset(ds,shuffledIndices(1:numTrain)); dsVal = subset(ds,shuffledIndices(numTrain+1:numTrain+numVal)); dsTest = subset(ds,shuffledIndices(numTrain+numVal+1:end));
增强训练数据
通过使用 transform 函数,并结合由 augmentDataForPCBDefectDetection 辅助函数指定的自定义预处理操作,来扩充训练数据。此辅助函数作为支持文件包含在本示例中。augmentDataForPCBDefectDetection 函数对输入数据应用以下扩展操作:
随机水平翻转(对称)
按 [1, 1.1] 范围内的缩放因子进行随机缩放
在 [-50, 50] 像素范围内进行水平和垂直方向的随机平移
dsTrain = transform(dsTrain,@augmentDataForPCBDefectDetection);
定义 YOLOX 目标检测器网络架构
使用 yoloxObjectDetector 函数创建 YOLOX 目标检测器。指定以 CSP-DarkNet-53 为基础网络、并在 COCO 数据集上训练而成的预训练网络 [1]。请指定类名和网络输入尺寸。
inputSize = [800 800 3];
detectorIn = yoloxObjectDetector("tiny-coco",classNames,InputSize=inputSize);指定训练选项
使用 trainingOptions (Deep Learning Toolbox) 函数指定网络训练选项。使用 SGDM 求解器对目标检测器进行训练,最多 100 个 epoch。请将 ValidationData 名称-值参量指定为验证数据。将 OutputNetwork 设置为 "best-validation-loss",这样在训练结束时,即可获得训练过程中验证损失最低的网络。
options = trainingOptions("sgdm", ... InitialLearnRate=5e-4, ... LearnRateSchedule="piecewise", ... LearnRateDropFactor=0.99, ... LearnRateDropPeriod=1, ... MiniBatchSize=20, ... MaxEpochs=100, ... ExecutionEnvironment="auto", ... Shuffle="every-epoch", ... VerboseFrequency=25, ... ValidationFrequency=100, ... ValidationData=dsVal, ... ResetInputNormalization=false, ... OutputNetwork="best-validation-loss", ... GradientThreshold=30, ... L2Regularization=5e-4);
训练检测器
要训练检测器,请将 doTraining 变量设置为 true。使用 trainYOLOXObjectDetector 函数对检测器进行训练。
如果可用,请在一块或多块 GPU 上进行训练。使用 GPU 需要 Parallel Computing Toolbox™ 许可证和支持 CUDA® 的 NVIDIA® GPU。有关详细信息,请参阅GPU 计算要求 (Parallel Computing Toolbox)。在配备 24 GB 内存的 NVIDIA Titan RTX™ 上,训练大约需要 7.5 小时。
doTraining =false; if doTraining [detector,info] = trainYOLOXObjectDetector(dsTrain,detectorIn,options,"FreezeSubNetwork","none"); modelDateTime = string(datetime("now",Format="yyyy-MM-dd-HH-mm-ss")); save(fullfile(tempdir,"trainedPCBDefectDetectorYoloX"+modelDateTime+".mat"), ... "detector"); else load("trainedPCBDefectDetectorYOLOX.mat"); end
评估检测器
检测所有测试图像的边界框。将检测阈值设置为较低的值以检测到尽可能多的目标。这有助于您评估在整个检测分数值范围内检测性能的表现。
detectionResults = detect(detector,dsTest,Threshold=0.01);
使用 evaluateObjectDetection 函数,对测试集的检测结果计算目标检测度量。
metrics = evaluateObjectDetection(detectionResults,dsTest);
计算并显示每个类别的平均精确率 (AP) 得分。精确率量化了检测器正确分类目标的能力。
AP = averagePrecision(metrics); table(classNames,AP)
ans=6×2 table
'missing_hole' 0.9809
'mouse_bite' 0.8571
'open_circuit' 0.9432
'short' 0.9735
'spur' 0.9427
'spurious_copper' 0.8899
计算每个缺陷目标检测的召回率和精确率值。召回率量化了检测器检测某类所有相关目标的能力。精确率-召回率 (PR) 曲线突显了在不同召回率水平下,检测器的精确程度。理想情况下,所有召回水平的精确率均为 1。绘制测试数据的 PR 曲线。
classNameStrings = metrics.ClassNames; class =classNameStrings(4); [precision, recall, ~] = precisionRecall(metrics,ClassName=class); plot(recall{:},precision{:}) title(sprintf("Average Precision for '" + class + "' Defect: " + "%.2f",averagePrecision(metrics,ClassName=class)), interpreter="none") xlabel("Recall") ylabel("Precision") grid on

评估基于目标大小的检测度量
使用 metricsByArea 函数研究目标大小对检测器性能的影响,该函数可计算特定目标大小范围内的目标检测度量。要评估基于大小的度量,您可以根据一组自定义范围来定义目标大小的范围。首先,根据测试集目标面积分布的第 33 百分位数和第 66 百分位数分界点,将测试图像的边界框尺寸划分为小、中、大三类目标尺寸。
绘制测试集中的目标尺寸分布图,其中边界框面积定义了目标尺寸。
testSetObjects = dsTest.UnderlyingDatastores{2};
objectLabels = readall(testSetObjects);
boxes = objectLabels(:,1);
boxes = vertcat(boxes{:});
boxArea = prod(boxes(:,3:4),2);
histogram(boxArea)
title("Bounding Box Area Distribution")
xlabel("Box Area");
ylabel("Count")
定义边界框的区域范围,然后使用 metricsByArea 对所定义的区域范围进行目标检测度量。经过训练的检测器的平均精度均值 (mAP) 度量在小、中、大三种目标尺寸下表现大致相当,其中对中型目标的检测性能略有提升。
boxPrctileBoundaries = prctile(boxArea,100*[1/3,2/3]); metricsByArea(metrics,[0, boxPrctileBoundaries, inf])
ans=3×4 table
0 3.5737e+03 144 0.8416 0.8416
3.5737e+03 5107 145 0.9605 0.9605
5107 Inf 144 0.8854 0.8854
参考资料
[1] Ge, Zheng, Songtao Liu, Feng Wang, Zeming Li, and Jian Sun."YOLOX:Exceeding YOLO Series in 2021", arXiv, August 6, 2021. https://arxiv.org/abs/2107.08430.
[2] Huang, Weibo, and Peng Wei."A PCB Dataset for Defects Detection and Classification."Preprint, submitted January 23, 2019. https://arxiv.org/abs/1901.08204.
[3] PCB-DATASET.Accessed December 20, 2022. https://github.com/Ironbrotherstyle/PCB-DATASET.
另请参阅
yoloxObjectDetector | trainYOLOXObjectDetector | detect | metricsByArea | evaluateObjectDetection | trainingOptions (Deep Learning Toolbox) | transform
主题
- Detect Small Objects Using Tiled Training of YOLOX Network
- YOLOX 目标检测入门指南
- Evaluate Object Detector Performance
- Choose an Object Detector
- 在 MATLAB 中进行深度学习 (Deep Learning Toolbox)
- 预训练的深度神经网络 (Deep Learning Toolbox)

