PaddleDetection笔记


PaddleDetection是一个基于PaddlePaddle的目标检测端到端开发套件,可用于版面分析等通过视觉特征进行检测、分类、(分割)、 关键点检测的任务2D关键点检测),配合clas完成 属性识别
模型效果
整体结构

数据准备

数据处理模块

PaddleDetection的数据处理模块的所有代码逻辑在ppdet/data/中,数据处理模块用于加载数据并将其转换成适用于物体检测模型的训练、评估、推理所需要的格式。 数据处理模块的主要构成如下架构所示:

  ppdet/data/
  ├── reader.py     # 基于Dataloader封装的Reader模块
  ├── source  # 数据源管理模块
  │   ├── dataset.py      # 定义数据源基类,各类数据集继承于此
  │   ├── coco.py         # COCO数据集解析与格式化数据
  │   ├── voc.py          # Pascal VOC数据集解析与格式化数据
  │   ├── widerface.py    # WIDER-FACE数据集解析与格式化数据
  │   ├── category.py    # 相关数据集的类别信息
  ├── transform  # 数据预处理模块
  │   ├── batch_operators.py  # 定义各类基于批量数据的预处理算子
  │   ├── op_helper.py    # 预处理算子的辅助函数
  │   ├── operators.py    # 定义各类基于单张图片的预处理算子
  │   ├── gridmask_utils.py    # GridMask数据增强函数
  │   ├── autoaugment_utils.py  # AutoAugment辅助函数
  ├── shm_utils.py     # 用于使用共享内存的辅助函数

数据源管理模块-source

  • 基类DetDataSet
    数据集定义在source目录下,其中dataset.py中定义了数据集的基类DetDataSet, 所有的数据集均继承于基类,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/datasets中的默认配置即可。
datasets配置
此外,在parse_dataset函数中,保存了类别名到id的映射的一个字典cname2cid。在coco数据集中,会利用COCO API从标注文件中加载数据集的类别名,并设置此字典。在voc数据集中,如果设置use_default_label=False,将从label_list.txt中读取类别列表,反之将使用voc默认的类别列表。

数据预处理模块-transform

数据增强算子

PaddleDetection中支持了种类丰富的数据增强算子,有单图像数据增强算子与批数据增强算子两种方式,您可选取合适的算子组合使用。单图像数据增强算子定义在transform/operators.py中,已支持的单图像数据增强算子详见下表:
transform/operators.py
批数据增强算子定义在transform/batch_operators.py中, 目前支持的算子列表如下:
transform/batch_operators.py
几点说明:

  • 数据增强算子的输入为sample或者samples,每一个sample对应上文所说的DetDataSet输出的roidbs中的一个样本,如coco_rec或者voc_rec
  • 单图像数据增强算子(Mixup, Cutmix等除外)也可用于批数据处理中。但是,单图像处理算子和批图像处理算子仍有一些差异,以RandomResize和BatchRandomResize为例,RandomResize会将一个Batch中的每张图片进行随机缩放,但是每一张图像Resize之后的形状不尽相同,BatchRandomResize则会将一个Batch中的所有图片随机缩放到相同的形状。
  • 除BatchRandomResize外,定义在transform/batch_operators.py的批数据增强算子接收的输入图像均为CHW形式,所以使用这些批数据增强算子�前请先使用Permute进行处理。如果用到Gt2xxxTarget算子,需要将其放置在靠后的位置。NormalizeBox算子建议放置在Gt2xxxTarget之前。将这些限制条件总结下来,推荐的预处理算子的顺序为
  - XXX: {}
  - ...
  - BatchRandomResize: {...} # 如果不需要,可以移除,如果需要,放置在Permute之前
  - Permute: {} # 必须项
  - NormalizeBox: {} # 如果需要,建议放在Gt2XXXTarget之前
  - PadBatch: {...} # 如果不需要可移除,如果需要,建议放置在Permute之后
  - Gt2XXXTarget: {...} # 建议与PadBatch放置在最后的位置
自定义数据增强算子

如果需要自定义数据增强算子,那么您需要了解下数据增强算子的相关逻辑。数据增强算子基类为定义在transform/operators.py中的BaseOperator类,单图像数据增强算子与批数据增强算子均继承自这个基类。完整定义参考源码,以下代码显示了BaseOperator类的关键函数: apply和__call__方法

