paddle学习赛——钢铁目标检测(yolov5ppyoloe+,Faster-RCNN)
Posted 神洛华
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了paddle学习赛——钢铁目标检测(yolov5ppyoloe+,Faster-RCNN)相关的知识,希望对你有一定的参考价值。
文章目录
参考:
- 《飞桨新人赛:钢铁缺陷检测挑战赛-第1名方案》FasterRCNN+Swin
- 《飞桨新人赛:钢铁缺陷检测挑战赛-第2名方案》FasterRCNN
- 《飞桨新人赛:钢铁缺陷检测挑战赛-第3名方案》
一、赛事简介
- 比赛地址:https://aistudio.baidu.com/aistudio/competition/detail/114/0/introduction
- 赛题介绍:本次比赛为图像目标识别比赛,要求参赛选手识别出钢铁表面出现缺陷的位置,并给出锚点框的坐标,同时对不同的缺陷进行分类。
- 数据简介:本数据集来自NEU表面缺陷检测数据集,收集了6种典型的热轧带钢表面缺陷,即氧化铁皮压入(RS)、斑块(Pa)、开裂(Cr)、点蚀(PS)、夹杂(In)和划痕(Sc)。下图为六种典型表面缺陷的示例,每幅图像的分辨率为200 * 200像素。
- 训练集图片1400张,测试集图片400张
提交内容及格式:
- 结果文件命名:submission.csv(否则无法成功提交)
- 结果文件格式:.csv(否则无法成功提交)
- 结果文件内容:submission.csv结果文件需包含多行记录,每行包括4个字段,内容示例如下:
image_id bbox category_id confidence
1400 [0, 0, 0, 0] 0 1
各字段含义如下:
- image_id(int): 图片id
- bbox(list[float]): 检测框坐标(XMin, YMin, XMax, YMax)
- category_id: 缺陷所属类别(int),类别对应字典为:‘ crazing’:0,’inclusion’:1, ’pitted_surface’:2, ,’scratches’:3,’patches’:4,’rolled-in_scale’:5
- confidence(float): 置信度
备注: 每一行记录1个检测框,并给出对应的category_id;同张图片中检测到的多个检测框,需分别记录在不同的行内。
二、ppyoloe+l模型,41.32分 (PaddleDetection-voc)
2.1 安装PaddleDetection
- 克隆PaddleDetection
- 安装PaddleDetection文件夹的requirements.txt(python依赖)
- 编译安装paddledet
- 安装后确认测试通过
%cd ~/work
#!git clone https://github.com/PaddlePaddle/PaddleDetection.git
#如果github下载代码较慢,可尝试使用gitee
#git clone https://gitee.com/paddlepaddle/PaddleDetection
# 安装其他依赖
%cd PaddleDetection
!pip install -r requirements.txt
# 编译安装paddledet
!python setup.py install
#安装后确认测试通过:
!python ppdet/modeling/tests/test_architectures.py
!python ppdet/modeling/tests/test_architectures.py
W1001 15:08:57.768669 1185 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 11.2
W1001 15:08:57.773610 1185 gpu_resources.cc:91] device: 0, cuDNN Version: 8.2.
.......
----------------------------------------------------------------------
Ran 7 tests in 2.142s
OK
2.2 数据预处理
2.2.1 解压数据集
# 解压到work下的dataset文件夹
!mkdir dataset
!unzip ../data/test.zip -d dataset
!unzip ../data/train.zip -d dataset
# 重命名为annotations和images
!mv dataset/train/IMAGES dataset/train/images
!mv dataset/train/ANNOTATIONS dataset/train/annotations
2.2.2 自定义数据集(感觉很麻烦,暂时放弃)
PaddleDetection
的数据处理模块的所有代码逻辑在ppdet/data/
中,数据处理模块用于加载数据并将其转换成适用于物体检测模型的训练、评估、推理所需要的格式。- 数据集定义在
source
目录下,其中dataset.py
中定义了数据集的基类DetDataSet
, 所有的数据集均继承于基类,DetDataset基类里定义了如下等方法:
- 当一个数据集类继承自DetDataSet,那么它只需要实现parse_dataset函数即可
parse_dataset
根据数据集设置:
- 数据集根路径
dataset_dir
- 图片文件夹
image_dir
- 标注文件路径
anno_path
取出所有的样本,并将其保存在一个列表roidbs中,每一个列表中的元素为一个样本xxx_rec(比如coco_rec或者voc_rec),用dict表示,dict中包含样本的image, gt_bbox, gt_class等字段。COCO和Pascal-VOC数据集中的xxx_rec的数据结构定义如下:
xxx_rec =
'im_file': im_fname, # 一张图像的完整路径
'im_id': np.array([img_id]), # 一张图像的ID序号
'h': im_h, # 图像高度
'w': im_w, # 图像宽度
'is_crowd': is_crowd, # 是否是群落对象, 默认为0 (VOC中无此字段)
'gt_class': gt_class, # 标注框标签名称的ID序号
'gt_bbox': gt_bbox, # 标注框坐标(xmin, ymin, xmax, ymax)
'gt_poly': gt_poly, # 分割掩码,此字段只在coco_rec中出现,默认为None
'difficult': difficult # 是否是困难样本,此字段只在voc_rec中出现,默认为0
-
xxx_rec中的内容也可以通过DetDataSet的data_fields参数来控制,即可以过滤掉一些不需要的字段,但大多数情况下不需要修改,按照configs/dataset中的默认配置即可。
-
此外,在parse_dataset函数中,保存了类别名到id的映射的一个字典cname2cid。在coco数据集中,会利用COCO API从标注文件中加载数据集的类别名,并设置此字典。在voc数据集中,如果设置use_default_label=False,将从label_list.txt中读取类别列表,反之将使用voc默认的类别列表。
2.2.3 准备VOC数据集(直接用这个)
参考:《如何准备训练数据》
-
尝试coco数据集
- COCO数据标注是将所有训练图像的标注都存放到一个json文件中。数据以字典嵌套的形式存放
- 用户数据集转成COCO数据后目录结构如下:
dataset/xxx/ ├── annotations │ ├── train.json # coco数据的标注文件 │ ├── valid.json # coco数据的标注文件 ├── images │ ├── xxx1.jpg │ ├── xxx2.jpg │ ├── xxx3.jpg │ | ... ...
- json格式标注文件,得自己生成,目前我知道的就是用
paddledetection./tools/
中提供的x2coco.py
,将VOC数据集、labelme标注的数据集或cityscape数据集转换为COCO数据(生成json标准为文件)。这样太麻烦,还不如直接用VOC格式训练。
-
尝试自定义数据集(参考《数据处理模块》,重写
parse_dataset
感觉也很麻烦) -
准备voc数据集(最简单,麻烦一点的就是生成txt文件)
-
模仿VOC数据集目录结构,新建
VOCdevkit
文件夹并进入其中,然后继续新建VOC2007
文件夹并进入其中,之后新建Annotations
、JPEGImages
和ImageSets
文件夹,最后进入ImageSets
文件夹中新建Main
文件夹,至此完成VOC数据集目录结构的建立。 -
将该数据集中的
train/annotations/xmls
与val/annotations/xmls
(如果有val验证集的话)下的所有xml标注文件拷贝到VOCdevkit/VOC2007/Annotations
中, -
将该数据集中的
train/images/
与val/images/
下的所有图片拷贝到VOCdevkit/VOC2007/JPEGImages
中 -
最后在数据集根目录下输出最终的trainval.txt和test.txt文件(可用pandas完成,一会说):
-
-
生成VOC格式目录。
如果觉得后面移动文件很麻烦,可以先生成VOC目录,再将数据集解压到VOC2007中,将其图片和标注文件夹分别重命名为Annotations
和JPEGImages
。
%cd work
!mkdir VOCdevkit
%cd VOCdevkit
!mkdir VOC2007
%cd VOC2007
!mkdir Annotations JPEGImages ImageSets
%cd ImageSets
!mkdir Main
%cd ../../
- 生成
trainval.txt
和val.txt
由于该数据集中缺少已标注图片名列表文件trainval.txt
和val.txt
,所以需要进行生成,用pandas处理更直观
# 遍历图片和标注文件夹,将所有文件后缀正确的文件添加到列表中
import os
import pandas as pd
ls_xml,ls_image=[],[]
for xml in os.listdir('dataset/train/annotations'):
if xml.split('.')[1]=='xml':
ls_xml.append(xml)
for image in os.listdir('dataset/train/images'):
if image.split('.')[1]=='jpg':
ls_image.append(image)
读取xml
文件列表和image
文件名列表之后,要先进行排序。
- 直接df.sort_values([‘image’,‘xml’],inplace=True)是先对image排序,再对xml排序,是整个表排序而不是单列分别排序,这样的结果是不对的
- 直接分别排序再合并,结果也不对。因为添加xml列的时候,默认是按key=index来合并的,而两个列表的文件都是乱序的,这样排序后index也不相同,所以需要分别排序后重设索引,且丢弃原先索引,最后再合并。
df=pd.DataFrame(ls_image,columns=['image'])
df.sort_values('image',inplace=True)
df=df.reset_index(drop=True)
s=pd.Series(ls_xml).sort_values().reset_index(drop=True)
df['xml']=s
df.head(3)
image xml
0 0.jpg 0.xml
1 1.jpg 1.xml
2 10.jpg 10.xml
训练时,文件都是相对路径,所以要加前缀VOC2007/JPEGImages/
和VOC2007/Annotations/
%cd VOCdevkit
trainval=df.sample(frac=1)
trainval.image=trainval.image.apply(lambda x : 'VOC2007/JPEGImages/'+str(x))
trainval.xml=trainval.xml.apply(lambda x : 'VOC2007/Annotations/'+str(x))
trainval.to_csv('trainval.txt',sep=' ',index=0,header=0)
# 划分出训练集和验证集,保存为txt格式,中间用空格隔开
train_df=trainval[:1200]
val_df=trainval[1200:]
train_df.to_csv('train.txt',sep=' ',index=0,header=0)
val_df.to_csv('val.txt',sep=' ',index=0,header=0)
!cp -r train/annotations/* ../VOCdevkit/VOC2007/Annotations
!cp -r train/images/* ../VOCdevkit/VOC2007/JPEGImages
查看一张图片信息:
from PIL import Image
image = Image.open('dataset/train/images/0.jpg')
print('width: ', image.width)
print('height: ', image.height)
print('size: ', image.size)
print('mode: ', image.mode)
print('format: ', image.format)
print('category: ', image.category)
print('readonly: ', image.readonly)
print('info: ', image.info)
image.show()
2.3 修改配置文件,准备训练
- 模型效果请参考ppyolo文档
- 配置参数参考yolo配置参数说明、《如何更好的理解reader和自定义修改reader文件》
- PaddleYOLO库集成了yolo系列模型,包括yolov5/6/7/X,后续可以试试。
- 修改配置文件
- 手动复制一个
configs/ppyoloe/ppyoloe_plus_crn_m_80e_coco.yml
文件的副本,其它类似,防止改错了无法还原 configs/datasets/voc.yml
不用复制,免得下次重新写,修改后如下:(TestDataset
最好不要写dataset_dir
字段,否则后面infer.py
推断的时候,选择参数save_results=True
会报错label_list label_list.txt not a file
)metric: VOC map_type: 11point num_classes: 6 TrainDataset: !VOCDataSet dataset_dir: ../VOCdevkit anno_path: train.txt label_list: label_list.txt data_fields: ['image', 'gt_bbox', 'gt_class', 'difficult'] EvalDataset: !VOCDataSet dataset_dir: ../VOCdevkit anno_path: val.txt label_list: label_list.txt data_fields: ['image', 'gt_bbox', 'gt_class', 'difficult'] TestDataset: !ImageFolder anno_path: ../VOCdevkit/label_list.txt
- 学习率改为0.00025,epoch=60,max_epochs=72,!LinearWarmup下的epoch改为4。
- reader部分训练验证集的batch_size从8改为16,推理时bs也改为16,大大加快推理速度(之前默认为1,特别慢)
- PP-YOLOE+支持混合精度训练,请添加
--amp
. - 使用YOLOv3模型如何通过yml文件修改输入图片尺寸
Multi-Scale Training
:多尺度训练 。yolov3中作者认为网络输入尺寸固定的话,模型鲁棒性受限,所以考虑多尺度训练。具体的,在训练过程中每隔10个batches,重新随机选择输入图片的尺寸[320,352,416…608](Darknet-19最终将图片缩放32倍,所以一般选择32的倍数)。- 模型预测部署需要用到指定的尺寸时,首先在训练前需要修改
configs/_base_/yolov3_reader.yml
中的TrainReader
的BatchRandomResize
中target_size
包含指定的尺寸,训练完成后,在评估或者预测时,需要将EvalReader
和TestReader
中的Resize
的target_size
修改成对应的尺寸,如果是需要模型导出(export_model),则需要将TestReader
中的image_shape
修改为对应的图片输入尺寸 。 - 如果只改了训练集入网尺寸,验证测试集尺寸不变,会报错
- Paddle中支持的优化器Optimizer在PaddleDetection中均支持,需要手动修改下配置文件即可
- 手动复制一个
ppyoloe_plus_reader.yml
修改如下:(图片都很小,把默认的入网尺寸改了)
worker_num: 4
eval_height: &eval_height 224
eval_width: &eval_width 224
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: [96, 128, 160, 192, 224, 256, 288,320,352], 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: 16
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: 16
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 #最好是1,下文会说明
训练参数列表:(可通过–help查看)
FLAG | 支持脚本 | 用途 | 默认值 | 备注 |
---|---|---|---|---|
-c | ALL | 指定配置文件 | None | 必选,例如-c configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.yml |
-o | ALL | 设置或更改配置文件里的参数内容 | None | 相较于-c 设置的配置文件有更高优先级,例如:-o use_gpu=False |
–eval | train | 是否边训练边测试 | False | 如需指定,直接--eval 即可 |
-r/–resume_checkpoint | train | 恢复训练加载的权重路径 | None | 例如:-r output/faster_rcnn_r50_1x_coco/10000 |
–slim_config | ALL | 模型压缩策略配置文件 | None | 例如--slim_config configs/slim/prune/yolov3_prune_l1_norm.yml |
–use_vdl | train/infer | 是否使用VisualDL记录数据,进而在VisualDL面板中显示 | False | VisualDL需Python>=3.5 |
–vdl_log_dir | train/infer | 指定 VisualDL 记录数据的存储路径 | train:vdl_log_dir/scalar infer: vdl_log_dir/image | VisualDL需Python>=3.5 |
–output_eval | eval | 评估阶段保存json路径 | None | 例如 --output_eval=eval_output , 默认为当前路径 |
–json_eval | eval | 是否通过已存在的bbox.json或者mask.json进行评估 | False | 如需指定,直接--json_eval 即可, json文件路径在--output_eval 中设置 |
–classwise | eval | 是否评估单类AP和绘制单类PR曲线 | False | 如需指定,直接--classwise 即可 |
–output_dir | infer/export_model | 预测后结果或导出模型保存路径 | ./output | 例如--output_dir=output |
–draw_threshold | infer | 可视化时分数阈值 | 0.5 | 例如--draw_threshold=0.7 |
–infer_dir | infer | 用于预测的图片文件夹路径 | None | --infer_img 和--infer_dir 必须至少设置一个 |
–infer_img | infer | 用于预测的图片路径 | None | --infer_img 和--infer_dir 必须至少设置一个,infer_img 具有更高优先级 |
–save_results | infer | 是否在文件夹下将图片的预测结果保存到文件中 | False | 可选 |
2.4 ppyoloe+s,mAP=77.6%
# lr=0.0002,epoch=40,time=2572s
%cd ~/work/PaddleDetection/
!python -u tools/train.py -c configs/ppyoloe/ppyoloe_plus_crn_s_80e_coco-Copy1.yml \\
--use_vdl=true \\
--vdl_log_dir=vdl_dir/scalar \\
--eval \\
--amp
[10/02 02:51:09] ppdet.engine INFO: Epoch: [45] [ 0/75] learning_rate: 0.000085 loss: 1.671754 loss_cls: 0.781011 loss_iou: 0.174941 loss_dfl: 0.880325 loss_l1: 0.378740 eta: 0:10:17 batch_cost: 0.5481 data_cost: 0.0049 ips: 29.1918 images/s
[10/02 02:51:58] ppdet.engine INFO: Epoch: [46] [ 0/75] learning_rate: 0.000080 loss: 1.672976 loss_cls: 0.782366 loss_iou: 0.173936 loss_dfl: 0.885129 loss_l1: 0.378303 eta: 0:09:36 batch_cost: 0.5459 data_cost: 0.0049 ips: 29.3068 images/s
[10/02 02:52:48] ppdet.engine INFO: Epoch: [47] [ 0/75] learning_rate: 0.000075 loss: 1.679924 loss_cls: 0.791866 loss_iou: 0.173251 loss_dfl: 0.892923 loss_l1: 0.371434 eta: 0:08:55 batch_cost: 0.5490 data_cost: 0.0049 ips: 29.1445 images/s
[10/02 02:53:37] ppdet.engine INFO: Epoch: [48] [ 0/75] learning_rate: 0.000069 loss: 1.669277 loss_cls: 0.785255 loss_iou: 0.173793 loss_dfl: 0.879943 loss_l1: 0.384001 eta: 0:08:14 batch_cost: 0.5546 data_cost: 0.0072 ips: 28.8511 images/s
[10/02 02:54:25] ppdet.engine INFO: Epoch: [49] [ 0/75] learning_rate: 0.000064 loss: 1.653534 loss_cls: 0.783021 loss_iou: 0.173808 loss_dfl: 0.865887 loss_l1: 0.377161 eta: 0:07:32 batch_cost: 0.5445 data_cost: 0.0080 ips: 29.3847 images/s
[10/02 02:55:18] ppdet.utils.checkpoint INFO: Save checkpoint: output/ppyoloe_plus_crn_l_80e_coco-Copy1
[10/02 02以上是关于paddle学习赛——钢铁目标检测(yolov5ppyoloe+,Faster-RCNN)的主要内容,如果未能解决你的问题,请参考以下文章