(1)大佬教程
基于PaddleDetection的PCB瑕疵检测_AI Studio的博客-CSDN博客
(2)blibli视频
253-14_PCB电路板缺陷检测_项目配置文件_dec_哔哩哔哩_bilibili
(3)coco数据集说明
『深度应用』目标检测coco数据集格式介绍 - 腾讯云开发者社区-腾讯云
(1)下载地址

印刷电路板(PCB)瑕疵数据集。它是一个公共合成PCB数据集,包含1386张图像,具有6种缺陷(漏孔、鼠咬、开路、短路、杂散、杂铜),用于图像检测、分类和配准任务
看了一下,上面地址下载的数据集,是voc格式的
(2)根据百度教程来的话可以通过AIstudio直接下载

(1)查看各个缺陷的分布情况(类别数是否均匀,如果不均匀可以考虑调整loss的计算方法)
(2)查看锚框的长宽比,看看都是什么形状的
(3)看看锚框的大小(和原图大小的比值,看看是不是都是小物体)
(4)文件pcb_dataset_analysis.py如下
- import json
- from collections import defaultdict
- import matplotlib.pyplot as plt
- %matplotlib inline
-
- with open("/home/aistudio/work/PCB_DATASET/Annotations/train.json") as f:
- data = json.load(f)
-
- imgs = {}
- for img in data['images']:
- imgs[img['id']] = {
- 'h': img['height'],
- 'w': img['width'],
- 'area': img['height'] * img['width'],
- }
-
- hw_ratios = []
- area_ratios = []
- label_count = defaultdict(int)
- for anno in data['annotations']:
- hw_ratios.append(anno['bbox'][3]/anno['bbox'][2])
- area_ratios.append(anno['area']/imgs[anno['image_id']]['area'])
- label_count[anno['category_id']] += 1
-
- #查看各个缺陷的分布情况(类别数是否均匀,如果不均匀可以考虑调整loss的计算方法)
- print( label_count, len(data['annotations']) / len(data['images']) )
-
- #查看锚框的长宽比,看看都是什么形状的
- plt.hist(hw_ratios, bins=100, range=[0, 2])
- plt.show()
-
- #看看锚框的大小(和原图大小的比值,看看是不是都是小物体)
- plt.hist(area_ratios, bins=100, range=[0, 0.005])
- plt.show()
1)各个缺陷的分布和每张图的缺陷数如下
#查看各个缺陷的分布情况(类别数是否均匀,如果不均匀可以考虑调整loss的计算方法)
print( label_count, len(data['annotations']) / len(data['images']) )

2)长宽比的分布如下
#查看锚框的长宽比,看看都是什么形状的
plt.hist(hw_ratios, bins=100, range=[0, 2])
plt.show()

3)锚框和图的面积比如下
#看看锚框的大小(和原图大小的比值,看看是不是都是小物体)
plt.hist(area_ratios, bins=100, range=[0, 0.005])
plt.show()

(1)paddle官网
飞桨PaddlePaddle-源于产业实践的开源深度学习平台
(2)下载指定PaddleDetection

(3)对应的github地址如下
https://github.com/PaddlePaddle/PaddleDetection
- #(1)在对应目录下
- conda activate chenpaddle_cp310
-
- #(2)安装相关环境
- pip install -r requirements.txt
-
- pip install pycocotools
(1)一下参考来自官网
基于PaddleDetection的PCB瑕疵检测-FasterRCNN - 飞桨AI Studio
(2)配置参数

