Prechádzať zdrojové kódy

Merge pull request #1 from PaddlePaddle/develop

pull
Jason 5 rokov pred
rodič
commit
6bc6ea21d9
92 zmenil súbory, kde vykonal 3170 pridanie a 1098 odobranie
  1. 2 6
      .pre-commit-config.yaml
  2. 64 26
      README.md
  3. 8 0
      docs/FAQ.md
  4. 0 141
      docs/apis/datasets.md
  5. 38 0
      docs/apis/datasets/classification.md
  6. 63 0
      docs/apis/datasets/detection.md
  7. 31 0
      docs/apis/datasets/index.rst
  8. 42 0
      docs/apis/datasets/semantic_segmentation.md
  9. 3 3
      docs/apis/deploy.md
  10. 0 495
      docs/apis/load_model.md
  11. 188 0
      docs/apis/models/classification.md
  12. 180 0
      docs/apis/models/detection.md
  13. 12 0
      docs/apis/models/index.rst
  14. 85 0
      docs/apis/models/instance_segmentation.md
  15. 175 0
      docs/apis/models/semantic_segmentation.md
  16. 1 1
      docs/apis/slim.md
  17. 66 0
      docs/apis/transforms/augment.md
  18. 1 1
      docs/apis/transforms/cls_transforms.md
  19. 1 1
      docs/apis/transforms/det_transforms.md
  20. 1 0
      docs/apis/transforms/index.rst
  21. 1 1
      docs/apis/transforms/seg_transforms.md
  22. 4 3
      docs/apis/visualize.md
  23. 0 0
      docs/appendix/gpu_configure.md
  24. 0 0
      docs/appendix/how_to_offline_run.md
  25. 17 0
      docs/appendix/index.rst
  26. 13 13
      docs/appendix/metrics.md
  27. 1 21
      docs/appendix/model_zoo.md
  28. 0 75
      docs/client_use.md
  29. 0 17
      docs/conf.py
  30. 63 0
      docs/cv_solutions.md
  31. BIN
      docs/images/._文件(p37) BDSZYF000132754-docs jiangjiajun$ pwd :Users:jiangjiajun:Downloads:PaddleX-develop:docs:vdl1.png
  32. 0 0
      docs/images/00_loaddata.png
  33. BIN
      docs/images/anaconda_windows.png
  34. BIN
      docs/images/instance_segmentation.png
  35. BIN
      docs/images/mask_eval.png
  36. 0 0
      docs/images/paddlex.jpg
  37. BIN
      docs/images/seg_eval.png
  38. BIN
      docs/images/vdl1.jpg
  39. BIN
      docs/images/vdl2.jpg
  40. BIN
      docs/images/vdl3.jpg
  41. BIN
      docs/images/visualized_deeplab.jpg
  42. 22 13
      docs/index.rst
  43. 13 9
      docs/install.md
  44. 1 0
      docs/make.bat
  45. 1 0
      docs/paddlex_gui/how_to_use.md
  46. 29 0
      docs/paddlex_gui/index.rst
  47. 1 0
      docs/paddlex_gui/xx.md
  48. 19 10
      docs/quick_start.md
  49. 0 0
      docs/requirements.txt
  50. 0 0
      docs/tutorials/compress/slim/prune.md
  51. 0 0
      docs/tutorials/compress/slim/quant.md
  52. 7 0
      docs/tutorials/dataset_prepare.md
  53. 0 0
      docs/tutorials/datasets.md
  54. 68 0
      docs/tutorials/deploy/deploy.md
  55. 136 0
      docs/tutorials/deploy/deploy_cpp_linux.md
  56. 148 0
      docs/tutorials/deploy/deploy_cpp_win_vs2019.md
  57. BIN
      docs/tutorials/deploy/images/vs2019_step1.png
  58. BIN
      docs/tutorials/deploy/images/vs2019_step2.png
  59. BIN
      docs/tutorials/deploy/images/vs2019_step3.png
  60. BIN
      docs/tutorials/deploy/images/vs2019_step4.png
  61. BIN
      docs/tutorials/deploy/images/vs2019_step5.png
  62. BIN
      docs/tutorials/deploy/images/vs2019_step6.png
  63. 2 0
      docs/tutorials/deploy/index.rst
  64. 3 1
      docs/tutorials/index.rst
  65. 9 0
      docs/tutorials/train/classification.md
  66. 19 7
      paddlex/__init__.py
  67. 6 2
      paddlex/cv/datasets/coco.py
  68. 8 0
      paddlex/cv/datasets/dataset.py
  69. 16 27
      paddlex/cv/datasets/voc.py
  70. 61 38
      paddlex/cv/models/base.py
  71. 5 3
      paddlex/cv/models/classifier.py
  72. 7 3
      paddlex/cv/models/deeplabv3p.py
  73. 12 4
      paddlex/cv/models/faster_rcnn.py
  74. 13 4
      paddlex/cv/models/mask_rcnn.py
  75. 86 8
      paddlex/cv/models/slim/post_quantization.py
  76. 20 16
      paddlex/cv/models/slim/prune_config.py
  77. 9 8
      paddlex/cv/models/unet.py
  78. 44 31
      paddlex/cv/models/utils/pretrain_weights.py
  79. 14 4
      paddlex/cv/models/utils/visualize.py
  80. 5 2
      paddlex/cv/models/yolo_v3.py
  81. 50 18
      paddlex/cv/transforms/cls_transforms.py
  82. 70 33
      paddlex/cv/transforms/det_transforms.py
  83. 111 0
      paddlex/cv/transforms/imgaug_support.py
  84. 62 32
      paddlex/cv/transforms/seg_transforms.py
  85. 24 0
      paddlex/tools/__init__.py
  86. 43 0
      paddlex/tools/base.py
  87. 257 0
      paddlex/tools/x2coco.py
  88. 58 0
      paddlex/tools/x2imagenet.py
  89. 332 0
      paddlex/tools/x2seg.py
  90. 199 0
      paddlex/tools/x2voc.py
  91. 115 13
      paddlex/utils/utils.py
  92. 5 8
      setup.py

+ 2 - 6
.pre-commit-config.yaml

@@ -1,12 +1,8 @@
--   repo: local
+-   repo: https://github.com/PaddlePaddle/mirrors-yapf.git
+    sha: 0d79c0c469bab64f7229c9aca2b1186ef47f0e37
     hooks:
     -   id: yapf
-        name: yapf
-        entry: yapf
-        language: system
-        args: [-i, --style .style.yapf]
         files: \.py$
-
 -   repo: https://github.com/pre-commit/pre-commit-hooks
     sha: a11d9314b22d8f8c7556443875b731ef05965464
     hooks:

+ 64 - 26
README.md

@@ -1,48 +1,86 @@
-<img src="./paddlex.png" width = "300" height = "47" alt="PaddleX" align=center />
+<p align="center">
+  <img src="./docs/images/paddlex.png" width="360" height ="60" alt="PaddleX" align="middle" />
+</p>
 
