【项目014】基于R-CNN系列模型的目标检测(路标识别) 返回首页

作者:欧新宇(Xinyu OU)
当前版本:Release v1.0
开发平台:Paddle 2.3.2, PaddleDetection-release-2.4
运行环境:Intel Core i7-7700K CPU 4.2GHz, nVidia GeForce GTX 1080 Ti
本教案所涉及的数据集仅用于教学和交流使用,请勿用作商用。

最后更新:2022年4月10日


路标识别是自动驾驶汽车能安全运行在道路上的前提,本项目基于PaddleDetection工具包及RCNN系列模型进行实现,数据集可以从百度AIStudio进行下载,链接地址如下:
URL: https://aistudio.baidu.com/aistudio/datasetdetail/127202

【任务一】PaddleDetection环境的安装与调试

任务描述: 在安装有PaddlePaddle的计算机上完成PaddleDetection的安装和测试。
任务要求:

  1. 学会在安装好PaddlePaddle的Windows系统中安装PaddleDetection工具包;
  2. 能够解决PaddleDetecion安装过程中遇到的各种问题;
  3. 能够通过测试判断PaddleDetection是否被正确安装。

1.1 PaddleDetection的下载

  1. 从官网下载PaddleDetection(当前最新版v2.4)https://github.com/PaddlePaddle/PaddleDetection
  2. 解压 PaddleDetection-release-2.4.zip 工具包到项目文件夹 MyProjects,实现方法有两种:
    1). 使用Windows文件管理方法进行解压,并将文件夹名改为 DetectionRoadSign(便于项目管理)或直接使用带版本的命名 PaddleDetection-release-2.4(便于版本管理),本教案使用后者进行实现。
    2). 使用下列Python代码实现解压
import os
import zipfile

# 设置工作路径
workspace = 'D:\\Workspace\\MyProjects'
if not os.path.exists(workspace):
    os.makedirs(workspace)
os.chdir(workspace)

# 将PaddleDetection解压到工作路径的更目录
f = zipfile.ZipFile('D:\Workspace\安装包\Paddle\PaddleDetection-release-2.4.zip', 'r')
for file in f.namelist():
    f.extract(file, './')
f.close()

1.2 PaddleDetection的安装

PaddleDetection的具体安装配置方法,请参考 【项目01】Python机器学习环境的安装和配置。 通常,PaddleDetection环境的安装只需要执行一次,确认服务器或本地环境已经具备相关依赖文件后,可跳过该步。

>> python setup.py install

安装成功将得到如下提示:

Finished processing dependencies for paddledet==2.4.0

1.3 PaddleDetection的测试

>> python ppdet/modeling/tests/test_architectures.py

验证通过将得到如下提示:

Ran 7 tests in 12.816s
OK

【任务二】Windows工程环境的设置

任务描述: 在本地计算机中配置和部署好用于目标检测的相关文件夹和文件。
任务要求:
1.理解项目化部署的重要性;
2.能够根据需要完成必要文件夹的创建,并将相关文件保存到指定文件夹。

为了便于项目管理,本课程所有环境都按照统一规范进行设置,详细内容请参考 【项目01】Python机器学习环境的安装和配置。

如上图所示,我们在 PaddleDetecion-release-2.4 的根目录中可以看到多个不同功能的文件夹,其中 configs 保存了预制的多个经典模型,包括faster_rcnn, yolov3, ppyolo等;tools 文件夹中保存了PaddleDetection工具用于训练验证推理等功能的可执行文件。此外,我们需要在根目录下创建任务发布文件夹 contrib,并在该目录下创建任务文件夹 RoadSign 用于实现路标识别。在该目录下,我们再创建三个功能文件夹,分别为:

【任务三】数据准备

任务描述: 下载路标识别数据集,并按规范解压到指定目录,用于后续的训练、评估和预测。
任务要求:
1.任意从coco或voc两种标签模式中选择一种用于训练;
2.观察并熟悉两种数据标注结构的基本方法,能够理解并看懂基于voc标注的xml文件和基于coco标注的json文件;
3.能够对数据标注进行简单的可视化分析。

3.1 数据集下载

