新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于Faster-RCNN的PCB缺陷检测实战:从VOC数据到ECA-FPN骨干选型

发布时间:2026/10/1 17:33:40来源:尧图网络
基于Faster-RCNN的PCB缺陷检测实战:从VOC数据到ECA-FPN骨干选型
简介这是一套面向高校学生与开发者的PCB元器件缺陷检测实战项目基于Python与Faster-RCNN实现配套完整源码、开发文档与项目解析适用于毕业设计、课程设计及工程开发等场景。项目围绕VOC0712数据集展开涵盖训练、预测与评估三条主线既可训练标准数据集也能迁移到自建数据集预测阶段支持预训练权重与自训练权重两种方式评估环节同样区分公开测试集与自有数据便于对照验证模型效果。压缩包共79个文件以35个py源码与39个pyc编译文件为主另含md说明文档、txt依赖清单及license等整体约214KB目录按数据预处理、网络结构、训练与评估模块清晰划分包含RPN、ResNet、VGG、FPN等多种骨干实现及mAP评估脚本。目前已有381人学习下载读者可据此掌握从数据标注、锚框聚类到模型训练与指标评估的完整流程并在此基础上快速延伸改造。1. 从一张贴片板子说起这套 Faster-RCNN PCB 缺陷检测源码到底能跑出什么去年帮一个做小批量 SMT 打样的朋友看板子他们产线末端还是靠人眼在放大镜下找漏件、错件、极性反。一天几百片眼睛看花是常态漏检率随班次往后走肉眼可见地涨。后来我拿这套基于 Python Faster-RCNN 的 PCB 元器件缺陷检测源码在几张实拍图上跑了一遍推理漏件和错件基本都能框出来置信度也稳。这套东西的价值不在于算法多新而在于它把从 VOC 数据标注、锚框聚类、训练、评估到单图预测的整条链路都摊开给你了frcnn_predict.py、train.py、get_map.py各司其职nets目录里还塞了 ResNet50、ResNet101、VGG16 以及带 ECA 注意力的 FPN 变体方便你换骨干做对比实验。它适合三类人赶毕业设计需要一套能跑通、能改、能写进论文的检测项目课程设计想拿真实工业场景练手以及做项目开发想快速搭一个缺陷检测 baseline 的工程师。前提是你得接受它是个「工程脚手架」而不是「开箱即用产品」——数据得自己标权重得自己训参数得自己调。2. 环境与数据准备把 VOC07 格式的 PCB 数据集喂进 Faster-RCNN2.1 为什么这套代码坚持用 VOC 格式而不是直接读 COCO打开voc_annotation.py和Data_preproces目录就能看出来整个数据流是围绕 VOC 的Annotations/*.xml和JPEGImages/*.jpg设计的。voc_annotation.py干的事很直接遍历标注目录把每张图的类别和 bbox 坐标抽出来写成2007_train.txt和2007_val.txt这种一行一图的索引文件。选 VOC 而不是 COCO核心原因是 PCB 缺陷检测的类别通常很少——漏件、错件、极性反、偏移、虚焊五到十类顶天了VOC 的 XML 结构对这种小类别场景足够用而且标注工具LabelImg 之类导出 VOC 是默认选项省一道转换。order_name.py则是给文件名做排序规整的避免训练集和验证集划分时因为文件名乱序导致分布不均。常见做法是先把原始图片按 8:2 或 9:1 分到JPEGImages和Annotations对应的训练/验证子集再跑voc_annotation.py生成索引。这里有个容易忽略的点voc_annotation.py里的classes列表必须和你 XML 里的name字段完全一致大小写、空格都算否则训练时类别对不上loss 会一直卡在高位。2.2 数据增强与锚框聚类data_expansion.py和kmeans_anchors怎么配合PCB 图像的缺陷目标普遍偏小一块板子上几十上百个元件漏掉一个电阻可能就占几十个像素。data_expansion.py提供的是离线增强思路——旋转、翻转、亮度扰动把样本量撑起来。但真正影响小目标召回的是锚框尺寸。kmeans_anchors目录下的脚本就是干这个的拿你训练集里所有 GT bbox 的宽高做 K-means 聚类聚出 9 组 anchor 尺寸替换掉anchors.py里的默认值。# kmeans_anchors 核心逻辑示意基于项目内脚本整理 import numpy as np def kmeans_anchors(bboxes, k9, max_iter300): # bboxes: N x 2 的宽高数组 # 随机初始化 k 个聚类中心 centers bboxes[np.random.choice(len(bboxes), k, replaceFalse)] for _ in range(max_iter): # 计算每个 bbox 到各中心的 IoU 距离 distances 1 - iou_matrix(bboxes, centers) labels distances.argmin(axis1) new_centers np.array([bboxes[labels i].mean(axis0) for i in range(k)]) if np.allclose(new_centers, centers): break centers new_centers return centers # 按面积排序后写回 anchors.py逻辑说明K-means 在这里聚的是 bbox 的宽高不是坐标位置目的是让 anchor 的尺度分布贴合你的数据。参数上k9对应 Faster-RCNN 每个位置 9 个 anchormax_iter给 300 足够收敛。跑完之后把输出的 9 组宽高按从小到大排好填进anchors.py的anchors_size列表。这一步不做默认 anchor 是按 COCO 通用目标设的对 PCB 上的小元件会明显偏大小目标召回直接掉一截。2.3 依赖安装与训练入口requirements.txt和train.py的参数怎么读环境这块requirements.txt里主要是 torch、torchvision、numpy、Pillow、opencv-python 这几样。我一般会先建虚拟环境再装避免和系统里的包打架。# 建环境并安装依赖 python -m venv pcb_env source pcb_env/bin/activate # Windows 用 pcb_env\Scripts\activate pip install -r requirements.txt # 如果 torch 版本和 CUDA 不匹配去官网按对应命令单独装装完先别急着训打开train.py看几个关键参数Cuda控制是否用 GPUinput_shape是输入分辨率PCB 小目标建议至少 600x600Init_Epoch和Freeze_Epoch决定冻结骨干的轮数Unfreeze_Epoch是解冻后的总轮数batch_size受显存限制。FasterRCNN_train.py是实际训练循环所在utils_fit.py封装了单轮训练和验证callbacks.py管学习率衰减和模型保存。第一次跑建议先用冻结骨干训 20 轮看 loss 是否下降再解冻微调。提示input_shape改大能提升小目标检测但显存占用是平方级增长8G 显存建议不超过 800x800。3. 训练与骨干网络选型ResNet50、ResNet101 和 ECA-FPN 到底选哪个3.1 骨干网络对比从nets目录看四种主干的取舍nets目录里躺着resnet50.py、resnet101.py、vgg16.py、resnet50_FPN.py、resnet50_ECA_FPN.py这就是给你做对比实验用的。选型逻辑不复杂VGG16 是最原始的 Faster-RCNN 骨干显存吃得凶、速度慢但特征提取稳适合当 baseline 对照ResNet50 是性价比首选速度和精度平衡大多数 PCB 缺陷场景够用ResNet101 层数深对大目标和小目标都有提升但训练慢、显存高适合你数据量够、追求 mAP 上限resnet50_ECA_FPN是加了 ECA 注意力机制的 FPN 变体ECA 是通道注意力几乎不增加参数量对小目标和密集目标场景有增益PCB 这种元件密集的图我一般优先试这个。骨干参数量量级显存占用适用场景VGG16大高baseline 对照ResNet50中中通用首选ResNet101大高数据足、追精度ResNet50_ECA_FPN中中偏高小目标、密集目标切换骨干不用改训练逻辑在train.py里改backbone参数即可FasterRCNN_train.py会根据名字去nets里取对应网络。rpn.py是区域建议网络classifier.py是 ROI 分类回归头这两个是 Faster-RCNN 的固定组件换骨干不影响它们。3.2 训练流程实操冻结、解冻与 loss 监控训练分两阶段是这套代码的默认设计。第一阶段冻结骨干只训 RPN 和分类头学习率给 1e-3 左右让随机初始化的头先收敛第二阶段解冻全部学习率降到 1e-4整体微调。utils_fit.py里的fit_one_epoch会返回每轮的分类 loss、回归 loss 和总 losscallbacks.py里的LossHistory负责记录。# train.py 关键参数片段按项目结构整理 Cuda True input_shape [600, 600] # 小目标建议 600 起步 backbone resnet50_eca_fpn # 骨干选择 Init_Epoch 0 Freeze_Epoch 20 # 冻结阶段轮数 Unfreeze_Epoch 100 # 总轮数 Freeze_batch_size 8 Unfreeze_batch_size 4 # 解冻后显存涨batch 调小 lr 1e-4逻辑说明Freeze_Epoch到Unfreeze_Epoch之间是解冻微调Freeze_batch_size比Unfreeze_batch_size大是因为冻结时骨干不存梯度显存省。监控 loss 时重点看回归 loss如果它一直不降多半是 anchor 尺寸不对或学习率太大分类 loss 震荡则可能是类别不平衡PCB 缺陷里正常元件远多于缺陷需要靠数据增强或类别权重压一压。3.3 评估指标get_map.py和utils_map.py怎么算 mAPget_map.py是评估入口底层调utils_map.py里的get_map函数按 VOC 的 11 点或全点插值法算每个类别的 AP再平均成 mAP。跑评估前要确认classes_path和训练时一致测试集索引文件路径对。utils_bbox.py里的解码逻辑负责把网络输出的偏移量还原成实际坐标soft_nms.py是可选的软 NMSPCB 上元件挨得近时普通 NMS 容易把相邻元件的框误删软 NMS 用分数衰减代替直接剔除密集场景下召回更稳。# 评估命令 python get_map.py # 输出每个类别的 AP 和总 mAP同时会在 map_out 目录存 PR 曲线参数上get_map.py里的confidence阈值控制哪些预测框参与评估默认 0.02 左右是为了算全量 PR 曲线实际部署时推理阈值要另设一般 0.5 起步。utils_map.py里还处理了多类别的匹配逻辑IoU 阈值默认 0.5如果你的缺陷框重叠严重可以适当放宽到 0.45 再观察。4. 推理与部署frcnn_predict.py单图预测和批量检测怎么改4.1 单图预测从权重加载到画框输出frcnn_predict.py是推理主脚本流程是加载权重、预处理图片、前向、解码、NMS、画框。Suggestion_box.py负责画框和类别文字utils_bbox.py里的DecodeBox做偏移解码。# frcnn_predict.py 推理核心按项目结构整理 from nets.frcnn import FasterRCNN from utils.utils_bbox import DecodeBox # 加载模型和权重 model FasterRCNN(num_classeslen(classes), backbonebackbone) model.load_state_dict(torch.load(weights_path, map_locationcpu)) model.eval() # 预处理resize 到 input_shape归一化 image cv2.imread(img_path) image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) image cv2.resize(image, (input_shape[1], input_shape[0])) image np.transpose(image / 255.0, (2, 0, 1))[None] # 前向 解码 NMS with torch.no_grad(): roi_cls_locs, roi_scores, rois, _ model(torch.from_numpy(image).float()) results decodebox(roi_cls_locs, roi_scores, rois, input_shape) # results 里是 [x1,y1,x2,y2,score,class_id]按 score 过滤后画框逻辑说明input_shape必须和训练时一致否则解码坐标会错位。confidence过滤阈值在推理时建议 0.5太低会出一堆误框。nms_iou默认 0.3 到 0.5PCB 元件密集时调低到 0.3 能减少重叠框。Suggestion_box.py里的draw_boxes支持中文类别名但需要字体文件默认用英文标签更省事。4.2 批量检测与结果导出把单图脚本改成产线可用的批处理单图预测只能演示实际产线要批量。改法是把frcnn_predict.py里的图片读取换成遍历目录结果写 CSV 或 JSON。utils.py里有cvtColor和resize_image工具函数可以复用。import os, csv from PIL import Image def batch_predict(img_dir, output_csv): with open(output_csv, w, newline) as f: writer csv.writer(f) writer.writerow([image, class, score, x1, y1, x2, y2]) for name in os.listdir(img_dir): if not name.lower().endswith((.jpg, .png)): continue img_path os.path.join(img_dir, name) results predict_single(img_path) # 复用单图推理 for box in results: writer.writerow([name, box[class], box[score], box[x1], box[y1], box[x2], box[y2]])逻辑说明批量推理时注意显存释放每张图推理完torch.cuda.empty_cache()一下避免长跑爆显存。输出 CSV 方便后续做统计和追溯产线上一般还要加时间戳和工位号。如果要做实时检测把frcnn_predict.py的输入换成摄像头帧但 Faster-RCNN 本身速度不快ResNet50 骨干在 1080Ti 上单帧大概 100ms 出头产线节拍快的话得考虑换轻量骨干或降输入分辨率。4.3 权重文件与训练日志的管理习惯train.py默认把权重存到logs目录按 epoch 命名。我一般会额外存一份best_epoch_weights.pth按验证集 mAP 最高的那轮存而不是最后一轮。因为 PCB 缺陷检测容易过拟合最后一轮未必最好。callbacks.py里的ModelCheckpoint可以改成按 mAP 保存。训练日志用LossHistory存成 txt画 loss 曲线时直接读别每次重新训。注意权重文件别和代码混在一个目录提交.gitignore里已经忽略了logs和map_out自己加权重时也走这个规则不然仓库会很大。5. 避坑与排查PCB 缺陷检测训练里最容易翻车的五个点5.1 现象训练 loss 正常下降但 mAP 一直低于 0.2原因最常见的是voc_annotation.py里的classes列表和 XML 里的类别名不一致或者验证集索引文件里混进了训练集的图。另一个可能是 anchor 没重新聚类默认 anchor 和 PCB 小目标尺度差太远。解决先打印classes列表和 XML 里出现的所有name做比对确保完全一致。然后跑一遍kmeans_anchors把结果写回anchors.py。最后检查2007_train.txt和2007_val.txt有没有重复行用sort | uniq -d查一下。5.2 现象推理时框的位置整体偏移或框到板子外面原因input_shape和训练时不一致或者DecodeBox里的anchors_size和训练用的对不上。Faster-RCNN 的解码依赖 anchor 尺寸改了 anchor 没同步改推理配置就会偏。解决确认train.py和frcnn_predict.py里的input_shape、anchors_size、backbone三个参数完全一致。如果训练中途换过 anchor推理必须用同一套。5.3 现象相邻元件只框出一个另一个被 NMS 吃掉原因普通 NMS 按 IoU 直接剔除PCB 上电阻电容挨得近IoU 容易超阈值。soft_nms.py就是为这个准备的但默认没启用。解决在推理解码后把 NMS 换成soft_nms或者把nms_iou从 0.5 调到 0.3。软 NMS 的sigma参数控制衰减速度默认 0.5密集场景可以调到 0.3 让衰减更快。5.4 现象训练到一半显存爆了报 CUDA out of memory原因解冻阶段骨干开始存梯度显存需求比冻结阶段高不少Unfreeze_batch_size没相应调小。或者input_shape设太大。解决解冻阶段把 batch_size 降到冻结阶段的一半甚至三分之一。如果还爆把input_shape从 800 降到 600。再不行就上梯度累积用时间换显存。5.5 现象评估 mAP 很高但实际图片上漏检明显原因评估用的是测试集和实际场景分布不一致。PCB 缺陷检测里测试集如果和训练集同批次拍摄光照、角度都一样mAP 会虚高。实际产线换批次、换光源就崩。解决评估集要单独留一批不同时间、不同光照下拍的图。data_expansion.py里的亮度扰动和旋转增强要开足让模型对光照和角度鲁棒。另外推理阈值别照搬评估阈值实际部署时按漏检和误检的代价重新定。6. 进阶技巧用 ECA 注意力 软 NMS 把密集小目标召回再拉一截这套代码里最值得深挖的是resnet50_ECA_FPN.py和soft_nms.py的组合。ECA 注意力的核心是在 FPN 的每个通道上做自适应卷积用极小的参数量换通道间的特征重标定。PCB 上元件密集通道注意力能让网络更关注缺陷区域的特征响应抑制背景板面的干扰。我一般会在train.py里把backbone设成resnet50_eca_fpn同时把soft_nms在推理阶段启用两个一起上密集小目标的召回能比默认配置高几个点。具体操作上先确认nets/resnet50_ECA_FPN.py里的 ECA 模块被正确插入到 FPN 的每个输出层之后。ECA 的实现通常是一个AdaptiveAvgPool加一维卷积再加Sigmoid卷积核大小k由通道数自适应算出来。如果你要改k注意它和通道数的关系别硬编码。# ECA 模块核心按 nets 目录结构整理 class ECA(nn.Module): def __init__(self, channel, k_size3): super(ECA, self).__init__() self.avg_pool nn.AdaptiveAvgPool2d(1) self.conv nn.Conv1d(1, 1, kernel_sizek_size, padding(k_size - 1) // 2, biasFalse) self.sigmoid nn.Sigmoid() def forward(self, x): y self.avg_pool(x) # [B, C, 1, 1] y self.conv(y.squeeze(-1).transpose(-1, -2)) # [B, 1, C] y y.transpose(-1, -2).unsqueeze(-1) # [B, C, 1, 1] return x * self.sigmoid(y) # 通道加权逻辑说明k_size是一维卷积核大小控制跨通道交互的范围默认 3 对大多数场景够用。padding保证输出长度和输入一致。这个模块几乎不增加计算量但能让 FPN 的多尺度特征在通道维度上更聚焦。配合soft_nms使用时推理阶段把nms_iou设 0.3、sigma设 0.3密集元件的召回会明显改善。验证方法上我习惯做两组对照一组默认 ResNet50 普通 NMS一组 ECA-FPN 软 NMS其他参数完全一致跑同一个测试集看 mAP 和每类 AP。如果 ECA 那组在小目标类别比如漏件、偏移上 AP 涨了说明注意力起作用了如果没涨甚至掉了多半是 ECA 插入位置不对或者k_size不合适回去调。从那以后我每次换骨干或改 NMS都强制先跑一遍对照实验再决定用哪套配置绝不凭感觉拍脑袋。这套源码的价值就在于它把对比实验的架子搭好了你只需要换参数、跑评估、看数字。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

C++高性能Socket类设计:断线重连、跨平台非阻塞与多线程安全 2026/10/1 19:06:05

C++高性能Socket类设计:断线重连、跨平台非阻塞与多线程安全

简介:这是一份面向C初学者与网络编程入门者的轻量级Socket封装类实现资源,聚焦于TCP通信基础能力构建,适用于课程设计、实验开发及小型网络工具原型开发。资源包含一个头文件(MySocket.h)和一个实现文件(My…

阅读更多 →
不安全状态≠死锁:从银行家算法到真实系统排查指南 2026/10/1 19:06:05

不安全状态≠死锁:从银行家算法到真实系统排查指南

学习操作系统的时候,几乎每本教材都会放一张嵌套图:安全状态套着不安全状态,再套着死锁状态,然后配一句“死锁一定处于不安全状态,但不安全状态不一定会死锁”。这句话我在考试前背得滚瓜烂熟,但真正理解它…

阅读更多 →
Hermes v0.10.0 Tool Gateway:智能体工具调用的工程化基石 2026/10/1 19:05:58

Hermes v0.10.0 Tool Gateway:智能体工具调用的工程化基石

1. 为什么工具网关成了智能体落地的关键一环Hermes v0.10.0 Tool Gateway 这个版本发布之后,我花了一整天把工具网关的源码和配置文档完整过了一遍。如果你正在做智能体应用,尤其是让大模型去调用外部业务工具的时候,这个版本值得仔细看。Too…

阅读更多 →
Keil报错L6218E: Image$$ARM_LIB_STACK$$ZI$$Limit未定义?启动文件不匹配是根源 2026/10/1 19:05:58

Keil报错L6218E: Image$$ARM_LIB_STACK$$ZI$$Limit未定义?启动文件不匹配是根源

先说结论:这个报错不是因为你代码写错了,也不是芯片选错了,而是工程环境里缺少了C库初始化栈空间所需的链接符号。很多人第一次碰到Error: L6218E: Undefined symbol Image$$ARM_LIB_STACK$$ZI$$Limit时会直接懵掉,网上搜一圈&…

阅读更多 →
Vue 3 + Vite 项目报错:Failed to resolve module specifier “vue“ 的排查与修复 2026/10/1 19:05:58

Vue 3 + Vite 项目报错:Failed to resolve module specifier “vue“ 的排查与修复

说实话,看到 Uncaught TypeError: Failed to resolve module specifier "vue" 这个报错的时候,我第一反应是“构建产物是不是坏了”。但后来发现,这不是bug,是构建产物里的模块引用方式,和浏览器原生ES Mo…

阅读更多 →
Python自动化SQL注入检测工具源码解析与调试实战 2026/10/1 19:05:58

Python自动化SQL注入检测工具源码解析与调试实战

简介:这是一套基于Python实现的自动化SQL注入检测工具完整源码,面向计算机、网络安全及通信相关专业的学生与从业者,可用于毕业设计、课程大作业或安全入门进阶学习。项目围绕布尔盲注、时间盲注等常见注入类型展开,配套查询参数提…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