在检测目录下创建chenfastrcnn 目录,然后创建文件pcb_faster_rcnn_r50_fpn_3x_coco.yml内容如下
- metric: COCO # Label评价指标,coco IoU:0.5:0.95
- num_classes: 7 # 类别数量,coco类别比实际类别(voc类别)+1
-
- TrainDataset:
- !COCODataSet
- image_dir: images
- anno_path: Annotations/train.json
- dataset_dir: /home/chen/deep_data/pcb/PCB_DATASET_AI_STUDIO/PCB_DATASET
- data_fields: ['image', 'gt_bbox', 'gt_class']#, 'is_crowd'
-
- EvalDataset:
- !COCODataSet
- image_dir: images
- anno_path: Annotations/val.json
- dataset_dir: /home/chen/deep_data/pcb/PCB_DATASET_AI_STUDIO/PCB_DATASET
-
- TestDataset:
- !ImageFolder
- anno_path: Annotations/val.json
-
-
- use_gpu: true # 根据硬件选择是否使用GPU
- log_iter: 10 # 日志窗口的尺度
- save_dir: output/ # 模型输出文件夹
- snapshot_epoch: 1 # 生成快照的频率,即每1个周期生成一次
-
- epoch: 24 ### 训练周期:24
-
- LearningRate: ### 学习率:阶段学习率
- base_lr: 0.0025 # 起始学习率:0.0025
- schedulers:
- - !PiecewiseDecay ## 阶段学习率
- gamma: 0.1 # 每次学习率变化为原来的1/10
- milestones: [16, 22] # 总共进行两次学习率的降低
- - !LinearWarmup ## 慢启动,共执行200次迭代,学习率为初始学习率的0.1
- start_factor: 0.1
- steps: 200
-
- OptimizerBuilder: ### 优化方法:基于动量的SGD
- optimizer:
- momentum: 0.9
- type: Momentum
- regularizer:
- factor: 0.0001
- type: L2
-
- architecture: FasterRCNN # 总框架类型
- # 预训练模型
- pretrain_weights: https://paddledet.bj.bcebos.com/models/pretrained/ResNet50_cos_pretrained.pdparams
-
- ## 检测模型的体系结构,包含骨干、支路、区域建议、BBox头和BBox头后处理
- FasterRCNN:
- backbone: ResNet # 主干网络:ResNet
- neck: FPN # 特征金字塔网络
- rpn_head: RPNHead # 区域建议头:基于FPN的RPNHead
- bbox_head: BBoxHead # BBox头:BBoxHead
- # post process
- bbox_post_process: BBoxPostProcess # BBox后处理器
-
- ResNet:
- # index 0 stands for res2
- depth: 50 # 深度50,即ResNet50
- norm_type: bn # 正则化类型BN,基本上是唯一选择
- freeze_at: 0 # 冻结部分,ResNet的前两层
- return_idx: [0,1,2,3] # 提取特征的位置,即用于FPN的特征,其实index为0
- num_stages: 4
-
- FPN:
- out_channel: 256 # FPN通道数:256
-
- RPNHead:
- anchor_generator: ## Anchor生成器
- aspect_ratios: [0.5, 1.0, 2.0] # Anchor的比例1:2,1:1,2:1
- anchor_sizes: [[32], [64], [128], [256], [512]] # Anchor的尺度
- strides: [4, 8, 16, 32, 64] # Anchor的步长
- rpn_target_assign: ## RPN设置
- batch_size_per_im: 256 # RPN采样数量: 256
- fg_fraction: 0.5 # 正样本数量: 256*0.5=128
- negative_overlap: 0.3 # 负样本IoU<0.3
- positive_overlap: 0.7 # 正阳IoU>0.7
- use_random: True
- train_proposal: ## 训练建议框设置
- min_size: 0.0
- nms_thresh: 0.7 # 训练阶段nms阈值
- pre_nms_top_n: 2000 # 第一阶段nms数量
- post_nms_top_n: 1000 # 第二阶段nms数量
- topk_after_collect: True
- test_proposal: ## 测试建议框设置
- min_size: 0.0
- nms_thresh: 0.7 # 测试阶段nms阈值
- pre_nms_top_n: 1000 # 第一阶段nms数量
- post_nms_top_n: 1000 # 第二阶段nms数量
-
- BBoxHead: ## BBox头
- head: TwoFCHead # 两个FC头
- roi_extractor:
- resolution: 7 # RoIPooling特征层的尺度7×7
- sampling_ratio: 0
- aligned: True # 启用RoIAlign
- bbox_assigner: BBoxAssigner
-
- BBoxAssigner:
- batch_size_per_im: 512 # batch数量:512
- bg_thresh: 0.5 # 背景阈值<0.5
- fg_thresh: 0.5 # 前景阈值>0.5
- fg_fraction: 0.25
- use_random: True
-
- TwoFCHead:
- out_channel: 1024 # 全连接层特征维度(后面紧跟分类和回归层):1024
-
-
- BBoxPostProcess:
- decode: RCNNBox
- nms:
- name: MultiClassNMS
- keep_top_k: 100
- score_threshold: 0.05
- nms_threshold: 0.5
-
- worker_num: 2
-
-
- TrainReader:
- sample_transforms: # 数据预处理
- - Decode: {}
- - RandomResize: {target_size: [[640, 1333], [672, 1333], [704, 1333], [736, 1333], [768, 1333], [800, 1333]], interp: 2, keep_ratio: True}
- - RandomFlip: {prob: 0.5}
- - NormalizeImage: {is_scale: true, mean: [0.485,0.456,0.406], std: [0.229, 0.224,0.225]}
- - Permute: {}
- batch_transforms:
- - PadBatch: {pad_to_stride: 32}
- batch_size: 1 # 每批大尺度
- shuffle: true # 是否随机
- drop_last: true # 最后一个batch不足batch_sizes时,是否将多余数据进行丢弃
-
-
- EvalReader:
- sample_transforms:
- - Decode: {}
- - Resize: {interp: 2, target_size: [800, 1333], keep_ratio: True}
- - NormalizeImage: {is_scale: true, mean: [0.485,0.456,0.406], std: [0.229, 0.224,0.225]}
- - Permute: {}
- batch_transforms:
- - PadBatch: {pad_to_stride: 32}
- batch_size: 1
- shuffle: false
- drop_last: false
- drop_empty: false
-
-
- TestReader:
- sample_transforms:
- - Decode: {}
- - Resize: {interp: 2, target_size: [800, 1333], keep_ratio: True}
- - NormalizeImage: {is_scale: true, mean: [0.485,0.456,0.406], std: [0.229, 0.224,0.225]}
- - Permute: {}
- batch_transforms:
- - PadBatch: {pad_to_stride: 32}
- batch_size: 1
- shuffle: false
- drop_last: false
(2)在PaddleDetection-release-2.5目录下的终端中执行如下命令
- CUDA_VISIBLE_DEVICES=0
-
-
- python -u tools/train.py -c /home/chen/chen_deep/02PaddleDetection/PaddleDetection-release-2.5/chenfastrcnn/pcb_faster_rcnn_r50_fpn_3x_coco.yml --eval
-
- 或者
-
- python -u tools/train.py -c /home/chen/chen_deep/02PaddleDetection/PaddleDetection-release-2.5/chenfastrcnn/pcb_faster_rcnn_r50_fpn_3x_coco.yml --eval -o use_gpu=True
-
-
- 或者
-
- python -u tools/train.py -c /home/chen/chen_deep/02PaddleDetection/PaddleDetection-release-2.5/chenfastrcnn/pcb_faster_rcnn_r50_fpn_3x_coco.yml --eval -o use_gpu=False
(3)训练得到的模型在output下面