本项目使用 road-sign-detection 的比赛数据。该数据集包含877张图片,被划分为speedlimit, crosswalk, trafficligh, stop四个类别。为了便于公平评估,我们已经将数据集按照[8:2]的比例进行划分,其中训练集701张图、测试集176张图。本课程提供voc格式和coco格式的数据标签,已发布至百度AIStudio平台,URL: https://aistudio.baidu.com/aistudio/datasetdetail/127202

备注: voc格式和coco格式是目标检测数据集常用的两种数据标注格式,前者使用xml定义样本的标注,每个样本都包含一个xml文件;后者使用json文件定义标注,所有样本都保存在一个json文件中。

3.2 数据集解压

要求按照【任务二】中的说明,将下载好 RoadSign数据集 解压到 ExpDatasets/RoadSign 目录中。

【任务四】配置文件的准备

任务描述: 使用PaddleDetection配置 Faster RCNN 模型,并实现对路标识别 数据集RoadSign 的训练。
任务要求:

  1. 能够按照规范完成FasterRCNN模型所有配置文件的组合,并保存在指定的项目文件夹;
  2. 能够根据数据集和项目的实际情况,正确修改相关配置文件;
  3. 能够完成FasterRCNN模型的训练,并解决训练过程中可能出现的常见问题。

4.1 配置文件简介

PaddleDetection的模型都是基于yaml文件完成配置,在不对模型进行修改的时候,只需要设置yaml中的超参数即可完成快速的训练和部署。此处,为避免不可恢复错误,要求按照【任务二】的说明,,复制原版配置文件到项目文件夹 contrib/RoadSign 后,再对副本配置文件进行修改。在 [发布版] 的项中,我们给出六种预先配置好的模型,用于实验对比。本教案中,我们针对其中的模型 D. faster_rcnn_r50_fpn_1x_coco 进行介绍。六种模型具体包括:

在以上各版本的模型中,各参数含义描述如下:

下面以 faster_rcnn_r50_fpn_1x_coco.yml为例子,说明PaddleDetection关键超参数配置文件的组成和相互之间的逻辑关系,如下图所示:

4.2 配置文件准备

本项目在配置模型超参数时,需要先需要复制/创建如下文件:

  1. PaddleDetecion-release-2.4 根目录下创建项目集文件夹 contrib,并在该文件夹下创建针对本项目的 RoadSign 文件夹,同时创建 configs, datasets, outputs 三个文件夹,分别用于保存模型配置文件、数据集配置文件和输出结果文件。
  2. configs 文件夹中拷贝 runtime.yml 文件至 contrib/RoadSign/configs 文件夹。
  3. configs/faster_rcnn 文件夹中拷贝 faster_rcnn_r34_fpn_1x_coco.yml 文件至 contrib/RoadSign/configs 文件夹。
  4. configs/faster_rcnn/_base_ 文件夹中拷贝下列文件至 contrib/RoadSign/configs/_base_ 文件夹,包括:faster_rcnn_r50_fpn.yml, faster_fpn_reader.ymloptimizer_1x.yml
  5. configs/datasets 文件夹中复制 coco_detection_ymlcontrib/RoadSign/datasets 文件夹,并更名为 roadsign_coco.yml

4.3 配置文件详细参数介绍

4.3.1 项目的配置文件

项目配置文件:configs/faster_rcnn_r50_fpn_1x_coco.yml

_BASE_: [                                  # 需要继承的相关配置文件
  'runtime.yml',                           # 全局配置文件
  '../datasets/roadsign_coco.yml',         # 路标数据集配置文件
  '_base_/optimizer_1x.yml',               # 优化器配置文件
  '_base_/faster_rcnn_r50_fpn.yml',        # 主干网络配置文件
  '_base_/faster_fpn_reader.yml',          # 数据读取器配置文件
]
weights: contrib/RoadSign/output/faster_rcnn_r50_fpn_1x_coco/best_model    # 最终模型保存的位置,用于实现评估与推理时的模型调用

4.3.2 全局配置文件

全局配置: configs/runtime.yml

use_gpu: true         # 根据硬件选择是否使用GPU
log_iter: 10          # 设置多少次迭代显示一次训练日志
save_dir: output      # 模型保存的文件夹
snapshot_epoch: 1     # 每隔多少个周期保存一次模型
print_flops: true    # 是否显示计算吞吐量,注意启用该选项需要安装paddleslim

4.3.3 数据集配置文件

数据集配置: configs/datasets/roadsign_coco.yml