class BaseOperator(object):

  ...

  def apply(self, sample, context=None):
      return sample

  def __call__(self, sample, context=None):
      if isinstance(sample, Sequence):
          for i in range(len(sample)):
              sample[i] = self.apply(sample[i], context)
      else:
          sample = self.apply(sample, context)
      return sample

__call__方法为BaseOperator的调用入口,接收一个sample(单图像)或者多个sample(多图像)作为输入,并调用apply函数对一个或者多个sample进行处理。大多数情况下,你只需要继承BaseOperator重写apply方法或者重写__call__方法即可,如下所示,定义了一个XXXOp继承自BaseOperator,并注册:

@register_op
class XXXOp(BaseOperator):
  def __init__(self,...):

    super(XXXImage, self).__init__()
    ...

  # 大多数情况下只需要重写apply方法
  def apply(self, sample, context=None):
    ...
    省略对输入的sample具体操作
    ...
    return sample

  # 如果有需要,可以重写__call__方法,如Mixup, Gt2XXXTarget等
  # def __call__(self, sample, context=None):
  #   ...
  #   省略对输入的sample具体操作
  #   ...
  #   return sample

大多数情况下,只需要重写apply方法即可,如transform/operators.py中除Mixup和Cutmix外的预处理算子。对于批处理的情况一般需要重写__call__方法,如transform/batch_operators.py的预处理算子。

Reader

Reader相关的类定义在reader.py, 其中定义了BaseDataLoader类。BaseDataLoaderpaddle.io.DataLoader的基础上封装了一层,其具备paddle.io.DataLoader的所有功能,并能够实现不同模型对于DetDataset的不同需求,如可以通过对Reader进行设置,以控制DetDataset支持Mixup, Cutmix等操作。除此之外,数据预处理算子通过Compose类和BatchCompose类组合起来分别传入DetDatasetpaddle.io.DataLoader中。 所有的Reader类都继承自BaseDataLoader类,具体可参见源码。

相关配置及运行

Dataset、Reader配置
  1. Dataset配置
    关于Dataset的配置文件存在于configs/datasets文件夹。比如COCO数据集的配置文件如下:
metric: COCO # 目前支持COCO, VOC, OID, WiderFace等评估标准
num_classes: 80 # num_classes数据集的类别数,不包含背景类

TrainDataset:
  !COCODataSet
    image_dir: train2017 # 训练集的图片所在文件相对于dataset_dir的路径
    anno_path: annotations/instances_train2017.json # 训练集的标注文件相对于dataset_dir的路径
    dataset_dir: dataset/coco #数据集所在路径,相对于PaddleDetection路径
    data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd'] # 控制dataset输出的sample所包含的字段,注意此为TrainDataset独有的且必须配置的字段

EvalDataset:
  !COCODataSet
    image_dir: val2017 # 验证集的图片所在文件夹相对于dataset_dir的路径
    anno_path: annotations/instances_val2017.json # 验证集的标注文件相对于dataset_dir的路径
    dataset_dir: dataset/coco # 数据集所在路径,相对于PaddleDetection路径

TestDataset:
  !ImageFolder
    anno_path: annotations/instances_val2017.json # 标注文件所在路径,仅用于读取数据集的类别信息,支持json和txt格式
    dataset_dir: dataset/coco # 数据集所在路径,若添加了此行,则`anno_path`路径为`dataset_dir/anno_path`,若此行不设置或去掉此行,则`anno_path`路径即为`anno_path`

在PaddleDetection的yml配置文件中,使用!直接序列化模块实例(可以是函数,实例等),上述的配置文件均使用Dataset进行了序列化。
注意: 请运行前自行仔细检查数据集的配置路径,在训练或验证时如果TrainDataset和EvalDataset的路径配置有误,会提示自动下载数据集。若使用自定义数据集,在推理时如果TestDataset路径配置有误,会提示使用默认COCO数据集的类别信息

  1. Reader配置
    不同模型专用的Reader定义在每一个模型的文件夹下,如yolov3的Reader配置文件定义在configs/yolov3/_base_/yolov3_reader.yml。一个Reader的示例配置如下:
worker_num: 2
TrainReader:
  sample_transforms:
    - Decode: {}
    ...
  batch_transforms:
    ...
  batch_size: 8
  shuffle: true
  drop_last: true
  use_shared_memory: true

EvalReader:
  sample_transforms:
    - Decode: {}
    ...
  batch_size: 1

TestReader:
  inputs_def:
    image_shape: [3, 608, 608]
  sample_transforms:
    - Decode: {}
    ...
  batch_size: 1

你可以在Reader中定义不同的预处理算子,每张卡的batch_size以及DataLoader的worker_num等。

运行

在PaddleDetection的训练、评估和测试运行程序中,都通过创建Reader迭代器。Reader在ppdet/engine/trainer.py中创建。下面的代码展示了如何创建训练时的Reader

from ppdet.core.workspace import create
# build data loader
self.dataset = cfg['TrainDataset']
self.loader = create('TrainReader')(selfdataset, cfg.worker_num)

相应的预测以及评估时的Reader与之类似,具体可参考ppdet/engine/trainer.py源码。

COCO数据集

标注格式

COCO数据标注是将所有训练图像的标注都存放到一个json文件中。数据以字典嵌套的形式存放。
json文件中包含以下key:

  • info,表示标注文件info。
  • licenses,表示标注文件licenses。
  • images,表示标注文件中图像信息列表,每个元素是一张图像的信息。如下为其中一张图像的信息:
{
    'license': 3,                       # license
    'file_name': '000000391895.jpg',    # file_name
     # coco_url
    'coco_url': 'http://images.cocodataset.org/train2017/000000391895.jpg',
    'height': 360,                      # image height
    'width': 640,                       # image width
    'date_captured': '2013-11-14 11:18:45', # date_captured
    # flickr_url
    'flickr_url': 'http://farm9.staticflickr.com/8186/8119368305_4e622c8349_z.jpg',
    'id': 391895                        # image id
}

instance_val.json

  • annotations,表示标注文件中目标物体的标注信息列表,每个元素是一个目标物体的标注信息。如下为其中一个目标物体的标注信息:
{

    'segmentation':             # 物体的分割标注
    'area': 2765.1486500000005, # 物体的区域面积
    'iscrowd': 0,               # iscrowd
    'image_id': 558840,         # image id
    'bbox': [199.84, 200.46, 77.71, 70.88], # bbox [x1,y1,w,h]
    'category_id': 58,          # category_id
    'id': 156                   # image id
}

文件结构

dataset_detection/crop/
├── annotations
│   ├── instance_train.json
│   ├── instance_val.json
├── train_data
│   ├── img_detail...
│   ├── img_invoice...
│   │   ...
├── test_data
│   ├── img_detail...
│   ├── img_invoice...
│   │   ...

source/coco.py中定义并注册了COCODataSet数据集类,其继承自DetDataSet,并实现了parse_dataset方法,调用COCO API加载并解析COCO格式数据源roidbscname2cid,具体可参见source/coco.py源码。将其他数据集转换成COCO格式可以参考用户数据转成COCO数据

Pascal VOC数据集

主要由xml文件和image文件组成,其组织结构如下所示:

  dataset/voc/
  ├── trainval.txt
  ├── test.txt
  ├── label_list.txt (optional)
  ├── VOCdevkit/VOC2007
  │   ├── Annotations
  │       ├── 001789.xml
  │       │   ...
  │   ├── JPEGImages
  │       ├── 001789.jpg
  │       │   ...
  │   ├── ImageSets|   ...
  ├── VOCdevkit/VOC2012
  │   ├── Annotations
  │       ├── 2011_003876.xml
  │       │   ...
  │   ├── JPEGImages
  │       ├── 2011_003876.jpg
  │       │   ...
  │   ├── ImageSets
  │       │   ...

source/voc.py中定义并注册了VOCDataSet数据集,它继承自DetDataSet基类,并重写了parse_dataset方法,解析VOC数据集中xml格式标注文件,更新roidbscname2cid。将其他数据集转换成VOC格式可以参考用户数据转成VOC数据

自定义数据集

如果COCODataSet和VOCDataSet不能满足你的需求,可以通过自定义数据集的方式来加载你的数据集。只需要以下两步即可实现自定义数据集

  1. 新建source/xxx.py,定义类XXXDataSet继承自DetDataSet基类,完成注册与序列化,并重写parse_dataset方法对roidbscname2cid更新:
from ppdet.core.workspace import register, serializable

#注册并序列化
@register
@serializable
class XXXDataSet(DetDataSet):
    def __init__(self,
                dataset_dir=None,
                image_dir=None,
                anno_path=None,
                ...
                ):
        self.roidbs = None
        self.cname2cid = None
        ...

    def parse_dataset(self):
        ...
        省略具体解析数据逻辑
        ...
        self.roidbs, self.cname2cid = records, cname2cid
  1. source/__init__.py中添加引用:
from . import xxx
from .xxx import *

完成以上两步就将新的数据源XXXDataSet添加好了,你可以参考配置及运行实现自定义数据集的使用。

配置文件说明

ppyolo_r50vd_dcn_1x_coco.yml为例,这个模型由五个子配置文件组成:
ppyolo_r50vd_dcn_1x_coco.yml

  • 数据配置文件 coco_detection.yml
# 数据评估类型
metric: COCO
# 数据集的类别数
num_classes: 80

# TrainDataset
TrainDataset:
  !COCODataSet
    # 图像数据路径,相对 dataset_dir 路径,os.path.join(dataset_dir, image_dir)
    image_dir: train2017
    # 标注文件路径,相对 dataset_dir 路径,os.path.join(dataset_dir, anno_path)
    anno_path: annotations/instances_train2017.json
    # 数据文件夹
    dataset_dir: dataset/coco
    # data_fields
    data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']

EvalDataset:
  !COCODataSet
    # 图像数据路径,相对 dataset_dir 路径,os.path.join(dataset_dir, image_dir)
    image_dir: val2017
    # 标注文件路径,相对 dataset_dir 路径,os.path.join(dataset_dir, anno_path)
    anno_path: annotations/instances_val2017.json
    # 数据文件夹,os.path.join(dataset_dir, anno_path)
    dataset_dir: dataset/coco

TestDataset:
  !ImageFolder
    # 标注文件路径,相对 dataset_dir 路径
    anno_path: annotations/instances_val2017.json
  • 优化器配置文件 optimizer_1x.yml
# 总训练轮数
epoch: 405

# 学习率设置
LearningRate:
  # 默认为8卡训学习率
  base_lr: 0.01
  # 学习率调整策略
  schedulers:
  - !PiecewiseDecay
    gamma: 0.1
    # 学习率变化位置(轮数)
    milestones:
    - 243
    - 324
  # Warmup
  - !LinearWarmup
    start_factor: 0.
    steps: 4000

# 优化器
OptimizerBuilder:
  # 优化器
  optimizer:
    momentum: 0.9
    type: Momentum
  # 正则化
  regularizer:
    factor: 0.0005
    type: L2
  • 数据读取配置文件 ppyolo_reader.yml
# 每张GPU reader进程个数
worker_num: 2
# 训练数据
TrainReader:
  inputs_def:
    num_max_boxes: 50
  # 训练数据transforms
  sample_transforms:
    - Decode: {}
    - Mixup: {alpha: 1.5, beta: 1.5}
    - RandomDistort: {}
    - RandomExpand: {fill_value: [123.675, 116.28, 103.53]}
    - RandomCrop: {}
    - RandomFlip: {}
  # batch_transforms
  batch_transforms:
    - BatchRandomResize: {target_size: [320, 352, 384, 416, 448, 480, 512, 544, 576, 608], random_size: True, random_interp: True, keep_ratio: False}
    - NormalizeBox: {}
    - PadBox: {num_max_boxes: 50}
    - BboxXYXY2XYWH: {}
    - NormalizeImage: {mean: [0.485, 0.456, 0.406], std: [0.229, 0.224, 0.225], is_scale: True}
    - Permute: {}
    - Gt2YoloTarget: {anchor_masks: [[6, 7, 8], [3, 4, 5], [0, 1, 2]], anchors: [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]], downsample_ratios: [32, 16, 8]}
  # 训练时batch_size
  batch_size: 24
  # 读取数据是否乱序
  shuffle: true
  # 是否丢弃最后不能完整组成batch的数据
  drop_last: true
  # mixup_epoch,大于最大epoch,表示训练过程一直使用mixup数据增广
  mixup_epoch: 25000
  # 是否通过共享内存进行数据读取加速,需要保证共享内存大小(如/dev/shm)满足大于1G
  use_shared_memory: true