(4)测试以下图片,以下命令还有问题,会报错
python -u tools/infer.py -c /home/chen/chen_deep/02PaddleDetection/PaddleDetection-release-2.5/chenfastrcnn/pcb_faster_rcnn_r50_fpn_3x_coco.yml --infer_img=/home/chen/deep_data/pcb/PCB_DATASET_AI_STUDIO/PCB_DATASET/images/04_missing_hole_10.jpg -o weights=output/pcb_faster_rcnn_r50_fpn_3x_coco/best_model.pdparams use_gpu=True
(1)以下引用参考来自paddle官网
黑盒教程真有意思 :(
(2)其中ppyoloe_plus_crn_m_80e_obj365_pretrained_pcb.yml内容如下
- _BASE_: [
- './_base_/pcb_detection.yml',
- '../../runtime.yml',
- '../_base_/optimizer_80e.yml',
- '../_base_/ppyoloe_plus_crn.yml',
- '../_base_/ppyoloe_plus_reader.yml',
- ]
-
- log_iter: 100
- snapshot_epoch: 5
- weights: output/ppyoloe_plus_crn_m_80e_coco_pretrained_pcb/model_final
-
- pretrain_weights: https://bj.bcebos.com/v1/paddledet/models/ppyoloe_plus_crn_m_80e_coco.pdparams
- depth_mult: 0.67
- width_mult: 0.75
(3)'./_base_/pcb_detection.yml',文件如下
- metric: COCO
- num_classes: 6
-
- TrainDataset:
- !COCODataSet
- image_dir: images
- anno_path: pcb_cocoanno/train.json
- dataset_dir: dataset/PCB_coco/
- data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']
-
- EvalDataset:
- !COCODataSet
- image_dir: images
- anno_path: pcb_cocoanno/val.json
- dataset_dir: dataset/PCB_coco/
-
- TestDataset:
- !ImageFolder
- anno_path: pcb_cocoanno/val.json # also support txt (like VOC's label_list.txt)
- dataset_dir: dataset/PCB_coco/ # if set, anno_path will be 'dataset_dir/anno_path'
(4)'../../runtime.yml',文件内容如下
- use_gpu: true
- use_xpu: false
- log_iter: 20
- save_dir: output
- snapshot_epoch: 1
- print_flops: false
-
- # Exporting the model
- export:
- post_process: True # Whether post-processing is included in the network when export model.
- nms: True # Whether NMS is included in the network when export model.
- benchmark: False # It is used to testing model performance, if set `True`, post-process and NMS will not be exported.
- fuse_conv_bn: False
(5) '../_base_/optimizer_80e.yml',内容如下
- epoch: 80
-
- LearningRate:
- base_lr: 0.001
- schedulers:
- - !CosineDecay
- max_epochs: 96
- - !LinearWarmup
- start_factor: 0.
- epochs: 5
-
- OptimizerBuilder:
- optimizer:
- momentum: 0.9
- type: Momentum
- regularizer:
- factor: 0.0005
- type: L2
(6)ppyoloe_plus_crn.yml
- architecture: YOLOv3
- norm_type: sync_bn
- use_ema: true
- ema_decay: 0.9998
- ema_black_list: ['proj_conv.weight']
- custom_black_list: ['reduce_mean']
-
- YOLOv3:
- backbone: CSPResNet
- neck: CustomCSPPAN
- yolo_head: PPYOLOEHead
- post_process: ~
-
- CSPResNet:
- layers: [3, 6, 6, 3]
- channels: [64, 128, 256, 512, 1024]
- return_idx: [1, 2, 3]
- use_large_stem: True
- use_alpha: True
-
- CustomCSPPAN:
- out_channels: [768, 384, 192]
- stage_num: 1
- block_num: 3
- act: 'swish'
- spp: true
-
- PPYOLOEHead:
- fpn_strides: [32, 16, 8]
- grid_cell_scale: 5.0
- grid_cell_offset: 0.5
- static_assigner_epoch: 30
- use_varifocal_loss: True
- loss_weight: {class: 1.0, iou: 2.5, dfl: 0.5}
- static_assigner:
- name: ATSSAssigner
- topk: 9
- assigner:
- name: TaskAlignedAssigner
- topk: 13
- alpha: 1.0
- beta: 6.0
- nms:
- name: MultiClassNMS
- nms_top_k: 1000
- keep_top_k: 300
- score_threshold: 0.01
- nms_threshold: 0.7
(7)ppyoloe_plus_crn.yml
- worker_num: 4
- eval_height: &eval_height 640
- eval_width: &eval_width 640
- eval_size: &eval_size [*eval_height, *eval_width]
-
- TrainReader:
- sample_transforms:
- - Decode: {}
- - RandomDistort: {}
- - RandomExpand: {fill_value: [123.675, 116.28, 103.53]}
- - RandomCrop: {}
- - RandomFlip: {}
- batch_transforms:
- - BatchRandomResize: {target_size: [320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, 736, 768], random_size: True, random_interp: True, keep_ratio: False}
- - NormalizeImage: {mean: [0., 0., 0.], std: [1., 1., 1.], norm_type: none}
- - Permute: {}
- - PadGT: {}
- batch_size: 8
- shuffle: true
- drop_last: true
- use_shared_memory: true
- collate_batch: true
-
- EvalReader:
- sample_transforms:
- - Decode: {}
- - Resize: {target_size: *eval_size, keep_ratio: False, interp: 2}
- - NormalizeImage: {mean: [0., 0., 0.], std: [1., 1., 1.], norm_type: none}
- - Permute: {}
- batch_size: 2
-
- TestReader:
- inputs_def:
- image_shape: [3, *eval_height, *eval_width]
- sample_transforms:
- - Decode: {}
- - Resize: {target_size: *eval_size, keep_ratio: False, interp: 2}
- - NormalizeImage: {mean: [0., 0., 0.], std: [1., 1., 1.], norm_type: none}
- - Permute: {}
- batch_size: 1