-[![Build Status](https://travis-ci.org/PaddlePaddle/PaddleX.svg?branch=release/v1.6)](https://travis-ci.org/PaddlePaddle/PaddleX)
 [![License](https://img.shields.io/badge/license-Apache%202-red.svg)](LICENSE)
 [![Version](https://img.shields.io/github/release/PaddlePaddle/PaddleX.svg)](https://github.com/PaddlePaddle/PaddleX/releases)
 ![python version](https://img.shields.io/badge/python-3.6+-orange.svg)
 ![support os](https://img.shields.io/badge/os-linux%2C%20win%2C%20mac-yellow.svg)
 
-PaddleX是基于飞桨技术生态的全流程深度学习模型开发工具。具备易集成,易使用,全流程等特点。PaddleX作为深度学习开发工具,不仅提供了开源的内核代码,可供用户灵活使用或集成,同时也提供了配套的前端可视化客户端套件,让用户以可视化的方式进行模型开发,免去代码开发过程,访问[PaddleX官网](https://www.paddlepaddle.org.cn/paddle/paddlex)获取更多相关细节。
+PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习全流程开发工具。具备**全流程打通**、**融合产业实践**、**易用易集成**三大特点。
+
+## 特点
+
+- **全流程打通** 
+  - 数据准备:支持LabelMe,精灵标注等主流数据标注工具协议,同时无缝集成[EasyData智能数据服务平台](https://ai.baidu.com/easydata/), 助力开发者高效获取AI开发所需高质量数据。
+  - 模型训练:基于飞桨核心框架集成[PaddleClas](https://github.com/PaddlePaddle/PaddleClas), [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection), [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg)视觉开发套件,[VisualDL](https://github.com/PaddlePaddle/VisualDL)可视化分析组件,高效完成模型训练。
+  - 多端部署:内置[PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim)模型压缩工具和AES模型加密SDK,结合Paddle Inference和[Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite)便捷完成高性能且可靠的多端部署。
+
+- **融合产业实践** 
+  - 精选飞桨产业实践的成熟模型结构,开放案例实践教程,加速开发者产业落地。
+  - 通过[PaddleHub](https://github.com/PaddlePaddle/Paddle)内置丰富的飞桨高质量预训练模型,助力开发者高效实现飞桨Master模式。
+
+- **易用易集成**
+  - PadldeX提供简洁易用的全流程API,几行代码即可实现上百种数据增强、模型可解释性、C++模型部署等功能。
+  - 提供以PaddleX API为核心集成的跨平台GUI界面,降低深度学习全流程应用门槛。
+
+
 ## 安装
-### pip安装(使用Python代码进行模型训练)
-> **依赖**
-> - cython
-> - pycocotools
-> - python3
+
+PaddleX提供两种开发模式,满足不同场景和用户需求:
+
+- **Python开发模式:** 通过Python API方式完成全流程使用或集成,该模型提供全面、灵活、开放的深度学习功能,有更高的定制化空间。
+
+- **GUI开发模式:** 以PaddleX API为核心集成的跨平台GUI客户端,支持`Python开发模式`下的常用功能,以更低门槛的方式快速完成产业验证的模型训练。
+
+开发者可根据自身需要按需选择不同的模式进行安装使用。
+
+
+### Python开发模式安装
+
+**前置依赖**
+* paddlepaddle >= 1.8.0
+* python >= 3.5
+* cython
+* pycocotools
+
 ```
 pip install paddlex -i https://mirror.baidu.com/pypi/simple
 ```
 
-### PaddleX模型训练客户端安装(使用可视化界面进行模型训练)
-> 进入官网[下载使用](https://www.paddlepaddle.org.cn/paddle/paddleX)
+### GUI开发模式安装
+
+进入PaddleX官网[下载使用](https://www.paddlepaddle.org.cn/paddle/paddlex),申请下载绿色安装包,开箱即用。
+GUI模式的使用教程可参考[PaddleX GUI模式使用教程](https://paddlex.readthedocs.io/zh_CN/latest/client_use.html)
+
+## 使用文档 
 
-## 文档
 推荐访问[PaddleX在线使用文档](https://paddlex.readthedocs.io/zh_CN/latest/index.html),快速查阅读使用教程和API文档说明。
 
-- [10分钟快速上手PaddleX模型训练](docs/quick_start.md)
-- [PaddleX使用教程](docs/tutorials)
-- [PaddleX模型库](docs/model_zoo.md)
-- [导出模型部署](docs/deploy.md)
-- [使用PaddleX客户端进行模型训练](docs/client_use.md)
+- [10分钟快速上手](https://paddlex.readthedocs.io/zh_CN/latest/quick_start.html)
+- [PaddleX模型训练](https://paddlex.readthedocs.io/zh_CN/latest/tutorials/train/index.html#id1)
+- [PaddleX模型压缩](https://paddlex.readthedocs.io/zh_CN/latest/slim/index.html#id1)
+- [PaddleX模型库](https://paddlex.readthedocs.io/zh_CN/latest/model_zoo.html#id1)
+- [PaddleX多端部署](docs/deploy.md)
+
+## 在线教程
 
+基于AIStudio平台,快速在线体验PaddleX的Python开发模式教程。
 
-## 反馈
+- [PaddleX快速上手——MobileNetV3-ssld 化妆品分类](https://aistudio.baidu.com/aistudio/projectdetail/450220)
+- [PaddleX快速上手——Faster-RCNN AI识虫](https://aistudio.baidu.com/aistudio/projectdetail/439888)
+- [PaddleX快速上手——DeepLabv3+ 视盘分割](https://aistudio.baidu.com/aistudio/projectdetail/440197)
+
+## 交流与反馈
 
 - 项目官网: https://www.paddlepaddle.org.cn/paddle/paddlex
 - PaddleX用户QQ群: 1045148026 (手机QQ扫描如下二维码快速加入)  
-<img src="./QQGroup.jpeg" width="195" height="300" alt="QQGroup" align=center />
+<img src="./docs/images/QQGroup.jpeg" width="195" height="300" alt="QQGroup" align="center" />
+
+## FAQ
 
+## 更新日志
 
-## 飞桨技术生态
+## 贡献代码
 
-- [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection)
-- [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg)
-- [PaddleClas](https://github.com/PaddlePaddle/PaddleClas)
-- [PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim)
-- [PaddleHub](https://github.com/PaddlePaddle/PaddleHub)
-- [PaddleLite](https://github.com/PaddlePaddle/Paddle-Lite)
-- [VisualDL](https://github.com/PaddlePaddle/VisualDL)
+我们非常欢迎您为PaddleX贡献代码或者提供使用建议。如果您可以修复某个issue或者增加一个新功能,欢迎给我们提交Pull Requests.

+ 8 - 0
docs/FAQ.md

@@ -0,0 +1,8 @@
+{% extends "!layout.html" %}
+  {% block footer %} {{ super() }}
+
+  <style>
+         .wy-nav-content { max-width: 1080px; }
+  </style>
+
+{% endblock %}

+ 0 - 141
docs/apis/datasets.md

@@ -1,141 +0,0 @@
-# 数据集-datasets
-
-## ImageNet类
-```
-paddlex.datasets.ImageNet(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
-```
-读取ImageNet格式的分类数据集,并对样本进行相应的处理。ImageNet数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
-
-示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/classification/mobilenetv2.py#L25)
-
-### 参数
-
-> * **data_dir** (str): 数据集所在的目录路径。  
-> * **file_list** (str): 描述数据集图片文件和类别id的文件路径(文本内每行路径为相对`data_dir`的相对路径)。  
-> * **label_list** (str): 描述数据集包含的类别信息文件路径。  
-> * **transforms** (paddlex.cls.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.cls.transforms](./transforms/cls_transforms.md)。  
-> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。  
-> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
-> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
-> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
-
-## VOCDetection类
-
-```
-paddlex.datasets.VOCDetection(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
-```
-
-读取PascalVOC格式的检测数据集,并对样本进行相应的处理。PascalVOC数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
-
-示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/detection/yolov3_mobilenetv1.py#L29)
-
-### 参数
-
-> * **data_dir** (str): 数据集所在的目录路径。  
-> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
-> * **label_list** (str): 描述数据集包含的类别信息文件路径。  
-> * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。  
-> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
-> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
-> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
-> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
-
-## CocoDetection类
-
-```
-paddlex.datasets.CocoDetection(data_dir, ann_file, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
-```
-
-读取MSCOCO格式的检测数据集,并对样本进行相应的处理,该格式的数据集同样可以应用到实例分割模型的训练中。MSCOCO数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
-
-示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/detection/mask_rcnn_r50_fpn.py#L27)
-
-### 参数
-
-> * **data_dir** (str): 数据集所在的目录路径。  
-> * **ann_file** (str): 数据集的标注文件,为一个独立的json格式文件。
-> * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。  
-> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。  
-> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
-> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
-> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
-
-## SegDataset类
-
-```
-paddlex.datasets.SegDataset(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
-```
-
-读取语分分割任务数据集,并对样本进行相应的处理。语义分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
-
-示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/segmentation/unet.py#L27)
-
-### 参数
-
-> * **data_dir** (str): 数据集所在的目录路径。  
-> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
-> * **label_list** (str): 描述数据集包含的类别信息文件路径。  
-> * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.seg.transforms](./transforms/seg_transforms.md)。  
-> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
-> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
-> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
-> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。 
-
-## EasyDataCls类
-```
-paddlex.datasets.SegDataset(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
-```
-读取EasyData图像分类数据集,并对样本进行相应的处理。EasyData图像分类任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
-
-
-### 参数
-
-> * **data_dir** (str): 数据集所在的目录路径。  
-> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
-> * **label_list** (str): 描述数据集包含的类别信息文件路径。  
-> * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.cls.transforms](./transforms/cls_transforms.md)。  
-> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
-> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
-> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
-> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
-
-## EasyDataDet类
-
-```
-paddlex.datasets.EasyDataDet(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
-```
-
-读取EasyData目标检测格式数据集,并对样本进行相应的处理,该格式的数据集同样可以应用到实例分割模型的训练中。EasyData目标检测或实例分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
-
-
-### 参数
-
-> * **data_dir** (str): 数据集所在的目录路径。  
-> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
-> * **label_list** (str): 描述数据集包含的类别信息文件路径。  
-> * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。  
-> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
-> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
-> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
-> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
-
-
-## EasyDataSeg类
-
-```
-paddlex.datasets.EasyDataSeg(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
-```
-
-读取EasyData语分分割任务数据集,并对样本进行相应的处理。EasyData语义分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
-
-
-### 参数
-
-> * **data_dir** (str): 数据集所在的目录路径。  
-> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
-> * **label_list** (str): 描述数据集包含的类别信息文件路径。  
-> * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.seg.transforms](./transforms/seg_transforms.md)。  
-> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
-> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
-> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
-> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。 

+ 38 - 0
docs/apis/datasets/classification.md

@@ -0,0 +1,38 @@
+# 图像分类数据集
+
+## ImageNet类
+```
+paddlex.datasets.ImageNet(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
+```
+读取ImageNet格式的分类数据集,并对样本进行相应的处理。ImageNet数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
+
+示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/classification/mobilenetv2.py#L25)
+
+> **参数**
+
+> > * **data_dir** (str): 数据集所在的目录路径。  
+> > * **file_list** (str): 描述数据集图片文件和类别id的文件路径(文本内每行路径为相对`data_dir`的相对路径)。  
+> > * **label_list** (str): 描述数据集包含的类别信息文件路径。  
+> > * **transforms** (paddlex.cls.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.cls.transforms](./transforms/cls_transforms.md)。  
+> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。  
+> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
+> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
+> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
+
+## EasyDataCls类
+```
+paddlex.datasets.EasyDatasetCls(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
+```
+
+> 读取EasyData平台标注图像分类数据集,并对样本进行相应的处理。EasyData图像分类任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)。 
+
+> **参数**
+
+> > * **data_dir** (str): 数据集所在的目录路径。  
+> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
+> > * **label_list** (str): 描述数据集包含的类别信息文件路径。  
+> > * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.cls.transforms](./transforms/cls_transforms.md)。  
+> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
+> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
+> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
+> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。

+ 63 - 0
docs/apis/datasets/detection.md

@@ -0,0 +1,63 @@
+# 检测和实例分割数据集
+
+## VOCDetection类
+
+```
+paddlex.datasets.VOCDetection(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
+```
+
+> 仅用于**目标检测**。读取PascalVOC格式的检测数据集,并对样本进行相应的处理。PascalVOC数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
+
+> 示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/detection/yolov3_mobilenetv1.py#L29)
+
+> **参数**
+
+> > * **data_dir** (str): 数据集所在的目录路径。  
+> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
+> > * **label_list** (str): 描述数据集包含的类别信息文件路径。  
+> > * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。  
+> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
+> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
+> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
+> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
+
+## CocoDetection类
+
+```
+paddlex.datasets.CocoDetection(data_dir, ann_file, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
+```
+
+> 用于**目标检测或实例分割**。读取MSCOCO格式的检测数据集,并对样本进行相应的处理,该格式的数据集同样可以应用到实例分割模型的训练中。MSCOCO数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
+
+> 示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/detection/mask_rcnn_r50_fpn.py#L27)
+
+> **参数**
+
+> > * **data_dir** (str): 数据集所在的目录路径。  
+> > * **ann_file** (str): 数据集的标注文件,为一个独立的json格式文件。
+> > * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。  
+> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。  
+> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
+> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
+> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
+
+## EasyDataDet类
+
+```
+paddlex.datasets.EasyDataDet(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
+```
+
+> 用于**目标检测或实例分割**。读取EasyData目标检测格式数据集,并对样本进行相应的处理,该格式的数据集同样可以应用到实例分割模型的训练中。EasyData目标检测或实例分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
+
+
+> **参数**
+
+> > * **data_dir** (str): 数据集所在的目录路径。  
+> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
+> > * **label_list** (str): 描述数据集包含的类别信息文件路径。  
+> > * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。  
+> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
+> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
+> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
+> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
+

+ 31 - 0
docs/apis/datasets/index.rst

@@ -0,0 +1,31 @@
+数据集-datasets
+============================
+
+PaddleX目前支持主流的CV数据集格式和 `EasyData <https://ai.baidu.com/easydata/>`_ 数据标注平台的标注数据格式,此外PaddleX也提升了数据格式转换工具API,支持包括LabelMe,精灵标注助手和EasyData平台数据格式的转换,可以参考PaddleX的tools API文档。
+
+下表为各数据集格式与相应任务的对应关系,
+
++------------------------+------------+----------+----------+----------+
+| 数据集格式             | 图像分类   | 目标检测 | 实例分割 | 语义分割 |
++========================+============+==========+==========+==========+
+| ImageNet               | √          | -        | -        | -        |
++------------------------+------------+----------+----------+----------+
+| VOCDetection           | -          | √        | -        | -        |
++------------------------+------------+----------+----------+----------+
+| CocoDetection          | -          | √        | √        | -        |
++------------------------+------------+----------+----------+----------+
+| SegDataset             | -          | -        | -        | √        |
++------------------------+------------+----------+----------+----------+
+| EasyDataCls            | √          | -        | -        | -        |
++------------------------+------------+----------+----------+----------+
+| EasyDataDet            | -          | √        | √        | -        |
++------------------------+------------+----------+----------+----------+
+| EasyDataSeg            | -          | -        | -        | √        |
++------------------------+------------+----------+----------+----------+
+
+.. toctree::
+   :maxdepth: 2
+
+   classification.md
+   detection.md
+   semantic_segmentation.md

+ 42 - 0
docs/apis/datasets/semantic_segmentation.md

@@ -0,0 +1,42 @@
+# 语义分割数据集
+
+## SegDataset类
+
+```
+paddlex.datasets.SegDataset(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
+```
+
+> 读取语义分割任务数据集,并对样本进行相应的处理。语义分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
+
+> 示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/segmentation/unet.py#L27)
+
+> **参数**
+
+> > * **data_dir** (str): 数据集所在的目录路径。  
+> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
+> > * **label_list** (str): 描述数据集包含的类别信息文件路径。  
+> > * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.seg.transforms](./transforms/seg_transforms.md)。  
+> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
+> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
+> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
+> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。 
+
+## EasyDataSeg类
+
+```
+paddlex.datasets.EasyDataSeg(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
+```
+
+> 读取EasyData语义分割任务数据集,并对样本进行相应的处理。EasyData语义分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)  
+
+
+> **参数**
+
+> > * **data_dir** (str): 数据集所在的目录路径。  
+> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
+> > * **label_list** (str): 描述数据集包含的类别信息文件路径。  
+> > * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.seg.transforms](./transforms/seg_transforms.md)。  
+> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
+> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。  
+> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
+> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。 

+ 3 - 3
docs/apis/deploy.md

@@ -1,12 +1,12 @@
-接口说明
+PaddleX API说明文档
 ============================
 
 .. toctree::
    :maxdepth: 2
 
    transforms/index.rst
-   datasets.md
-   models.md
+   datasets/index.rst
+   models/index.rst
    slim.md
    load_model.md
    visualize.md

+ 0 - 495
docs/apis/load_model.md

@@ -1,495 +0,0 @@
-# 模型-models
-
-## 分类模型
-
-### ResNet50类
-
-```python
-paddlex.cls.ResNet50(num_classes=1000)
-```
-
-构建ResNet50分类器,并实现其训练、评估和预测。  
-
-#### **参数:**
-
-> - **num_classes** (int): 类别数。默认为1000。  
-
-#### 分类器训练函数接口
-
-> ```python
-> train(self, num_epochs, train_dataset, train_batch_size=64, eval_dataset=None, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.025, lr_decay_epochs=[30, 60, 90], lr_decay_gamma=0.1, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5)
-> ```
->
-> **参数:**
->
-> > - **num_epochs** (int): 训练迭代轮数。
-> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
-> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认值为64。
-> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
-> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
-> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代步数)。默认为2。
-> > - **save_dir** (str): 模型保存路径。
-> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为'IMAGENET'。
-> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
-> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.025。
-> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[30, 60, 90]。
-> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
-> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
-> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
-> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
-> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
-> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
-
-#### 分类器评估函数接口
-
-> ```python
-> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False)
-> ```
->
-> **参数:**
->
-> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
-> > - **batch_size** (int): 验证数据批大小。默认为1。
-> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
-> > - **return_details** (bool): 是否返回详细信息,默认False。
->
-> **返回值:**
->
-> > - **dict**: 当return_details为False时,返回dict, 包含关键字:'acc1'、'acc5',分别表示最大值的accuracy、前5个最大值的accuracy。
-> > - **tuple** (metrics, eval_details): 当`return_details`为True时,增加返回dict,包含关键字:'true_labels'、'pred_scores',分别代表真实类别id、每个类别的预测得分。
-
-#### 分类器预测函数接口
-
-> ```python
-> predict(self, img_file, transforms=None, topk=5)
-> ```
->
-> **参数:**
->
-> > - **img_file** (str): 预测图像路径。
-> > - **transforms** (paddlex.cls.transforms): 数据预处理操作。
-> > - **topk** (int): 预测时前k个最大值。
-
-> **返回值:**
->
-> > - **list**: 其中元素均为字典。字典的关键字为'category_id'、'category'、'score',
-> >       分别对应预测类别id、预测类别标签、预测得分。
-
-### 其它分类器类
-
-除`ResNet50`外,`paddlex.cls`下还提供了`ResNet18`、`ResNet34`、`ResNet101`、`ResNet50_vd`、`ResNet101_vd`、`ResNet50_vd_ssld`、`ResNet101_vd_ssld`、`DarkNet53`、`MobileNetV1`、`MobileNetV2`、`MobileNetV3_small`、`MobileNetV3_large`、`MobileNetV3_small_ssld`、`MobileNetV3_large_ssld`、`Xception41`、`Xception65`、`Xception71`、`ShuffleNetV2`,  使用方式(包括函数接口和参数)均与`ResNet50`一致,各模型效果可参考[模型库](../model_zoo.md)中列表。
-
-
-
-## 检测模型
-
-### YOLOv3类
-
-```python
-paddlex.det.YOLOv3(num_classes=80, backbone='MobileNetV1', anchors=None, anchor_masks=None, ignore_threshold=0.7, nms_score_threshold=0.01, nms_topk=1000, nms_keep_topk=100, nms_iou_threshold=0.45, label_smooth=False, train_random_shapes=[320, 352, 384, 416, 448, 480, 512, 544, 576, 608])
-```
-
-构建YOLOv3检测器,并实现其训练、评估和预测。  
-
-**参数:**
-
-> - **num_classes** (int): 类别数。默认为80。
-> - **backbone** (str): YOLOv3的backbone网络,取值范围为['DarkNet53', 'ResNet34', 'MobileNetV1', 'MobileNetV3_large']。默认为'MobileNetV1'。
-> - **anchors** (list|tuple): anchor框的宽度和高度,为None时表示使用默认值
->                  [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
->                   [59, 119], [116, 90], [156, 198], [373, 326]]。
-> - **anchor_masks** (list|tuple): 在计算YOLOv3损失时,使用anchor的mask索引,为None时表示使用默认值
->                    [[6, 7, 8], [3, 4, 5], [0, 1, 2]]。
-> - **ignore_threshold** (float): 在计算YOLOv3损失时,IoU大于`ignore_threshold`的预测框的置信度被忽略。默认为0.7。
-> - **nms_score_threshold** (float): 检测框的置信度得分阈值,置信度得分低于阈值的框应该被忽略。默认为0.01。
-> - **nms_topk** (int): 进行NMS时,根据置信度保留的最大检测框数。默认为1000。
-> - **nms_keep_topk** (int): 进行NMS后,每个图像要保留的总检测框数。默认为100。
-> - **nms_iou_threshold** (float): 进行NMS时,用于剔除检测框IOU的阈值。默认为0.45。
-> - **label_smooth** (bool): 是否使用label smooth。默认值为False。
-> - **train_random_shapes** (list|tuple): 训练时从列表中随机选择图像大小。默认值为[320, 352, 384, 416, 448, 480, 512, 544, 576, 608]。
-
-#### YOLOv3训练函数接口
-
-> ```python
-> train(self, num_epochs, train_dataset, train_batch_size=8, eval_dataset=None, save_interval_epochs=20, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=1.0/8000, warmup_steps=1000, warmup_start_lr=0.0, lr_decay_epochs=[213, 240], lr_decay_gamma=0.1, metric=None, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5)
-> ```
->
-> **参数:**
->
-> > - **num_epochs** (int): 训练迭代轮数。
-> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
-> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认值为8。
-> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
-> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为20。
-> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
-> > - **save_dir** (str): 模型保存路径。默认值为'output'。
-> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
-> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
-> > - **learning_rate** (float): 默认优化器的学习率。默认为1.0/8000。
-> > - **warmup_steps** (int):  默认优化器进行warmup过程的步数。默认为1000。
-> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为0.0。
-> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[213, 240]。
-> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
-> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
-> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
-> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在PascalVOC数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
-> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
-> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
-> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
-
-#### YOLOv3评估函数接口
-
-> ```python
-> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
-> ```
->
-> **参数:**
->
-> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
-> > - **batch_size** (int): 验证数据批大小。默认为1。
-> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
-> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC';如为COCODetection,则`metric`为'COCO'默认为None。
-> > - **return_details** (bool): 是否返回详细信息。默认值为False。
-> >
->  **返回值:**
->
-> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当`return_details`为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'或者’bbox_map‘,分别表示平均准确率平均值在各个阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;’gt‘:真实标注框相关信息。
-
-#### YOLOv3预测函数接口
-
-> ```python
-> predict(self, img_file, transforms=None)
-> ```
->
-> **参数:**
->
-> > - **img_file** (str): 预测图像路径。
-> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
->
-> **返回值:**
->
-> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key'bbox', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
-
-### FasterRCNN类
-
-```python
-paddlex.det.FasterRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_ratios=[0.5, 1.0, 2.0], anchor_sizes=[32, 64, 128, 256, 512])
-
-```
-
-构建FasterRCNN检测器,并实现其训练、评估和预测。  
-
-**参数:**
-
-> - **num_classes** (int): 包含了背景类的类别数。默认为81。
-> - **backbone** (str): FasterRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50vd', 'ResNet101', 'ResNet101vd']。默认为'ResNet50'。
-> - **with_fpn** (bool): 是否使用FPN结构。默认为True。
-> - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
-> - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
-
-#### FasterRCNN训练函数接口
-
-> ```python
-> train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, save_interval_epochs=1, log_interval_steps=2,save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.0025, warmup_steps=500, warmup_start_lr=1.0/1200, lr_decay_epochs=[8, 11], lr_decay_gamma=0.1, metric=None, use_vdl=False, early_stop=False, early_stop_patience=5)
->
-> ```
->
-> **参数:**
->
-> > - **num_epochs** (int): 训练迭代轮数。
-> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
-> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认为2。
-> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
-> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
-> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
-> > - **save_dir** (str): 模型保存路径。默认值为'output'。
-> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
-> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
-> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.0025。
-> > - **warmup_steps** (int):  默认优化器进行warmup过程的步数。默认为500。
-> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为1.0/1200。
-> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[8, 11]。
-> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
-> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
-> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
-> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
-> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
-
-#### FasterRCNN评估函数接口
-
-> ```python
-> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
->
-> ```
->
-> **参数:**
->
-> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
-> > - **batch_size** (int): 验证数据批大小。默认为1。
-> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
-> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC'; 如为COCODetection,则`metric`为'COCO'。
-> > - **return_details** (bool): 是否返回详细信息。默认值为False。
-> >
-> **返回值:**
->
-> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当`return_details`为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'或者’bbox_map‘,分别表示平均准确率平均值在各个IoU阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;’gt‘:真实标注框相关信息。
-
-#### FasterRCNN预测函数接口
-
-> ```python
-> predict(self, img_file, transforms=None)
->
-> ```
->
-> **参数:**
->
-> > - **img_file** (str): 预测图像路径。
-> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
->
-> **返回值:**
->
-> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key'bbox', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
-
-### MaskRCNN类
-
-```python
-paddlex.det.MaskRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_ratios=[0.5, 1.0, 2.0], anchor_sizes=[32, 64, 128, 256, 512])
-
-```
-
-构建MaskRCNN检测器,并实现其训练、评估和预测。  
-
-**参数:**
-
-> - **num_classes** (int): 包含了背景类的类别数。默认为81。
-> - **backbone** (str): MaskRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50vd', 'ResNet101', 'ResNet101vd']。默认为'ResNet50'。
-> - **with_fpn** (bool): 是否使用FPN结构。默认为True。
-> - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
-> - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
-
-#### MaskRCNN训练函数接口
-
-> ```python
-> train(self, num_epochs, train_dataset, train_batch_size=1, eval_dataset=None, save_interval_epochs=1, log_interval_steps=20, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=1.0/800, warmup_steps=500, warmup_start_lr=1.0 / 2400, lr_decay_epochs=[8, 11], lr_decay_gamma=0.1, metric=None, use_vdl=False, early_stop=False, early_stop_patience=5)
->
-> ```
->
-> **参数:**
->
-> > - **num_epochs** (int): 训练迭代轮数。
-> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
-> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认为1。
-> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
-> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
-> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
-> > - **save_dir** (str): 模型保存路径。默认值为'output'。
-> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
-> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
-> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.00125。
-> > - **warmup_steps** (int):  默认优化器进行warmup过程的步数。默认为500。
-> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为1.0/2400。
-> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[8, 11]。
-> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
-> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
-> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
-> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
-> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
-
-#### MaskRCNN评估函数接口
-
-> ```python
-> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
->
-> ```
->
-> **参数:**
->
-> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
-> > - **batch_size** (int): 验证数据批大小。默认为1。
-> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
-> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC'; 如为COCODetection,则`metric`为'COCO'。
-> > - **return_details** (bool): 是否返回详细信息。默认值为False。
-> >
-> **返回值:**
->
-> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当return_details为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'和'segm_mmap'或者’bbox_map‘和'segm_map',分别表示预测框和分割区域平均准确率平均值在各个IoU阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测框结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;'mask',对应元素预测区域结果列表,每个预测结果由图像id、预测区域类别id、预测区域坐标、预测区域得分;’gt‘:真实标注框和标注区域相关信息。
-
-#### MaskRCNN预测函数接口
-
-> ```python
-> predict(self, img_file, transforms=None)
->
-> ```
->
-> **参数:**
->
-> > - **img_file** (str): 预测图像路径。
-> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
->
-> **返回值:**
->
-> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key'bbox', 'mask', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、Mask信息,类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
-
-## 分割模型
-
-### DeepLabv3p类
-
-```python
-paddlex.seg.DeepLabv3p(num_classes=2, backbone='MobileNetV2_x1.0', output_stride=16, aspp_with_sep_conv=True, decoder_use_sep_conv=True, encoder_with_aspp=True, enable_decoder=True, use_bce_loss=False, use_dice_loss=False, class_weight=None, ignore_index=255)
-
-```
-
-构建DeepLabv3p分割器,并实现其训练、评估和预测。
-
-**参数:**
-
-> - **num_classes** (int): 类别数。
-> - **backbone** (str): DeepLabv3+的backbone网络,实现特征图的计算,取值范围为['Xception65', 'Xception41', 'MobileNetV2_x0.25', 'MobileNetV2_x0.5', 'MobileNetV2_x1.0', 'MobileNetV2_x1.5', 'MobileNetV2_x2.0'],'MobileNetV2_x1.0'。
-> - **output_stride** (int): backbone 输出特征图相对于输入的下采样倍数,一般取值为8或16。默认16。
-> - **aspp_with_sep_conv** (bool):  decoder模块是否采用separable convolutions。默认True。
-> - **decoder_use_sep_conv** (bool): decoder模块是否采用separable convolutions。默认True。
-> - **encoder_with_aspp** (bool): 是否在encoder阶段采用aspp模块。默认True。
-> - **enable_decoder** (bool): 是否使用decoder模块。默认True。
-> - **use_bce_loss** (bool): 是否使用bce loss作为网络的损失函数,只能用于两类分割。可与dice loss同时使用。默认False。
-> - **use_dice_loss** (bool): 是否使用dice loss作为网络的损失函数,只能用于两类分割,可与bce loss同时使用,当`use_bce_loss`和`use_dice_loss`都为False时,使用交叉熵损失函数。默认False。
-> - **class_weight** (list/str): 交叉熵损失函数各类损失的权重。当`class_weight`为list的时候,长度应为`num_classes`。当`class_weight`为str时, weight.lower()应为'dynamic',这时会根据每一轮各类像素的比重自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,即平时使用的交叉熵损失函数。
-> - **ignore_index** (int): label上忽略的值,label为`ignore_index`的像素不参与损失函数的计算。默认255。
-
-#### DeepLabv3训练函数接口
-
-> ```python
-> train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, eval_batch_size=1, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.01, lr_decay_power=0.9, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5):
->
-> ```
->
-> **参数:**
-> >
-> > - **num_epochs** (int): 训练迭代轮数。
-> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
-> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认2。
-> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
-> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
-> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
-> > - **save_dir** (str): 模型保存路径。默认'output'
-> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认'IMAGENET'。
-> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认的优化器:使用fluid.optimizer.Momentum优化方法,polynomial的学习率衰减策略。
-> > - **learning_rate** (float): 默认优化器的初始学习率。默认0.01。
-> > - **lr_decay_power** (float): 默认优化器学习率衰减指数。默认0.9。
-> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认False。
-> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
-> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
-> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
-> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
-
-#### DeepLabv3评估函数接口
-
-> ```python
-> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False):
-> ```
-
->  **参数:**
-> >
-> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
-> > - **batch_size** (int): 评估时的batch大小。默认1。
-> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
-> > - **return_details** (bool): 是否返回详细信息。默认False。
-
-> **返回值:**
-> >
-> > - **dict**: 当`return_details`为False时,返回dict。包含关键字:'miou'、'category_iou'、'macc'、
-> >   'category_acc'和'kappa',分别表示平均iou、各类别iou、平均准确率、各类别准确率和kappa系数。
-> > - **tuple** (metrics, eval_details):当`return_details`为True时,增加返回dict (eval_details),
-> >   包含关键字:'confusion_matrix',表示评估的混淆矩阵。
-
-#### DeepLabv3预测函数接口
-
-> ```
-> predict(self, im_file, transforms=None):
-> ```
-
-> **参数:**
-> >
-> > - **img_file** (str): 预测图像路径。
-> > - **transforms** (paddlex.seg.transforms): 数据预处理操作。
-
-> **返回值:**
-> >
-> > - **dict**: 包含关键字'label_map'和'score_map', 'label_map'存储预测结果灰度图,像素值表示对应的类别,'score_map'存储各类别的概率,shape=(h, w, num_classes)。
-
-### UNet类
-
-```python
-paddlex.seg.UNet(num_classes=2, upsample_mode='bilinear', use_bce_loss=False, use_dice_loss=False, class_weight=None, ignore_index=255)
-```
-
-构建UNet分割器,并实现其训练、评估和预测。
-
-
-**参数:**
-
-> - **num_classes** (int): 类别数。
-> - **upsample_mode** (str): UNet decode时采用的上采样方式,取值为'bilinear'时利用双线行差值进行上菜样,当输入其他选项时则利用反卷积进行上菜样,默认为'bilinear'。
-> - **use_bce_loss** (bool): 是否使用bce loss作为网络的损失函数,只能用于两类分割。可与dice loss同时使用。默认False。
-> - **use_dice_loss** (bool): 是否使用dice loss作为网络的损失函数,只能用于两类分割,可与bce loss同时使用。当use_bce_loss和use_dice_loss都为False时,使用交叉熵损失函数。默认False。
-> - **class_weight** (list/str): 交叉熵损失函数各类损失的权重。当`class_weight`为list的时候,长度应为`num_classes`。当`class_weight`为str时, weight.lower()应为'dynamic',这时会根据每一轮各类像素的比重自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,即平时使用的交叉熵损失函数。
-> - **ignore_index** (int): label上忽略的值,label为`ignore_index`的像素不参与损失函数的计算。默认255。
-
-#### Unet训练函数接口
-
-> ```python
-> train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, eval_batch_size=1, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='COCO', optimizer=None, learning_rate=0.01, lr_decay_power=0.9, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5):
-> ```
->
-> **参数:**
-> >
-> > - **num_epochs** (int): 训练迭代轮数。
-> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
-> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认2。
-> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
-> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
-> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
-> > - **save_dir** (str): 模型保存路径。默认'output'
-> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在COCO图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认'COCO'。
-> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认的优化器:使用fluid.optimizer.Momentum优化方法,polynomial的学习率衰减策略。
-> > - **learning_rate** (float): 默认优化器的初始学习率。默认0.01。
-> > - **lr_decay_power** (float): 默认优化器学习率衰减指数。默认0.9。
-> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认False。
-> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
-> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
-> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
-> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
-
-#### Unet评估函数接口
-
-> ```
-> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False):
-> ```
-
-> **参数:**
-> >
-> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
-> > - **batch_size** (int): 评估时的batch大小。默认1。
-> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
-> > - **return_details** (bool): 是否返回详细信息。默认False。
-
-> **返回值:**
-> >
-> > - **dict**: 当return_details为False时,返回dict。包含关键字:'miou'、'category_iou'、'macc'、
-> >   'category_acc'和'kappa',分别表示平均iou、各类别iou、平均准确率、各类别准确率和kappa系数。
-> > - **tuple** (metrics, eval_details):当return_details为True时,增加返回dict (eval_details),
-> >   包含关键字:'confusion_matrix',表示评估的混淆矩阵。
-
-#### Unet预测函数接口
-
-> ```
-> predict(self, im_file, transforms=None):
-> ```
-
-> **参数:**
-> >
-> > - **img_file** (str): 预测图像路径。
-> > - **transforms** (paddlex.seg.transforms): 数据预处理操作。
-
-> **返回值:**
-> >
-> > - **dict**: 包含关键字'label_map'和'score_map', 'label_map'存储预测结果灰度图,像素值表示对应的类别,'score_map'存储各类别的概率,shape=(h, w, num_classes)。

+ 188 - 0
docs/apis/models/classification.md

@@ -0,0 +1,188 @@
+# 图像分类
+
+## ResNet50类
+
+```python
+paddlex.cls.ResNet50(num_classes=1000)
+```
+
+> 构建ResNet50分类器,并实现其训练、评估和预测。  
+
+**参数**
+
+> - **num_classes** (int): 类别数。默认为1000。  
+
+### train 训练接口
+
+```python
+train(self, num_epochs, train_dataset, train_batch_size=64, eval_dataset=None, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.025, lr_decay_epochs=[30, 60, 90], lr_decay_gamma=0.1, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
+```
+>
+> **参数**
+>
+> > - **num_epochs** (int): 训练迭代轮数。
+> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
+> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认值为64。
+> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
+> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
+> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代步数)。默认为2。
+> > - **save_dir** (str): 模型保存路径。
+> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为'IMAGENET'。
+> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
+> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.025。
+> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[30, 60, 90]。
+> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
+> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
+> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
+> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
+> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
+> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
+> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
+
+### evaluate 评估接口
+
+```python
+evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False)
+```
+>
+> **参数**
+>
+> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
+> > - **batch_size** (int): 验证数据批大小。默认为1。
+> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
+> > - **return_details** (bool): 是否返回详细信息,默认False。
+>
+> **返回值**
+>
+> > - **dict**: 当return_details为False时,返回dict, 包含关键字:'acc1'、'acc5',分别表示最大值的accuracy、前5个最大值的accuracy。
+> > - **tuple** (metrics, eval_details): 当`return_details`为True时,增加返回dict,包含关键字:'true_labels'、'pred_scores',分别代表真实类别id、每个类别的预测得分。
+
+### predict 预测接口
+
+```python
+predict(self, img_file, transforms=None, topk=5)
+```
+
+> 分类模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`ResNet50.test_transforms`和`ResNet50.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
+
+> **参数**
+>
+> > - **img_file** (str): 预测图像路径。
+> > - **transforms** (paddlex.cls.transforms): 数据预处理操作。
+> > - **topk** (int): 预测时前k个最大值。
+
+> **返回值**
+>
+> > - **list**: 其中元素均为字典。字典的关键字为'category_id'、'category'、'score',
+> >       分别对应预测类别id、预测类别标签、预测得分。
+
+## 其它分类器类
+
+PaddleX提供了共计22种分类器,所有分类器均提供同`ResNet50`相同的训练`train`,评估`evaluate`和预测`predict`接口,各模型效果可参考[模型库](../appendix/model_zoo.md)。
+
+### ResNet18
+```python
+paddlex.cls.ResNet18(num_classes=1000)
+```
+
+### ResNet34
+```python
+paddlex.cls.ResNet34(num_classes=1000)
+```
+
+
+### ResNet50
+```python
+paddlex.cls.ResNet50(num_classes=1000)
+```
+
+### ResNet50_vd
+```python
+paddlex.cls.ResNet50_vd(num_classes=1000)
+```
+
+### ResNet50_vd_ssld
+```python
+paddlex.cls.ResNet50_vd_ssld(num_classes=1000)
+```
+
+### ResNet101
+```python
+paddlex.cls.ResNet101(num_classes=1000)
+```
+
+### ResNet101_vd
+```python
+paddlex.cls.ResNet101_vdnum_classes=1000)
+```
+
+### ResNet101_vd_ssld
+```python
+paddlex.cls.ResNet101_vd_ssld(num_classes=1000)
+```
+
+### DarkNet53
+```python
+paddlex.cls.DarkNet53(num_classes=1000)
+```
+
+### MobileNetV1
+```python
+paddlex.cls.MobileNetV1(num_classes=1000)
+```
+
+### MobileNetV2
+```python
+paddlex.cls.MobileNetV2(num_classes=1000)
+```
+
+### MobileNetV3_small
+```python
+paddlex.cls.MobileNetV3_small(num_classes=1000)
+```
+
+### MobileNetV3_small_ssld
+```python
+paddlex.cls.MobileNetV3_small_ssld(num_classes=1000)
+```
+
+### MobileNetV3_large
+```python
+paddlex.cls.MobileNetV3_large(num_classes=1000)
+```
+
+### MobileNetV3_large_ssld
+```python
+paddlex.cls.MobileNetV3_large_ssld(num_classes=1000)
+```
+
+### Xception65
+```python
+paddlex.cls.Xception65(num_classes=1000)
+```
+
+### Xception71
+```python
+paddlex.cls.Xception71(num_classes=1000)
+```
+
+### ShuffleNetV2
+```python
+paddlex.cls.ShuffleNetV2(num_classes=1000)
+```
+
+### DenseNet121
+```python
+paddlex.cls.DenseNet121(num_classes=1000)
+```
+
+### DenseNet161
+```python
+paddlex.cls.DenseNet161(num_classes=1000)
+```
+
+### DenseNet201
+```python
+paddlex.cls.DenseNet201(num_classes=1000)
+```
+

+ 180 - 0
docs/apis/models/detection.md

@@ -0,0 +1,180 @@
+# 目标检测
+
+## YOLOv3类
+
+```python
+paddlex.det.YOLOv3(num_classes=80, backbone='MobileNetV1', anchors=None, anchor_masks=None, ignore_threshold=0.7, nms_score_threshold=0.01, nms_topk=1000, nms_keep_topk=100, nms_iou_threshold=0.45, label_smooth=False, train_random_shapes=[320, 352, 384, 416, 448, 480, 512, 544, 576, 608])
+```
+
+> 构建YOLOv3检测器。**注意在YOLOv3,num_classes不需要包含背景类,如目标包括human、dog两种,则num_classes设为2即可,这里与FasterRCNN/MaskRCNN有差别**
+
+> **参数**
+> 
+> > - **num_classes** (int): 类别数。默认为80。
+> > - **backbone** (str): YOLOv3的backbone网络,取值范围为['DarkNet53', 'ResNet34', 'MobileNetV1', 'MobileNetV3_large']。默认为'MobileNetV1'。
+> > - **anchors** (list|tuple): anchor框的宽度和高度,为None时表示使用默认值
+> >                  [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
+>                   [59, 119], [116, 90], [156, 198], [373, 326]]。
+> > - **anchor_masks** (list|tuple): 在计算YOLOv3损失时,使用anchor的mask索引,为None时表示使用默认值
+> >                    [[6, 7, 8], [3, 4, 5], [0, 1, 2]]。
+> > - **ignore_threshold** (float): 在计算YOLOv3损失时,IoU大于`ignore_threshold`的预测框的置信度被忽略。默认为0.7。
+> > - **nms_score_threshold** (float): 检测框的置信度得分阈值,置信度得分低于阈值的框应该被忽略。默认为0.01。
+> > - **nms_topk** (int): 进行NMS时,根据置信度保留的最大检测框数。默认为1000。
+> > - **nms_keep_topk** (int): 进行NMS后,每个图像要保留的总检测框数。默认为100。
+> > - **nms_iou_threshold** (float): 进行NMS时,用于剔除检测框IOU的阈值。默认为0.45。
+> > - **label_smooth** (bool): 是否使用label smooth。默认值为False。
+> > - **train_random_shapes** (list|tuple): 训练时从列表中随机选择图像大小。默认值为[320, 352, 384, 416, 448, 480, 512, 544, 576, 608]。
+
+### train 训练接口
+
+```python
+train(self, num_epochs, train_dataset, train_batch_size=8, eval_dataset=None, save_interval_epochs=20, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=1.0/8000, warmup_steps=1000, warmup_start_lr=0.0, lr_decay_epochs=[213, 240], lr_decay_gamma=0.1, metric=None, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
+```
+
+> YOLOv3模型的训练接口,函数内置了`piecewise`学习率衰减策略和`momentum`优化器。
+
+> **参数**
+>
+> > - **num_epochs** (int): 训练迭代轮数。
+> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
+> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认值为8。
+> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
+> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为20。
+> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
+> > - **save_dir** (str): 模型保存路径。默认值为'output'。
+> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
+> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
+> > - **learning_rate** (float): 默认优化器的学习率。默认为1.0/8000。
+> > - **warmup_steps** (int):  默认优化器进行warmup过程的步数。默认为1000。
+> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为0.0。
+> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[213, 240]。
+> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
+> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
+> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
+> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在PascalVOC数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
+> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
+> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
+> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
+> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
+
+### evaluate 评估接口
+
+```python
+evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
+```
+
+> YOLOv3模型的评估接口,模型评估后会返回在验证集上的指标`box_map`(metric指定为'VOC'时)或`box_mmap`(metric指定为`COCO`时)。
+
+> **参数**
+>
+> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
+> > - **batch_size** (int): 验证数据批大小。默认为1。
+> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
+> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC';如为COCODetection,则`metric`为'COCO'默认为None, 如为EasyData类型数据集,同时也会使用'VOC'。
+> > - **return_details** (bool): 是否返回详细信息。默认值为False。
+> >
+>  **返回值**
+>
+> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当`return_details`为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'或者’bbox_map‘,分别表示平均准确率平均值在各个阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;’gt‘:真实标注框相关信息。
+
+### predict 预测接口
+
+```python
+predict(self, img_file, transforms=None)
+```
+
+> YOLOv3模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`YOLOv3.test_transforms`和`YOLOv3.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义`test_transforms`传入给`predict`接口
+
+> **参数**
+>
+> > - **img_file** (str): 预测图像路径。
+> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
+>
+> **返回值**
+>
+> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key包括'bbox', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
+
+
+## FasterRCNN类
+
+```python
+paddlex.det.FasterRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_ratios=[0.5, 1.0, 2.0], anchor_sizes=[32, 64, 128, 256, 512])
+
+```
+
+> 构建FasterRCNN检测器。 **注意在FasterRCNN中,num_classes需要设置为类别数+背景类,如目标包括human、dog两种,则num_classes需设为3,多的一种为背景background类别**
+
+> **参数**
+
+> > - **num_classes** (int): 包含了背景类的类别数。默认为81。
+> > - **backbone** (str): FasterRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd']。默认为'ResNet50'。
+> > - **with_fpn** (bool): 是否使用FPN结构。默认为True。
+> > - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
+> > - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
+
+### train 训练接口
+
+```python
+train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, save_interval_epochs=1, log_interval_steps=2,save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.0025, warmup_steps=500, warmup_start_lr=1.0/1200, lr_decay_epochs=[8, 11], lr_decay_gamma=0.1, metric=None, use_vdl=False, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
+```
+
+> FasterRCNN模型的训练接口,函数内置了`piecewise`学习率衰减策略和`momentum`优化器。
+
+> **参数**
+>
+> > - **num_epochs** (int): 训练迭代轮数。
+> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
+> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认为2。
+> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
+> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
+> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
+> > - **save_dir** (str): 模型保存路径。默认值为'output'。
+> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
+> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
+> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.0025。
+> > - **warmup_steps** (int):  默认优化器进行warmup过程的步数。默认为500。
+> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为1.0/1200。
+> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[8, 11]。
+> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
+> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
+> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
+> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
+> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
+> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
+
+### evaluate 接口
+
+```python
+evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
+```
+
+> FasterRCNN模型的评估接口,模型评估后会返回在验证集上的指标box_map(metric指定为’VOC’时)或box_mmap(metric指定为COCO时)。
+
+> **参数**
+>
+> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
+> > - **batch_size** (int): 验证数据批大小。默认为1。当前只支持设置为1。
+> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
+> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC'; 如为COCODetection,则`metric`为'COCO'。
+> > - **return_details** (bool): 是否返回详细信息。默认值为False。
+> >
+> **返回值**
+>
+> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当`return_details`为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'或者’bbox_map‘,分别表示平均准确率平均值在各个IoU阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;’gt‘:真实标注框相关信息。
+
+### predict 预测接口
+
+```python
+predict(self, img_file, transforms=None)
+```
+
+> FasterRCNN模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`FasterRCNN.test_transforms`和`FasterRCNN.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
+
+> **参数**
+>
+> > - **img_file** (str): 预测图像路径。
+> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
+>
+> **返回值**
+>
+> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key包括'bbox', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。

+ 12 - 0
docs/apis/models/index.rst

@@ -0,0 +1,12 @@
+模型集-models
+============================
+
+PaddleX目前支持 `四种视觉任务解决方案 <../../cv_solutions.html>`_ ,包括图像分类、目标检测、实例分割和语义分割。对于每种视觉任务,PaddleX又提供了1种或多种模型,用户可根据需求及应用场景选取。
+
+.. toctree::
+   :maxdepth: 2
+
+   classification.md
+   detection.md
+   instance_segmentation.md
+   semantic_segmentation.md

+ 85 - 0
docs/apis/models/instance_segmentation.md

@@ -0,0 +1,85 @@
+# 实例分割
+
+## MaskRCNN类
+
+```python
+paddlex.det.MaskRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_ratios=[0.5, 1.0, 2.0], anchor_sizes=[32, 64, 128, 256, 512])
+
+```
+
+> 构建MaskRCNN检测器。**注意在MaskRCNN中,num_classes需要设置为类别数+背景类,如目标包括human、dog两种,则num_classes需设为3,多的一种为背景background类别**
+
+> **参数**
+
+> > - **num_classes** (int): 包含了背景类的类别数。默认为81。
+> > - **backbone** (str): MaskRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd']。默认为'ResNet50'。
+> > - **with_fpn** (bool): 是否使用FPN结构。默认为True。
+> > - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
+> > - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
+
+#### train 训练接口
+
+```python
+train(self, num_epochs, train_dataset, train_batch_size=1, eval_dataset=None, save_interval_epochs=1, log_interval_steps=20, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=1.0/800, warmup_steps=500, warmup_start_lr=1.0 / 2400, lr_decay_epochs=[8, 11], lr_decay_gamma=0.1, metric=None, use_vdl=False, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
+```
+
+> MaskRCNN模型的训练接口,函数内置了`piecewise`学习率衰减策略和`momentum`优化器。
+
+> **参数**
+>
+> > - **num_epochs** (int): 训练迭代轮数。
+> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
+> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认为1。
+> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
+> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
+> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
+> > - **save_dir** (str): 模型保存路径。默认值为'output'。
+> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
+> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
+> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.00125。
+> > - **warmup_steps** (int):  默认优化器进行warmup过程的步数。默认为500。
+> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为1.0/2400。
+> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[8, 11]。
+> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
+> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
+> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
+> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
+> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
+> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
+
+#### evaluate 评估接口
+
+```python
+evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
+```
+
+> MaskRCNN模型的评估接口,模型评估后会返回在验证集上的指标box_mmap(metric指定为COCO时)和相应的seg_mmap。
+
+> **参数**
+>
+> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
+> > - **batch_size** (int): 验证数据批大小。默认为1。当前只支持设置为1。
+> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
+> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC'; 如为COCODetection,则`metric`为'COCO'。
+> > - **return_details** (bool): 是否返回详细信息。默认值为False。
+> >
+> **返回值**
+>
+> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当return_details为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'和'segm_mmap'或者’bbox_map‘和'segm_map',分别表示预测框和分割区域平均准确率平均值在各个IoU阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测框结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;'mask',对应元素预测区域结果列表,每个预测结果由图像id、预测区域类别id、预测区域坐标、预测区域得分;’gt‘:真实标注框和标注区域相关信息。
+
+#### predict 预测接口
+
+```python
+predict(self, img_file, transforms=None)
+```
+
+> MaskRCNN模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在FasterRCNN.test_transforms和FasterRCNN.eval_transforms中。如未在训练时定义eval_dataset,那在调用预测predict接口时,用户需要再重新定义test_transforms传入给predict接口。
+
+> **参数**
+>
+> > - **img_file** (str): 预测图像路径。
+> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
+>
+> **返回值**
+>
+> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key'bbox', 'mask', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、Mask信息,类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。

+ 175 - 0
docs/apis/models/semantic_segmentation.md

@@ -0,0 +1,175 @@
+# 语义分割
+
+## DeepLabv3p类
+
+```python
+paddlex.seg.DeepLabv3p(num_classes=2, backbone='MobileNetV2_x1.0', output_stride=16, aspp_with_sep_conv=True, decoder_use_sep_conv=True, encoder_with_aspp=True, enable_decoder=True, use_bce_loss=False, use_dice_loss=False, class_weight=None, ignore_index=255)
+
+```
+
+> 构建DeepLabv3p分割器。
+
+> **参数**
+
+> > - **num_classes** (int): 类别数。
+> > - **backbone** (str): DeepLabv3+的backbone网络,实现特征图的计算,取值范围为['Xception65', 'Xception41', 'MobileNetV2_x0.25', 'MobileNetV2_x0.5', 'MobileNetV2_x1.0', 'MobileNetV2_x1.5', 'MobileNetV2_x2.0'],'MobileNetV2_x1.0'。
+> > - **output_stride** (int): backbone 输出特征图相对于输入的下采样倍数,一般取值为8或16。默认16。
+> > - **aspp_with_sep_conv** (bool):  decoder模块是否采用separable convolutions。默认True。
+> > - **decoder_use_sep_conv** (bool): decoder模块是否采用separable convolutions。默认True。
+> > - **encoder_with_aspp** (bool): 是否在encoder阶段采用aspp模块。默认True。
+> > - **enable_decoder** (bool): 是否使用decoder模块。默认True。
+> > - **use_bce_loss** (bool): 是否使用bce loss作为网络的损失函数,只能用于两类分割。可与dice loss同时使用。默认False。
+> > - **use_dice_loss** (bool): 是否使用dice loss作为网络的损失函数,只能用于两类分割,可与bce loss同时使用,当`use_bce_loss`和`use_dice_loss`都为False时,使用交叉熵损失函数。默认False。
+> > - **class_weight** (list/str): 交叉熵损失函数各类损失的权重。当`class_weight`为list的时候,长度应为`num_classes`。当`class_weight`为str时, weight.lower()应为'dynamic',这时会根据每一轮各类像素的比重自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,即平时使用的交叉熵损失函数。
+> > - **ignore_index** (int): label上忽略的值,label为`ignore_index`的像素不参与损失函数的计算。默认255。
+
+### train 训练接口
+
+```python
+train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, eval_batch_size=1, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.01, lr_decay_power=0.9, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None):
+```
+
+> DeepLabv3p模型的训练接口,函数内置了`polynomial`学习率衰减策略和`momentum`优化器。
+
+> **参数**
+> >
+> > - **num_epochs** (int): 训练迭代轮数。
+> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
+> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认2。
+> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
+> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
+> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
+> > - **save_dir** (str): 模型保存路径。默认'output'
+> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认'IMAGENET'。
+> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认的优化器:使用fluid.optimizer.Momentum优化方法,polynomial的学习率衰减策略。
+> > - **learning_rate** (float): 默认优化器的初始学习率。默认0.01。
+> > - **lr_decay_power** (float): 默认优化器学习率衰减指数。默认0.9。
+> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认False。
+> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
+> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
+> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
+> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
+> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
+
+### evaluate 评估接口
+
+```python
+evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False):
+```
+
+> DeepLabv3p模型评估接口。
+
+>  **参数**
+> >
+> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
+> > - **batch_size** (int): 评估时的batch大小。默认1。
+> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
+> > - **return_details** (bool): 是否返回详细信息。默认False。
+
+> **返回值**
+> >
+> > - **dict**: 当`return_details`为False时,返回dict。包含关键字:'miou'、'category_iou'、'macc'、
+> >   'category_acc'和'kappa',分别表示平均iou、各类别iou、平均准确率、各类别准确率和kappa系数。
+> > - **tuple** (metrics, eval_details):当`return_details`为True时,增加返回dict (eval_details),
+> >   包含关键字:'confusion_matrix',表示评估的混淆矩阵。
+
+### predict 预测接口
+
+```
+predict(self, im_file, transforms=None):
+```
+
+> DeepLabv3p模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`DeepLabv3p.test_transforms`和`DeepLabv3p.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
+
+> **参数**
+> >
+> > - **img_file** (str): 预测图像路径。
+> > - **transforms** (paddlex.seg.transforms): 数据预处理操作。
+
+> **返回值**
+> >
+> > - **dict**: 包含关键字'label_map'和'score_map', 'label_map'存储预测结果灰度图,像素值表示对应的类别,'score_map'存储各类别的概率,shape=(h, w, num_classes)。
+
+## UNet类
+
+```python
+paddlex.seg.UNet(num_classes=2, upsample_mode='bilinear', use_bce_loss=False, use_dice_loss=False, class_weight=None, ignore_index=255)
+```
+
+> 构建UNet分割器。
+
+> **参数**
+
+> > - **num_classes** (int): 类别数。
+> > - **upsample_mode** (str): UNet decode时采用的上采样方式,取值为'bilinear'时利用双线行差值进行上菜样,当输入其他选项时则利用反卷积进行上菜样,默认为'bilinear'。
+> > - **use_bce_loss** (bool): 是否使用bce loss作为网络的损失函数,只能用于两类分割。可与dice loss同时使用。默认False。
+> > - **use_dice_loss** (bool): 是否使用dice loss作为网络的损失函数,只能用于两类分割,可与bce loss同时使用。当use_bce_loss和use_dice_loss都为False时,使用交叉熵损失函数。默认False。
+> > - **class_weight** (list/str): 交叉熵损失函数各类损失的权重。当`class_weight`为list的时候,长度应为`num_classes`。当`class_weight`为str时, weight.lower()应为'dynamic',这时会根据每一轮各类像素的比重自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,即平时使用的交叉熵损失函数。
+> > - **ignore_index** (int): label上忽略的值,label为`ignore_index`的像素不参与损失函数的计算。默认255。
+
+### train 训练接口
+
+```python
+train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, eval_batch_size=1, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='COCO', optimizer=None, learning_rate=0.01, lr_decay_power=0.9, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None):
+```
+
+> UNet模型训练接口。
+
+> **参数**
+> >
+> > - **num_epochs** (int): 训练迭代轮数。
+> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
+> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认2。
+> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
+> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
+> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
+> > - **save_dir** (str): 模型保存路径。默认'output'
+> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在COCO图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认'COCO'。
+> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认的优化器:使用fluid.optimizer.Momentum优化方法,polynomial的学习率衰减策略。
+> > - **learning_rate** (float): 默认优化器的初始学习率。默认0.01。
+> > - **lr_decay_power** (float): 默认优化器学习率衰减指数。默认0.9。
+> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认False。
+> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
+> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
+> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
+> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
+> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
+
+#### evaluate 评估接口
+
+```
+evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False):
+```
+
+> UNet模型评估接口。
+
+> **参数**
+> >
+> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
+> > - **batch_size** (int): 评估时的batch大小。默认1。
+> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
+> > - **return_details** (bool): 是否返回详细信息。默认False。
+
+> **返回值**
+> >
+> > - **dict**: 当return_details为False时,返回dict。包含关键字:'miou'、'category_iou'、'macc'、
+> >   'category_acc'和'kappa',分别表示平均iou、各类别iou、平均准确率、各类别准确率和kappa系数。
+> > - **tuple** (metrics, eval_details):当return_details为True时,增加返回dict (eval_details),
+> >   包含关键字:'confusion_matrix',表示评估的混淆矩阵。
+
+#### predict 预测接口
+
+```
+predict(self, im_file, transforms=None):
+```
+
+> UNet模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`UNet.test_transforms`和`UNet.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
+
+> **参数**
+> >
+> > - **img_file** (str): 预测图像路径。
+> > - **transforms** (paddlex.seg.transforms): 数据预处理操作。
+
+> **返回值**
+> >
+> > - **dict**: 包含关键字'label_map'和'score_map', 'label_map'存储预测结果灰度图,像素值表示对应的类别,'score_map'存储各类别的概率,shape=(h, w, num_classes)。

+ 1 - 1
docs/apis/slim.md

@@ -2,7 +2,7 @@
 
 ## 计算参数敏感度
 ```
-paddlex.slim.cal_params_sensetives(model, save_file, eval_dataset, batch_size=8)
+paddlex.slim.cal_params_sensitivities(model, save_file, eval_dataset, batch_size=8)
 ```
 计算模型中可裁剪参数在验证集上的敏感度,并将敏感度信息保存至文件`save_file`
 1. 获取模型中可裁剪卷积Kernel的名称。

+ 66 - 0
docs/apis/transforms/augment.md

@@ -0,0 +1,66 @@
+# 数据增强与imgaug支持
+
+数据增强操作可用于在模型训练时,增加训练样本的多样性,从而提升模型的泛化能力。
+
+## PaddleX内置增强操作
+
+PaddleX对于图像分类、目标检测、实例分割和语义分割内置了部分常见的数据增强操作,如下表所示,
+
+| 任务类型 | 增强方法     |
+| :------- | :------------|
+| 图像分类 | [RandomCrop](cls_transforms.html#randomcrop)、[RandomHorizontalFlip](cls_transforms.html#randomhorizontalflip)、[RandomVerticalFlip](cls_transforms.html#randomverticalflip)、 <br> [RandomRotate](cls_transforms.html#randomratate)、 [RandomDistort](cls_transforms.html#randomdistort) |
+|目标检测<br>实例分割| [RandomHorizontalFlip](det_transforms.html#randomhorizontalflip)、[RandomDistort](det_transforms.html#randomdistort)、[RandomCrop](det_transforms.html#randomcrop)、<br> [[MixupImage](det_transforms.html#mixupimage)(仅支持YOLOv3模型)、RandomExpand](det_transforms.html#randomexpand) |
+|语义分割  | [RandomHorizontalFlip](seg_transforms.html#randomhorizontalflip)、[RandomVerticalFlip](seg_transforms.html#randomverticalflip)、[RandomRangeScaling](seg_transforms.html#randomrangescaling)、<br> [RandomStepScaling](seg_transforms.html#randomstepscaling)、[RandomPaddingCrop](seg_transforms.html#randompaddingcrop)、 [RandomBlur](seg_transforms.html#randomblur)、<br> [RandomRotation](seg_transforms.html#randomrotation)、[RandomScaleAspect](seg_transforms.html#randomscaleaspect)、[RandomDistort](seg_transforms.html#randomdistort) |
+
+## imgaug增强库的支持
+
+PaddleX目前已适配imgaug图像增强库,用户可以直接在PaddleX构造`transforms`时,调用imgaug的方法, 如下示例
+```
+import paddlex as pdx
+from paddlex.cls import transforms
+import imgaug.augmenters as iaa
+train_transforms = transforms.Compose([
+    # 随机在[0.0 3.0]中选值对图像进行模糊
+    iaa.blur.GaussianBlur(sigma=(0.0, 3.0)),
+    transforms.RandomCrop(crop_size=224),
+    transforms.Normalize()
+])
+```
+除了上述用法,`Compose`接口中也支持imgaug的`Someof`、`Sometimes`、`Sequential`、`Oneof`等操作,开发者可以通过这些方法随意组合出增强流程。由于imgaug对于标注信息(目标检测框和实例分割mask)与PaddleX模型训练逻辑有部分差异,**目前在检测和分割中,只支持pixel-level的增强方法,(即在增强时,不对图像的大小和方向做改变) 其它方法仍在适配中**,详情可见下表,
+
+| 增强方法 | 图像分类 | 目标检测<br> 实例分割 | 语义分割 | 备注 |
+| :------  | :------- | :-------------------- | :------- | :--- |
+| [imgaug.augmenters.arithmetic](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_arithmetic.html) |√ |√ |√ | Cutout, DropoutJpegCompression等|
+| [imgaug.augmenters.artistic](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_artistic.html) |√ |√ |√ | 图像卡通化|
+| [imgaug.augmenters.blur](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_blur.html) |√ |√ |√ | GaussianBlur, AverageBlur等|
+| [imgaug.augmenters.collections](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_collections.html) |√ | | |提供了RandAugment方法 |
+| [imgaug.augmenters.color](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_color.html) |√ |√ |√ | Brightness, Hue等色调的增强方法|
+| [imgaug.augmenters.contrast](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_contrast.html) |√ |√ |√ | 多种对比度增强方式|
+| [imgaug.augmenters.convolutional](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_convolutional.html) |√ |√ |√ | 应用卷积kernel到图像 |
+| [imgaug.augmenters.edges](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_edges.html) |√ |√ |√ | 图像边缘化等方法|
+| [imgaug.augmenters.flip](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_flip.html) |√ | | | Fliplr和Flipud翻转方法|
+| [imgaug.augmenters.geometric](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_geometric.html) |√ | | | Affine、Rotate等增强方法|
+| [imgaug.augmenters.imgcorruptlike](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_imgcorruptlike.html) |√ |√ |√ | GaussianNoise等图像噪声增强方法|
+| [imgaug.augmenters.pillike](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_pillike.html) |√ | | | |
+| [imgaug.augmenters.pooling](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_pooling.html) |√ | | |应用pooling操作到图像 |
+| [imgaug.augmenters.segmentation](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_segmentation.html) |√ | | | 应用分割方法到图像|
+| [imgaug.augmenters.size](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_size.html) |√ | | | Reisze、Crop、Pad等操作|
+| [imgaug.augmenters.weather](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_weather.html) |√ |√ |√ | 多种模拟天气等增强方法|
+
+需要注意的是,imgaug的基础方法中,如`imgaug.augmenters.blur`仅为图像处理操作,并无概率设置,而在CV模型训练中,增强操作往往是以一定概率应用在样本上,因此我们可以通过imgaug的`Someof`、`Sometimes`、`Sequential`、`Oneof`等操作来组合实现,如下代码所示,
+> - `Someof` 执行定义增强方法列表中的部分方法
+> - `Sometimes` 以一定概率执行定义的增强方法列表
+> - `Sequential` 按顺序执行定义的增强方法列表
+```
+image imgaug.augmenters as iaa
+from paddlex.cls import transforms
+# 以0.6的概率对图像样本进行模糊
+img_augmenters = iaa.Sometimes(0.6, [
+    iaa.blur.GaussianBlur(sigma=(0.0, 3.0))
+])
+train_transforms = transforms.Compose([
+    img_augmenters,
+    transforms.RandomCrop(crop_size=224),
+    transforms.Normalize()
+])
+```

+ 1 - 1
docs/apis/transforms/cls_transforms.md

@@ -1,4 +1,4 @@
-# 分类-paddlex.cls.transforms
+# 图像分类-cls.transforms
 
 对图像分类任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。
 

+ 1 - 1
docs/apis/transforms/det_transforms.md

@@ -1,4 +1,4 @@
-# 检测-paddlex.det.transforms
+# 检测和实例分割-det.transforms
 
 对目标检测任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。
 

+ 1 - 0
docs/apis/transforms/index.rst

@@ -9,3 +9,4 @@ transforms为PaddleX的模型训练提供了数据的预处理和数据增强接
    cls_transforms.md
    det_transforms.md
    seg_transforms.md
+   augment.md

+ 1 - 1
docs/apis/transforms/seg_transforms.md

@@ -1,4 +1,4 @@
-# 分割-paddlex.seg.transforms
+# 语义分割-seg.transforms
 
 对用于分割任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。
 

+ 4 - 3
docs/apis/visualize.md → docs/apis/visualize.md

@@ -3,11 +3,12 @@ Anaconda是一个开源的Python发行版本,其包含了conda、Python等180
 
 ## Windows安装Anaconda
 ### 第一步 下载
-在Anaconda官网[(https://www.anaconda.com/products/individual)](https://www.anaconda.com/products/individual)选择下载Windows Python3.7 64-Bit版本
+- 在Anaconda官网[(https://www.anaconda.com/products/individual)](https://www.anaconda.com/products/individual)选择下载Windows Python3.7 64-Bit版本
+- 确保已经安装`Visual C++ Build Tools`(可以在开始菜单中找到),如未安装,请[点击下载](https://go.microsoft.com/fwlink/?LinkId=691126)安装。
 
 ### 第二步 安装
 运行下载的安装包(以.exe为后辍),根据引导完成安装, 用户可自行修改安装目录(如下图)
-![](./images/anaconda_windows.png)
+![](../images/anaconda_windows.png)
 
 ### 第三步 使用
 - 点击Windows系统左下角的Windows图标,打开:所有程序->Anaconda3/2(64-bit)->Anaconda Prompt  
@@ -21,7 +22,7 @@ conda activate my_paddlex
 conda install git
 # 安装pycocotools
 pip install cython
-pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI
+pip install git+https://gitee.com/jiangjiajun/philferriere-cocoapi.git#subdirectory=PythonAPI
 # 安装paddlepaddle-gpu
 pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
 # 安装paddlex

+ 0 - 0
docs/gpu_configure.md → docs/appendix/gpu_configure.md


+ 0 - 0
docs/how_to_offline_run.md → docs/appendix/how_to_offline_run.md


+ 17 - 0
docs/appendix/index.rst

@@ -0,0 +1,17 @@
+附录
+=======================================
+
+
+.. toctree::
+   :maxdepth: 1
+   :caption: 目录:
+
+   model_zoo.md
+   metrics.md
+
+* PaddleX版本: v0.1.7
+* 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex  
+* 项目GitHub: https://github.com/PaddlePaddle/PaddleX/tree/develop  
+* 官方QQ用户群: 1045148026  
+* GitHub Issue反馈: http://www.github.com/PaddlePaddle/PaddleX/issues
+

+ 13 - 13
docs/metrics.md → docs/appendix/metrics.md

@@ -1,4 +1,4 @@
-# 指标及日志含义
+# PaddleX指标及日志
 
 PaddleX在模型训练、评估过程中,都会有相应的日志和指标反馈,本文档用于说明这些日志和指标的含义。
 
@@ -6,7 +6,7 @@ PaddleX在模型训练、评估过程中,都会有相应的日志和指标反
 
 PaddleX所有模型在训练过程中,输出的日志信息都包含了6个通用的统计信息,用于辅助用户进行模型训练,例如**分割模型**的训练日志,如下图所示。
 
-![](./images/seg_train.png)
+![](../images/seg_train.png)
 
 各字段含义如下:
 
@@ -26,7 +26,7 @@ PaddleX所有模型在训练过程中,输出的日志信息都包含了6个通
 
 PaddleX所有模型在训练过程中会根据用户设定的`save_interval_epochs`参数,每间隔一定轮数进行评估和保存。例如**分类模型**的评估日志,如下图所示。
 
-![](images/cls_eval.png)
+![](../images/cls_eval.png)
 
 上图中第1行表明验证数据集中样本数为240,需要迭代8步才能评估完所有验证数据;第5行用于表明第2轮的模型已经完成保存操作;第6行则表明当前保存的模型中,第2轮的模型在验证集上指标最优(分类任务看`acc1`,此时`acc1`值为0.258333),最优模型会保存在`best_model`目录中。
 
@@ -38,7 +38,7 @@ PaddleX所有模型在训练过程中会根据用户设定的`save_interval_epoc
 
 > 注: acck准确率是针对一张图片进行计算的:把模型在各个类别上的预测得分按从高往低进行排序,取出前k个预测类别,若这k个预测类别包含了真值类,则认为该图片分类正确。
 
-![](images/cls_train.png)
+![](../images/cls_train.png)
 
 
 上图中第1行中的`acc1`表示参与当前迭代步数的训练样本的平均top1准确率,值越高代表模型越优;`acc5`表示参与当前迭代步数的训练样本的平均top5(若类别数n少于5,则为topn)准确率,值越高代表模型越优。第4行中的`loss`表示整个训练集的平均损失函数值,`acc1`表示整个训练集的平均top1准确率,`acc5`表示整个训练集的平均top5准确率。
@@ -46,7 +46,7 @@ PaddleX所有模型在训练过程中会根据用户设定的`save_interval_epoc
 
 ### 评估日志字段
 
-![](images/cls_eval.png)
+![](../images/cls_eval.png)
 
 上图中第3行中的`acc1`表示整个验证集的平均top1准确率,`acc5`表示整个验证集的平均top5准确率。
 
@@ -59,7 +59,7 @@ PaddleX所有模型在训练过程中会根据用户设定的`save_interval_epoc
 
 YOLOv3的训练日志只包括训练通用统计信息(见上文训练通用统计信息)。
 
-![](images/yolo_train.png)
+![](../images/yolo_train.png)
 
 上图中第5行`loss`表示整个训练集的平均损失函数loss值。
 
@@ -75,7 +75,7 @@ FasterRCNN的训练日志除了通用统计信息外,还包括`loss_cls`、`lo
 | loss_rpn_bbox      | RPN子网络中检测框回归损失函数值  |
 | loss              | 所有子网络损失函数值之和          |
 
-![](images/faster_train.png)
+![](../images/faster_train.png)
 
 上图中第1行`loss`, `loss_cls`、`loss_bbox`、`loss_rpn_clss`、`loss_rpn_bbox`都是参与当前迭代步数的训练样本的损失值,而第7行是针整个训练集的损失函数值。
 
@@ -93,7 +93,7 @@ MaskRCNN的训练日志除了通用统计信息外,还包括`loss_cls`、`loss
 | loss_rpn_bbox      | RPN子网络中检测框回归损失函数值  |
 | loss              | 所有子网络损失函数值之和          |
 
-![](images/mask_train.png)
+![](../images/mask_train.png)
 
 上图中第1行`loss`, `loss_cls`、`loss_bbox`、`loss_mask`、`loss_rpn_clss`、`loss_rpn_bbox`都是参与当前迭代步数的训练样本的损失值,而第7行是针整个训练集的损失函数值。
 
@@ -103,7 +103,7 @@ MaskRCNN的训练日志除了通用统计信息外,还包括`loss_cls`、`loss
 
 #### VOC评估标准
 
-![](images/voc_eval.png)
+![](../images/voc_eval.png)
 
 > 注:`map`为平均准确率的平均值,即IoU(Intersection Over Union)取0.5时各个类别的准确率-召回率曲线下面积的平均值。
 
@@ -115,11 +115,11 @@ MaskRCNN的训练日志除了通用统计信息外,还包括`loss_cls`、`loss
 
 COCO格式的数据集不仅可以用于训练目标检测模型,也可以用于训练实例分割模型。在目标检测中,PaddleX主要反馈针对检测框的`bbox_mmAP`指标;在实例分割中,还包括针对Mask的`seg_mmAP`指标。如下所示,第一张日志截图为目标检测的评估结果,第二张日志截图为实例分割的评估结果。
 
-![](images/faster_eval.png)
+![](../images/faster_eval.png)
 
 上图中红框标注的`bbox_mmap`表示整个验证集的检测框平均准确率平均值。
 
-![](images/mask_eval.png)
+![](../images/mask_eval.png)
 上图中红框标注的`bbox_mmap`和`seg_mmap`分别表示整个验证集的检测框平均准确率平均值、Mask平均准确率平均值。
 
 ## 分割特有统计信息
@@ -128,7 +128,7 @@ COCO格式的数据集不仅可以用于训练目标检测模型,也可以用
 
 语义分割的训练日志只包括训练通用统计信息(见上文训练通用统计信息)。
 
-![](images/seg_train.png)
+![](../images/seg_train.png)
 
 ### 评估日志字段
 
@@ -142,4 +142,4 @@ COCO格式的数据集不仅可以用于训练目标检测模型,也可以用
 | category_acc       | 各类别的准确率,即各类别预测正确的像素数/预测为该类别的总像素数  |
 | kappa      | kappa系数,用于一致性检验  |
 
-![](images/seg_eval.png)
+![](../images/seg_eval.png)

+ 1 - 21
docs/model_zoo.md → docs/appendix/model_zoo.md

@@ -1,7 +1,4 @@
-# 模型库
-本文档梳理了PaddleX v0.1.0支持的模型,同时也提供了在各个数据集上的预训练模型和对应验证集上的指标。用户也可自行下载对应的代码,在安装PaddleX后,即可使用相应代码训练模型。
-
-表中相关模型也可下载好作为相应模型的预训练模型,通过`pretrain_weights`指定目录加载使用。
+# PaddleX模型库
 
 ## 图像分类模型
 > 表中模型相关指标均为在ImageNet数据集上使用PaddlePaddle Python预测接口测试得到(测试GPU型号为Nvidia Tesla P40),预测速度为每张图片预测用时(不包括预处理和后处理),表中符号`-`表示相关指标暂未测试。
@@ -53,20 +50,3 @@
 
 > 表中模型相关指标均为在MSCOCO数据集上测试得到。
 
-| 模型 |模型大小 | 预测时间(毫秒) | BoxAP | SegAP(%) |
-|:---------|:---------|:----------|:---------|:--------|
-|MaskRCNN-ResNet50|51.2MB| 86.096 | 36.5 |32.2|
-|MaskRCNN-ResNet50-FPN|184.6MB | 65.859 | 37.9 |34.2|
-|MaskRCNN-ResNet50_vd-FPN |185.5MB | 63.191 | 39.8 |35.4|
-|MaskRCNN-ResNet101-FPN|268.6MB | 77.024 | 39.5 |35.2|
-|MaskRCNN-ResNet101vd-FPN |268.6MB | 76.307 | 41.4 |36.8|
-
-## 语义分割模型
-
-> 表中符号`-`表示相关指标暂未测试。
-
-| 模型| 模型大小 | 预测速度 | mIOU |
-|:--------|:----------|:----------|:----------|
-| UNet|53.7M | - |-|
-| DeepLabv3+/Xception65| 165.1M |- | 0.7930 |
-| DeepLabv3+/MobileNetV2 | 7.4M | - | 0.6981 |

+ 0 - 75
docs/client_use.md

@@ -1,75 +0,0 @@
-# 使用PaddleX客户端进行模型训练
-
-**第一步:下载PaddleX客户端**
-
-您需要前往 [官网](https://www.paddlepaddle.org.cn/paddle/paddlex)填写基本信息后下载试用PaddleX客户端
-
-
-**第二步:准备数据**
-
-在开始模型训练前,您需要根据不同的任务类型,将数据标注为相应的格式。目前PaddleX支持【图像分类】、【目标检测】、【语义分割】、【实例分割】四种任务类型。不同类型任务的数据处理方式可查看[数据标注方式](https://github.com/PaddlePaddle/PaddleX/tree/master/DataAnnotation/AnnotationNote)。
-
-
-**第三步:导入我的数据集**
-
-① 数据标注完成后,您需要根据不同的任务,将数据和标注文件,按照客户端提示更名并保存到正确的文件中。
-
-② 在客户端新建数据集,选择与数据集匹配的任务类型,并选择数据集对应的路径,将数据集导入。
-
-![](./images/00_loaddata.png)
-
-③ 选定导入数据集后,客户端会自动校验数据及标注文件是否合规,校验成功后,您可根据实际需求,将数据集按比例划分为训练集、验证集、测试集。
-
-④ 您可在「数据分析」模块按规则预览您标注的数据集,双击单张图片可放大查看。
-
-![](./images/01_datasplit.png)
-
-
-
-**第四步:创建项目**
-
-① 在完成数据导入后,您可以点击「新建项目」创建一个项目。
-
-② 您可根据实际任务需求选择项目的任务类型,需要注意项目所采用的数据集也带有任务类型属性,两者需要进行匹配。
-
-![](./images/02_newproject.png)
-
-
-
-**第五步:项目开发**
-
-① **数据选择**:项目创建完成后,您需要选择已载入客户端并校验后的数据集,并点击下一步,进入参数配置页面。
-
-![](./images/03_choosedata.png)
-
-② **参数配置**:主要分为**模型参数**、**训练参数**、**优化策略**三部分。您可根据实际需求选择模型结构及对应的训练参数、优化策略,使得任务效果最佳。
-
-![](./images/04_parameter.png)
-
-参数配置完成后,点击启动训练,模型开始训练并进行效果评估。
-
-③ **训练可视化**:
-
-在训练过程中,您可通过VisualDL查看模型训练过程时的参数变化、日志详情,及当前最优的训练集和验证集训练指标。模型在训练过程中通过点击"终止训练"随时终止训练过程。
-
-![](./images/05_train.png)
-
-![](./images/06_VisualDL.png)
-
-模型训练结束后,点击”下一步“,进入模型评估页面。
-
-
-
-④ **模型评估**
-
-在模型评估页面,您可将训练后的模型应用在切分时留出的「验证数据集」以测试模型在验证集上的效果。评估方法包括混淆矩阵、精度、召回率等。在这个页面,您也可以直接查看模型在测试数据集上的预测效果。
-
-根据评估结果,您可决定进入模型发布页面,或返回先前步骤调整参数配置重新进行训练。
-
-![](./images/07_evaluate.png)
-
-⑤**模型发布**
-
-当模型效果满意后,您可根据实际的生产环境需求,选择将模型发布为需要的版本。
-
-![](./images/08_deploy.png)

+ 0 - 17
docs/conf.py

@@ -1,17 +0,0 @@
-# 模型转换
-
-## 转ONNX模型
-PaddleX基于[Paddle2ONNX工具](https://github.com/PaddlePaddle/paddle2onnx),提供了便捷的API,支持用户将PaddleX训练保存的模型导出为ONNX模型。
-通过如下示例代码,用户即可将PaddleX训练好的MobileNetV2模型导出
-```
-import paddlex as pdx
-pdx.convertor.to_onnx(model_dir='paddle_mobilenet', save_dir='onnx_mobilenet')
-```
-
-## 转PaddleLite模型
-PaddleX可支持导出为[PaddleLite](https://github.com/PaddlePaddle/Paddle-Lite)支持的模型格式,用于支持用户将模型部署更多硬件设备。
-通过如下示例代码,用户即可将PaddleX训练好的MobileNetV2模型导出
-```
-import paddlex as pdx
-pdx.convertor.to_lite(model_dir='paddle_mobilenet', save_dir='lite_mobilnet', terminal='arm')
-```

+ 63 - 0
docs/cv_solutions.md

@@ -0,0 +1,63 @@
+# PaddleX视觉方案介绍  
+
+PaddleX目前提供了4种视觉任务解决方案,分别为图像分类、目标检测、实例分割和语义分割。用户可以根据自己的任务类型按需选取。
+
+## 图像分类
+图像分类任务指的是输入一张图片,模型预测图片的类别,如识别为风景、动物、车等。
+
+![](./images/image_classification.png)
+
+对于图像分类任务,针对不同的应用场景,PaddleX提供了百度改进的模型,见下表所示
+
+|    模型    | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | 准确率 | 备注 |
+| :--------- | :------  | :---------- | :-----------| :-------------  | :----- | :--- |
+| MobileNetV3_small_ssld | 12M | ? | ? | ? | 71.3% |适用于移动端场景 |
+| MobileNetV3_large_ssld | 21M | ? | ? | ? | 79.0% | 适用于移动端/服务端场景 |
+| ResNet50_vd_ssld | 102.8MB | ? | ? | ? | 82.4% | 适用于服务端场景 |
+| ResNet101_vd_ssld | 179.2MB | ? | ? | ? |83.7% | 适用于服务端场景 |
+
+除上述模型外,PaddleX还支持近20种图像分类模型,模型列表可参考[PaddleX模型库](../appendix/model_zoo.md)
+
+
+## 目标检测
+目标检测任务指的是输入图像,模型识别出图像中物体的位置(用矩形框框出来,并给出框的位置),和物体的类别,如在手机等零件质检中,用于检测外观上的瑕疵等。
+
+![](./images/object_detection.png)
+
+对于目标检测,针对不同的应用场景,PaddleX提供了主流的YOLOv3模型和Faster-RCNN模型,见下表所示
+
+|   模型   | 模型大小  | GPU预测速度 | CPU预测速度 |ARM芯片预测速度 | BoxMAP | 备注 |
+| :------- | :-------  | :---------  | :---------- | :-------------  | :----- | :--- |
+| YOLOv3-MobileNetV1 | 101.2M | ? | ? | ? | 29.3 | |
+| YOLOv3-MobileNetV3 | 94.6M | ? | ? | ? | 31.6 | |
+| YOLOv3-ResNet34 | 169.7M | ? | ? | ? | 36.2 | |
+| YOLOv3-DarkNet53 | 252.4 | ? | ? | ? | 38.9 | |
+
+除YOLOv3模型外,PaddleX同时也支持FasterRCNN模型,支持FPN结构和5种backbone网络,详情可参考[PaddleX模型库](../appendix/model_zoo.md)
+
+## 实例分割
+在目标检测中,模型识别出图像中物体的位置和物体的类别。而实例分割则是在目标检测的基础上,做了像素级的分类,将框内的属于目标物体的像素识别出来。
+
+![](./images/instance_segmentation.png)
+
+PaddleX目前提供了实例分割MaskRCNN模型,支持5种不同的backbone网络,详情可参考[PaddleX模型库](../appendix/model_zoo.md)
+
+|  模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | BoxMAP | SegMAP | 备注 |
+| :---- | :------- | :---------- | :---------- | :-------------  | :----- | :----- | :--- |
+| MaskRCNN-ResNet50_vd-FPN | 185.5M | ? | ? | ? | 39.8 | 35.4 | |
+| MaskRCNN-ResNet101_vd-FPN | 268.6M | ? | ? | ? | 41.4 | 36.8 | |
+
+
+## 语义分割
+语义分割用于对图像做像素级的分类,应用在人像分类、遥感图像识别等场景。  
+
+![](./images/semantic_segmentation.png)
+
+对于语义分割,PaddleX也针对不同的应用场景,提供了不同的模型选择,如下表所示
+
+| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | mIOU | 备注 |
+| :---- | :------- | :---------- | :---------- | :-------------  | :----- | :----- |
+| DeepLabv3p-MobileNetV2_x0.25 | | ? | ? | ? | ? | ? |
+| DeepLabv3p-MobileNetV2_x1.0 | | ? | ? | ? | ? | ? |
+| DeepLabv3p-Xception65 | | ? | ? | ? | ? | ? |
+| UNet | | ? | ? | ? | ? | ? |

BIN
docs/images/._文件(p37) BDSZYF000132754-docs jiangjiajun$ pwd :Users:jiangjiajun:Downloads:PaddleX-develop:docs:vdl1.png


+ 0 - 0
docs/images/00_loaddata.png → docs/images/00_loaddata.png


BIN
docs/images/anaconda_windows.png


BIN
docs/images/instance_segmentation.png


BIN
docs/images/mask_eval.png


+ 0 - 0
docs/images/paddlex.jpg → docs/images/paddlex.jpg


BIN
docs/images/seg_eval.png


BIN
docs/images/vdl1.jpg


BIN
docs/images/vdl2.jpg


BIN
docs/images/vdl3.jpg


BIN
docs/images/visualized_deeplab.jpg


+ 22 - 13
docs/index.rst

@@ -1,28 +1,37 @@
 欢迎使用PaddleX!
 =======================================
 
-PaddleX是基于飞桨技术生态的深度学习全流程开发工具。具备易集成,易使用,全流程等特点。PaddleX作为深度学习开发工具,不仅提供了开源的内核代码,可供用户灵活使用或集成,同时也提供了配套的前端可视化客户端套件,让用户以可视化地方式进行模型开发,相关细节可查阅PaddleX官网
+PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习全流程开发工具。具备 **全流程打通** 、**融合产业实践** 、**易用易集成** 三大特点
 
-本文档为PaddleX内核代码使用手册
+
+全流程打通 
+  | - **数据准备**: 支持LabelMe,精灵标注等主流数据标注工具协议,同时无缝集成 `EasyData智能数据服务平台 <https://ai.baidu.com/easydata/>`_ ,助力开发者高效获取AI开发所需高质量数据。
+  | - **模型训练**: 基于飞桨核心框架集成 `PaddleClas <https://github.com/PaddlePaddle/PaddleClas>`_ ,`PaddleDetection <https://github.com/PaddlePaddle/PaddleDetection>`_ ,`PaddleSeg <https://github.com/PaddlePaddle/PaddleSeg>`_ 视觉开发套件 ,`VisualDL <https://github.com/PaddlePaddle/VisualDL>`_ 可视化分析组件,高效完成模型训练。
+  | _ **多端部署**: 内置 `PaddleSlim <https://github.com/PaddlePaddle/PaddleSlim>`_ 模型压缩工具和AES模型加密SDK,结合Paddle Inference和 `Paddle Lite <https://github.com/PaddlePaddle/Paddle-Lite>`_ 便捷完成高性能且可靠的多端部署。
+
+融合产业实践
+  | - 精选飞桨产业实践的成熟模型结构,开放案例实践教程,加速开发者产业落地。
+  | - 通过 `PaddleHub <https://github.com/PaddlePaddle/PaddleHub>`_ 内置丰富的飞桨高质量预训练模型,助力开发者高效实现飞桨Master模式。
+
+易用易集成
+  | - PadldeX提供简洁易用的全流程API,几行代码即可实现上百种数据增强、模型可解释性、C++模型部署等功能。
+  | - 提供以PaddleX API为核心集成的跨平台GUI界面,降低深度学习全流程应用门槛。
 
 .. toctree::
-   :maxdepth: 1
-   :caption: 目录:
+   :maxdepth: 2
+   :caption: 文档目录:
 
    quick_start.md
    install.md
-   model_zoo.md
-   slim/index
-   apis/index
-   datasets.md 
-   gpu_configure.md
    tutorials/index.rst
-   metrics.md
-   deploy.md
-   client_use.md
+   cv_solutions.md
+   apis/index.rst
+   paddlex_gui/index.rst
+   update.md
    FAQ.md
+   appendix/index.rst
 
-* PaddleX版本: v0.1.6
+* PaddleX版本: v0.1.7
 * 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex  
 * 项目GitHub: https://github.com/PaddlePaddle/PaddleX/tree/develop  
 * 官方QQ用户群: 1045148026  

+ 13 - 9
docs/install.md

@@ -1,34 +1,38 @@
-# 安装
+# 快速安装
 
 以下安装过程默认用户已安装好**paddlepaddle-gpu或paddlepaddle(版本大于或等于1.7.1)**,paddlepaddle安装方式参照[飞桨官网](https://www.paddlepaddle.org.cn/install/quick)
 
-> 推荐使用Anaconda Python环境,Anaconda下安装PaddleX参考文档[Anaconda安装使用](./anaconda_install.md)
+> 推荐使用Anaconda Python环境,Anaconda下安装PaddleX参考文档[Anaconda安装使用](../appendix/anaconda_install.md)
 
-## Github代码安装
-github代码会跟随开发进度不断更新
+## pip安装
 
 > 注意其中pycocotools在Windows安装较为特殊,可参考下面的Windows安装命令  
 
 ```
+pip install paddlex -i https://mirror.baidu.com/pypi/simple
+```
+
+
+## Github代码安装
+github代码会跟随开发进度不断更新
+
+```
 git clone https://github.com/PaddlePaddle/PaddleX.git
 cd PaddleX
 git checkout develop
 python setup.py install
 ```
 
-## pip安装
-```
-pip install paddlex -i https://mirror.baidu.com/pypi/simple
-```
 
 ## 安装问题
 ### 1. pycocotools安装问题  
 > PaddleX依赖pycocotools包,如安装pycocotools失败,可参照如下方式安装pycocotools
 
 **Windows**  
+> Windows安装时可能会提示缺少`Microsoft Visual C++ 2015 build tools`,[点击下载](https://go.microsoft.com/fwlink/?LinkId=691126)安装再执行如下pip命令
 ```
 pip install cython
-pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI
+pip install git+https://gitee.com/jiangjiajun/philferriere-cocoapi.git#subdirectory=PythonAPI
 ```
 
 **Linux/Mac安装**

+ 1 - 0
docs/make.bat

@@ -0,0 +1 @@
+# PaddleX GUI下载安装

+ 1 - 0
docs/paddlex_gui/how_to_use.md

@@ -0,0 +1 @@
+# PaddleX GUI如何训练模型

+ 29 - 0
docs/paddlex_gui/index.rst

@@ -0,0 +1,29 @@
+PaddleX GUI使用文档
+=======================================
+
+PaddleX GUI是基于PaddleX开发实现的可视化模型训练套件,可以让开发者免去代码开发的步骤,通过点选式地操作就可以快速完成模型的训练开发。PaddleXGUI具有 **数据集可视化分析** 、**模型参数自动推荐** 、**跨平台使用** 三大特点。
+
+数据集可视化分析
+  | PaddleX支持导入常见的图像分类、目标检测、实例分割和语义分割数据集,并对数据集的样本分布,标注结果进行可视化展示,数据集的情况一目了然!
+
+模型参数自动推荐
+  | 根据用户的电脑配置和数据集情况,自动推荐模型训练参数,免去用户查看文档,被各种参数所烦的忧心事!
+
+跨平台使用
+  | PaddleX GUI完全跨平台,支持Linux、Windows和Mac三大主流系统!
+
+
+.. toctree::
+   :maxdepth: 2
+   :caption: 文档目录:
+
+   download.md
+   how_to_use.md
+   xx.md
+
+* PaddleX版本: v0.1.7
+* 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex  
+* 项目GitHub: https://github.com/PaddlePaddle/PaddleX/tree/develop  
+* 官方QQ用户群: 1045148026  
+* GitHub Issue反馈: http://www.github.com/PaddlePaddle/PaddleX/issues
+

+ 1 - 0
docs/paddlex_gui/xx.md

@@ -0,0 +1 @@
+# 其它

+ 19 - 10
docs/quick_start.md

@@ -2,22 +2,31 @@
 
 本文档在一个小数据集上展示了如何通过PaddleX进行训练,您可以阅读PaddleX的**使用教程**来了解更多模型任务的训练使用方式。本示例同步在AIStudio上,可直接[在线体验模型训练](https://aistudio.baidu.com/aistudio/projectdetail/439860)
 
-## 1. 准备蔬菜分类数据集
+
+## 1. 安装PaddleX
+> 安装相关过程和问题可以参考PaddleX的[安装文档](./install.md)。
 ```
-wget https://bj.bcebos.com/paddlex/datasets/vegetables_cls.tar.gz
-tar xzvf vegetables_cls.tar.gz
+pip install paddlex -i https://mirror.baidu.com/pypi/simple
 ```
 
-## 2. 训练代码开发
-通过如下`train.py`代码进行训练
-> 设置使用0号GPU卡
+## 2. 准备蔬菜分类数据集
 ```
-import os
-os.environ['CUDA_VISIBLE_DEVICES'] = '0'
-import paddlex as pdx
+wget https://bj.bcebos.com/paddlex/datasets/vegetables_cls.tar.gz
+tar xzvf vegetables_cls.tar.gz
 ```
 
-> 定义训练和验证时的数据处理流程, 在`train_transforms`中加入了`RandomCrop`和`RandomHorizontalFlip`两种数据增强方式
+## 3. 训练代码开发
+PaddleX的所有模型训练和预测均只涉及到5个API接口,分别是
+> - [transforms](apis/transforms/index) 图像数据处理
+> - [datasets](apis/datasets.md) 数据集加载
+> - [models](apis/models.md) 模型类型定义
+> - [train](apis/models.md) 开始训练
+> - [predict](apis/models.md) 模型预测 
+ 
+在本示例,通过如下`train.py`代码进行训练, 训练环境为1张Tesla P40 GPU卡。  
+
+### 3.1 定义`transforms`数据处理流程
+由于训练时数据增强操作的加入,因此模型在训练和验证过程中,数据处理流程需要分别进行定义。如下所示,代码在`train_transforms`中加入了[RandomCrop](apis/transforms/cls_transforms.html#RandomCrop)和[RandomHorizontalFlip](apis/transforms/cls_transforms.html#RandomHorizontalFlip)两种数据增强方式
 ```
 from paddlex.cls import transforms
 train_transforms = transforms.Compose([

+ 0 - 0
docs/requirements.txt → docs/requirements.txt


+ 0 - 0
docs/slim/prune.md → docs/tutorials/compress/slim/prune.md


+ 0 - 0
docs/slim/quant.md → docs/tutorials/compress/slim/quant.md


+ 7 - 0
docs/tutorials/dataset_prepare.md

@@ -0,0 +1,7 @@
+# 数据准备
+
+## 数据标注
+
+## 主流标注软件支持
+
+## EasyData数据标注支持

+ 0 - 0
docs/datasets.md → docs/tutorials/datasets.md


+ 68 - 0
docs/tutorials/deploy/deploy.md

@@ -0,0 +1,68 @@
+# 模型预测部署
+
+本文档指引用户如何采用更高性能地方式来部署使用PaddleX训练的模型。使用本文档模型部署方式,会在模型运算过程中,对模型计算图进行优化,同时减少内存操作,相对比普通的paddlepaddle模型加载和预测方式,预测速度平均可提升1倍,具体各模型性能对比见[预测性能对比](#预测性能对比)
+
+## 服务端部署
+
+### 导出inference模型
+
+在服务端部署的模型需要首先将模型导出为inference格式模型,导出的模型将包括`__model__`、`__params__`和`model.yml`三个文名,分别为模型的网络结构,模型权重和模型的配置文件(包括数据预处理参数等等)。在安装完PaddleX后,在命令行终端使用如下命令导出模型到当前目录`inferece_model`下。
+> 可直接下载小度熊分拣模型测试本文档的流程[xiaoduxiong_epoch_12.tar.gz](https://bj.bcebos.com/paddlex/models/xiaoduxiong_epoch_12.tar.gz)
+
+```
+paddlex --export_inference --model_dir=./xiaoduxiong_epoch_12 --save_dir=./inference_model
+```
+
+使用TensorRT预测时,需指定模型的图像输入shape:[w,h]。
+**注**:
+- 分类模型请保持于训练时输入的shape一致。
+- 指定[w,h]时,w和h中间逗号隔开,不允许存在空格等其他字符
+
+```
+paddlex --export_inference --model_dir=./xiaoduxiong_epoch_12 --save_dir=./inference_model --fixed_input_shape=[640,960]
+```
+
+### Python部署
+PaddleX已经集成了基于Python的高性能预测接口,在安装PaddleX后,可参照如下代码示例,进行预测。相关的接口文档可参考[paddlex.deploy](apis/deploy.md)
+> 点击下载测试图片 [xiaoduxiong_test_image.tar.gz](https://bj.bcebos.com/paddlex/datasets/xiaoduxiong_test_image.tar.gz)
+
+```
+import paddlex as pdx
+predictor = pdx.deploy.create_predictor('./inference_model')
+result = predictor.predict(image='xiaoduxiong_test_image/JPEGImages/WeChatIMG110.jpeg')
+```
+
+### C++部署
+
+C++部署方案位于目录`deploy/cpp/`下,且独立于PaddleX其他模块。该方案支持在 Windows 和 Linux 完成编译、二次开发集成和部署运行。具体使用方法和编译:
+
+- Linux平台:[linux](deploy_cpp_linux.md)
+- window平台:[windows](deploy_cpp_win_vs2019.md)
+
+### 预测性能对比
+
+#### 测试环境
+
+- CUDA 9.0
+- CUDNN 7.5
+- PaddlePaddle 1.71
+- GPU: Tesla P40
+- AnalysisPredictor 指采用Python的高性能预测方式
+- Executor 指采用paddlepaddle普通的python预测方式
+- Batch Size均为1,耗时单位为ms/image,只计算模型运行时间,不包括数据的预处理和后处理
+
+| 模型 | AnalysisPredictor耗时 | Executor耗时 | 输入图像大小 |
+| :---- | :--------------------- | :------------ | :------------ |
+| resnet50 | 4.84 | 7.57 | 224*224 |
+| mobilenet_v2 | 3.27 | 5.76 | 224*224 |
+| unet | 22.51 | 34.60 |513*513 |
+| deeplab_mobile | 63.44 | 358.31 |1025*2049 |
+| yolo_mobilenetv2 | 15.20 | 19.54 |  608*608 |
+| faster_rcnn_r50_fpn_1x | 50.05 | 69.58 |800*1088 |
+| faster_rcnn_r50_1x | 326.11 | 347.22 | 800*1067 |
+| mask_rcnn_r50_fpn_1x | 67.49 | 91.02 | 800*1088 |
+| mask_rcnn_r50_1x | 326.11 | 350.94 | 800*1067 |
+
+## 移动端部署
+
+> Lite模型导出正在集成中,即将开源...

+ 136 - 0
docs/tutorials/deploy/deploy_cpp_linux.md

@@ -0,0 +1,136 @@
+# Linux平台编译指南
+
+## 说明
+本文档在 `Linux`平台使用`GCC 4.8.5` 和 `GCC 4.9.4`测试过,如果需要使用更高G++版本编译使用,则需要重新编译Paddle预测库,请参考: [从源码编译Paddle预测库](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html#id12)。
+
+## 前置条件
+* G++ 4.8.2 ~ 4.9.4
+* CUDA 9.0 / CUDA 10.0, CUDNN 7+ (仅在使用GPU版本的预测库时需要)
+* CMake 3.0+
+
+请确保系统已经安装好上述基本软件,**下面所有示例以工作目录 `/root/projects/`演示**。
+
+### Step1: 下载代码
+
+ `git clone https://github.com/PaddlePaddle/PaddleX.git`
+
+**说明**:其中`C++`预测代码在`/root/projects/PaddleX/deploy/cpp` 目录,该目录不依赖任何`PaddleX`下其他目录。
+
+
+### Step2: 下载PaddlePaddle C++ 预测库 fluid_inference
+
+PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持TensorRT,提供了不同的预编译版本,目前PaddleX依赖于Paddle1.7版本,以下提供了多个不同版本的Paddle预测库:
+
+|  版本说明   | 预测库(1.7.2版本)  |
+|  ----  | ----  |
+| ubuntu14.04_cpu_avx_mkl  | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.7.2-cpu-avx-mkl/fluid_inference.tgz) |
+| ubuntu14.04_cpu_avx_openblas  | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.7.2-cpu-avx-openblas/fluid_inference.tgz) |
+| ubuntu14.04_cpu_noavx_openblas  | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.7.2-cpu-noavx-openblas/fluid_inference.tgz) |
+| ubuntu14.04_cuda9.0_cudnn7_avx_mkl  | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.7.2-gpu-cuda9-cudnn7-avx-mkl/fluid_inference.tgz) |
+| ubuntu14.04_cuda10.0_cudnn7_avx_mkl  | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.7.2-gpu-cuda10-cudnn7-avx-mkl/fluid_inference.tgz ) |
+| ubuntu14.04_cuda10.1_cudnn7.6_avx_mkl_trt6  | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.7.2-gpu-cuda10.1-cudnn7.6-avx-mkl-trt6%2Ffluid_inference.tgz) |
+
+更多和更新的版本,请根据实际情况下载:  [C++预测库下载列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_guide/inference_deployment/inference/windows_cpp_inference.html#id1)
+
+下载并解压后`/root/projects/fluid_inference`目录包含内容为:
+```
+fluid_inference
+├── paddle # paddle核心库和头文件
+|
+├── third_party # 第三方依赖库和头文件
+|
+└── version.txt # 版本和编译信息
+```
+
+**注意:** 预编译版本除`nv-jetson-cuda10-cudnn7.5-trt5` 以外其它包都是基于`GCC 4.8.5`编译,使用高版本`GCC`可能存在 `ABI`兼容性问题,建议降级或[自行编译预测库](https://www.paddlepaddle.org.cn/documentation/docs/zh/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html#id12)。
+
+
+### Step4: 编译
+
+编译`cmake`的命令在`scripts/build.sh`中,请根据实际情况修改主要参数,其主要内容说明如下:
+```
+# 是否使用GPU(即是否使用 CUDA)
+WITH_GPU=OFF
+# 使用MKL or openblas
+WITH_MKL=ON
+# 是否集成 TensorRT(仅WITH_GPU=ON 有效)
+WITH_TENSORRT=OFF
+# TensorRT 的lib路径
+TENSORRT_DIR=/path/to/TensorRT/
+# Paddle 预测库路径
+PADDLE_DIR=/path/to/fluid_inference/
+# Paddle 的预测库是否使用静态库来编译
+# 使用TensorRT时,Paddle的预测库通常为动态库
+WITH_STATIC_LIB=ON
+# CUDA 的 lib 路径
+CUDA_LIB=/path/to/cuda/lib/
+# CUDNN 的 lib 路径
+CUDNN_LIB=/path/to/cudnn/lib/
+
+# OPENCV 路径, 如果使用自带预编译版本可不修改
+OPENCV_DIR=$(pwd)/deps/opencv3gcc4.8/
+sh $(pwd)/scripts/bootstrap.sh
+
+# 以下无需改动
+rm -rf build
+mkdir -p build
+cd build
+cmake .. \
+    -DWITH_GPU=${WITH_GPU} \
+    -DWITH_MKL=${WITH_MKL} \
+    -DWITH_TENSORRT=${WITH_TENSORRT} \
+    -DTENSORRT_DIR=${TENSORRT_DIR} \
+    -DPADDLE_DIR=${PADDLE_DIR} \
+    -DWITH_STATIC_LIB=${WITH_STATIC_LIB} \
+    -DCUDA_LIB=${CUDA_LIB} \
+    -DCUDNN_LIB=${CUDNN_LIB} \
+    -DOPENCV_DIR=${OPENCV_DIR}
+make
+
+```
+
+修改脚本设置好主要参数后,执行`build`脚本:
+ ```shell
+ sh ./scripts/build.sh
+ ```
+
+### Step5: 预测及可视化
+编译成功后,预测demo的可执行程序分别为`build/detector`,`build/classifer`,`build/segmenter`,用户可根据自己的模型类型选择,其主要命令参数说明如下:
+
+|  参数   | 说明  |
+|  ----  | ----  |
+| model_dir  | 导出的预测模型所在路径 |
+| image  | 要预测的图片文件路径 |
+| image_list  | 按行存储图片路径的.txt文件 |
+| use_gpu  | 是否使用 GPU 预测, 支持值为0或1(默认值为0) |
+| use_trt  | 是否使用 TensorTr 预测, 支持值为0或1(默认值为0) |
+| gpu_id  | GPU 设备ID, 默认值为0 |
+| save_dir | 保存可视化结果的路径, 默认值为"output",classfier无该参数 |
+
+## 样例
+
+可使用[小度熊识别模型](deploy.md#导出inference模型)中导出的`inference_model`和测试图片进行预测。
+
+`样例一`:
+
+不使用`GPU`测试图片 `/path/to/xiaoduxiong.jpeg`  
+
+```shell
+./build/detector --model_dir=/path/to/inference_model --image=/path/to/xiaoduxiong.jpeg --save_dir=output
+```
+图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
+
+
+`样例二`:
+
+使用`GPU`预测多个图片`/path/to/image_list.txt`,image_list.txt内容的格式如下:
+```
+/path/to/images/xiaoduxiong1.jpeg
+/path/to/images/xiaoduxiong2.jpeg
+...
+/path/to/images/xiaoduxiongn.jpeg
+```
+```shell
+./build/detector --model_dir=/path/to/models/inference_model --image_list=/root/projects/images_list.txt --use_gpu=1 --save_dir=output
+```
+图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。

+ 148 - 0
docs/tutorials/deploy/deploy_cpp_win_vs2019.md

@@ -0,0 +1,148 @@
+# Visual Studio 2019 Community CMake 编译指南
+
+## 说明
+Windows 平台下,我们使用`Visual Studio 2019 Community` 进行了测试。微软从`Visual Studio 2017`开始即支持直接管理`CMake`跨平台编译项目,但是直到`2019`才提供了稳定和完全的支持,所以如果你想使用CMake管理项目编译构建,我们推荐你使用`Visual Studio 2019`环境下构建。
+
+## 前置条件
+* Visual Studio 2019
+* CUDA 9.0 / CUDA 10.0, CUDNN 7+ (仅在使用GPU版本的预测库时需要)
+* CMake 3.0+
+
+请确保系统已经安装好上述基本软件,我们使用的是`VS2019`的社区版。
+
+**下面所有示例以工作目录为 `D:\projects`演示**。
+
+### Step1: 下载代码
+
+下载源代码
+```shell
+d:
+mkdir projects
+cd projects
+git clone https://github.com/PaddlePaddle/PaddleX.git
+```
+
+**说明**:其中`C++`预测代码在`PaddleX/deploy/cpp` 目录,该目录不依赖任何`PaddleX`下其他目录。
+
+
+### Step2: 下载PaddlePaddle C++ 预测库 fluid_inference
+
+PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持TensorRT,提供了不同的预编译版本,目前PaddleX依赖于Paddle1.7版本,以下提供了多个不同版本的Paddle预测库:
+
+|  版本说明   | 预测库(1.7.2版本)  | 编译器 | 构建工具| cuDNN | CUDA
+|  ----  |  ----  |  ----  |  ----  | ---- | ---- |
+| cpu_avx_mkl  | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.7.2/win-infer/mkl/cpu/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 |
+| cpu_avx_openblas  | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.7.2/win-infer/open/cpu/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 |
+| cuda9.0_cudnn7_avx_mkl  | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.7.2/win-infer/mkl/post97/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 | 7.4.1 | 9.0 |
+| cuda9.0_cudnn7_avx_openblas  | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.7.2/win-infer/open/post97/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 | 7.4.1 | 9.0 |
+| cuda10.0_cudnn7_avx_mkl  | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.7.2/win-infer/mkl/post107/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 | 7.5.0 | 9.0 |
+
+
+更多和更新的版本,请根据实际情况下载:  [C++预测库下载列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html#id1)
+
+解压后`D:\projects\fluid_inference*\`目录下主要包含的内容为:
+```
+├── \paddle\ # paddle核心库和头文件
+|
+├── \third_party\ # 第三方依赖库和头文件
+|
+└── \version.txt # 版本和编译信息
+```
+
+### Step3: 安装配置OpenCV
+
+1. 在OpenCV官网下载适用于Windows平台的3.4.6版本, [下载地址](https://sourceforge.net/projects/opencvlibrary/files/3.4.6/opencv-3.4.6-vc14_vc15.exe/download)  
+2. 运行下载的可执行文件,将OpenCV解压至指定目录,如`D:\projects\opencv`
+3. 配置环境变量,如下流程所示  
+    - 我的电脑->属性->高级系统设置->环境变量
+    - 在系统变量中找到Path(如没有,自行创建),并双击编辑
+    - 新建,将opencv路径填入并保存,如`D:\projects\opencv\build\x64\vc14\bin`
+
+### Step4: 使用Visual Studio 2019直接编译CMake
+
+1. 打开Visual Studio 2019 Community,点击`继续但无需代码`
+
+![step2](images/vs2019_step1.png)
+
+2. 点击: `文件`->`打开`->`CMake`
+
+![step2.1](images/vs2019_step2.png)
+
+选择项目代码所在路径,并打开`CMakeList.txt`:
+
+![step2.2](images/vs2019_step3.png)
+
+3. 点击:`项目`->`PADDLEX_INFERENCE的CMake设置`
+
+![step3](images/vs2019_step4.png)
+
+4. 点击`浏览`,分别设置编译选项指定`CUDA`、`OpenCV`、`Paddle预测库`的路径
+
+依赖库路径的含义说明如下(带*表示仅在使用**GPU版本**预测库时指定, 其中CUDA库版本尽量对齐,**使用9.0、10.0版本,不使用9.2、10.1等版本CUDA库**):
+
+|  参数名   | 含义  |
+|  ----  | ----  |
+| *CUDA_LIB  | CUDA的库路径, 注:请将CUDNN的cudnn.lib文件拷贝到CUDA_LIB路径下 |
+| OPENCV_DIR  | OpenCV的安装路径, |
+| PADDLE_DIR | Paddle c++预测库的路径 |
+
+**注意:** 1. 使用`CPU`版预测库,请把`WITH_GPU`的`值`去掉勾 2. 如果使用的是`openblas`版本,请把`WITH_MKL`的`值`去掉勾
+
+![step4](images/vs2019_step5.png)
+
+**设置完成后**, 点击上图中`保存并生成CMake缓存以加载变量`。
+
+5. 点击`生成`->`全部生成`
+
+![step6](images/vs2019_step6.png)
+
+
+### Step5: 预测及可视化
+
+上述`Visual Studio 2019`编译产出的可执行文件在`out\build\x64-Release`目录下,打开`cmd`,并切换到该目录:
+
+```
+d:
+cd D:\projects\PaddleX\deploy\cpp\out\build\x64-Release
+```
+
+编译成功后,预测demo的入口程序为`detector`,`classifer`,`segmenter`,用户可根据自己的模型类型选择,其主要命令参数说明如下:
+
+|  参数   | 说明  |
+|  ----  | ----  |
+| model_dir  | 导出的预测模型所在路径 |
+| image  | 要预测的图片文件路径 |
+| image_list  | 按行存储图片路径的.txt文件 |
+| use_gpu  | 是否使用 GPU 预测, 支持值为0或1(默认值为0) |
+| gpu_id  | GPU 设备ID, 默认值为0 |
+| save_dir | 保存可视化结果的路径, 默认值为"output",classfier无该参数 |
+
+
+## 样例
+
+可使用[小度熊识别模型](deploy.md#导出inference模型)中导出的`inference_model`和测试图片进行预测。
+
+`样例一`:
+
+不使用`GPU`测试图片  `\\path\\to\\xiaoduxiong.jpeg`  
+
+```shell
+.\detector --model_dir=\\path\\to\\inference_model --image=D:\\images\\xiaoduxiong.jpeg --save_dir=output
+
+```
+图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
+
+
+`样例二`:
+
+使用`GPU`预测多个图片`\\path\\to\\image_list.txt`,image_list.txt内容的格式如下:
+```
+\\path\\to\\images\\xiaoduxiong1.jpeg
+\\path\\to\\images\\xiaoduxiong2.jpeg
+...
+\\path\\to\\images\\xiaoduxiongn.jpeg
+```
+```shell
+.\detector --model_dir=\\path\\to\\inference_model --image_list=\\path\\to\\images_list.txt --use_gpu=1 --save_dir=output
+```
+图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。

BIN
docs/tutorials/deploy/images/vs2019_step1.png


BIN
docs/tutorials/deploy/images/vs2019_step2.png


BIN
docs/tutorials/deploy/images/vs2019_step3.png


BIN
docs/tutorials/deploy/images/vs2019_step4.png


BIN
docs/tutorials/deploy/images/vs2019_step5.png


BIN
docs/tutorials/deploy/images/vs2019_step6.png


+ 2 - 0
docs/tutorials/deploy/index.rst

@@ -0,0 +1,2 @@
+多端部署
+==============

+ 3 - 1
docs/tutorials/index.rst

@@ -1,8 +1,10 @@
-使用教程
+PaddleX全流程开发教程
 =========================
 
 .. toctree::
    :maxdepth: 1
 
+   dataset_prepare.md
    train/index.rst
    compress/index.rst
+   deploy/index.rst

+ 9 - 0
docs/tutorials/train/classification.md

@@ -0,0 +1,9 @@
+# 更新日志
+
+- 2020.05.17
+> - 发布v0.1.8 pip更新
+> - 修复部分代码Bug
+> - 新增EasyData平台数据标注格式支持
+> - 支持imgaug数据增强库的pixel-level算子
+
+

+ 19 - 7
paddlex/__init__.py

@@ -13,27 +13,39 @@
 # limitations under the License.
 
 from __future__ import absolute_import
+import os
+if 'FLAGS_eager_delete_tensor_gb' not in os.environ:
+    os.environ['FLAGS_eager_delete_tensor_gb'] = '0.0'
+if 'FLAGS_allocator_strategy' not in os.environ:
+    os.environ['FLAGS_allocator_strategy'] = 'auto_growth'
+if "CUDA_VISIBLE_DEVICES" in os.environ:
+    if os.environ["CUDA_VISIBLE_DEVICES"].count("-1") > 0:
+        os.environ["CUDA_VISIBLE_DEVICES"] = ""
 from .utils.utils import get_environ_info
 from . import cv
 from . import det
 from . import seg
 from . import cls
 from . import slim
+from . import tools
 
 try:
     import pycocotools
 except:
-    print("[WARNING] pycocotools is not installed, detection model is not available now.")
-    print("[WARNING] pycocotools install: https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/install.md")
-
-import paddlehub as hub
-if hub.version.hub_version < '1.6.2':
-    raise Exception("[ERROR] paddlehub >= 1.6.2 is required")
+    print(
+        "[WARNING] pycocotools is not installed, detection model is not available now."
+    )
+    print(
+        "[WARNING] pycocotools install: https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/install.md"
+    )
 
+#import paddlehub as hub
+#if hub.version.hub_version < '1.6.2':
+#    raise Exception("[ERROR] paddlehub >= 1.6.2 is required")
 
 env_info = get_environ_info()
 load_model = cv.models.load_model
 datasets = cv.datasets
 
 log_level = 2
-__version__ = '0.1.6.github'
+__version__ = '0.1.9.github'

+ 6 - 2
paddlex/cv/datasets/coco.py

@@ -100,7 +100,7 @@ class CocoDetection(VOCDetection):
             gt_score = np.ones((num_bbox, 1), dtype=np.float32)
             is_crowd = np.zeros((num_bbox, 1), dtype=np.int32)
             difficult = np.zeros((num_bbox, 1), dtype=np.int32)
-            gt_poly = [None] * num_bbox
+            gt_poly = None
 
             for i, box in enumerate(bboxes):
                 catid = box['category_id']
@@ -108,6 +108,8 @@ class CocoDetection(VOCDetection):
                 gt_bbox[i, :] = box['clean_bbox']
                 is_crowd[i][0] = box['iscrowd']
                 if 'segmentation' in box:
+                    if gt_poly is None:
+                        gt_poly = [None] * num_bbox
                     gt_poly[i] = box['segmentation']
 
             im_info = {
@@ -119,9 +121,11 @@ class CocoDetection(VOCDetection):
                 'gt_class': gt_class,
                 'gt_bbox': gt_bbox,
                 'gt_score': gt_score,
-                'gt_poly': gt_poly,
                 'difficult': difficult
             }
+            if gt_poly is not None:
+                label_info['gt_poly'] = gt_poly
+
             coco_rec = (im_info, label_info)
             self.file_list.append([im_fname, coco_rec])
 

+ 8 - 0
paddlex/cv/datasets/dataset.py

@@ -254,3 +254,11 @@ class Dataset:
             buffer_size=self.buffer_size,
             batch_size=batch_size,
             drop_last=drop_last)
+
+    def set_num_samples(self, num_samples):
+        if num_samples > len(self.file_list):
+            logging.warning(
+                "You want set num_samples to {}, but your dataset only has {} samples, so we will keep your dataset num_samples as {}"
+                .format(num_samples, len(self.file_list), len(self.file_list)))
+            num_samples = len(self.file_list)
+        self.num_samples = num_samples

+ 16 - 27
paddlex/cv/datasets/voc.py

@@ -95,8 +95,8 @@ class VOCDetection(Dataset):
                 if not osp.isfile(xml_file):
                     continue
                 if not osp.exists(img_file):
-                    raise IOError(
-                        'The image file {} is not exist!'.format(img_file))
+                    raise IOError('The image file {} is not exist!'.format(
+                        img_file))
                 tree = ET.parse(xml_file)
                 if tree.find('id') is None:
                     im_id = np.array([ct])
@@ -122,25 +122,20 @@ class VOCDetection(Dataset):
                     y2 = float(obj.find('bndbox').find('ymax').text)
                     x1 = max(0, x1)
                     y1 = max(0, y1)
-                    x2 = min(im_w - 1, x2)
-                    y2 = min(im_h - 1, y2)
+                    if im_w > 0.5 and im_h > 0.5:
+                        x2 = min(im_w - 1, x2)
+                        y2 = min(im_h - 1, y2)
                     gt_bbox[i] = [x1, y1, x2, y2]
                     is_crowd[i][0] = 0
                     difficult[i][0] = _difficult
                     annotations['annotations'].append({
-                        'iscrowd':
-                        0,
-                        'image_id':
-                        int(im_id[0]),
+                        'iscrowd': 0,
+                        'image_id': int(im_id[0]),
                         'bbox': [x1, y1, x2 - x1 + 1, y2 - y1 + 1],
-                        'area':
-                        float((x2 - x1 + 1) * (y2 - y1 + 1)),
-                        'category_id':
-                        cname2cid[cname],
-                        'id':
-                        ann_ct,
-                        'difficult':
-                        _difficult
+                        'area': float((x2 - x1 + 1) * (y2 - y1 + 1)),
+                        'category_id': cname2cid[cname],
+                        'id': ann_ct,
+                        'difficult': _difficult
                     })
                     ann_ct += 1
 
@@ -153,7 +148,6 @@ class VOCDetection(Dataset):
                     'gt_class': gt_class,
                     'gt_bbox': gt_bbox,
                     'gt_score': gt_score,
-                    'gt_poly': [],
                     'difficult': difficult
                 }
                 voc_rec = (im_info, label_info)
@@ -161,14 +155,10 @@ class VOCDetection(Dataset):
                     self.file_list.append([img_file, voc_rec])
                     ct += 1
                     annotations['images'].append({
-                        'height':
-                        im_h,
-                        'width':
-                        im_w,
-                        'id':
-                        int(im_id[0]),
-                        'file_name':
-                        osp.split(img_file)[1]
+                        'height': im_h,
+                        'width': im_w,
+                        'id': int(im_id[0]),
+                        'file_name': osp.split(img_file)[1]
                     })
 
         if not len(self.file_list) > 0:
@@ -199,8 +189,7 @@ class VOCDetection(Dataset):
             else:
                 mix_pos = 0
             im_info['mixup'] = [
-                files[mix_pos][0],
-                copy.deepcopy(files[mix_pos][1][0]),
+                files[mix_pos][0], copy.deepcopy(files[mix_pos][1][0]),
                 copy.deepcopy(files[mix_pos][1][1])
             ]
             self._pos += 1

+ 61 - 38
paddlex/cv/models/base.py

@@ -70,6 +70,8 @@ class BaseAPI:
         self.sync_bn = False
         # 当前模型状态
         self.status = 'Normal'
+        # 已完成迭代轮数,为恢复训练时的起始轮数
+        self.completed_epochs = 0
 
     def _get_single_card_bs(self, batch_size):
         if batch_size % len(self.places) == 0:
@@ -182,35 +184,62 @@ class BaseAPI:
                        fuse_bn=False,
                        save_dir='.',
                        sensitivities_file=None,
-                       eval_metric_loss=0.05):
-        pretrain_dir = osp.join(save_dir, 'pretrain')
-        if not os.path.isdir(pretrain_dir):
-            if os.path.exists(pretrain_dir):
-                os.remove(pretrain_dir)
-            os.makedirs(pretrain_dir)
-        if hasattr(self, 'backbone'):
-            backbone = self.backbone
-        else:
-            backbone = self.__class__.__name__
-        pretrain_weights = get_pretrain_weights(
-            pretrain_weights, self.model_type, backbone, pretrain_dir)
+                       eval_metric_loss=0.05,
+                       resume_checkpoint=None):
+        if not resume_checkpoint:
+            pretrain_dir = osp.join(save_dir, 'pretrain')
+            if not os.path.isdir(pretrain_dir):
+                if os.path.exists(pretrain_dir):
+                    os.remove(pretrain_dir)
+                os.makedirs(pretrain_dir)
+            if hasattr(self, 'backbone'):
+                backbone = self.backbone
+            else:
+                backbone = self.__class__.__name__
+            pretrain_weights = get_pretrain_weights(
+                pretrain_weights, self.model_type, backbone, pretrain_dir)
         if startup_prog is None:
             startup_prog = fluid.default_startup_program()
         self.exe.run(startup_prog)
-        if pretrain_weights is not None:
+        if resume_checkpoint:
+            logging.info(
+                "Resume checkpoint from {}.".format(resume_checkpoint),
+                use_color=True)
+            paddlex.utils.utils.load_pretrain_weights(
+                self.exe, self.train_prog, resume_checkpoint, resume=True)
+            if not osp.exists(osp.join(resume_checkpoint, "model.yml")):
+                raise Exception(
+                    "There's not model.yml in {}".format(resume_checkpoint))
+            with open(osp.join(resume_checkpoint, "model.yml")) as f:
+                info = yaml.load(f.read(), Loader=yaml.Loader)
+                self.completed_epochs = info['completed_epochs']
+        elif pretrain_weights is not None:
             logging.info(
-                "Load pretrain weights from {}.".format(pretrain_weights))
+                "Load pretrain weights from {}.".format(pretrain_weights),
+                use_color=True)
             paddlex.utils.utils.load_pretrain_weights(
                 self.exe, self.train_prog, pretrain_weights, fuse_bn)
         # 进行裁剪
         if sensitivities_file is not None:
+            import paddleslim
             from .slim.prune_config import get_sensitivities
             sensitivities_file = get_sensitivities(sensitivities_file, self,
                                                    save_dir)
             from .slim.prune import get_params_ratios, prune_program
+            logging.info(
+                "Start to prune program with eval_metric_loss = {}".format(
+                    eval_metric_loss),
+                use_color=True)
+            origin_flops = paddleslim.analysis.flops(self.test_prog)
             prune_params_ratios = get_params_ratios(
                 sensitivities_file, eval_metric_loss=eval_metric_loss)
             prune_program(self, prune_params_ratios)
+            current_flops = paddleslim.analysis.flops(self.test_prog)
+            remaining_ratio = current_flops / origin_flops
+            logging.info(
+                "Finish prune program, before FLOPs:{}, after prune FLOPs:{}, remaining ratio:{}"
+                .format(origin_flops, current_flops, remaining_ratio),
+                use_color=True)
             self.status = 'Prune'
 
     def get_model_info(self):
@@ -248,6 +277,7 @@ class BaseAPI:
                     name = op.__class__.__name__
                     attr = op.__dict__
                     info['Transforms'].append({name: attr})
+        info['completed_epochs'] = self.completed_epochs
         return info
 
     def save_model(self, save_dir):
@@ -255,7 +285,10 @@ class BaseAPI:
             if osp.exists(save_dir):
                 os.remove(save_dir)
             os.makedirs(save_dir)
-        fluid.save(self.train_prog, osp.join(save_dir, 'model'))
+        if self.train_prog is not None:
+            fluid.save(self.train_prog, osp.join(save_dir, 'model'))
+        else:
+            fluid.save(self.test_prog, osp.join(save_dir, 'model'))
         model_info = self.get_model_info()
         model_info['status'] = self.status
         with open(
@@ -395,17 +428,16 @@ class BaseAPI:
 
         if use_vdl:
             # VisualDL component
-            log_writer = LogWriter(vdl_logdir, sync_cycle=20)
-            train_step_component = OrderedDict()
-            eval_component = OrderedDict()
+            log_writer = LogWriter(vdl_logdir)
 
         thresh = 0.0001
         if early_stop:
             earlystop = EarlyStop(early_stop_patience, thresh)
         best_accuracy_key = ""
         best_accuracy = -1.0
-        best_model_epoch = 1
-        for i in range(num_epochs):
+        best_model_epoch = -1
+        start_epoch = self.completed_epochs
+        for i in range(start_epoch, num_epochs):
             records = list()
             step_start_time = time.time()
             epoch_start_time = time.time()
@@ -434,13 +466,7 @@ class BaseAPI:
 
                     if use_vdl:
                         for k, v in step_metrics.items():
-                            if k not in train_step_component.keys():
-                                with log_writer.mode('Each_Step_while_Training'
-                                                     ) as step_logger:
-                                    train_step_component[
-                                        k] = step_logger.scalar(
-                                            'Training: {}'.format(k))
-                            train_step_component[k].add_record(num_steps, v)
+                            log_writer.add_scalar('Metrics/Training(Step): {}'.format(k), v, num_steps)
 
                     # 估算剩余时间
                     avg_step_time = np.mean(time_stat)
@@ -477,7 +503,7 @@ class BaseAPI:
                 current_save_dir = osp.join(save_dir, "epoch_{}".format(i + 1))
                 if not osp.isdir(current_save_dir):
                     os.makedirs(current_save_dir)
-                if eval_dataset is not None:
+                if eval_dataset is not None and eval_dataset.num_samples > 0:
                     self.eval_metrics, self.eval_details = self.evaluate(
                         eval_dataset=eval_dataset,
                         batch_size=eval_batch_size,
@@ -485,6 +511,7 @@ class BaseAPI:
                         return_details=True)
                     logging.info('[EVAL] Finished, Epoch={}, {} .'.format(
                         i + 1, dict2str(self.eval_metrics)))
+                    self.completed_epochs += 1
                     # 保存最优模型
                     best_accuracy_key = list(self.eval_metrics.keys())[0]
                     current_accuracy = self.eval_metrics[best_accuracy_key]
@@ -500,19 +527,15 @@ class BaseAPI:
                             if isinstance(v, np.ndarray):
                                 if v.size > 1:
                                     continue
-                            if k not in eval_component:
-                                with log_writer.mode('Each_Epoch_on_Eval_Data'
-                                                     ) as eval_logger:
-                                    eval_component[k] = eval_logger.scalar(
-                                        'Evaluation: {}'.format(k))
-                            eval_component[k].add_record(i + 1, v)
+                            log_writer.add_scalar("Metrics/Eval(Epoch): {}".format(k), v, i+1)
                 self.save_model(save_dir=current_save_dir)
                 time_eval_one_epoch = time.time() - eval_epoch_start_time
                 eval_epoch_start_time = time.time()
-                logging.info(
-                    'Current evaluated best model in eval_dataset is epoch_{}, {}={}'
-                    .format(best_model_epoch, best_accuracy_key,
-                            best_accuracy))
+                if best_model_epoch > 0:
+                    logging.info(
+                        'Current evaluated best model in eval_dataset is epoch_{}, {}={}'
+                        .format(best_model_epoch, best_accuracy_key,
+                                best_accuracy))
                 if eval_dataset is not None and early_stop:
                     if earlystop(current_accuracy):
                         break

+ 5 - 3
paddlex/cv/models/classifier.py

@@ -112,7 +112,8 @@ class BaseClassifier(BaseAPI):
               sensitivities_file=None,
               eval_metric_loss=0.05,
               early_stop=False,
-              early_stop_patience=5):
+              early_stop_patience=5,
+              resume_checkpoint=None):
         """训练。
 
         Args:
@@ -137,6 +138,7 @@ class BaseClassifier(BaseAPI):
             early_stop (bool): 是否使用提前终止训练策略。默认值为False。
             early_stop_patience (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内
                 连续下降或持平,则终止训练。默认值为5。
+            resume_checkpoint (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
 
         Raises:
             ValueError: 模型从inference model进行加载。
@@ -160,8 +162,8 @@ class BaseClassifier(BaseAPI):
             pretrain_weights=pretrain_weights,
             save_dir=save_dir,
             sensitivities_file=sensitivities_file,
-            eval_metric_loss=eval_metric_loss)
-
+            eval_metric_loss=eval_metric_loss,
+            resume_checkpoint=resume_checkpoint)
         # 训练
         self.train_loop(
             num_epochs=num_epochs,

+ 7 - 3
paddlex/cv/models/deeplabv3p.py

@@ -234,7 +234,8 @@ class DeepLabv3p(BaseAPI):
               sensitivities_file=None,
               eval_metric_loss=0.05,
               early_stop=False,
-              early_stop_patience=5):
+              early_stop_patience=5,
+              resume_checkpoint=None):
         """训练。
 
         Args:
@@ -258,6 +259,7 @@ class DeepLabv3p(BaseAPI):
             early_stop (bool): 是否使用提前终止训练策略。默认值为False。
             early_stop_patience (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内
                 连续下降或持平,则终止训练。默认值为5。
+            resume_checkpoint (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
 
         Raises:
             ValueError: 模型从inference model进行加载。
@@ -284,7 +286,8 @@ class DeepLabv3p(BaseAPI):
             pretrain_weights=pretrain_weights,
             save_dir=save_dir,
             sensitivities_file=sensitivities_file,
-            eval_metric_loss=eval_metric_loss)
+            eval_metric_loss=eval_metric_loss,
+            resume_checkpoint=resume_checkpoint)
         # 训练
         self.train_loop(
             num_epochs=num_epochs,
@@ -405,5 +408,6 @@ class DeepLabv3p(BaseAPI):
                 w, h = info[1][1], info[1][0]
                 pred = pred[0:h, 0:w]
             else:
-                raise Exception("Unexpected info '{}' in im_info".format(info[0]))
+                raise Exception("Unexpected info '{}' in im_info".format(
+                    info[0]))
         return {'label_map': pred, 'score_map': result[1]}

+ 12 - 4
paddlex/cv/models/faster_rcnn.py

@@ -167,7 +167,8 @@ class FasterRCNN(BaseAPI):
               metric=None,
               use_vdl=False,
               early_stop=False,
-              early_stop_patience=5):
+              early_stop_patience=5,
+              resume_checkpoint=None):
         """训练。
 
         Args:
@@ -193,6 +194,7 @@ class FasterRCNN(BaseAPI):
             early_stop (bool): 是否使用提前终止训练策略。默认值为False。
             early_stop_patience (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内
                 连续下降或持平,则终止训练。默认值为5。
+            resume_checkpoint (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
 
         Raises:
             ValueError: 评估类型不在指定列表中。
@@ -231,7 +233,9 @@ class FasterRCNN(BaseAPI):
             startup_prog=fluid.default_startup_program(),
             pretrain_weights=pretrain_weights,
             fuse_bn=fuse_bn,
-            save_dir=save_dir)
+            save_dir=save_dir,
+            resume_checkpoint=resume_checkpoint)
+
         # 训练
         self.train_loop(
             num_epochs=num_epochs,
@@ -255,7 +259,7 @@ class FasterRCNN(BaseAPI):
 
         Args:
             eval_dataset (paddlex.datasets): 验证数据读取器。
-            batch_size (int): 验证数据批大小。默认为1。
+            batch_size (int): 验证数据批大小。默认为1。当前只支持设置为1。
             epoch_id (int): 当前评估模型所在的训练轮数。
             metric (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,
                 根据用户传入的Dataset自动选择,如为VOCDetection,则metric为'VOC';
@@ -284,7 +288,11 @@ class FasterRCNN(BaseAPI):
                         "eval_dataset should be datasets.VOCDetection or datasets.COCODetection."
                     )
         assert metric in ['COCO', 'VOC'], "Metric only support 'VOC' or 'COCO'"
-
+        if batch_size > 1:
+            batch_size = 1
+            logging.warning(
+                "Faster RCNN supports batch_size=1 only during evaluating, so batch_size is forced to be set to 1."
+            )
         dataset = eval_dataset.generator(
             batch_size=batch_size, drop_last=False)
 

+ 13 - 4
paddlex/cv/models/mask_rcnn.py

@@ -132,7 +132,8 @@ class MaskRCNN(FasterRCNN):
               metric=None,
               use_vdl=False,
               early_stop=False,
-              early_stop_patience=5):
+              early_stop_patience=5,
+              resume_checkpoint=None):
         """训练。
 
         Args:
@@ -158,6 +159,7 @@ class MaskRCNN(FasterRCNN):
             early_stop (bool): 是否使用提前终止训练策略。默认值为False。
             early_stop_patience (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内
                 连续下降或持平,则终止训练。默认值为5。
+            resume_checkpoint (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
 
         Raises:
             ValueError: 评估类型不在指定列表中。
@@ -169,7 +171,8 @@ class MaskRCNN(FasterRCNN):
                 metric = 'COCO'
             else:
                 raise Exception(
-                    "train_dataset should be datasets.COCODetection or datasets.EasyDataDet.")
+                    "train_dataset should be datasets.COCODetection or datasets.EasyDataDet."
+                )
         assert metric in ['COCO', 'VOC'], "Metric only support 'VOC' or 'COCO'"
         self.metric = metric
         if not self.trainable:
@@ -197,7 +200,8 @@ class MaskRCNN(FasterRCNN):
             startup_prog=fluid.default_startup_program(),
             pretrain_weights=pretrain_weights,
             fuse_bn=fuse_bn,
-            save_dir=save_dir)
+            save_dir=save_dir,
+            resume_checkpoint=resume_checkpoint)
         # 训练
         self.train_loop(
             num_epochs=num_epochs,
@@ -221,7 +225,7 @@ class MaskRCNN(FasterRCNN):
 
         Args:
             eval_dataset (paddlex.datasets): 验证数据读取器。
-            batch_size (int): 验证数据批大小。默认为1。
+            batch_size (int): 验证数据批大小。默认为1。当前只支持设置为1。
             epoch_id (int): 当前评估模型所在的训练轮数。
             metric (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,
                 根据用户传入的Dataset自动选择,如为VOCDetection,则metric为'VOC';
@@ -249,6 +253,11 @@ class MaskRCNN(FasterRCNN):
                     raise Exception(
                         "eval_dataset should be datasets.COCODetection.")
         assert metric in ['COCO', 'VOC'], "Metric only support 'VOC' or 'COCO'"
+        if batch_size > 1:
+            batch_size = 1
+            logging.warning(
+                "Mask RCNN supports batch_size=1 only during evaluating, so batch_size is forced to be set to 1."
+            )
         data_generator = eval_dataset.generator(
             batch_size=batch_size, drop_last=False)
 

+ 86 - 8
paddlex/cv/models/slim/post_quantization.py

@@ -19,6 +19,9 @@ from paddle.fluid.contrib.slim.quantization import PostTrainingQuantization
 import paddlex.utils.logging as logging
 import paddle.fluid as fluid
 import os
+import re
+import numpy as np
+import time
 
 
 class PaddleXPostTrainingQuantization(PostTrainingQuantization):
@@ -123,28 +126,37 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
             the program of quantized model.
         '''
         self._preprocess()
-
+        batch_ct = 0
+        for data in self._data_loader():
+            batch_ct += 1
+            if self._batch_nums and batch_ct >= self._batch_nums:
+                break
         batch_id = 0
+        logging.info("Start to run batch!")
         for data in self._data_loader():
+            start = time.time()
             self._executor.run(
                 program=self._program,
                 feed=data,
                 fetch_list=self._fetch_list,
                 return_numpy=False)
             self._sample_data(batch_id)
-
-            if batch_id % 5 == 0:
-                logging.info("run batch: {}".format(batch_id))
+            end = time.time()
+            logging.debug('[Run batch data] Batch={}/{}, time_each_batch={} s.'.format(
+                str(batch_id + 1),
+                str(batch_ct),
+                str(end-start)))
             batch_id += 1
             if self._batch_nums and batch_id >= self._batch_nums:
                 break
-        logging.info("all run batch: ".format(batch_id))
-        logging.info("calculate scale factor ...")
+        logging.info("All run batch: ".format(batch_id))
+        logging.info("Calculate scale factor ...")
         self._calculate_scale_factor()
-        logging.info("update the program ...")
+        logging.info("Update the program ...")
         self._update_program()
-
+        logging.info("Save ...")
         self._save_output_scale()
+        logging.info("Finish quant!")
         return self._program
 
     def save_quantized_model(self, save_model_path):
@@ -221,3 +233,69 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
         for var in self._program.list_vars():
             if var.name in self._quantized_act_var_name:
                 var.persistable = True
+                
+    def _calculate_scale_factor(self):
+        '''
+        Calculate the scale factor of quantized variables.
+        '''
+        # apply channel_wise_abs_max quantization for weights
+        ct = 1
+        for var_name in self._quantized_weight_var_name:
+            start = time.time()
+            data = self._sampling_data[var_name]
+            scale_factor_per_channel = []
+            for i in range(data.shape[0]):
+                abs_max_value = np.max(np.abs(data[i]))
+                scale_factor_per_channel.append(abs_max_value)
+            self._quantized_var_scale_factor[
+                var_name] = scale_factor_per_channel
+            end = time.time()
+            logging.debug('[Calculate weight] Weight_id={}/{}, time_each_weight={} s.'.format(
+                str(ct),
+                str(len(self._quantized_weight_var_name)),
+                str(end-start)))
+            ct += 1
+            
+        ct = 1
+        # apply kl quantization for activation
+        if self._is_use_cache_file:
+            for var_name in self._quantized_act_var_name:
+                start = time.time()
+                sampling_data = []
+                filenames = [f for f in os.listdir(self._cache_dir) \
+                    if re.match(var_name + '_[0-9]+.npy', f)]
+                for filename in filenames:
+                    file_path = os.path.join(self._cache_dir, filename)
+                    sampling_data.append(np.load(file_path))
+                    os.remove(file_path)
+                sampling_data = np.concatenate(sampling_data)
+
+                if self._algo == "KL":
+                    self._quantized_var_scale_factor[var_name] = \
+                        self._get_kl_scaling_factor(np.abs(sampling_data))
+                else:
+                    self._quantized_var_scale_factor[var_name] = \
+                        np.max(np.abs(sampling_data))
+                end = time.time()
+                logging.debug('[Calculate activation] Activation_id={}/{}, time_each_activation={} s.'.format(
+                    str(ct),
+                    str(len(self._quantized_act_var_name)),
+                    str(end-start)))
+                ct += 1
+        else:
+            for var_name in self._quantized_act_var_name:
+                start = time.time()
+                self._sampling_data[var_name] = np.concatenate(
+                    self._sampling_data[var_name])
+                if self._algo == "KL":
+                    self._quantized_var_scale_factor[var_name] = \
+                        self._get_kl_scaling_factor(np.abs(self._sampling_data[var_name]))
+                else:
+                    self._quantized_var_scale_factor[var_name] = \
+                        np.max(np.abs(self._sampling_data[var_name]))
+                end = time.time()
+                logging.debug('[Calculate activation] Activation_id={}/{}, time_each_activation={} s.'.format(
+                    str(ct),
+                    str(len(self._quantized_act_var_name)),
+                    str(end-start)))
+                ct += 1

+ 20 - 16
paddlex/cv/models/slim/prune_config.py

@@ -15,7 +15,7 @@
 import numpy as np
 import os.path as osp
 import paddle.fluid as fluid
-import paddlehub as hub
+#import paddlehub as hub
 import paddlex
 
 sensitivities_data = {
@@ -105,22 +105,26 @@ def get_sensitivities(flag, model, save_dir):
             model_type)
         url = sensitivities_data[model_type]
         fname = osp.split(url)[-1]
-        try:
-            hub.download(fname, save_path=save_dir)
-        except Exception as e:
-            if isinstance(e, hub.ResourceNotFoundError):
-                raise Exception(
-                    "Resource for model {}(key='{}') not found".format(
-                        model_type, fname))
-            elif isinstance(e, hub.ServerConnectionError):
-                raise Exception(
-                    "Cannot get reource for model {}(key='{}'), please check your internet connecgtion"
-                    .format(model_type, fname))
-            else:
-                raise Exception(
-                    "Unexpected error, please make sure paddlehub >= 1.6.2 {}".
-                    format(str(e)))
+        paddlex.utils.download(url, path=save_dir)
         return osp.join(save_dir, fname)
+
+
+#        try:
+#            hub.download(fname, save_path=save_dir)
+#        except Exception as e:
+#            if isinstance(e, hub.ResourceNotFoundError):
+#                raise Exception(
+#                    "Resource for model {}(key='{}') not found".format(
+#                        model_type, fname))
+#            elif isinstance(e, hub.ServerConnectionError):
+#                raise Exception(
+#                    "Cannot get reource for model {}(key='{}'), please check your internet connecgtion"
+#                    .format(model_type, fname))
+#            else:
+#                raise Exception(
+#                    "Unexpected error, please make sure paddlehub >= 1.6.2 {}".
+#                    format(str(e)))
+#        return osp.join(save_dir, fname)
     else:
         raise Exception(
             "sensitivities need to be defined as directory path or `DEFAULT`(download sensitivities automatically)."

+ 9 - 8
paddlex/cv/models/unet.py

@@ -121,7 +121,8 @@ class UNet(DeepLabv3p):
               sensitivities_file=None,
               eval_metric_loss=0.05,
               early_stop=False,
-              early_stop_patience=5):
+              early_stop_patience=5,
+              resume_checkpoint=None):
         """训练。
 
         Args:
@@ -145,14 +146,14 @@ class UNet(DeepLabv3p):
             early_stop (bool): 是否使用提前终止训练策略。默认值为False。
             early_stop_patience (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内
                 连续下降或持平,则终止训练。默认值为5。
+            resume_checkpoint (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
 
         Raises:
             ValueError: 模型从inference model进行加载。
         """
-        return super(
-            UNet,
-            self).train(num_epochs, train_dataset, train_batch_size,
-                        eval_dataset, save_interval_epochs, log_interval_steps,
-                        save_dir, pretrain_weights, optimizer, learning_rate,
-                        lr_decay_power, use_vdl, sensitivities_file,
-                        eval_metric_loss, early_stop, early_stop_patience)
+        return super(UNet, self).train(
+            num_epochs, train_dataset, train_batch_size, eval_dataset,
+            save_interval_epochs, log_interval_steps, save_dir,
+            pretrain_weights, optimizer, learning_rate, lr_decay_power,
+            use_vdl, sensitivities_file, eval_metric_loss, early_stop,
+            early_stop_patience, resume_checkpoint)

+ 44 - 31
paddlex/cv/models/utils/pretrain_weights.py

@@ -1,5 +1,5 @@
 import paddlex
-import paddlehub as hub
+#import paddlehub as hub
 import os
 import os.path as osp
 
@@ -85,40 +85,53 @@ def get_pretrain_weights(flag, model_type, backbone, save_dir):
                 backbone = 'DetResNet50'
         assert backbone in image_pretrain, "There is not ImageNet pretrain weights for {}, you may try COCO.".format(
             backbone)
-        try:
-            hub.download(backbone, save_path=new_save_dir)
-        except Exception as e:
-            if isinstance(e, hub.ResourceNotFoundError):
-                raise Exception(
-                    "Resource for backbone {} not found".format(backbone))
-            elif isinstance(e, hub.ServerConnectionError):
-                raise Exception(
-                    "Cannot get reource for backbone {}, please check your internet connecgtion"
-                    .format(backbone))
-            else:
-                raise Exception(
-                    "Unexpected error, please make sure paddlehub >= 1.6.2")
-        return osp.join(new_save_dir, backbone)
+        url = image_pretrain[backbone]
+        fname = osp.split(url)[-1].split('.')[0]
+        paddlex.utils.download_and_decompress(url, path=new_save_dir)
+        return osp.join(new_save_dir, fname)
+#        try:
+#            hub.download(backbone, save_path=new_save_dir)
+#        except Exception as e:
+#            if isinstance(e, hub.ResourceNotFoundError):
+#                raise Exception(
+#                    "Resource for backbone {} not found".format(backbone))
+#            elif isinstance(e, hub.ServerConnectionError):
+#                raise Exception(
+#                    "Cannot get reource for backbone {}, please check your internet connecgtion"
+#                    .format(backbone))
+#            else:
+#                raise Exception(
+#                    "Unexpected error, please make sure paddlehub >= 1.6.2")
+#        return osp.join(new_save_dir, backbone)
     elif flag == 'COCO':
         new_save_dir = save_dir
         if hasattr(paddlex, 'pretrain_dir'):
             new_save_dir = paddlex.pretrain_dir
-        assert backbone in coco_pretrain, "There is not COCO pretrain weights for {}, you may try ImageNet.".format(
-            backbone)
-        try:
-            hub.download(backbone, save_path=new_save_dir)
-        except Exception as e:
-            if isinstance(hub.ResourceNotFoundError):
-                raise Exception(
-                    "Resource for backbone {} not found".format(backbone))
-            elif isinstance(hub.ServerConnectionError):
-                raise Exception(
-                    "Cannot get reource for backbone {}, please check your internet connecgtion"
-                    .format(backbone))
-            else:
-                raise Exception(
-                    "Unexpected error, please make sure paddlehub >= 1.6.2")
-        return osp.join(new_save_dir, backbone)
+        url = coco_pretrain[backbone]
+        fname = osp.split(url)[-1].split('.')[0]
+        paddlex.utils.download_and_decompress(url, path=new_save_dir)
+        return osp.join(new_save_dir, fname)
+
+
+#        new_save_dir = save_dir
+#        if hasattr(paddlex, 'pretrain_dir'):
+#            new_save_dir = paddlex.pretrain_dir
+#        assert backbone in coco_pretrain, "There is not COCO pretrain weights for {}, you may try ImageNet.".format(
+#            backbone)
+#        try:
+#            hub.download(backbone, save_path=new_save_dir)
+#        except Exception as e:
+#            if isinstance(hub.ResourceNotFoundError):
+#                raise Exception(
+#                    "Resource for backbone {} not found".format(backbone))
+#            elif isinstance(hub.ServerConnectionError):
+#                raise Exception(
+#                    "Cannot get reource for backbone {}, please check your internet connecgtion"
+#                    .format(backbone))
+#            else:
+#                raise Exception(
+#                    "Unexpected error, please make sure paddlehub >= 1.6.2")
+#        return osp.join(new_save_dir, backbone)
     else:
         raise Exception(
             "pretrain_weights need to be defined as directory path or `IMAGENET` or 'COCO' (download pretrain weights automatically)."

+ 14 - 4
paddlex/cv/models/utils/visualize.py

@@ -16,6 +16,7 @@ import os
 import cv2
 import colorsys
 import numpy as np
+import time
 import paddlex.utils.logging as logging
 from .detection_eval import fixed_linspace, backup_linspace, loadRes
 
@@ -25,8 +26,12 @@ def visualize_detection(image, result, threshold=0.5, save_dir='./'):
         Visualize bbox and mask results
     """
 
-    image_name = os.path.split(image)[-1]
-    image = cv2.imread(image)
+    if isinstance(image, np.ndarray):
+        image_name = str(int(time.time())) + '.jpg'
+    else:
+        image_name = os.path.split(image)[-1]
+        image = cv2.imread(image)
+
     image = draw_bbox_mask(image, result, threshold=threshold)
     if save_dir is not None:
         if not os.path.exists(save_dir):
@@ -56,13 +61,18 @@ def visualize_segmentation(image, result, weight=0.6, save_dir='./'):
     c3 = cv2.LUT(label_map, color_map[:, 2])
     pseudo_img = np.dstack((c1, c2, c3))
 
-    im = cv2.imread(image)
+    if isinstance(image, np.ndarray):
+        im = image
+        image_name = str(int(time.time())) + '.jpg'
+    else:
+        image_name = os.path.split(image)[-1]
+        im = cv2.imread(image)
+
     vis_result = cv2.addWeighted(im, weight, pseudo_img, 1 - weight, 0)
 
     if save_dir is not None:
         if not os.path.exists(save_dir):
             os.makedirs(save_dir)
-        image_name = os.path.split(image)[-1]
         out_path = os.path.join(save_dir, 'visualize_{}'.format(image_name))
         cv2.imwrite(out_path, vis_result)
         logging.info('The visualized result is saved as {}'.format(out_path))

+ 5 - 2
paddlex/cv/models/yolo_v3.py

@@ -166,7 +166,8 @@ class YOLOv3(BaseAPI):
               sensitivities_file=None,
               eval_metric_loss=0.05,
               early_stop=False,
-              early_stop_patience=5):
+              early_stop_patience=5,
+              resume_checkpoint=None):
         """训练。
 
         Args:
@@ -195,6 +196,7 @@ class YOLOv3(BaseAPI):
             early_stop (bool): 是否使用提前终止训练策略。默认值为False。
             early_stop_patience (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内
                 连续下降或持平,则终止训练。默认值为5。
+            resume_checkpoint (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
 
         Raises:
             ValueError: 评估类型不在指定列表中。
@@ -236,7 +238,8 @@ class YOLOv3(BaseAPI):
             pretrain_weights=pretrain_weights,
             save_dir=save_dir,
             sensitivities_file=sensitivities_file,
-            eval_metric_loss=eval_metric_loss)
+            eval_metric_loss=eval_metric_loss,
+            resume_checkpoint=resume_checkpoint)
         # 训练
         self.train_loop(
             num_epochs=num_epochs,

+ 50 - 18
paddlex/cv/transforms/cls_transforms.py

@@ -13,13 +13,22 @@
 # limitations under the License.
 
 from .ops import *
+from .imgaug_support import execute_imgaug
 import random
 import os.path as osp
 import numpy as np
 from PIL import Image, ImageEnhance
 
 
-class Compose:
+class ClsTransform:
+    """分类Transform的基类
+    """
+
+    def __init__(self):
+        pass
+
+
+class Compose(ClsTransform):
     """根据数据预处理/增强算子对输入数据进行操作。
        所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。
 
@@ -39,6 +48,15 @@ class Compose:
                             'must be equal or larger than 1!')
         self.transforms = transforms
 
+        # 检查transforms里面的操作,目前支持PaddleX定义的或者是imgaug操作
+        for op in self.transforms:
+            if not isinstance(op, ClsTransform):
+                import imgaug.augmenters as iaa
+                if not isinstance(op, iaa.Augmenter):
+                    raise Exception(
+                        "Elements in transforms should be defined in 'paddlex.cls.transforms' or class of imgaug.augmenters.Augmenter, see docs here: https://paddlex.readthedocs.io/zh_CN/latest/apis/transforms/"
+                    )
+
     def __call__(self, im, label=None):
         """
         Args:
@@ -48,20 +66,34 @@ class Compose:
             tuple: 根据网络所需字段所组成的tuple;
                 字段由transforms中的最后一个数据预处理操作决定。
         """
-        try:
-            im = cv2.imread(im).astype('float32')
-        except:
-            raise TypeError('Can\'t read The image file {}!'.format(im))
+        if isinstance(im, np.ndarray):
+            if len(im.shape) != 3:
+                raise Exception(
+                    "im should be 3-dimension, but now is {}-dimensions".
+                    format(len(im.shape)))
+        else:
+            try:
+                im = cv2.imread(im).astype('float32')
+            except:
+                raise TypeError('Can\'t read The image file {}!'.format(im))
         im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
         for op in self.transforms:
-            outputs = op(im, label)
-            im = outputs[0]
-            if len(outputs) == 2:
-                label = outputs[1]
+            if isinstance(op, ClsTransform):
+                outputs = op(im, label)
+                im = outputs[0]
+                if len(outputs) == 2:
+                    label = outputs[1]
+            else:
+                import imgaug.augmenters as iaa
+                if isinstance(op, iaa.Augmenter):
+                    im, = execute_imgaug(op, im)
+                outputs = (im, )
+                if label is not None:
+                    outputs = (im, label)
         return outputs
 
 
-class RandomCrop:
+class RandomCrop(ClsTransform):
     """对图像进行随机剪裁,模型训练时的数据增强操作。
 
     1. 根据lower_scale、lower_ratio、upper_ratio计算随机剪裁的高、宽。
@@ -104,7 +136,7 @@ class RandomCrop:
             return (im, label)
 
 
-class RandomHorizontalFlip:
+class RandomHorizontalFlip(ClsTransform):
     """以一定的概率对图像进行随机水平翻转,模型训练时的数据增强操作。
 
     Args:
@@ -132,7 +164,7 @@ class RandomHorizontalFlip:
             return (im, label)
 
 
-class RandomVerticalFlip:
+class RandomVerticalFlip(ClsTransform):
     """以一定的概率对图像进行随机垂直翻转,模型训练时的数据增强操作。
 
     Args:
@@ -160,7 +192,7 @@ class RandomVerticalFlip:
             return (im, label)
 
 
-class Normalize:
+class Normalize(ClsTransform):
     """对图像进行标准化。
 
     1. 对图像进行归一化到区间[0.0, 1.0]。
@@ -195,7 +227,7 @@ class Normalize:
             return (im, label)
 
 
-class ResizeByShort:
+class ResizeByShort(ClsTransform):
     """根据图像短边对图像重新调整大小(resize)。
 
     1. 获取图像的长边和短边长度。
@@ -242,7 +274,7 @@ class ResizeByShort:
             return (im, label)
 
 
-class CenterCrop:
+class CenterCrop(ClsTransform):
     """以图像中心点扩散裁剪长宽为`crop_size`的正方形
 
     1. 计算剪裁的起始点。
@@ -272,7 +304,7 @@ class CenterCrop:
             return (im, label)
 
 
-class RandomRotate:
+class RandomRotate(ClsTransform):
     def __init__(self, rotate_range=30, prob=0.5):
         """以一定的概率对图像在[-rotate_range, rotaterange]角度范围内进行旋转,模型训练时的数据增强操作。
 
@@ -306,7 +338,7 @@ class RandomRotate:
             return (im, label)
 
 
-class RandomDistort:
+class RandomDistort(ClsTransform):
     """以一定的概率对图像进行随机像素内容变换,模型训练时的数据增强操作。
 
     1. 对变换的操作顺序进行随机化操作。
@@ -397,7 +429,7 @@ class RandomDistort:
             return (im, label)
 
 
-class ArrangeClassifier:
+class ArrangeClassifier(ClsTransform):
     """获取训练/验证/预测所需信息。注意:此操作不需用户自己显示调用
 
     Args:

+ 70 - 33
paddlex/cv/transforms/det_transforms.py

@@ -24,11 +24,20 @@ import numpy as np
 import cv2
 from PIL import Image, ImageEnhance
 
+from .imgaug_support import execute_imgaug
 from .ops import *
 from .box_utils import *
 
 
-class Compose:
+class DetTransform:
+    """检测数据处理基类
+    """
+
+    def __init__(self):
+        pass
+
+
+class Compose(DetTransform):
     """根据数据预处理/增强列表对输入数据进行操作。
        所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。
 
@@ -49,8 +58,16 @@ class Compose:
         self.transforms = transforms
         self.use_mixup = False
         for t in self.transforms:
-            if t.__class__.__name__ == 'MixupImage':
+            if type(t).__name__ == 'MixupImage':
                 self.use_mixup = True
+        # 检查transforms里面的操作,目前支持PaddleX定义的或者是imgaug操作
+        for op in self.transforms:
+            if not isinstance(op, DetTransform):
+                import imgaug.augmenters as iaa
+                if not isinstance(op, iaa.Augmenter):
+                    raise Exception(
+                        "Elements in transforms should be defined in 'paddlex.det.transforms' or class of imgaug.augmenters.Augmenter, see docs here: https://paddlex.readthedocs.io/zh_CN/latest/apis/transforms/"
+                    )
 
     def __call__(self, im, im_info=None, label_info=None):
         """
@@ -84,11 +101,18 @@ class Compose:
         def decode_image(im_file, im_info, label_info):
             if im_info is None:
                 im_info = dict()
-            try:
-                im = cv2.imread(im_file).astype('float32')
-            except:
-                raise TypeError(
-                    'Can\'t read The image file {}!'.format(im_file))
+            if isinstance(im_file, np.ndarray):
+                if len(im_file.shape) != 3:
+                    raise Exception(
+                        "im should be 3-dimensions, but now is {}-dimensions".
+                        format(len(im_file.shape)))
+                im = im_file
+            else:
+                try:
+                    im = cv2.imread(im_file).astype('float32')
+                except:
+                    raise TypeError('Can\'t read The image file {}!'.format(
+                        im_file))
             im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
             # make default im_info with [h, w, 1]
             im_info['im_resize_info'] = np.array(
@@ -117,12 +141,19 @@ class Compose:
         for op in self.transforms:
             if im is None:
                 return None
-            outputs = op(im, im_info, label_info)
-            im = outputs[0]
+            if isinstance(op, DetTransform):
+                outputs = op(im, im_info, label_info)
+                im = outputs[0]
+            else:
+                im = execute_imgaug(op, im)
+                if label_info is not None:
+                    outputs = (im, im_info, label_info)
+                else:
+                    outputs = (im, im_info)
         return outputs
 
 
-class ResizeByShort:
+class ResizeByShort(DetTransform):
     """根据图像的短边调整图像大小(resize)。
 
     1. 获取图像的长边和短边长度。
@@ -178,8 +209,8 @@ class ResizeByShort:
         im_short_size = min(im.shape[0], im.shape[1])
         im_long_size = max(im.shape[0], im.shape[1])
         scale = float(self.short_size) / im_short_size
-        if self.max_size > 0 and np.round(
-                scale * im_long_size) > self.max_size:
+        if self.max_size > 0 and np.round(scale *
+                                          im_long_size) > self.max_size:
             scale = float(self.max_size) / float(im_long_size)
         resized_width = int(round(im.shape[1] * scale))
         resized_height = int(round(im.shape[0] * scale))
@@ -194,7 +225,7 @@ class ResizeByShort:
             return (im, im_info, label_info)
 
 
-class Padding:
+class Padding(DetTransform):
     """1.将图像的长和宽padding至coarsest_stride的倍数。如输入图像为[300, 640],
        `coarest_stride`为32,则由于300不为32的倍数,因此在图像最右和最下使用0值
        进行padding,最终输出图像为[320, 640]。
@@ -262,8 +293,8 @@ class Padding:
         if isinstance(self.target_size, int):
             padding_im_h = self.target_size
             padding_im_w = self.target_size
-        elif isinstance(self.target_size, list) or isinstance(
-                self.target_size, tuple):
+        elif isinstance(self.target_size, list) or isinstance(self.target_size,
+                                                              tuple):
             padding_im_w = self.target_size[0]
             padding_im_h = self.target_size[1]
         elif self.coarsest_stride > 0:
@@ -281,8 +312,8 @@ class Padding:
             raise ValueError(
                 'the size of image should be less than target_size, but the size of image ({}, {}), is larger than target_size ({}, {})'
                 .format(im_w, im_h, padding_im_w, padding_im_h))
-        padding_im = np.zeros((padding_im_h, padding_im_w, im_c),
-                              dtype=np.float32)
+        padding_im = np.zeros(
+            (padding_im_h, padding_im_w, im_c), dtype=np.float32)
         padding_im[:im_h, :im_w, :] = im
         if label_info is None:
             return (padding_im, im_info)
@@ -290,7 +321,7 @@ class Padding:
             return (padding_im, im_info, label_info)
 
 
-class Resize:
+class Resize(DetTransform):
     """调整图像大小(resize)。
 
     - 当目标大小(target_size)类型为int时,根据插值方式,
@@ -369,7 +400,7 @@ class Resize:
             return (im, im_info, label_info)
 
 
-class RandomHorizontalFlip:
+class RandomHorizontalFlip(DetTransform):
     """随机翻转图像、标注框、分割信息,模型训练时的数据增强操作。
 
     1. 随机采样一个0-1之间的小数,当小数小于水平翻转概率时,
@@ -447,7 +478,7 @@ class RandomHorizontalFlip:
             return (im, im_info, label_info)
 
 
-class Normalize:
+class Normalize(DetTransform):
     """对图像进行标准化。
 
     1. 归一化图像到到区间[0.0, 1.0]。
@@ -491,7 +522,7 @@ class Normalize:
             return (im, im_info, label_info)
 
 
-class RandomDistort:
+class RandomDistort(DetTransform):
     """以一定的概率对图像进行随机像素内容变换,模型训练时的数据增强操作
 
     1. 对变换的操作顺序进行随机化操作。
@@ -585,7 +616,7 @@ class RandomDistort:
             return (im, im_info, label_info)
 
 
-class MixupImage:
+class MixupImage(DetTransform):
     """对图像进行mixup操作,模型训练时的数据增强操作,目前仅YOLOv3模型支持该transform。
 
     当label_info中不存在mixup字段时,直接返回,否则进行下述操作:
@@ -714,7 +745,7 @@ class MixupImage:
             return (im, im_info, label_info)
 
 
-class RandomExpand:
+class RandomExpand(DetTransform):
     """随机扩张图像,模型训练时的数据增强操作。
     1. 随机选取扩张比例(扩张比例大于1时才进行扩张)。
     2. 计算扩张后图像大小。
@@ -796,7 +827,7 @@ class RandomExpand:
         return (canvas, im_info, label_info)
 
 
-class RandomCrop:
+class RandomCrop(DetTransform):
     """随机裁剪图像。
     1. 若allow_no_crop为True,则在thresholds加入’no_crop’。
     2. 随机打乱thresholds。
@@ -892,8 +923,9 @@ class RandomCrop:
                 crop_y = np.random.randint(0, h - crop_h)
                 crop_x = np.random.randint(0, w - crop_w)
                 crop_box = [crop_x, crop_y, crop_x + crop_w, crop_y + crop_h]
-                iou = iou_matrix(gt_bbox, np.array([crop_box],
-                                                   dtype=np.float32))
+                iou = iou_matrix(
+                    gt_bbox, np.array(
+                        [crop_box], dtype=np.float32))
                 if iou.max() < thresh:
                     continue
 
@@ -901,16 +933,21 @@ class RandomCrop:
                     continue
 
                 cropped_box, valid_ids = crop_box_with_center_constraint(
-                    gt_bbox, np.array(crop_box, dtype=np.float32))
+                    gt_bbox, np.array(
+                        crop_box, dtype=np.float32))
                 if valid_ids.size > 0:
                     found = True
                     break
 
             if found:
                 if 'gt_poly' in label_info and len(label_info['gt_poly']) > 0:
-                    crop_polys = crop_segms(label_info['gt_poly'], valid_ids,
-                                            np.array(crop_box, dtype=np.int64),
-                                            h, w)
+                    crop_polys = crop_segms(
+                        label_info['gt_poly'],
+                        valid_ids,
+                        np.array(
+                            crop_box, dtype=np.int64),
+                        h,
+                        w)
                     if [] in crop_polys:
                         delete_id = list()
                         valid_polys = list()
@@ -944,7 +981,7 @@ class RandomCrop:
         return (im, im_info, label_info)
 
 
-class ArrangeFasterRCNN:
+class ArrangeFasterRCNN(DetTransform):
     """获取FasterRCNN模型训练/验证/预测所需信息。
 
     Args:
@@ -1019,7 +1056,7 @@ class ArrangeFasterRCNN:
         return outputs
 
 
-class ArrangeMaskRCNN:
+class ArrangeMaskRCNN(DetTransform):
     """获取MaskRCNN模型训练/验证/预测所需信息。
 
     Args:
@@ -1103,7 +1140,7 @@ class ArrangeMaskRCNN:
         return outputs
 
 
-class ArrangeYOLOv3:
+class ArrangeYOLOv3(DetTransform):
     """获取YOLOv3模型训练/验证/预测所需信息。
 
     Args:

+ 111 - 0
paddlex/cv/transforms/imgaug_support.py

@@ -0,0 +1,111 @@
+# copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import numpy as np
+import copy
+
+
+def execute_imgaug(augmenter, im, bboxes=None, polygons=None,
+                   segment_map=None):
+    # 预处理,将bboxes, polygons转换成imgaug格式
+    import imgaug.augmentables.kps as kps
+    import imgaug.augmentables.bbs as bbs
+
+    aug_im = im.astype('uint8')
+    aug_im = augmenter.augment(image=aug_im)
+    return aug_im
+
+    # TODO imgaug的标注处理逻辑与paddlex已存的transform存在部分差异
+    # 目前仅支持对原图进行处理,因此只能使用pixlevel的imgaug增强操作
+    # 以下代码暂不会执行
+    aug_bboxes = None
+    if bboxes is not None:
+        aug_bboxes = list()
+        for i in range(len(bboxes)):
+            x1 = bboxes[i, 0]
+            y1 = bboxes[i, 1]
+            x2 = bboxes[i, 2]
+            y2 = bboxes[i, 3]
+            aug_bboxes.append(bbs.BoundingBox(x1, y1, x2, y2))
+
+    aug_points = None
+    if polygons is not None:
+        aug_points = list()
+        for i in range(len(polygons)):
+            num = len(polygons[i])
+            for j in range(num):
+                tmp = np.reshape(polygons[i][j], (-1, 2))
+                for k in range(len(tmp)):
+                    aug_points.append(kps.Keypoint(tmp[k, 0], tmp[k, 1]))
+
+    aug_segment_map = None
+    if segment_map is not None:
+        if len(segment_map.shape) == 2:
+            h, w = segment_map.shape
+            aug_segment_map = np.reshape(segment_map, (1, h, w, 1))
+        elif len(segment_map.shape) == 3:
+            h, w, c = segment_map.shape
+            aug_segment_map = np.reshape(segment_map, (1, h, w, c))
+        else:
+            raise Exception(
+                "Only support 2-dimensions for 3-dimensions for segment_map")
+
+    unnormalized_batch = augmenter.augment(
+        image=aug_im,
+        bounding_boxes=aug_bboxes,
+        keypoints=aug_points,
+        segmentation_maps=aug_segment_map,
+        return_batch=True)
+    aug_im = unnormalized_batch.images_aug[0]
+    aug_bboxes = unnormalized_batch.bounding_boxes_aug
+    aug_points = unnormalized_batch.keypoints_aug
+    aug_seg_map = unnormalized_batch.segmentation_maps_aug
+
+    aug_im = aug_im.astype('float32')
+
+    if aug_bboxes is not None:
+        converted_bboxes = list()
+        for i in range(len(aug_bboxes)):
+            converted_bboxes.append([
+                aug_bboxes[i].x1, aug_bboxes[i].y1, aug_bboxes[i].x2,
+                aug_bboxes[i].y2
+            ])
+        aug_bboxes = converted_bboxes
+
+    aug_polygons = None
+    if aug_points is not None:
+        aug_polygons = copy.deepcopy(polygons)
+        idx = 0
+        for i in range(len(aug_polygons)):
+            num = len(aug_polygons[i])
+            for j in range(num):
+                num_points = len(aug_polygons[i][j]) // 2
+                for k in range(num_points):
+                    aug_polygons[i][j][k * 2] = aug_points[idx].x
+                    aug_polygons[i][j][k * 2 + 1] = aug_points[idx].y
+                    idx += 1
+
+    result = [aug_im]
+    if aug_bboxes is not None:
+        result.append(np.array(aug_bboxes))
+    if aug_polygons is not None:
+        result.append(aug_polygons)
+    if aug_seg_map is not None:
+        n, h, w, c = aug_seg_map.shape
+        if len(segment_map.shape) == 2:
+            aug_seg_map = np.reshape(aug_seg_map, (h, w))
+        elif len(segment_map.shape) == 3:
+            aug_seg_map = np.reshape(aug_seg_map, (h, w, c))
+        result.append(aug_seg_map)
+    return result

+ 62 - 32
paddlex/cv/transforms/seg_transforms.py

@@ -14,6 +14,7 @@
 # limitations under the License.
 
 from .ops import *
+from .imgaug_support import execute_imgaug
 import random
 import os.path as osp
 import numpy as np
@@ -22,7 +23,15 @@ import cv2
 from collections import OrderedDict
 
 
-class Compose:
+class SegTransform:
+    """ 分割transform基类
+    """
+
+    def __init__(self):
+        pass
+
+
+class Compose(SegTransform):
     """根据数据预处理/增强算子对输入数据进行操作。
        所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。
 
@@ -43,6 +52,14 @@ class Compose:
                             'must be equal or larger than 1!')
         self.transforms = transforms
         self.to_rgb = False
+        # 检查transforms里面的操作,目前支持PaddleX定义的或者是imgaug操作
+        for op in self.transforms:
+            if not isinstance(op, SegTransform):
+                import imgaug.augmenters as iaa
+                if not isinstance(op, iaa.Augmenter):
+                    raise Exception(
+                        "Elements in transforms should be defined in 'paddlex.seg.transforms' or class of imgaug.augmenters.Augmenter, see docs here: https://paddlex.readthedocs.io/zh_CN/latest/apis/transforms/"
+                    )
 
     def __call__(self, im, im_info=None, label=None):
         """
@@ -60,26 +77,39 @@ class Compose:
 
         if im_info is None:
             im_info = list()
-        try:
-            im = cv2.imread(im).astype('float32')
-        except:
-            raise ValueError('Can\'t read The image file {}!'.format(im))
+        if isinstance(im, np.ndarray):
+            if len(im.shape) != 3:
+                raise Exception(
+                    "im should be 3-dimensions, but now is {}-dimensions".
+                    format(len(im.shape)))
+        else:
+            try:
+                im = cv2.imread(im).astype('float32')
+            except:
+                raise ValueError('Can\'t read The image file {}!'.format(im))
         if self.to_rgb:
             im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
         if label is not None:
             if not isinstance(label, np.ndarray):
                 label = np.asarray(Image.open(label))
         for op in self.transforms:
-            outputs = op(im, im_info, label)
-            im = outputs[0]
-            if len(outputs) >= 2:
-                im_info = outputs[1]
-            if len(outputs) == 3:
-                label = outputs[2]
+            if isinstance(op, SegTransform):
+                outputs = op(im, im_info, label)
+                im = outputs[0]
+                if len(outputs) >= 2:
+                    im_info = outputs[1]
+                if len(outputs) == 3:
+                    label = outputs[2]
+            else:
+                im = execute_imgaug(op, im)
+                if label is not None:
+                    outputs = (im, im_info, label)
+                else:
+                    outputs = (im, im_info)
         return outputs
 
 
-class RandomHorizontalFlip:
+class RandomHorizontalFlip(SegTransform):
     """以一定的概率对图像进行水平翻转。当存在标注图像时,则同步进行翻转。
 
     Args:
@@ -115,7 +145,7 @@ class RandomHorizontalFlip:
             return (im, im_info, label)
 
 
-class RandomVerticalFlip:
+class RandomVerticalFlip(SegTransform):
     """以一定的概率对图像进行垂直翻转。当存在标注图像时,则同步进行翻转。
 
     Args:
@@ -150,7 +180,7 @@ class RandomVerticalFlip:
             return (im, im_info, label)
 
 
-class Resize:
+class Resize(SegTransform):
     """调整图像大小(resize),当存在标注图像时,则同步进行处理。
 
     - 当目标大小(target_size)类型为int时,根据插值方式,
@@ -260,7 +290,7 @@ class Resize:
             return (im, im_info, label)
 
 
-class ResizeByLong:
+class ResizeByLong(SegTransform):
     """对图像长边resize到固定值,短边按比例进行缩放。当存在标注图像时,则同步进行处理。
 
     Args:
@@ -301,7 +331,7 @@ class ResizeByLong:
             return (im, im_info, label)
 
 
-class ResizeByShort:
+class ResizeByShort(SegTransform):
     """根据图像的短边调整图像大小(resize)。
 
     1. 获取图像的长边和短边长度。
@@ -360,8 +390,8 @@ class ResizeByShort:
         im_short_size = min(im.shape[0], im.shape[1])
         im_long_size = max(im.shape[0], im.shape[1])
         scale = float(self.short_size) / im_short_size
-        if self.max_size > 0 and np.round(
-                scale * im_long_size) > self.max_size:
+        if self.max_size > 0 and np.round(scale *
+                                          im_long_size) > self.max_size:
             scale = float(self.max_size) / float(im_long_size)
         resized_width = int(round(im.shape[1] * scale))
         resized_height = int(round(im.shape[0] * scale))
@@ -378,7 +408,7 @@ class ResizeByShort:
             return (im, im_info, label)
 
 
-class ResizeRangeScaling:
+class ResizeRangeScaling(SegTransform):
     """对图像长边随机resize到指定范围内,短边按比例进行缩放。当存在标注图像时,则同步进行处理。
 
     Args:
@@ -392,8 +422,8 @@ class ResizeRangeScaling:
     def __init__(self, min_value=400, max_value=600):
         if min_value > max_value:
             raise ValueError('min_value must be less than max_value, '
-                             'but they are {} and {}.'.format(
-                                 min_value, max_value))
+                             'but they are {} and {}.'.format(min_value,
+                                                              max_value))
         self.min_value = min_value
         self.max_value = max_value
 
@@ -427,7 +457,7 @@ class ResizeRangeScaling:
             return (im, im_info, label)
 
 
-class ResizeStepScaling:
+class ResizeStepScaling(SegTransform):
     """对图像按照某一个比例resize,这个比例以scale_step_size为步长
     在[min_scale_factor, max_scale_factor]随机变动。当存在标注图像时,则同步进行处理。
 
@@ -502,7 +532,7 @@ class ResizeStepScaling:
             return (im, im_info, label)
 
 
-class Normalize:
+class Normalize(SegTransform):
     """对图像进行标准化。
     1.尺度缩放到 [0,1]。
     2.对图像进行减均值除以标准差操作。
@@ -550,7 +580,7 @@ class Normalize:
             return (im, im_info, label)
 
 
-class Padding:
+class Padding(SegTransform):
     """对图像或标注图像进行padding,padding方向为右和下。
     根据提供的值对图像或标注图像进行padding操作。
 
@@ -642,7 +672,7 @@ class Padding:
             return (im, im_info, label)
 
 
-class RandomPaddingCrop:
+class RandomPaddingCrop(SegTransform):
     """对图像和标注图进行随机裁剪,当所需要的裁剪尺寸大于原图时,则进行padding操作。
 
     Args:
@@ -730,8 +760,8 @@ class RandomPaddingCrop:
                 h_off = np.random.randint(img_height - crop_height + 1)
                 w_off = np.random.randint(img_width - crop_width + 1)
 
-                im = im[h_off:(crop_height + h_off), w_off:(
-                    w_off + crop_width), :]
+                im = im[h_off:(crop_height + h_off), w_off:(w_off + crop_width
+                                                            ), :]
                 if label is not None:
                     label = label[h_off:(crop_height + h_off), w_off:(
                         w_off + crop_width)]
@@ -741,7 +771,7 @@ class RandomPaddingCrop:
             return (im, im_info, label)
 
 
-class RandomBlur:
+class RandomBlur(SegTransform):
     """以一定的概率对图像进行高斯模糊。
 
     Args:
@@ -787,7 +817,7 @@ class RandomBlur:
             return (im, im_info, label)
 
 
-class RandomRotate:
+class RandomRotate(SegTransform):
     """对图像进行随机旋转, 模型训练时的数据增强操作。
     在旋转区间[-rotate_range, rotate_range]内,对图像进行随机旋转,当存在标注图像时,同步进行,
     并对旋转后的图像和标注图像进行相应的padding。
@@ -859,7 +889,7 @@ class RandomRotate:
             return (im, im_info, label)
 
 
-class RandomScaleAspect:
+class RandomScaleAspect(SegTransform):
     """裁剪并resize回原始尺寸的图像和标注图像。
     按照一定的面积比和宽高比对图像进行裁剪,并reszie回原始图像的图像,当存在标注图时,同步进行。
 
@@ -922,7 +952,7 @@ class RandomScaleAspect:
             return (im, im_info, label)
 
 
-class RandomDistort:
+class RandomDistort(SegTransform):
     """对图像进行随机失真。
 
     1. 对变换的操作顺序进行随机化操作。
@@ -1018,7 +1048,7 @@ class RandomDistort:
             return (im, im_info, label)
 
 
-class ArrangeSegmenter:
+class ArrangeSegmenter(SegTransform):
     """获取训练/验证/预测所需的信息。
 
     Args:

+ 24 - 0
paddlex/tools/__init__.py

@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# coding: utf-8
+# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from .x2imagenet import EasyData2ImageNet
+from .x2coco import LabelMe2COCO
+from .x2coco import EasyData2COCO
+from .x2voc import LabelMe2VOC
+from .x2voc import EasyData2VOC
+from .x2seg import JingLing2Seg
+from .x2seg import LabelMe2Seg
+from .x2seg import EasyData2Seg

+ 43 - 0
paddlex/tools/base.py

@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# coding: utf-8
+# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+import chardet
+import numpy as np
+
+class MyEncoder(json.JSONEncoder):
+    def default(self, obj):
+        if isinstance(obj, np.integer):
+            return int(obj)
+        elif isinstance(obj, np.floating):
+            return float(obj)
+        elif isinstance(obj, np.ndarray):
+            return obj.tolist()
+        else:
+            return super(MyEncoder, self).default(obj)
+        
+def is_pic(img_name):
+    valid_suffix = ["JPEG", "jpeg", "JPG", "jpg", "BMP", "bmp", "PNG", "png"]
+    suffix = img_name.split(".")[-1]
+    if suffix not in valid_suffix:
+        return False
+    return True
+
+def get_encoding(path):
+    f = open(path, 'rb')
+    data = f.read()
+    file_encoding = chardet.detect(data).get('encoding')
+    return file_encoding

+ 257 - 0
paddlex/tools/x2coco.py

@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+# coding: utf-8
+# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import cv2
+import json
+import os
+import os.path as osp
+import shutil
+import numpy as np
+import PIL.ImageDraw
+from .base import MyEncoder, is_pic, get_encoding
+        
+        
+class X2COCO(object):
+    def __init__(self):
+        self.images_list = []
+        self.categories_list = []
+        self.annotations_list = []
+    
+    def generate_categories_field(self, label, labels_list):
+        category = {}
+        category["supercategory"] = "component"
+        category["id"] = len(labels_list) + 1
+        category["name"] = label
+        return category
+    
+    def generate_rectangle_anns_field(self, points, label, image_id, object_id, label_to_num):
+        annotation = {}
+        seg_points = np.asarray(points).copy()
+        seg_points[1, :] = np.asarray(points)[2, :]
+        seg_points[2, :] = np.asarray(points)[1, :]
+        annotation["segmentation"] = [list(seg_points.flatten())]
+        annotation["iscrowd"] = 0
+        annotation["image_id"] = image_id + 1
+        annotation["bbox"] = list(
+            map(float, [
+                points[0][0], points[0][1], points[1][0] - points[0][0], points[1][
+                    1] - points[0][1]
+            ]))
+        annotation["area"] = annotation["bbox"][2] * annotation["bbox"][3]
+        annotation["category_id"] = label_to_num[label]
+        annotation["id"] = object_id + 1
+        return annotation
+    
+    def convert(self, image_dir, json_dir, dataset_save_dir):
+        """转换。
+        Args:
+            image_dir (str): 图像文件存放的路径。
+            json_dir (str): 与每张图像对应的json文件的存放路径。
+            dataset_save_dir (str): 转换后数据集存放路径。
+        """
+        assert osp.exists(image_dir), "he image folder does not exist!"
+        assert osp.exists(json_dir), "The json folder does not exist!"
+        assert osp.exists(dataset_save_dir), "The save folder does not exist!"
+        # Convert the image files.
+        new_image_dir = osp.join(dataset_save_dir, "JPEGImages")
+        if osp.exists(new_image_dir):
+            shutil.rmtree(new_image_dir)
+        os.makedirs(new_image_dir)
+        for img_name in os.listdir(image_dir):
+            if is_pic(img_name):
+                shutil.copyfile(
+                            osp.join(image_dir, img_name),
+                            osp.join(new_image_dir, img_name))
+        # Convert the json files.
+        self.parse_json(new_image_dir, json_dir)
+        coco_data = {}
+        coco_data["images"] = self.images_list
+        coco_data["categories"] = self.categories_list
+        coco_data["annotations"] = self.annotations_list
+        json_path = osp.join(dataset_save_dir, "annotations.json")
+        json.dump(
+            coco_data,
+            open(json_path, "w"),
+            indent=4,
+            cls=MyEncoder)
+    
+    
+class LabelMe2COCO(X2COCO):
+    """将使用LabelMe标注的数据集转换为COCO数据集。
+    """
+    def __init__(self):
+        super(LabelMe2COCO, self).__init__()
+        
+    def generate_images_field(self, json_info, image_id):
+        image = {}
+        image["height"] = json_info["imageHeight"]
+        image["width"] = json_info["imageWidth"]
+        image["id"] = image_id + 1
+        image["file_name"] = json_info["imagePath"].split("/")[-1]
+        return image
+    
+    def generate_polygon_anns_field(self, height, width, 
+                                    points, label, image_id, 
+                                    object_id, label_to_num):
+        annotation = {}
+        annotation["segmentation"] = [list(np.asarray(points).flatten())]
+        annotation["iscrowd"] = 0
+        annotation["image_id"] = image_id + 1
+        annotation["bbox"] = list(map(float, get_bbox(height, width, points)))
+        annotation["area"] = annotation["bbox"][2] * annotation["bbox"][3]
+        annotation["category_id"] = label_to_num[label]
+        annotation["id"] = object_id + 1
+        return annotation
+    
+    def get_bbox(self, height, width, points):
+        polygons = points
+        mask = np.zeros([height, width], dtype=np.uint8)
+        mask = PIL.Image.fromarray(mask)
+        xy = list(map(tuple, polygons))
+        PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
+        mask = np.array(mask, dtype=bool)
+        index = np.argwhere(mask == 1)
+        rows = index[:, 0]
+        clos = index[:, 1]
+        left_top_r = np.min(rows)
+        left_top_c = np.min(clos)
+        right_bottom_r = np.max(rows)
+        right_bottom_c = np.max(clos)
+        return [
+            left_top_c, left_top_r, right_bottom_c - left_top_c,
+            right_bottom_r - left_top_r
+        ]
+    
+    def parse_json(self, img_dir, json_dir):
+        image_id = -1
+        object_id = -1
+        labels_list = []
+        label_to_num = {}
+        for img_file in os.listdir(img_dir):
+            img_name_part = osp.splitext(img_file)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_file)))
+                continue
+            image_id = image_id + 1
+            with open(json_file, mode='r', \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                img_info = self.generate_images_field(json_info, image_id)
+                self.images_list.append(img_info)
+                for shapes in json_info["shapes"]:
+                    object_id = object_id + 1
+                    label = shapes["label"]
+                    if label not in labels_list:
+                        self.categories_list.append(\
+                            self.generate_categories_field(label, labels_list))
+                        labels_list.append(label)
+                        label_to_num[label] = len(labels_list)
+                    points = shapes["points"]
+                    p_type = shapes["shape_type"]
+                    if p_type == "polygon":
+                        self.annotations_list.append(
+                            self.generate_polygon_anns_field(json_info["imageHeight"], json_info[
+                                "imageWidth"], points, label, image_id,
+                                                object_id, label_to_num))
+                    if p_type == "rectangle":
+                        points.append([points[0][0], points[1][1]])
+                        points.append([points[1][0], points[0][1]])
+                        self.annotations_list.append(
+                            self.generate_rectangle_anns_field(points, label, image_id,
+                                                  object_id, label_to_num))
+                        
+    
+class EasyData2COCO(X2COCO):
+    """将使用EasyData标注的检测或分割数据集转换为COCO数据集。
+    """
+    def __init__(self):
+        super(EasyData2COCO, self).__init__()        
+    
+    def generate_images_field(self, img_path, image_id):
+        image = {}
+        img = cv2.imread(img_path)
+        image["height"] = img.shape[0]
+        image["width"] = img.shape[1]
+        image["id"] = image_id + 1
+        image["file_name"] = osp.split(img_path)[-1]
+        return image
+    
+    def generate_polygon_anns_field(self, points, segmentation, 
+                                    label, image_id, object_id,
+                                    label_to_num):
+        annotation = {}
+        annotation["segmentation"] = segmentation
+        annotation["iscrowd"] = 1 if len(segmentation) > 1 else 0
+        annotation["image_id"] = image_id + 1
+        annotation["bbox"] = list(map(float, [
+                points[0][0], points[0][1], points[1][0] - points[0][0], points[1][
+                    1] - points[0][1]
+            ]))
+        annotation["area"] = annotation["bbox"][2] * annotation["bbox"][3]
+        annotation["category_id"] = label_to_num[label]
+        annotation["id"] = object_id + 1
+        return annotation
+        
+    def parse_json(self, img_dir, json_dir):
+        from pycocotools.mask import decode
+        image_id = -1
+        object_id = -1
+        labels_list = []
+        label_to_num = {}
+        for img_file in os.listdir(img_dir):
+            img_name_part = osp.splitext(img_file)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_file)))
+                continue
+            image_id = image_id + 1
+            with open(json_file, mode='r', \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                img_info = self.generate_images_field(osp.join(img_dir, img_file), image_id)
+                self.images_list.append(img_info)
+                for shapes in json_info["labels"]:
+                    object_id = object_id + 1
+                    label = shapes["name"]
+                    if label not in labels_list:
+                        self.categories_list.append(\
+                            self.generate_categories_field(label, labels_list))
+                        labels_list.append(label)
+                        label_to_num[label] = len(labels_list)
+                    points = [[shapes["x1"], shapes["y1"]],
+                              [shapes["x2"], shapes["y2"]]]
+                    if "mask" not in shapes:
+                        points.append([points[0][0], points[1][1]])
+                        points.append([points[1][0], points[0][1]])
+                        self.annotations_list.append(
+                            self.generate_rectangle_anns_field(points, label, image_id,
+                                                  object_id, label_to_num))
+                    else:
+                        mask_dict = {}
+                        mask_dict['size'] = [img_info["height"], img_info["width"]]
+                        mask_dict['counts'] = shapes['mask'].encode()
+                        mask = decode(mask_dict)
+                        contours, hierarchy = cv2.findContours(
+                                (mask).astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
+                        segmentation = []
+                        for contour in contours:
+                            contour_list = contour.flatten().tolist()
+                            if len(contour_list) > 4:
+                                segmentation.append(contour_list)
+                        self.annotations_list.append(
+                            self.generate_polygon_anns_field(points, segmentation, label, image_id, object_id,
+                                                label_to_num))

+ 58 - 0
paddlex/tools/x2imagenet.py

@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+# coding: utf-8
+# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import cv2
+import json
+import os
+import os.path as osp
+import shutil
+import numpy as np
+from .base import MyEncoder, is_pic, get_encoding
+
+class EasyData2ImageNet(object):
+    """将使用EasyData标注的分类数据集转换为COCO数据集。
+    """
+    def __init__(self):
+        pass
+    
+    def convert(self, image_dir, json_dir, dataset_save_dir):
+        """转换。
+        Args:
+            image_dir (str): 图像文件存放的路径。
+            json_dir (str): 与每张图像对应的json文件的存放路径。
+            dataset_save_dir (str): 转换后数据集存放路径。
+        """
+        assert osp.exists(image_dir), "The image folder does not exist!"
+        assert osp.exists(json_dir), "The json folder does not exist!"
+        assert osp.exists(dataset_save_dir), "The save folder does not exist!"
+        assert len(os.listdir(dataset_save_dir)) == 0, "The save folder must be empty!"
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                continue
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                for output in json_info['labels']:
+                    cls_name = output['name']
+                    new_image_dir = osp.join(dataset_save_dir, cls_name)
+                    if not osp.exists(new_image_dir):
+                        os.makedirs(new_image_dir)
+                    if is_pic(img_name):
+                        shutil.copyfile(
+                                    osp.join(image_dir, img_name),
+                                    osp.join(new_image_dir, img_name))

+ 332 - 0
paddlex/tools/x2seg.py

@@ -0,0 +1,332 @@
+#!/usr/bin/env python
+# coding: utf-8
+# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import cv2
+import uuid
+import json
+import os
+import os.path as osp
+import shutil
+import numpy as np
+import PIL.Image
+from .base import MyEncoder, is_pic, get_encoding
+
+class X2Seg(object):
+    def __init__(self):
+        self.labels2ids = {'_background_': 0}
+        
+    def shapes_to_label(self, img_shape, shapes, label_name_to_value):
+        # 该函数基于https://github.com/wkentaro/labelme/blob/master/labelme/utils/shape.py实现。
+        def shape_to_mask(img_shape, points, shape_type=None,
+                  line_width=10, point_size=5):
+            mask = np.zeros(img_shape[:2], dtype=np.uint8)
+            mask = PIL.Image.fromarray(mask)
+            draw = PIL.ImageDraw.Draw(mask)
+            xy = [tuple(point) for point in points]
+            if shape_type == 'circle':
+                assert len(xy) == 2, 'Shape of shape_type=circle must have 2 points'
+                (cx, cy), (px, py) = xy
+                d = math.sqrt((cx - px) ** 2 + (cy - py) ** 2)
+                draw.ellipse([cx - d, cy - d, cx + d, cy + d], outline=1, fill=1)
+            elif shape_type == 'rectangle':
+                assert len(xy) == 2, 'Shape of shape_type=rectangle must have 2 points'
+                draw.rectangle(xy, outline=1, fill=1)
+            elif shape_type == 'line':
+                assert len(xy) == 2, 'Shape of shape_type=line must have 2 points'
+                draw.line(xy=xy, fill=1, width=line_width)
+            elif shape_type == 'linestrip':
+                draw.line(xy=xy, fill=1, width=line_width)
+            elif shape_type == 'point':
+                assert len(xy) == 1, 'Shape of shape_type=point must have 1 points'
+                cx, cy = xy[0]
+                r = point_size
+                draw.ellipse([cx - r, cy - r, cx + r, cy + r], outline=1, fill=1)
+            else:
+                assert len(xy) > 2, 'Polygon must have points more than 2'
+                draw.polygon(xy=xy, outline=1, fill=1)
+            mask = np.array(mask, dtype=bool)
+            return mask
+        cls = np.zeros(img_shape[:2], dtype=np.int32)
+        ins = np.zeros_like(cls)
+        instances = []
+        for shape in shapes:
+            points = shape['points']
+            label = shape['label']
+            group_id = shape.get('group_id')
+            if group_id is None:
+                group_id = uuid.uuid1()
+            shape_type = shape.get('shape_type', None)
+
+            cls_name = label
+            instance = (cls_name, group_id)
+
+            if instance not in instances:
+                instances.append(instance)
+            ins_id = instances.index(instance) + 1
+            cls_id = label_name_to_value[cls_name]
+            mask = shape_to_mask(img_shape[:2], points, shape_type)
+            cls[mask] = cls_id
+            ins[mask] = ins_id
+        return cls, ins
+    
+    def get_color_map_list(self, num_classes):
+        color_map = num_classes * [0, 0, 0]
+        for i in range(0, num_classes):
+            j = 0
+            lab = i
+            while lab:
+                color_map[i * 3] |= (((lab >> 0) & 1) << (7 - j))
+                color_map[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j))
+                color_map[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j))
+                j += 1
+                lab >>= 3
+        return color_map
+    
+    def convert(self, image_dir, json_dir, dataset_save_dir):
+        """转换。
+        Args:
+            image_dir (str): 图像文件存放的路径。
+            json_dir (str): 与每张图像对应的json文件的存放路径。
+            dataset_save_dir (str): 转换后数据集存放路径。
+        """
+        assert osp.exists(image_dir), "The image folder does not exist!"
+        assert osp.exists(json_dir), "The json folder does not exist!"
+        assert osp.exists(dataset_save_dir), "The save folder does not exist!"
+        # Convert the image files.
+        new_image_dir = osp.join(dataset_save_dir, "JPEGImages")
+        if osp.exists(new_image_dir):
+            shutil.rmtree(new_image_dir)
+        os.makedirs(new_image_dir)
+        for img_name in os.listdir(image_dir):
+            if is_pic(img_name):
+                shutil.copyfile(
+                            osp.join(image_dir, img_name),
+                            osp.join(new_image_dir, img_name))
+        # Convert the json files.
+        png_dir = osp.join(dataset_save_dir, "Annotations")
+        if osp.exists(png_dir):
+            shutil.rmtree(png_dir)
+        os.makedirs(png_dir)
+        self.get_labels2ids(new_image_dir, json_dir)
+        self.json2png(new_image_dir, json_dir, png_dir)
+        # Generate the labels.txt
+        ids2labels = {v : k for k, v in self.labels2ids.items()}
+        with open(osp.join(dataset_save_dir, 'labels.txt'), 'w') as fw:
+            for i in range(len(ids2labels)):
+                fw.write(ids2labels[i] + '\n')
+        
+
+class JingLing2Seg(X2Seg):
+    """将使用标注精灵标注的数据集转换为Seg数据集。
+    """
+    def __init__(self):
+        super(JingLing2Seg, self).__init__() 
+        
+    def get_labels2ids(self, image_dir, json_dir):
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_name)))
+                continue
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                if 'outputs' in json_info:
+                    for output in json_info['outputs']['object']:
+                        cls_name = output['name']
+                        if cls_name not in self.labels2ids:
+                            self.labels2ids[cls_name] =  len(self.labels2ids)
+    
+    def json2png(self, image_dir, json_dir, png_dir):
+        color_map = self.get_color_map_list(256)
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_name)))
+                continue
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                data_shapes = []
+                if 'outputs' in json_info:
+                    for output in json_info['outputs']['object']:
+                        if 'polygon' in output.keys():
+                            polygon = output['polygon']
+                            name = output['name']
+                            points = []
+                            for i in range(1, int(len(polygon) / 2) + 1):
+                                points.append(
+                                    [polygon['x' + str(i)], polygon['y' + str(i)]])
+                            shape = {
+                                'label': name,
+                                'points': points,
+                                'shape_type': 'polygon'
+                            }
+                            data_shapes.append(shape)
+                if 'size' not in json_info:
+                    continue
+            img_shape = (json_info['size']['height'], 
+                         json_info['size']['width'],
+                         json_info['size']['depth'])
+            lbl, _ = self.shapes_to_label(
+                img_shape=img_shape,
+                shapes=data_shapes,
+                label_name_to_value=self.labels2ids,
+            )
+            out_png_file = osp.join(png_dir, img_name_part + '.png')
+            if lbl.min() >= 0 and lbl.max() <= 255:
+                lbl_pil = PIL.Image.fromarray(lbl.astype(np.uint8), mode='P')
+                lbl_pil.putpalette(color_map)
+                lbl_pil.save(out_png_file)
+            else:
+                raise ValueError(
+                    '[%s] Cannot save the pixel-wise class label as PNG. '
+                    'Please consider using the .npy format.' % out_png_file)
+                
+                
+class LabelMe2Seg(X2Seg):
+    """将使用LabelMe标注的数据集转换为Seg数据集。
+    """
+    def __init__(self):
+        super(LabelMe2Seg, self).__init__()
+    
+    def get_labels2ids(self, image_dir, json_dir):
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_name)))
+                continue
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                for shape in json_info['shapes']:
+                    cls_name = shape['label']
+                    if cls_name not in self.labels2ids:
+                        self.labels2ids[cls_name] =  len(self.labels2ids)
+                     
+    def json2png(self, image_dir, json_dir, png_dir):
+        color_map = self.get_color_map_list(256)
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_name)))
+                continue
+            img_file = osp.join(image_dir, img_name)
+            img = np.asarray(PIL.Image.open(img_file))
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+            lbl, _ = self.shapes_to_label(
+                img_shape=img.shape,
+                shapes=json_info['shapes'],
+                label_name_to_value=self.labels2ids,
+            )
+            out_png_file = osp.join(png_dir, img_name_part + '.png')
+            if lbl.min() >= 0 and lbl.max() <= 255:
+                lbl_pil = PIL.Image.fromarray(lbl.astype(np.uint8), mode='P')
+                lbl_pil.putpalette(color_map)
+                lbl_pil.save(out_png_file)
+            else:
+                raise ValueError(
+                    '[%s] Cannot save the pixel-wise class label as PNG. '
+                    'Please consider using the .npy format.' % out_png_file)
+                
+                            
+class EasyData2Seg(X2Seg):
+    """将使用EasyData标注的分割数据集转换为Seg数据集。
+    """
+    def __init__(self):
+        super(EasyData2Seg, self).__init__()
+    
+    def get_labels2ids(self, image_dir, json_dir):
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_name)))
+                continue
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                for shape in json_info["labels"]:
+                    cls_name = shape['name']
+                    if cls_name not in self.labels2ids:
+                        self.labels2ids[cls_name] =  len(self.labels2ids)
+                        
+    def mask2polygon(self, mask, label):
+        contours, hierarchy = cv2.findContours(
+            (mask).astype(np.uint8), cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
+        segmentation = []
+        for contour in contours:
+            contour_list = contour.flatten().tolist()
+            if len(contour_list) > 4:
+                points = []
+                for i in range(0, len(contour_list), 2):
+                    points.append(
+                                [contour_list[i], contour_list[i + 1]])
+                shape = {
+                    'label': label,
+                    'points': points,
+                    'shape_type': 'polygon'
+                }
+                segmentation.append(shape)
+        return segmentation
+    
+    def json2png(self, image_dir, json_dir, png_dir):
+        from pycocotools.mask import decode
+        color_map = self.get_color_map_list(256)
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_name)))
+                continue
+            img_file = osp.join(image_dir, img_name)
+            img = np.asarray(PIL.Image.open(img_file))
+            img_h = img.shape[0]
+            img_w = img.shape[1]
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                data_shapes = []
+                for shape in json_info['labels']:
+                    mask_dict = {}
+                    mask_dict['size'] = [img_h, img_w]
+                    mask_dict['counts'] = shape['mask'].encode()
+                    mask = decode(mask_dict)
+                    polygon = self.mask2polygon(mask, shape["name"])
+                    data_shapes.extend(polygon)
+            lbl, _ = self.shapes_to_label(
+                img_shape=img.shape,
+                shapes=data_shapes,
+                label_name_to_value=self.labels2ids,
+            )
+            out_png_file = osp.join(png_dir, img_name_part + '.png')
+            if lbl.min() >= 0 and lbl.max() <= 255:
+                lbl_pil = PIL.Image.fromarray(lbl.astype(np.uint8), mode='P')
+                lbl_pil.putpalette(color_map)
+                lbl_pil.save(out_png_file)
+            else:
+                raise ValueError(
+                    '[%s] Cannot save the pixel-wise class label as PNG. '
+                    'Please consider using the .npy format.' % out_png_file)
+            
+
+

+ 199 - 0
paddlex/tools/x2voc.py

@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+# coding: utf-8
+# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import cv2
+import json
+import os
+import os.path as osp
+import shutil
+import numpy as np
+from .base import MyEncoder, is_pic, get_encoding
+
+class X2VOC(object):
+    def __init__(self):
+        pass
+    
+    def convert(self, image_dir, json_dir, dataset_save_dir):
+        """转换。
+        Args:
+            image_dir (str): 图像文件存放的路径。
+            json_dir (str): 与每张图像对应的json文件的存放路径。
+            dataset_save_dir (str): 转换后数据集存放路径。
+        """
+        assert osp.exists(image_dir), "The image folder does not exist!"
+        assert osp.exists(json_dir), "The json folder does not exist!"
+        assert osp.exists(dataset_save_dir), "The save folder does not exist!"
+        # Convert the image files.
+        new_image_dir = osp.join(dataset_save_dir, "JPEGImages")
+        if osp.exists(new_image_dir):
+            shutil.rmtree(new_image_dir)
+        os.makedirs(new_image_dir)
+        for img_name in os.listdir(image_dir):
+            if is_pic(img_name):
+                shutil.copyfile(
+                            osp.join(image_dir, img_name),
+                            osp.join(new_image_dir, img_name))
+        # Convert the json files.
+        xml_dir = osp.join(dataset_save_dir, "Annotations")
+        if osp.exists(xml_dir):
+            shutil.rmtree(xml_dir)
+        os.makedirs(xml_dir)
+        self.json2xml(new_image_dir, json_dir, xml_dir)
+        
+        
+class LabelMe2VOC(X2VOC):
+    """将使用LabelMe标注的数据集转换为VOC数据集。
+    """
+    def __init__(self):
+        pass
+    
+    def json2xml(self, image_dir, json_dir, xml_dir):
+        import xml.dom.minidom as minidom
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_name)))
+                continue
+            xml_doc = minidom.Document() 
+            root = xml_doc.createElement("annotation") 
+            xml_doc.appendChild(root)
+            node_folder = xml_doc.createElement("folder")
+            node_folder.appendChild(xml_doc.createTextNode("JPEGImages"))
+            root.appendChild(node_folder)
+            node_filename = xml_doc.createElement("filename")
+            node_filename.appendChild(xml_doc.createTextNode(img_name))
+            root.appendChild(node_filename)
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                h = json_info["imageHeight"]
+                w = json_info["imageWidth"]
+                node_size = xml_doc.createElement("size")
+                node_width = xml_doc.createElement("width")
+                node_width.appendChild(xml_doc.createTextNode(str(w)))
+                node_size.appendChild(node_width)
+                node_height = xml_doc.createElement("height")
+                node_height.appendChild(xml_doc.createTextNode(str(h)))
+                node_size.appendChild(node_height)
+                node_depth = xml_doc.createElement("depth")
+                node_depth.appendChild(xml_doc.createTextNode(str(3)))
+                node_size.appendChild(node_depth)
+                root.appendChild(node_size)
+                for shape in json_info["shapes"]:
+                    if shape["shape_type"] != "rectangle":
+                        continue
+                    label = shape["label"]
+                    (xmin, ymin), (xmax, ymax) = shape["points"]
+                    xmin, xmax = sorted([xmin, xmax])
+                    ymin, ymax = sorted([ymin, ymax])
+                    node_obj = xml_doc.createElement("object")
+                    node_name = xml_doc.createElement("name")
+                    node_name.appendChild(xml_doc.createTextNode(label))
+                    node_obj.appendChild(node_name)
+                    node_diff = xml_doc.createElement("difficult")
+                    node_diff.appendChild(xml_doc.createTextNode(str(0)))
+                    node_obj.appendChild(node_diff)
+                    node_box = xml_doc.createElement("bndbox")
+                    node_xmin = xml_doc.createElement("xmin")
+                    node_xmin.appendChild(xml_doc.createTextNode(str(xmin)))
+                    node_box.appendChild(node_xmin)
+                    node_ymin = xml_doc.createElement("ymin")
+                    node_ymin.appendChild(xml_doc.createTextNode(str(ymin)))
+                    node_box.appendChild(node_ymin)
+                    node_xmax = xml_doc.createElement("xmax")
+                    node_xmax.appendChild(xml_doc.createTextNode(str(xmax)))
+                    node_box.appendChild(node_xmax)
+                    node_ymax = xml_doc.createElement("ymax")
+                    node_ymax.appendChild(xml_doc.createTextNode(str(ymax)))
+                    node_box.appendChild(node_ymax)
+                    node_obj.appendChild(node_box)
+                    root.appendChild(node_obj)
+            with open(osp.join(xml_dir, img_name_part + ".xml"), 'w') as fxml:
+                xml_doc.writexml(fxml, indent='\t', addindent='\t', newl='\n', encoding="utf-8")
+                    
+                    
+class EasyData2VOC(X2VOC):
+    """将使用EasyData标注的分割数据集转换为VOC数据集。
+    """
+    def __init__(self):
+        pass
+    
+    def json2xml(self, image_dir, json_dir, xml_dir):
+        import xml.dom.minidom as minidom
+        for img_name in os.listdir(image_dir):
+            img_name_part = osp.splitext(img_name)[0]
+            json_file = osp.join(json_dir, img_name_part + ".json")
+            if not osp.exists(json_file):
+                os.remove(os.remove(osp.join(image_dir, img_name)))
+                continue
+            xml_doc = minidom.Document() 
+            root = xml_doc.createElement("annotation") 
+            xml_doc.appendChild(root)
+            node_folder = xml_doc.createElement("folder")
+            node_folder.appendChild(xml_doc.createTextNode("JPEGImages"))
+            root.appendChild(node_folder)
+            node_filename = xml_doc.createElement("filename")
+            node_filename.appendChild(xml_doc.createTextNode(img_name))
+            root.appendChild(node_filename)
+            img = cv2.imread(osp.join(image_dir, img_name))
+            h = img.shape[0]
+            w = img.shape[1]
+            node_size = xml_doc.createElement("size")
+            node_width = xml_doc.createElement("width")
+            node_width.appendChild(xml_doc.createTextNode(str(w)))
+            node_size.appendChild(node_width)
+            node_height = xml_doc.createElement("height")
+            node_height.appendChild(xml_doc.createTextNode(str(h)))
+            node_size.appendChild(node_height)
+            node_depth = xml_doc.createElement("depth")
+            node_depth.appendChild(xml_doc.createTextNode(str(3)))
+            node_size.appendChild(node_depth)
+            root.appendChild(node_size)
+            with open(json_file, mode="r", \
+                              encoding=get_encoding(json_file)) as j:
+                json_info = json.load(j)
+                for shape in json_info["labels"]:
+                    label = shape["name"]
+                    xmin = shape["x1"]
+                    ymin = shape["y1"]
+                    xmax = shape["x2"]
+                    ymax = shape["y2"]
+                    node_obj = xml_doc.createElement("object")
+                    node_name = xml_doc.createElement("name")
+                    node_name.appendChild(xml_doc.createTextNode(label))
+                    node_obj.appendChild(node_name)
+                    node_diff = xml_doc.createElement("difficult")
+                    node_diff.appendChild(xml_doc.createTextNode(str(0)))
+                    node_obj.appendChild(node_diff)
+                    node_box = xml_doc.createElement("bndbox")
+                    node_xmin = xml_doc.createElement("xmin")
+                    node_xmin.appendChild(xml_doc.createTextNode(str(xmin)))
+                    node_box.appendChild(node_xmin)
+                    node_ymin = xml_doc.createElement("ymin")
+                    node_ymin.appendChild(xml_doc.createTextNode(str(ymin)))
+                    node_box.appendChild(node_ymin)
+                    node_xmax = xml_doc.createElement("xmax")
+                    node_xmax.appendChild(xml_doc.createTextNode(str(xmax)))
+                    node_box.appendChild(node_xmax)
+                    node_ymax = xml_doc.createElement("ymax")
+                    node_ymax.appendChild(xml_doc.createTextNode(str(ymax)))
+                    node_box.appendChild(node_ymax)
+                    node_obj.appendChild(node_box)
+                    root.appendChild(node_obj)
+            with open(osp.join(xml_dir, img_name_part + ".xml"), 'w') as fxml:
+                xml_doc.writexml(fxml, indent='\t', addindent='\t', newl='\n', encoding="utf-8")                    
+                    

+ 115 - 13
paddlex/utils/utils.py

@@ -31,18 +31,7 @@ def seconds_to_hms(seconds):
     return hms_str
 
 
-def setting_environ_flags():
-    if 'FLAGS_eager_delete_tensor_gb' not in os.environ:
-        os.environ['FLAGS_eager_delete_tensor_gb'] = '0.0'
-    if 'FLAGS_allocator_strategy' not in os.environ:
-        os.environ['FLAGS_allocator_strategy'] = 'auto_growth'
-    if "CUDA_VISIBLE_DEVICES" in os.environ:
-        if os.environ["CUDA_VISIBLE_DEVICES"].count("-1") > 0:
-            os.environ["CUDA_VISIBLE_DEVICES"] = ""
-
-
 def get_environ_info():
-    setting_environ_flags()
     import paddle.fluid as fluid
     info = dict()
     info['place'] = 'cpu'
@@ -181,11 +170,85 @@ def load_pdparams(exe, main_prog, model_dir):
             len(vars_to_load), model_dir))
 
 
-def load_pretrain_weights(exe, main_prog, weights_dir, fuse_bn=False):
+def is_persistable(var):
+    import paddle.fluid as fluid
+    from paddle.fluid.proto.framework_pb2 import VarType
+
+    if var.desc.type() == fluid.core.VarDesc.VarType.FEED_MINIBATCH or \
+        var.desc.type() == fluid.core.VarDesc.VarType.FETCH_LIST or \
+        var.desc.type() == fluid.core.VarDesc.VarType.READER:
+        return False
+    return var.persistable
+
+
+def is_belong_to_optimizer(var):
+    import paddle.fluid as fluid
+    from paddle.fluid.proto.framework_pb2 import VarType
+
+    if not (isinstance(var, fluid.framework.Parameter)
+            or var.desc.need_check_feed()):
+        return is_persistable(var)
+    return False
+
+
+def load_pdopt(exe, main_prog, model_dir):
+    import paddle.fluid as fluid
+
+    optimizer_var_list = list()
+    vars_to_load = list()
+    import pickle
+    with open(osp.join(model_dir, 'model.pdopt'), 'rb') as f:
+        opt_dict = pickle.load(f) if six.PY2 else pickle.load(
+            f, encoding='latin1')
+    optimizer_var_list = list(
+        filter(is_belong_to_optimizer, main_prog.list_vars()))
+    exception_message = "the training process can not be resumed due to optimizer set now and last time is different. Recommend to use `pretrain_weights` instead of `resume_checkpoint`"
+    if len(optimizer_var_list) > 0:
+        for var in optimizer_var_list:
+            if var.name not in opt_dict:
+                raise Exception(
+                    "{} is not in saved paddlex optimizer, {}".format(
+                        var.name, exception_message))
+            if var.shape != opt_dict[var.name].shape:
+                raise Exception(
+                    "Shape of optimizer variable {} doesn't match.(Last: {}, Now: {}), {}"
+                    .format(var.name, opt_dict[var.name].shape,
+                            var.shape), exception_message)
+        optimizer_varname_list = [var.name for var in optimizer_var_list]
+        for k, v in opt_dict.items():
+            if k not in optimizer_varname_list:
+                raise Exception(
+                    "{} in saved paddlex optimizer is not in the model, {}".
+                    format(k, exception_message))
+        fluid.io.set_program_state(main_prog, opt_dict)
+
+    if len(optimizer_var_list) == 0:
+        raise Exception(
+            "There is no optimizer parameters in the model, please set the optimizer!"
+        )
+    else:
+        logging.info(
+            "There are {} optimizer parameters in {} are loaded.".format(
+                len(optimizer_var_list), model_dir))
+
+
+def load_pretrain_weights(exe,
+                          main_prog,
+                          weights_dir,
+                          fuse_bn=False,
+                          resume=False):
     if not osp.exists(weights_dir):
         raise Exception("Path {} not exists.".format(weights_dir))
     if osp.exists(osp.join(weights_dir, "model.pdparams")):
-        return load_pdparams(exe, main_prog, weights_dir)
+        load_pdparams(exe, main_prog, weights_dir)
+        if resume:
+            if osp.exists(osp.join(weights_dir, "model.pdopt")):
+                load_pdopt(exe, main_prog, weights_dir)
+            else:
+                raise Exception(
+                    "Optimizer file {} does not exist. Stop resumming training. Recommend to use `pretrain_weights` instead of `resume_checkpoint`"
+                    .format(osp.join(weights_dir, "model.pdopt")))
+        return
     import paddle.fluid as fluid
     vars_to_load = list()
     for var in main_prog.list_vars():
@@ -220,6 +283,45 @@ def load_pretrain_weights(exe, main_prog, weights_dir, fuse_bn=False):
             len(vars_to_load), weights_dir))
     if fuse_bn:
         fuse_bn_weights(exe, main_prog, weights_dir)
+    if resume:
+        exception_message = "the training process can not be resumed due to optimizer set now and last time is different. Recommend to use `pretrain_weights` instead of `resume_checkpoint`"
+        optimizer_var_list = list(
+            filter(is_belong_to_optimizer, main_prog.list_vars()))
+        if len(optimizer_var_list) > 0:
+            for var in optimizer_var_list:
+                if not osp.exists(osp.join(weights_dir, var.name)):
+                    raise Exception(
+                        "Optimizer parameter {} doesn't exist, {}".format(
+                            osp.join(weights_dir, var.name),
+                            exception_message))
+                pretrained_shape = parse_param_file(
+                    osp.join(weights_dir, var.name))
+                actual_shape = tuple(var.shape)
+                if pretrained_shape != actual_shape:
+                    raise Exception(
+                        "Shape of optimizer variable {} doesn't match.(Last: {}, Now: {}), {}"
+                        .format(var.name, pretrained_shape,
+                                actual_shape), exception_message)
+            optimizer_varname_list = [var.name for var in optimizer_var_list]
+            if os.exists(osp.join(weights_dir, 'learning_rate')
+                         ) and 'learning_rate' not in optimizer_varname_list:
+                raise Exception(
+                    "Optimizer parameter {}/learning_rate is not in the model, {}"
+                    .format(weights_dir, exception_message))
+            fluid.io.load_vars(
+                executor=exe,
+                dirname=weights_dir,
+                main_program=main_prog,
+                vars=optimizer_var_list)
+
+        if len(optimizer_var_list) == 0:
+            raise Exception(
+                "There is no optimizer parameters in the model, please set the optimizer!"
+            )
+        else:
+            logging.info(
+                "There are {} optimizer parameters in {} are loaded.".format(
+                    len(optimizer_var_list), weights_dir))
 
 
 class EarlyStop:

+ 5 - 8
setup.py

@@ -19,7 +19,7 @@ long_description = "PaddleX. A end-to-end deeplearning model development toolkit
 
 setuptools.setup(
     name="paddlex",
-    version='0.1.6',
+    version='0.1.9',
     author="paddlex",
     author_email="paddlex@baidu.com",
     description=long_description,
@@ -27,11 +27,10 @@ setuptools.setup(
     long_description_content_type="text/plain",
     url="https://github.com/PaddlePaddle/PaddleX",
     packages=setuptools.find_packages(),
-    setup_requires=['cython', 'numpy', 'sklearn'],
+    setup_requires=['cython', 'numpy'],
     install_requires=[
-        "pycocotools;platform_system!='Windows'", 
-        'pyyaml', 'colorama', 'tqdm', 'visualdl==1.3.0',
-        'paddleslim==1.0.1', 'paddlehub>=1.6.2'
+        "pycocotools;platform_system!='Windows'", 'pyyaml', 'colorama', 'tqdm',
+        'paddleslim==1.0.1', 'visualdl==2.0.0a2'
     ],
     classifiers=[
         "Programming Language :: Python :: 3",
@@ -39,6 +38,4 @@ setuptools.setup(
         "Operating System :: OS Independent",
     ],
     license='Apache 2.0',
-    entry_points={'console_scripts': [
-        'paddlex=paddlex.command:main',
-    ]})
+    entry_points={'console_scripts': ['paddlex=paddlex.command:main', ]})