metric: COCO          # 数据集的结构形态:MSCOCO
num_classes: 4        # 类别数量

TrainDataset:         # 训练集
  !COCODataSet
    dataset_dir: D:/Workspace/ExpDatasets/RoadSign               # 图像的根目录
    image_dir: images                                            # 图像存储的文件夹
    anno_path: annotations_coco/train.json                       # 图像的标注文件.json
    data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']    # json中的关键数据域[图像,bbox标注,类别,是否拥挤]

EvalDataset:         # 验证集
  !COCODataSet
    dataset_dir: D:/Workspace/ExpDatasets/RoadSign
    image_dir: images
    anno_path: annotations_coco/valid.json

TestDataset:         # 测试集
  !ImageFolder
    dataset_dir: D:/Workspace/ExpDatasets/RoadSign
    anno_path: annotations_coco/valid.json

4.3.4 数据读取器配置文件

数据读取器配置: configs/_base_/faster_fpn_reader.yml

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}         # 按照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                   # epoch/batch_size有余数时,是否将末尾的数据进行丢弃,训练中通常进行丢弃
  collate_batch: false


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


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

4.3.5 主干网络配置文件

主干网络配置: configs/_base_/faster_rcnn_r50_fpn.yml

architecture: FasterRCNN                     # 模型架构 FasterRCNN
pretrain_weights: https://paddledet.bj.bcebos.com/models/pretrained/ResNet50_cos_pretrained.pdparams

FasterRCNN:                                  # 定义FasterRCNN各模块名称
  backbone: ResNet                           # 主干网络:ResNet
  neck: FPN                                  # neck模块(特征提取):FPN特征金字塔
  rpn_head: RPNHead                          # RPN头:区域建议网络
  bbox_head: BBoxHead                        # BBox头:BoundingBox 区域回归模块
  # post process                             
  bbox_post_process: BBoxPostProcess         # 后处理模块


ResNet:
  # index 0 stands for res2
  depth: 50                    # 模型深度,此处标识为ResNet50
  norm_type: bn                # 设置是否启用batch-norm, bn正则化
  freeze_at: 0                 # 微调训练时冻结模块的起点,index=0表示的是res2,因此,第一组卷积在微调时将永久冻结 (fastRCNN)
  return_idx: [0,1,2,3]        # 实际参与微调的层为[2,3,4,5]
  num_stages: 4

FPN:
  out_channel: 256             # FPN输出的通道数为 256

RPNHead:
  anchor_generator:            ## Anchor采样的基本原则
    aspect_ratios: [0.5, 1.0, 2.0]                     # 采样长宽比例  
    anchor_sizes: [[32], [64], [128], [256], [512]]    # FPN采样基准尺度
    strides: [4, 8, 16, 32, 64]                        # 采样步长
  rpn_target_assign:           ## RPN采样规则
    batch_size_per_im: 256     # 共采样256个Anchor
    fg_fraction: 0.5           # 正样本比例为 0.5,即 512*0.5=256个
    negative_overlap: 0.3      # 与所有真实框的IoU<0.3的Anchor为负样本
    positive_overlap: 0.7      # 与任意真实框的IoU>0.7的Anchor为正样本
    use_random: True           # 使用随机方式进行采样
  train_proposal:
    min_size: 0.0
    nms_thresh: 0.7            # nms阈值 0.7
    pre_nms_top_n: 2000        # 使用RPN采样2000个RoIs用于后续的处理
    post_nms_top_n: 1000       # 经过对象性排序后保留1000个样本
    topk_after_collect: True
  test_proposal:
    min_size: 0.0
    nms_thresh: 0.7            # nms阈值 0.7
    pre_nms_top_n: 1000        # 使用RPN采样1000个RoIs用于后续的处理
    post_nms_top_n: 1000       # 经过对象性排序后保留1000个样本,原作为300个


BBoxHead:                     ## BBox头的超参数
  head: TwoFCHead             # 输出头为TwoFCHead,通道数为 1024
  roi_extractor:
    resolution: 7             # RoI的输出特征为 7×7,也即输入BBox的特征为7×7
    sampling_ratio: 0
    aligned: True             # 启用RoI Align模式
  bbox_assigner: BBoxAssigner

