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

资讯详情

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

Python+Faster R-CNN实战:PCB元器件缺陷检测全流程解析

Python+Faster R-CNN实战:PCB元器件缺陷检测全流程解析 简介面向毕业设计、课程设计与项目开发场景的PCB元器件缺陷检测完整项目基于Python与Faster-RCNN实现适合具备一定深度学习基础、需要完成目标检测实操的开发者。压缩包内共79个文件以Python源码35个py和pyc编译文件为主另含Markdown开发文档、依赖清单及配置文件整体约214KB内容紧凑、便于快速下载与查阅。项目围绕VOC07数据格式展开覆盖数据预处理与扩充、anchors计算、模型训练、预测和评估等环节支持在公开数据集或自建数据集上运行。训练部分提供resnet50、vgg16等骨干网络实现预测与评估部分可加载预训练权重或自行训练权重并调用脚本计算mAP等指标。当前已有381人浏览学习源码经过严格测试并附有训练、预测、评估的操作说明结构清晰、模块划分合理可直接作为毕业设计或课题研究的基础工程在此基础上扩展算法或更换数据集都较为方便。1. 用 Python 和 Faster R-CNN 做 PCB 元器件缺陷检测到底解决什么问题PCB 板出厂前要过外观检测传统做法是老师傅拿放大镜一块一块看漏检率全看当天状态速度也上不去。而“基于 pythonfaster-RCNN 的 PCB 元器件缺陷检测”这件事本质上是把漏检率稳定压到人工之下同时让检测动作可重复、可量化。它的核心价值不是“用深度学习换个方式看板子”而是用 Faster R-CNN 的两阶段检测结构在缺件、偏移、桥连、虚焊这些细微缺陷上拿到比单阶段模型更稳的召回。这套方案适合三类人正在做毕业设计或课程设计、需要从零跑通一个目标检测全流程的学生工厂或实验室里想验证 PCB AOI 替代人检可行性的工程师以及刚接触 Faster R-CNN、想知道这个模型在实际工业图像上到底怎么落地的人。整个过程没有玄学数据、标注、训练、调参、部署每一步都能复现但每一步也都有坑。下文按我自己的项目习惯从原理、数据、训练到部署逐步拆开讲。2. Faster R-CNN 为什么适合 PCB 缺陷检测先看懂模型再动手2.1 两阶段结构在工业检测里的天然优势Faster R-CNN 属于两阶段检测器第一阶段用 Region Proposal NetworkRPN在整张图上找可能存在目标的候选框第二阶段对每个候选框做分类和回归。和 YOLO、SSD 这类单阶段模型相比它的运行速度慢一些但候选框质量高对密集小目标的定位精度更好。PCB 缺陷场景恰好是个精度优先的任务。一块板子上几十个元器件缺件、偏移、桥连这类缺陷占图像面积通常不到百分之一而且同类缺陷在不同板卡上的形态差异很大。用单阶段模型直接回归容易在特征图上把小目标的信息淹没。Faster R-CNN 的 RPN 阶段会先扫一遍全图锚点把可能是缺陷的区域裁出来再进分类器精细判断这个“先粗筛再精判”的流程在工业视觉里更接近老师傅先扫一眼再拿放大镜确认的决策方式。选型理由如果不落到数据上是空的。我见过不少人拿公开 COCO 预训练权重直接跑 PCB 数据检出率很差回来骂模型不行。其实问题出在 PCB 图像和自然图像的域差异太大必须微调。Faster R-CNN 的微调成本可控ResNet-50 FPN 主干在单张 1080Ti 上就能训练这也是它在毕设和中小项目里比更重的模型更常用的原因。2.2 RPN 和 AnchorFaster R-CNN 的核心机制RPN 做的事是在特征图的每个位置上铺一组预设尺寸的 Anchor锚框然后判断每个 Anchor 里有没有目标并粗略回归一次框的位置。最后选出得分最高的若干框作为第二阶段 ROI 池化的输入。Anchor 的尺寸和比例直接决定了模型对小目标的敏感度。torchvision 里 Faster R-CNN 默认的 anchor_sizes 是 ((32,), (64,), (128,), (256,), (512,))这是按 COCO 数据集的物体尺度设计的搬到 PCB 上一定会不匹配。PCB 元器件缺陷的尺寸通常集中在 25×25 到 200×200 像素之间具体要看你的拍摄分辨率。修改 AnchorGenerator 是调优的第一步from torchvision.models.detection.rpn_utils import AnchorGenerator # 针对 PCB 小元器件设计的 5 组 Anchor 尺寸 anchor_sizes ((16,), (32,), (64,), (128,), (256,)) aspect_ratios ((0.5, 1.0, 2.0),) * len(anchor_sizes) anchor_generator AnchorGenerator(anchor_sizes, aspect_ratios)代码逻辑是把原来适配自然图像的锚框尺寸收敛到 PCB 板卡的元器件尺度范围内比例保持 0.5、1.0、2.0 三种覆盖长条形电阻和方形芯片的横竖比例。参数说明16 和 32 对应小型贴片电阻电容64 和 128 对应中型芯片256 兜底大型连接器。如果板卡图像里最小缺陷只有 10 像素需要再往下加一组 (8,)如果拍摄距离近图像里元器件普遍很大就把 16 这一组去掉给 256 以上留空间。2.3 特征金字塔在 PCB 多尺度缺陷上的作用FPNFeature Pyramid Network是 Faster R-CNN 里另一个不能忽视的组件。它让不同层级的特征图携带不同尺度的语义信息小缺陷回到底层高分辨率特征上找大缺陷在高层语义特征上判断。torchvision 的 fasterrcnn_resnet50_fpn 默认带 FPN但默认配置的 anchor 分配和 FPN 层级匹配是按 COCO 调的。训练时如果发现小元器件频繁漏检除了调 anchor还要看 FPN 的输出层次。Debug 时可以打印每个 proposal 是由哪一层网络输出的检查 model.rpn 的输出或者直接在训练脚本里记录 gt 框的尺寸分布按面积分布去对应 FPN 的 P2、P3、P4 层。一个简单经验——图像尺寸为 800×600 左右时12×12 到 20×20 像素的缺陷目标主要从 P2 层召回。如果数据集里这种小目标很多可以考虑在数据预处理时不压缩图像或者使用更大的输入尺寸。3. 数据与标注PCB 缺陷检测项目最容易被卡住的环节3.1 数据从哪来公开集打底、自采补足PCB 缺陷检测没有统一的公开大基准数据集现实做法分两步。先用已有的 PCB 开源数据集如部分高校公开的模板缺陷数据跑通全流程验证模型结构和训练参数没问题再拿自己的板卡图像做标注、微调。纯靠自采往往数量不够纯靠公开数据又和实际产线差异大。我一般会把数据集按缺陷类型分成缺件、偏移、桥连、虚焊、极性反、破损六类每类最少 200 张总计 1200 张起步。这个量对微调 Faster R-CNN 来说够用但分布必须均衡不能缺件 500 张、破损 50 张不然 mAP 值会被多数类拉高而被少数类拖垮。3.2 标注格式统一用 LabelImg 产出干净可用的 VOC 数据集标注工具用 LabelImg 最省事输出格式选择 VOCPascal VOC XML。它的产出是每张图片对应一个同名 XML 文件里面记录每个目标的类别名和 bbox 坐标。标注完成后第一步不是训练是写一个脚本检查所有 XML 的合法性。常见问题有三类bbox 坐标越界xmax 超过图片宽度、bbox 高宽为 0 或负值、类别名里混进了空格。这三类错误在训练时不会直接报错而是以“loss 异常波动”或“检测框奇怪偏移”的形式出现特别难排查。import xml.etree.ElementTree as ET import os xml_dir Annotations img_width, img_height 1280, 1024 # 按你的实际图像尺寸改 for xml_file in os.listdir(xml_dir): tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() for obj in root.iter(object): name obj.find(name).text bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) w, h xmax - xmin, ymax - ymin if w 0 or h 0: print(f[ERROR] {xml_file}: {name} bbox 高宽异常 {w}x{h}) if xmin 0 or ymin 0 or xmax img_width or ymax img_height: print(f[WARN] {xml_file}: {name} bbox 越界)这段脚本循环读取每个 XML逐个检查目标框的高宽和坐标范围发现问题立即定位到文件和类别名。参数说明xml_dir 指向标注目录img_width 和 img_height 填写标注时使用的原始图像尺寸。越界的 bbox 是因为标注时拖框拖出了图像边界负尺寸是标注误操作我处理时一般是直接用脚本把越界坐标 clamp 到边界负尺寸则删掉该目标样例重新标。3.3 数据集划分与增强小样本也能把数据用足划分比例我用 7:2:1训练 70%、验证 20%、测试 10%。划分脚本要保证各类缺陷在每个集合里的比例一致不能简单随机切分否则测试集里可能完全没有某一类缺陷mAP 计算出来虚高。import random from collections import defaultdict random.seed(42) xml_files [f for f in os.listdir(xml_dir) if f.endswith(.xml)] category_map defaultdict(list) for xml_file in xml_files: tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() categories [] for obj in root.iter(object): category obj.find(name).text categories.append(category) category_map[tuple(sorted(set(categories)))].append(xml_file) train_files, val_files, test_files [], [], [] for key, items in category_map.items(): random.shuffle(items) n len(items) train_files items[: int(n * 0.7)] val_files items[int(n * 0.7) : int(n * 0.9)] test_files items[int(n * 0.9) :]这段脚本先按每个 XML 里包含的类别组合分组再在组内按 7:2:1 比例切分保证每个类别组合在三个集合中都能出现。代码逻辑是categories 排序后做 key同类组合数据一起划分不会出现某一类全落在训练集、测试集里没有的情况。random.seed(42) 固定随机种子保证每次跑划分结果一致这对后续对比实验很重要——同一个项目里我的习惯是只用这一版划分不做重复采样。图像增强方面PCB 缺陷检测的关键约束是缺陷方向有实际含义。偏移缺陷的框方向不能翻转翻转后的图像会让“偏移”这类缺陷的物理方向失效。我一般只做两种增强小幅亮度扰动和对比度扰动配合 HSV 空间的微调模拟不同光照条件下拍摄的图像。几何增强只保留 90 度旋转且旋转时必须同步旋转 bbox 标注这里用 torchvision 的 transforms 配合自定义函数实现注意别用随机的水平翻转——它会直接把缺陷的物理方向翻反训练出来的模型在真实板卡上检测方向性缺陷时会翻车。4. 训练 Faster R-CNN 检测 PCB 缺陷从环境搭建到参数调优4.1 环境与工程结构torchvision 是最稳定的起点环境方面我推荐直接用 torchvision 内置的 Faster R-CNN 实现它封装了 RPN、ROI 池化、损失计算全流程比从零实现稳定太多。毕设和课程设计里需要展示源码深度解读 torchvision 自带的源码就够了完全没必要自己重写检测头。工程结构上项目源码一般按 dataset.py数据加载与增强、model.py模型构建与 Anchor 调整、train.py训练主流程、predict.py推理脚本四块组织再加 config.yaml 放参数。开发文档围绕这四块写数据集格式说明、模型结构说明、训练参数说明书、复现步骤。评阅人和面试官关心的不是代码量而是你能不能讲清每块代码对应论文里的哪一部分。conda create -n pcb_det python3.8 conda activate pcb_det pip install torch1.13.1cu117 torchvision0.14.1cu117 -f https://download.pytorch.org/whl/torch_stable.html安装时注意 torch 和 torchvision 的版本必须匹配两者之间用 0.14.1 配 1.13.1 是一组常见稳定组合。如果 GPU 显存只有 8G可以把图像 resize 到 800×800batch_size 设为 4。CPU 也能训练但极慢我只建议拿 CPU 做推理验证训练还是找个 GPU 环境云服务器按小时租也可以。4.2 构建模型与数据加载修改分类头、绑定 Anchor 配置模型构建代码是项目里最核心的展示段落import torchvision from torchvision.models.detection.faster_rcnn import FastRCNNPredictor # 使用 COCO 预训练权重做迁移学习基础 model torchvision.models.detection.fasterrcnn_resnet50_fpn(weightsDEFAULT) num_classes 7 # 背景 6 类缺陷 in_features model.roi_heads.box_predictor.cls_score.in_features model.roi_heads.box_predictor FastRCNNPredictor(in_features, num_classes) # 替换 Anchor 生成器适配 PCB 元器件尺寸 from torchvision.models.detection.rpn_utils import AnchorGenerator anchor_sizes ((16,), (32,), (64,), (128,), (256,)) aspect_ratios ((0.5, 1.0, 2.0),) * len(anchor_sizes) model.rpn.anchor_generator AnchorGenerator(anchor_sizes, aspect_ratios)代码逻辑分三步加载 COCO 预训练模型、替换分类头输出为 6 类加背景、替换 Anchor 配置。参数说明num_classes 必须等于缺陷类别数加 1算错了会在训练时报 shape 不匹配。这里要提醒一个常见误用——很多人只改分类头不动 Anchor 配置导致模型在 PCB 数据上收敛慢、小目标漏检。预训练权重的作用是让主干网络已经学到了通用的低级视觉特征PCB 图像虽然和自然图像差异大但边缘、纹理、颜色梯度这些底层特征是通用的迁移学习的收益依然明显。数据加载部分torchvision 的 Faster R-CNN 需要自定义 Dataset 返回图像和 target 字典target 里必须包含 boxes、labels、image_id 三个键训练时还需要 area、iscrowd。我习惯写一个 PCBDefectDataset 类内部用 xml.etree 解析 VOC 文件并按需做归一化。4.3 训练主循环一个能跑的最小脚本训练脚本核心段如下import torch from torch.utils.data import DataLoader model.train() optimizer torch.optim.SGD(model.parameters(), lr0.005, momentum0.9, weight_decay0.0005) scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size3, gamma0.1) for epoch in range(12): total_loss 0.0 for images, targets in dataloader: images [img.to(device) for img in images] targets [{k: v.to(device) for k, v in t.items()} for t in targets] loss_dict model(images, targets) losses sum(loss for loss in loss_dict.values()) optimizer.zero_grad() losses.backward() optimizer.step() total_loss losses.item() scheduler.step() print(fEpoch {epoch 1}, Loss: {total_loss / len(dataloader):.4f}) if (epoch 1) % 3 0: torch.save(model.state_dict(), fcheckpoints/epoch_{epoch 1}.pth)代码逻辑是标准的 PyTorch 训练循环模型接收原始图像和标注字典torchvision 内部计算分类损失、回归损失、RPN 损失sum 之后反向传播。参数说明学习率 0.005 是批量大小为 4、图像尺寸 800×800 下的常用起点如果 batch_size 是 8学习率可以提高到 0.01保持线性比例。StepLR 每 3 个 epoch 衰减为原来的十分之一12 个 epoch 内完成三次衰减是工业检测项目里比较稳的配置。如果 loss 在前 10 个 epoch 就不降了先看是不是学习率太大再检查标注数据是不是有脏数据。训练过程一定要看 loss 曲线。我在训练时习惯用 tensorboard 记录 loss_dict 里每一项的值pip install tensorboard tensorboard --logdir runs在浏览器里打开 6006 端口看 loss 曲线。total loss 在训练初期在 1.0 到 2.0 之间波动是正常的很多人看到 loss 不降到 0.1 就慌其实 Faster R-CNN 在工业数据集上总 loss 能稳定到 0.2 以下就算不错。画图时发现横坐标太密集、曲线看不清可以在 tensorboard 里调大 smooth 参数或者用日志文件按 epoch 采样输出不用像处理普通 matplotlib 图表那样折腾横轴刻度。4.4 评估模型mAP 计算和检测效果验证训练完不能只看 loss必须做量化评估。torchvision 官方提供了评估工具我用它计算 mAP 和各类别的 AP 值python -m torchvision.ops.detection.coco_eval --model fasterrcnn_resnet50_fpn --weights checkpoints/epoch_12.pth --data VOCdevkit/2007评估完成后重点看三样东西各类别 AP 是否均衡缺件类特别高、破损类特别低就是数据分布问题小目标的 AP 是否明显低于大目标说明 anchor 还没调到位验证集和测试集 mAP 差距是否过大过拟合信号PCB 小数据集上过拟合很常见。除此之外我会在测试集上把检测框叠加到原图上保存下来逐张翻看。mAP 数字是宏观指标单独看检测框能发现很多 mAP 看不出的问题——比如漏检是不是总出现在板卡边缘区域误检是不是集中在某个特定元器件型号上。这类现象驱动的分析比调参更值得花时间。5. 避坑指南PCB 缺陷检测训练中四个高频翻车点5.1 陷阱一训练 loss 不降反升最终发散现象是 loss 在前几个 epoch 不降甚至逐渐增大到 NaN。原因有两个一是学习率在当前 batch_size 和图像尺寸组合下过大二是标注数据里存在异常 bbox比如坐标超出图像范围、负尺寸导致回归目标计算异常。解决方法是先把学习率降到 0.001 试跑 10 个 epoch如果 loss 稳步下降说明是学习率问题调回 0.005 并配合 warmup 就好如果依然发散回到第 3.2 节那个 XML 检查脚本把异常标注全部清理掉再训练。我在第一次跑 PCB 数据时就踩过这个坑最后查出来是标注阶段有一批图片用了 960×1280 的原图另一批用了 640×480 的缩略图两批 XML 里的坐标混在一起回归目标完全错乱。5.2 陷阱二检测框整体偏移半个身位现象是缺陷类型判断正确但框的位置明显偏向一侧。原因是数据增强里加了水平翻转或 90 度旋转但 bbox 坐标没有同步变换。特别是方向性缺陷偏移、极性反翻转后框对不上模型学到了错误的映射关系。解决方法是做增强时只保留不影响缺陷物理含义的操作亮度扰动、对比度扰动、模糊、噪声。几何变换要么不做要么做成完全同步 bbox 的自定义函数。验证方法很直接把增强后的图像和 bbox 画出来看一张框如果和缺陷对齐了就说明没问题。5.3 陷阱三GPU 显存溢出训练中断现象是训练跑到一半报 CUDA out of memory。原因是 batch_size 和图像尺寸的组合超过了显存容量。8G 显存跑 800×800 图像batch_size 只能设 4跑到 1200×1200 就得降到 2 或 1。解决方法是梯度累积技术用小 batch_size 模拟大 batch 效果accumulation_steps 4 # 模拟 batch_size 实际 batch_size × 4 optimizer.zero_grad() for i, (images, targets) in enumerate(dataloader): loss_dict model(images, targets) losses sum(loss for loss in loss_dict.values()) losses.backward() if (i 1) % accumulation_steps 0: optimizer.step() optimizer.zero_grad()代码逻辑是前 4 个 batch 只做前向和梯度累积不更新参数第 4 个 batch 结束后统一更新一次等效于 batch_size 乘以 4。参数说明accumulation_steps 设 4 表示等效 batch_size 乘以 4梯度累积会等比放大学习率如果 batch_size 从 4 用累积做到 16学习率从 0.005 调到 0.01 效果更好。另一个常用做法是训练时禁用图像缩放缓存或把图像从 800×800 降到 640×640代价是小目标检出率下降能不动尽量不动。5.4 陷阱四小元器件漏检严重大缺陷全检出来了现象是电阻、电容这类小贴片元件缺陷经常漏检而大芯片缺陷几乎全中。原因是 Anchor 尺度覆盖不全默认 anchor 最小的 32 像素对 16 像素的小目标无能为力或者输入图像尺寸太小小目标在特征图上只剩几个像素。解决方法是按 2.2 节的代码调整 AnchorGenerator把最小尺寸降到 16 或 8。还可以将输入图像尺寸提高到 1216×1216 或原图比例让小目标在特征图上占据更多像素。改完之后重新训练 6-8 个 epoch观察小目标的 AP 是否提升。要注意这是“用训练时间换精度”的做法训练速度和显存占用都会上升适合毕设这种不在乎单次训练时长的场景。如果是产线落地我会优先考虑按板卡分区裁图把图像切成 4 块分别检测等效提高小目标分辨率比无限加大输入尺寸更可控。6. 把训练好的模型用起来推理脚本、性能验证与产线视角训练结束项目交付的核心是 predict.py 能稳定跑出检测结果。一个最小可用的推理脚本如下import torch import torchvision from PIL import Image from torchvision import transforms as T model torchvision.models.detection.fasterrcnn_resnet50_fpn(weightsNone) num_classes 7 in_features model.roi_heads.box_predictor.cls_score.in_features model.roi_heads.box_predictor torchvision.models.detection.faster_rcnn.FastRCNNPredictor(in_features, num_classes) model.load_state_dict(torch.load(checkpoints/epoch_12.pth, map_locationcpu)) model.eval() img Image.open(test_pcb.jpg).convert(RGB) x T.ToTensor()(img).unsqueeze(0) with torch.no_grad(): pred model(x)[0] score_threshold 0.5 keep pred[scores] score_threshold boxes pred[boxes][keep] labels pred[labels][keep] scores pred[scores][keep]推理脚本的关键逻辑是模型加载后必须 eval() 切到推理模式否则 BatchNorm 和 Dropout 在验证时行为不对检测结果会异常。参数说明score_threshold 是置信度阈值PCB 检测我一般设 0.5这值设高了漏检多设低了误检多。如果产线上对误检容忍度更低就把阈值调到 0.7同时接受一部分缺陷漏检这个权衡要按实际产线要求来定。推理跑通后要量化单人检测速度统计每张图的平均推理耗时。GPU 上 ResNet-50 的 Faster R-CNN 处理 800×800 图像大约在 100-200ms 之间CPU 上可能要 1-3 秒。产线检测节拍如果要求每块板子 500ms 以内这种情况我一般会走模型导出路线把 PyTorch 模型转成 TorchScript 再跑推理在 CUDA 上能带来 30%-50% 的加速。scripted_model torch.jit.script(model) scripted_model.save(pcb_det_scripted.pt)如果板卡检测是部署在嵌入式盒子里做实时检测就需要进一步考虑量化。INT8 量化能把模型体积压到四分之一推理速度翻倍但精度会掉 1-2 个点PCB 缺陷检测这类对漏检敏感的任务要谨慎用量化。我一般建议先用 TorchScript 做一次精度和速度的基准测试如果达不到产线节拍再做量化分支验证。在整个项目里开发文档最值得写的是调参记录和踩坑记录。你改了 anchor、调了学习率、换了增强方式每次改动对 mAP 的影响都要记录下来。这不仅是毕设答辩的加分项更是以后自己接手新板卡类型的底稿——换一块新 PCB把数据和 anchor 按记录改一遍半天就能复现一条好结果。这个习惯帮我避过很多次重头调参。最后提一句我在这个项目上最大的教训不要迷信公开预训练权重的默认参数能把 PCB 数据直接跑好也不要一上来就追求复杂的模型结构。先把 Faster R-CNN 默认配置跑通拿到一个 baseline再围绕 anchor 和数据做一轮一轮的调优每一步只改一个变量效果可验证、可回溯。希望这份笔记帮你在 PCB 缺陷检测这条路上少走点弯路。本文还有配套的精品资源点击获取
返回列表