# 评估数据
EvalReader:
  # 评估数据transforms
  sample_transforms:
    - Decode: {}
    - Resize: {target_size: [608, 608], keep_ratio: False, interp: 2}
    - NormalizeImage: {mean: [0.485, 0.456, 0.406], std: [0.229, 0.224, 0.225], is_scale: True}
    - Permute: {}
  # 评估时batch_size
  batch_size: 8

# 测试数据
TestReader:
  inputs_def:
    image_shape: [3, 608, 608]
  # 测试数据transforms
  sample_transforms:
    - Decode: {}
    - Resize: {target_size: [608, 608], keep_ratio: False, interp: 2}
    - NormalizeImage: {mean: [0.485, 0.456, 0.406], std: [0.229, 0.224, 0.225], is_scale: True}
    - Permute: {}
  # 测试时batch_size
  batch_size: 1
  • 模型配置文件 ppyolo_r50vd_dcn.yml
# 模型结构类型
architecture: YOLOv3
# 预训练模型地址
pretrain_weights: https://paddledet.bj.bcebos.com/models/pretrained/ResNet50_vd_ssld_pretrained.pdparams
# norm_type
norm_type: sync_bn
# 是否使用ema
use_ema: true
# ema_decay
ema_decay: 0.9998

# YOLOv3
YOLOv3:
  # backbone
  backbone: ResNet
  # neck
  neck: PPYOLOFPN
  # yolo_head
  yolo_head: YOLOv3Head
  # post_process
  post_process: BBoxPostProcess


# backbone
ResNet:
  # depth
  depth: 50
  # variant
  variant: d
  # return_idx, 0 represent res2
  return_idx: [1, 2, 3]
  # dcn_v2_stages
  dcn_v2_stages: [3]
  # freeze_at
  freeze_at: -1
  # freeze_norm
  freeze_norm: false
  # norm_decay
  norm_decay: 0.

# PPYOLOFPN
PPYOLOFPN:
  # 是否coord_conv
  coord_conv: true
  # 是否drop_block
  drop_block: true
  # block_size
  block_size: 3
  # keep_prob
  keep_prob: 0.9
  # 是否spp
  spp: true

# YOLOv3Head
YOLOv3Head:
  # anchors
  anchors: [[10, 13], [16, 30], [33, 23],
            [30, 61], [62, 45], [59, 119],
            [116, 90], [156, 198], [373, 326]]
  # anchor_masks
  anchor_masks: [[6, 7, 8], [3, 4, 5], [0, 1, 2]]
  # loss
  loss: YOLOv3Loss
  # 是否使用iou_aware
  iou_aware: true
  # iou_aware_factor
  iou_aware_factor: 0.4

# YOLOv3Loss
YOLOv3Loss:
  # ignore_thresh
  ignore_thresh: 0.7
  # downsample
  downsample: [32, 16, 8]
  # 是否label_smooth
  label_smooth: false
  # scale_x_y
  scale_x_y: 1.05
  # iou_loss
  iou_loss: IouLoss
  # iou_aware_loss
  iou_aware_loss: IouAwareLoss

# IouLoss
IouLoss:
  loss_weight: 2.5
  loss_square: true

# IouAwareLoss
IouAwareLoss:
  loss_weight: 1.0

# BBoxPostProcess
BBoxPostProcess:
  decode:
    name: YOLOBox
    conf_thresh: 0.01
    downsample_ratio: 32
    clip_bbox: true
    scale_x_y: 1.05
  # nms 配置
  nms:
    name: MatrixNMS
    keep_top_k: 100
    score_threshold: 0.01
    post_threshold: 0.01
    nms_top_k: -1
    background_label: -1

  • 运行时置文件 runtime.yml
# 是否使用gpu
use_gpu: true
# 日志打印间隔
log_iter: 20
# save_dir
save_dir: output
# 模型保存间隔时间
snapshot_epoch: 1

模型开发

新增模型算法

新增网络结构和配置文件,参考新增模型算法

训练

修改配置文件

  • 修改预训练模型路径pretrain_wights,输出模型路径weights,评估epoch数snapshot_epoch
  • 修改配置文件中的数据配置、类别数