BBoxAssigner:                 ## BBox回归的超参数
  batch_size_per_im: 512      # 采样总数为 512
  bg_thresh: 0.5              # IoU<0.5为负样本
  fg_thresh: 0.5              # IoU>0.5为正样本
  fg_fraction: 0.25           # 正样本比率为0.25,即 512*0.25=128个
  use_random: True            # 使用随机方式进行采样

TwoFCHead:
  out_channel: 1024           # 输入BBoxHead的特征通道数


BBoxPostProcess:              ## 后处理方法为:多类非极大抑制NMS
  decode: RCNNBox
  nms:
    name: MultiClassNMS
    keep_top_k: 100          # 保留评分最高的100个patch(Anchor)
    score_threshold: 0.05    # 评分最低阈值
    nms_threshold: 0.5       # nms阈值

4.3.6 优化器配置文件

优化器配置: configs/_base_/optimizer_1x.yml

epoch: 12                        # 迭代训练的周期数,默认为12个周期

LearningRate:                    # 学习率超参数
  base_lr: 0.01                  # 初始学习率
  schedulers:               
  - !PiecewiseDecay              # 学习率策略:分段学习率
    gamma: 0.1                   # 学习率衰减率超参数:0.1
    milestones: [8, 11]          # 学习率衰减的时刻点,第8个epoch和第11个epoch
  - !LinearWarmup                # 线性热身(学习率慢启动),避免较大的初始学习率引起损失过分振荡
    start_factor: 0.1            # 衰减率为 0.1
    steps: 1000                  # 热身周期为 1000次迭代

OptimizerBuilder:                # 优化方法设置
  optimizer:
    momentum: 0.9                # 动量值 0.9
    type: Momentum               # 优化方法:基于动量的随机梯度下降
  regularizer:
    factor: 0.0001               # 正则化因子  0.0001
    type: L2                     # 正则化方法 L2正则化

【任务五】模型训练

任务描述: 使用PaddleDetection的命令行模式进行训练。
任务要求:
1.能够使用PaddleDetection完成目标检测任务;
2.学会保存训练日志,以供后续分析使用。

在使用PaddleDetection训练时,首先需要指定用于训练的模型,其参数为 -c;其次,若开启了--eval,会在指定周期(snapshot_epoch)时使用验证集数据进行评估,并将保存所有的 checkpoint 模型。同时,将评估结果最好的checkpoint模型保存为 best_model。下面给出训练模型的基本命令,

>> python -u tools/train.py -c contrib/RoadSign/configs/faster_rcnn_r50_fpn_1x_coco.yml --eval

同时,下面给出Notebook版本的训练代码。值得注意的是,在Notebook中运行训练进程,无法实时打印出日志文件(只能在整个训练过程结束后,一次性打印出所有训练日志)。鉴于训练时间通常比较长,为了便于观察训练过程,建议使用Anaconda终端的命令行进行执行。

import os
workspace = 'D:\\Workspace\\MyProjects\\PaddleDetection-release-2.4'
# workspace = '/home/aistudio/PaddleDetection'
os.chdir(workspace)

##################### JupyterLab ######################################
model_template1 = 'faster_rcnn_r34_fpn_1x_coco'
model_template2 = 'faster_rcnn_r34_vd_fpn_1x_coco'
model_template3 = 'faster_rcnn_r50_1x_coco'
model_template4 = 'faster_rcnn_r50_fpn_1x_coco'
model_template5 = 'faster_rcnn_r50_vd_fpn_1x_coco'
model_template6 = 'faster_rcnn_r50_vd_fpn_2x_coco'
model_template = model_template4

# {model_template} 是Shell命令的变量名,由上面的赋值运算进行定义
!python -u tools/train.py -c contrib/Roadsign/configs/{model_template}.yml --eval

训练日志摘要如下:

loading annotations into memory...
Done (t=0.01s)
creating index...
index created!
W0405 18:35:09.661685 10216 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 6.1, Driver API Version: 11.1, Runtime API Version: 10.2
W0405 18:35:09.864145 10216 device_context.cc:465] device: 0, cuDNN Version: 7.6.
[04/05 18:35:13] ppdet.utils.checkpoint INFO: Finish loading model weights: C:\Users\Administrator/.cache/paddle/weights\ResNet50_cos_pretrained.pdparams
loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
[04/05 18:35:14] ppdet.engine INFO:  Model FLOPs : 163.633649G. (image shape is [1, 3, 1088, 800])
[04/05 18:35:15] ppdet.engine INFO: Epoch: [0] [  0/701] learning_rate: 0.001000 loss_rpn_cls: 0.688819 loss_rpn_reg: 0.003694 loss_bbox_cls: 1.531413 loss_bbox_reg: 0.067932 loss: 2.291858 eta: 0:27:57 batch_cost: 0.1995 data_cost: 0.0000 ips: 5.0134 images/s
[04/05 18:35:16] ppdet.engine INFO: Epoch: [0] [ 10/701] learning_rate: 0.001090 loss_rpn_cls: 0.677911 loss_rpn_reg: 0.008214 loss_bbox_cls: 0.295793 loss_bbox_reg: 0.026602 loss: 1.032018 eta: 0:24:14 batch_cost: 0.1704 data_cost: 0.0000 ips: 5.8670 images/s
[04/05 18:35:18] ppdet.engine INFO: Epoch: [0] [ 20/701] learning_rate: 0.001180 loss_rpn_cls: 0.240297 loss_rpn_reg: 0.008485 loss_bbox_cls: 0.122217 loss_bbox_reg: 0.006622 loss: 0.504521 eta: 0:24:12 batch_cost: 0.1730 data_cost: 0.0000 ips: 5.7791 images/s
[04/05 18:35:20] ppdet.engine INFO: Epoch: [0] [ 30/701] learning_rate: 0.001270 loss_rpn_cls: 0.074212 loss_rpn_reg: 0.009571 


[04/05 19:00:42] ppdet.engine INFO: Epoch: [11] [700/701] learning_rate: 0.000100 loss_rpn_cls: 0.000306 loss_rpn_reg: 0.006032 loss_bbox_cls: 0.028105 loss_bbox_reg: 0.058122 loss: 0.091564 eta: 0:00:00 batch_cost: 0.1575 data_cost: 0.0002 ips: 6.3501 images/s
[04/05 19:00:43] ppdet.utils.checkpoint INFO: Save checkpoint: output/RoadSign\faster_rcnn_r50_fpn_1x_coco
loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
[04/05 19:00:43] ppdet.engine INFO:  Model FLOPs : 163.633649G. (image shape is [1, 3, 1088, 800])
[04/05 19:00:43] ppdet.engine INFO: Eval iter: 0
[04/05 19:00:50] ppdet.engine INFO: Eval iter: 100
[04/05 19:00:56] ppdet.metrics.metrics INFO: The bbox result is saved to bbox.json.
loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
[04/05 19:00:56] ppdet.metrics.coco_utils INFO: Start evaluate...
Loading and preparing results...
DONE (t=0.00s)
creating index...
index created!
Running per image evaluation...
Evaluate annotation type *bbox*
DONE (t=0.08s).
Accumulating evaluation results...
DONE (t=0.07s).
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.704
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.929
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.752
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.668
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.776
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.671
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.659
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.767
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.767
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.711
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.824
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.755
[04/05 19:00:56] ppdet.engine INFO: Total sample number: 176, averge FPS: 14.098499763292608
[04/05 19:00:56] ppdet.engine INFO: Best test bbox ap is 0.704.
[04/05 19:00:57] ppdet.utils.checkpoint INFO: Save checkpoint: output/RoadSign\faster_rcnn_r50_fpn_1x_coco

【任务六】模型评估

任务描述: 使用PaddleDetection在验证集上对已经训练好的模型进行评估。
任务要求:
1.能够在命令行中完成对目标检测模型的评估;
2.能够使用Notebook完成对目标检测模型的评估;
3.能够根据评估结果分析模型的性能。

6.1 模型评估

PaddleDetection提供了tools/eval.py脚本用于评估模型,该命令可以使用模型的默认参数 weight 所指定的模型进行评估(建议),若使用预先下载的模型也可以通过 -o weights= 命令进行指定。参数 --classwise 可以打印出每个类别的精确度。下面给出在命令行中进行评估的命令:

>> python -u tools/eval.py -c contrib/RoadSign/configs/faster_rcnn_r50_fpn_1x_coco.yml --classwise

以下命令为Notebook中用于评估的代码:

# 评估
import os
workspace = 'D:\\Workspace\\MyProjects\\PaddleDetection-release-2.4'
# workspace = '/home/aistudio/PaddleDetection'
os.chdir(workspace)

##################### JupyterLab ######################################
model_template1 = 'faster_rcnn_r34_fpn_1x_coco'
model_template2 = 'faster_rcnn_r34_vd_fpn_1x_coco'
model_template3 = 'faster_rcnn_r50_1x_coco'
model_template4 = 'faster_rcnn_r50_fpn_1x_coco'
model_template5 = 'faster_rcnn_r50_vd_fpn_1x_coco'
model_template6 = 'faster_rcnn_r50_vd_fpn_2x_coco'
model_template = model_template4

# {model_template} 是Shell命令的变量名,由上面的赋值运算进行定义
!python -u tools/eval.py -c contrib/Roadsign/configs/{model_template}.yml --classwise
    loading annotations into memory...
    Done (t=0.00s)
    creating index...
    index created!
    [04/09 23:06:31] ppdet.utils.checkpoint INFO: Finish loading model weights: contrib/RoadSign/output/faster_rcnn_r50_fpn_1x_coco/best_model.pdparams
    loading annotations into memory...
    Done (t=0.00s)
    creating index...
    index created!
    [04/09 23:06:32] ppdet.engine INFO:  Model FLOPs : 163.633649G. (image shape is [1, 3, 1088, 800])
    [04/09 23:06:33] ppdet.engine INFO: Eval iter: 0
    [04/09 23:06:41] ppdet.engine INFO: Eval iter: 100
    [04/09 23:06:48] ppdet.metrics.metrics INFO: The bbox result is saved to bbox.json.
    loading annotations into memory...
    Done (t=0.00s)
    creating index...
    index created!
    [04/09 23:06:48] ppdet.metrics.coco_utils INFO: Start evaluate...
    Loading and preparing results...
    DONE (t=0.00s)
    creating index...
    index created!
    Running per image evaluation...
    Evaluate annotation type *bbox*
    DONE (t=0.11s).
    Accumulating evaluation results...
    DONE (t=0.06s).
     Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.704
     Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.929
     Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.752
     Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.668
     Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.776
     Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.671
     Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.659
     Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.767
     Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.767
     Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.711
     Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.824
     Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.755
    [04/09 23:06:48] ppdet.metrics.coco_utils INFO: Per-category of bbox AP: 
    +------------+-------+-----------+-------+--------------+-------+
    | category   | AP    | category  | AP    | category     | AP    |
    +------------+-------+-----------+-------+--------------+-------+
    | speedlimit | 0.866 | crosswalk | 0.646 | trafficlight | 0.471 |
    | stop       | 0.833 | None      | None  | None         | None  |
    +------------+-------+-----------+-------+--------------+-------+
    [04/09 23:06:48] ppdet.metrics.coco_utils INFO: per-category PR curve has output to bbox_pr_curve folder.
    [04/09 23:06:48] ppdet.engine INFO: Total sample number: 176, averge FPS: 10.85748081560342
    

    W0409 23:06:28.093667 17536 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 6.1, Driver API Version: 11.1, Runtime API Version: 10.2
    W0409 23:06:28.108626 17536 device_context.cc:465] device: 0, cuDNN Version: 7.6.

6.2 模实验结果分析

下表给给出了六个模型的评估结果,有兴趣的同学可以尝试进行多个模型的训练,并总结出不同模型之间的异同。

序号 模型名称 epoch IoU [0.5:0.95] IoU [0.5] FLOPs fps speedlimit crosswalk trafficlight stop
A faster_rcnn_r34_fpn_1x_coco 11/12 0.725 0.931 151.26G 5.84 0.868 0.661 0.579 0.814
B faster_rcnn_r34_vd_fpn_1x_coco 12/12 0.686 0.931 155.45G 13.59 0.86 0.664 0.438 0.783
C faster_rcnn_r50_1x_coco 12/12 0.640 0.891 90.17G 3.21 0.862 0.664 0.438 0.783
D faster_rcnn_r50_fpn_1x_coco 12/12 0.710 0.933 163.63G 12.22 0.871 0.689 0.441 0.84
E faster_rcnn_r50_vd_fpn_1x_coco 12/12 0.719 0.936 167.84G 11.77 0.884 0.678 0.481 0.832
F faster_rcnn_r50_vd_fpn_2x_coco 23/24 0.759 0.945 167.84G 11.77 0.882 0.696 0.602 0.853

【实验分析】(仅供参考)
从实验结果来看,可以得到如下结论:

  1. 该数据集相对比较简单,ResNet34即可得到比较好的结果,例如模型A性能已经很出众,但更加精细的配置后,更深的模型F(ResNet50)依然性能最优;
  2. 对比模型C-E,不难发现,特征金字塔网络、ResNet-D模块对于模型是有改进的,特别是FPN特征金字塔;
  3. 模型B相对于A更差,说明任务相对简单,在网络性能不足时,复杂的设计会使模型有一定的过拟合问题,也可能更复杂的模型需要更长的迭代周期才能收敛,抑或是超参数设置不合理;
  4. 模型C可能存在训练不足(欠拟合)或过拟合的问题,具体需要观察训练loss和训练精度来进行判断;
  5. 模型F具有最优性能,说明适当降低学习率,并保证更长的训练周期,有利于解决模型陷入局部最优,从而获得更好的性能;
  6. FPS项展示的是单张样本推理所需要的时间,不难发现fpn可以有效地提高推理速度。值得注意的是统计时间只包含推理时间,不包括模型载入及数据预处理的时间;
  7. 从分类AP(classwise-AP)可以发现,无论是哪个模型性能瓶颈主要都集中在trafficlight类别上,说明,针对该目标的改进可以有效提供整体的识别能力;其次,类别crosswalk的性能也并非很理想。

【任务七】模型预测与实验结果分析

任务描述: 在PaddleDetection中,使用给定的图片在训练好的模型上进行推理和预测。
任务要求:
1.能够在命令行中使用训练好的模型对给定图片进行推理和预测;
2.能够Notebook中使用训练好的模型对给定图片进行推理和预测;
3.能够将推理生成的图片进行可视化。

PaddleDetection提供了 tools/infer.py 预测工具,实现利用训练好的模型对给定图片进行预测。在 infer.py 命令中,-c {config.yml} 参数用于模型选择;--output_dir={output_dir} 参数用于指定结果输出路径;--infer_img={img_path} 参数用于选择待预测样本。下面给出该命令的范例:

python tools/infer.py -c contrib/RoadSign/configs/faster_rcnn_r50_fpn_1x_coco.yml --output_dir=contrib/RoadSign/output --infer_img=D:/Workspace/ExpDatasets/RoadSign/images/road838.png

下面给出Notebook中的推理代码,代码中同时实现将推理生成的图片进行可视化。

####### 预测
import os
import matplotlib.pyplot as plt 
import cv2

# 0. 设置工作路径
workspace = 'D:\\Workspace\\MyProjects\\PaddleDetection-release-2.4'
# workspace = '/home/aistudio/PaddleDetection'
os.chdir(workspace)

####### 1. 执行预测Inference
# 1.1 设置图片路径
img_root = 'D://Workspace//ExpDatasets//RoadSign//images'
img_file = 'road839.png'  
img_path = os.path.join(img_root, img_file)
output_dir = 'contrib/RoadSign/output'

# 1.2 设置模型路径
model_template1 = 'faster_rcnn_r34_fpn_1x_coco'
model_template2 = 'faster_rcnn_r34_vd_fpn_1x_coco'
model_template3 = 'faster_rcnn_r50_1x_coco'
model_template4 = 'faster_rcnn_r50_fpn_1x_coco'
model_template5 = 'faster_rcnn_r50_vd_fpn_1x_coco'
model_template6 = 'faster_rcnn_r50_vd_fpn_2x_coco'
model_template = model_template4

# 1.3 执行预测脚本
!python tools/infer.py -c configs/Roadsign/{model_template}.yml -o --output_dir={output_dir} --infer_img={img_path}

####### 2. 可视化Inference结果
# 2.1 设置Inference路径
infer_img_path = os.path.join('output', img_file)
infer_img = cv2.imread(infer_img_path)

# 2.1 PIL显示接口
plt.figure(figsize=(10,6))
plt.imshow(cv2.cvtColor(infer_img, cv2.COLOR_BGR2RGB))
plt.show()
# 2.2 OpenCV显示接口
# cv2.imshow('detection result', infer_img)
# cv2.waitKey(0)

output_26_1