metric: COCO
# 类别数
num_classes: 5

TrainDataset:
  !COCODataSet
    # 修改为你自己的训练数据目录
    image_dir: train_data
    # 修改为你自己的训练数据标签文件
    anno_path: annotations/instance_train.json
    # 修改为你自己的训练数据根目录
    dataset_dir: /data/ocr/images/dataset_detection/crop/
    data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']

EvalDataset:
  !COCODataSet
    # 修改为你自己的验证数据目录
    image_dir: test_data
    # 修改为你自己的验证数据标签文件
    anno_path: annotations/instance_val.json
    # 修改为你自己的验证数据根目录
    dataset_dir: /data/ocr/images/dataset_detection/crop/

TestDataset:
  !ImageFolder
    # 修改为你自己的测试数据标签文件
    anno_path: annotations/instance_val.json
    dataset_dir: /data/ocr/images/dataset_detection/crop/

训练

  • 单卡训练
# 训练日志会自动保存到 log 目录中
export CUDA_VISIBLE_DEVICES=0 #windows和Mac下不需要执行该命令
python3 tools/train.py \
    -c configs/picodet/legacy_model/application/layout_analysis/picodet_lcnet_x1_0_layout.yml \
    --eval
  • 多卡训练,通过–gpus参数指定卡号
export CUDA_VISIBLE_DEVICES=0,1,2,3 #windows和Mac下不需要执行该命令
python3 -m paddle.distributed.launch --gpus '0,1,2,3'  tools/train.py \
    -c configs/picodet/legacy_model/application/layout_analysis/picodet_lcnet_x1_0_layout.yml \
    --eval
  • 多机多卡训练
    • 不同机器的ip信息需要用逗号隔开,可以通过ifconfig或者ipconfig查看
    • 不同机器之间需要做免密设置,且可以直接ping通,否则无法完成通信。
    • 不同机器之间的代码、数据与运行命令或脚本需要保持一致,且所有的机器上都需要运行设置好的训练命令或者脚本。最终ip_list中的第一台机器的第一块设备是trainer0,以此类推。
    • 不同机器的起始端口可能不同,建议在启动多机任务前,在不同的机器中设置相同的多机运行起始端口,命令为export FLAGS_START_PORT=17000,端口值建议在10000~20000之间。
ip_list="10.127.6.17,10.127.5.142,10.127.45.13,10.127.44.151"
fleetrun \
--ips=${ip_list} \
--selected_gpu 0,1,2,3,4,5,6,7 \
tools/train.py -c configs/ppyoloe/ppyoloe_crn_s_300e_coco.yml \
--eval &>logs.txt 2>&1 &
  • Fine-tune其他任务
    使用预训练模型fine-tune其他任务时,可以直接加载预训练模型,形状不匹配的参数将自动忽略
export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
  # 如果模型中参数形状与加载权重形状不同,将不会加载这类参数
python -m paddle.distributed.launch --gpus 0,1,2,3,4,5,6,7 tools/train.py -c configs/yolov3/yolov3_mobilenet_v1_roadsign.yml -o pretrain_weights=output/model_final
  • 模型恢复训练
    由于一些原因导致训练中断,用户可以使用-r的命令恢复训练
export CUDA_VISIBLE_DEVICES=0 #windows和Mac下不需要执行该命令
python tools/train.py -c configs/yolov3/yolov3_mobilenet_v1_roadsign.yml -r output/faster_rcnn_r50_1x_coco/10000

--eval表示训练的同时,进行评估, 评估过程中默认将最佳模型,保存为 output/picodet_lcnet_x1_0_layout/best_accuracy

  • FGD蒸馏训练
    PaddleDetection支持了基于FGD(Focal and Global Knowledge Distillation for Detectors)蒸馏的目标检测模型训练过程,FGD蒸馏分为两个部分FocalGlobalFocal蒸馏分离图像的前景和背景,让学生模型分别关注教师模型的前景和背景部分特征的关键像素;Global蒸馏部分重建不同像素之间的关系并将其从教师转移到学生,以补偿Focal蒸馏中丢失的全局信息。
    更换数据集,修改【TODO】配置中的数据配置、类别数,具体可以参考4.1。启动训练:
# 单卡训练
export CUDA_VISIBLE_DEVICES=0
python3 tools/train.py \
    -c configs/picodet/legacy_model/application/layout_analysis/picodet_lcnet_x1_0_layout.yml \
    --slim_config configs/picodet/legacy_model/application/layout_analysis/picodet_lcnet_x2_5_layout.yml \
    --eval

-c: 指定模型配置文件。
--slim_config: 指定压缩策略配置文件。

评估、测试

  • 评估
# GPU 评估, weights 为待测权重
python3 tools/eval.py \
    -c configs/picodet/legacy_model/application/layout_analysis/picodet_lcnet_x1_0_layout.yml \
    -o weights=./output/picodet_lcnet_x1_0_layout/best_model
  • 测试
python3 tools/infer.py \
    -c configs/picodet/legacy_model/application/layout_analysis/picodet_lcnet_x1_0_layout.yml \
    -o weights='output/picodet_lcnet_x1_0_layout/best_model.pdparams' \
    --infer_img='docs/images/layout.jpg' \
    --output_dir=output_dir/ \
    --draw_threshold=0.5
  • --infer_img: 推理单张图片,也可以通过--infer_dir推理文件中的所有图片。
  • --output_dir: 指定可视化结果保存路径。
  • --draw_threshold:指定绘制结果框的NMS阈值。

导出、压缩、推理

导出

python3 tools/export_model.py \
    -c configs/picodet/legacy_model/application/layout_analysis/picodet_lcnet_x1_0_layout.yml \
    -o weights=output/picodet_lcnet_x1_0_layout/best_model \
    --output_dir=output_inference/
  • 如无需导出后处理,请指定:-o export.benchmark=True(如果-o已出现过,此处删掉-o)
  • 如无需导出NMS,请指定:-o export.nms=False

模型压缩

为了进一步对模型进行优化,PaddleDetection提供了基于PaddleSlim进行模型压缩的完整教程和benchmark。目前支持的方案:

  • 裁剪
  • 量化
  • 蒸馏
  • 联合策略
  • 更多关于模型压缩的文档,请参考模型压缩文档

推理

python3 deploy/python/infer.py \
    --model_dir=output_inference/picodet_lcnet_x1_0_layout/ \
    --image_file=docs/images/layout.jpg \
    --device=GPU
  • --device:指定GPU、CPU设备

模型推理完成,会看到以下log输出

------------------------------------------
-----------  Model Configuration -----------
Model Arch: PicoDet
Transform Order:
--transform op: Resize
--transform op: NormalizeImage
--transform op: Permute
--transform op: PadStride
--------------------------------------------
class_id:0, confidence:0.9921, left_top:[20.18,35.66],right_bottom:[341.58,600.99]
class_id:0, confidence:0.9914, left_top:[19.77,611.42],right_bottom:[341.48,901.82]
class_id:0, confidence:0.9904, left_top:[369.36,375.10],right_bottom:[691.29,600.59]
class_id:0, confidence:0.9835, left_top:[369.60,608.60],right_bottom:[691.38,736.72]
class_id:0, confidence:0.9830, left_top:[369.58,805.38],right_bottom:[690.97,901.80]
class_id:0, confidence:0.9716, left_top:[383.68,271.44],right_bottom:[688.93,335.39]
class_id:0, confidence:0.9452, left_top:[370.82,34.48],right_bottom:[688.10,63.54]
class_id:1, confidence:0.8712, left_top:[370.84,771.03],right_bottom:[519.30,789.13]
class_id:3, confidence:0.9856, left_top:[371.28,67.85],right_bottom:[685.73,267.72]
save result to: output/layout.jpg
Test iter 0
------------------ Inference Time Info ----------------------
total_time(ms): 2196.0, img_num: 1
average latency time(ms): 2196.00, QPS: 0.455373
preprocess_time(ms): 2172.50, inference_time(ms): 11.90, postprocess_time(ms): 11.60
  • Model:模型结构
  • Transform Order:预处理操作
  • class_id、confidence、left_top、right_bottom:分别表示类别id、置信度、左上角坐标、右下角坐标
  • save result to:可视化版面分析结果保存路径,默认保存到./output文件夹
  • Inference Time Info:推理时间,其中preprocess_time表示预处理耗时,inference_time表示模型预测耗时,postprocess_time表示后处理耗时

常见问题

往期的FAQ

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值