Explorar o código

Merge pull request #2 from PaddlePaddle/develop

Merge
SunAhong1993 %!s(int64=4) %!d(string=hai) anos
pai
achega
e68f8bc6c9
Modificáronse 100 ficheiros con 3867 adicións e 455 borrados
  1. 70 66
      README.md
  2. 0 126
      README_EN.md
  3. 168 0
      README_cn.md
  4. 1 1
      deploy/cpp/cmake/yaml-cpp.cmake
  5. 6 2
      deploy/cpp/demo/classifier.cpp
  6. 6 2
      deploy/cpp/demo/detector.cpp
  7. 6 2
      deploy/cpp/demo/segmenter.cpp
  8. 4 2
      deploy/cpp/demo/video_classifier.cpp
  9. 4 2
      deploy/cpp/demo/video_detector.cpp
  10. 4 2
      deploy/cpp/demo/video_segmenter.cpp
  11. 6 0
      deploy/cpp/include/paddlex/transforms.h
  12. 2 2
      deploy/cpp/scripts/jetson_build.sh
  13. 4 1
      deploy/cpp/src/paddlex.cpp
  14. 51 13
      deploy/cpp/src/transforms.cpp
  15. 1 3
      deploy/openvino/CMakeLists.txt
  16. 1 2
      deploy/openvino/cmake/yaml-cpp.cmake
  17. 6 2
      deploy/openvino/demo/classifier.cpp
  18. 6 2
      deploy/openvino/demo/detector.cpp
  19. 6 2
      deploy/openvino/demo/segmenter.cpp
  20. 6 0
      deploy/openvino/include/paddlex/transforms.h
  21. 18 7
      deploy/openvino/scripts/build.sh
  22. 10 1
      deploy/openvino/scripts/install_third-party.sh
  23. 8 3
      deploy/openvino/src/paddlex.cpp
  24. 50 14
      deploy/openvino/src/transforms.cpp
  25. 25 52
      deploy/raspberry/CMakeLists.txt
  26. 2 2
      deploy/raspberry/cmake/yaml-cpp.cmake
  27. 1 1
      deploy/raspberry/include/paddlex/visualize.h
  28. 12 3
      deploy/raspberry/scripts/build.sh
  29. 12 1
      deploy/raspberry/scripts/install_third-party.sh
  30. 7 4
      deploy/raspberry/src/paddlex.cpp
  31. 0 48
      docs/apis/analysis.md
  32. 18 0
      docs/apis/datasets.md
  33. BIN=BIN
      docs/apis/images/detection_analysis.jpg
  34. BIN=BIN
      docs/apis/images/insect_bbox-allclass-allarea.png
  35. 1 1
      docs/apis/index.rst
  36. 1 1
      docs/apis/models/classification.md
  37. 28 10
      docs/apis/models/detection.md
  38. 24 5
      docs/apis/models/instance_segmentation.md
  39. 77 0
      docs/apis/tools.md
  40. 14 3
      docs/apis/transforms/det_transforms.md
  41. 67 0
      docs/apis/visualize.md
  42. 20 0
      docs/change_log.md
  43. BIN=BIN
      docs/deploy/images/container.png
  44. BIN=BIN
      docs/deploy/images/images.png
  45. 1 1
      docs/deploy/index.rst
  46. 10 0
      docs/deploy/jetson/index.rst
  47. 121 0
      docs/deploy/jetson/jetson-docker.md
  48. 1 1
      docs/deploy/jetson/nvidia-jetson.md
  49. 2 1
      docs/deploy/openvino/export_openvino_model.md
  50. 3 1
      docs/deploy/openvino/introduction.md
  51. 1 1
      docs/deploy/openvino/python.md
  52. 91 0
      docs/deploy/raspberry/NCS2.md
  53. 19 11
      docs/deploy/raspberry/Raspberry.md
  54. 6 2
      docs/deploy/raspberry/export_nb_model.md
  55. 1 0
      docs/deploy/raspberry/index.rst
  56. 2 2
      docs/deploy/raspberry/python.md
  57. 1 0
      docs/examples/index.rst
  58. 99 0
      docs/examples/industrial_quality_inspection/README.md
  59. 97 0
      docs/examples/industrial_quality_inspection/accuracy_improvement.md
  60. 14 0
      docs/examples/industrial_quality_inspection/dataset.md
  61. 116 0
      docs/examples/industrial_quality_inspection/gpu_solution.md
  62. 102 0
      docs/examples/industrial_quality_inspection/tp_fp_list.md
  63. 35 0
      docs/gui/FAQ.md
  64. 0 46
      docs/gui/faq.md
  65. 20 0
      docs/gui/first_meet.md
  66. BIN=BIN
      docs/gui/images/paddlexoverview_en.jpg
  67. BIN=BIN
      docs/gui/images/paddlexoverview_en.png
  68. BIN=BIN
      docs/gui/images/star.png
  69. 28 0
      docs/gui/index.rst
  70. 191 0
      docs/gui/restful/data_struct.md
  71. BIN=BIN
      docs/gui/restful/img/classify_help.jpg
  72. BIN=BIN
      docs/gui/restful/img/detect_help.jpg
  73. BIN=BIN
      docs/gui/restful/img/framework.png
  74. BIN=BIN
      docs/gui/restful/img/gui_use.png
  75. BIN=BIN
      docs/gui/restful/img/ins_seg_help.jpg
  76. BIN=BIN
      docs/gui/restful/img/restful_api.png
  77. BIN=BIN
      docs/gui/restful/img/seg_help.jpg
  78. BIN=BIN
      docs/gui/restful/img/start_restful.png
  79. BIN=BIN
      docs/gui/restful/img/web_demo.png
  80. 49 0
      docs/gui/restful/index.rst
  81. 83 0
      docs/gui/restful/introduction.md
  82. 222 0
      docs/gui/restful/quick_start.md
  83. 69 0
      docs/gui/restful/restful.md
  84. 871 0
      docs/gui/restful/restful_api.md
  85. 55 0
      docs/gui/restful/tree.md
  86. BIN=BIN
      docs/gui/star.png
  87. 5 1
      docs/index.rst
  88. 79 0
      docs/luckydraw.md
  89. 99 0
      examples/industrial_quality_inspection/README.md
  90. 93 0
      examples/industrial_quality_inspection/accuracy_improvement.md
  91. 214 0
      examples/industrial_quality_inspection/cal_tp_fp.py
  92. 160 0
      examples/industrial_quality_inspection/compare.py
  93. 14 0
      examples/industrial_quality_inspection/dataset.md
  94. 26 0
      examples/industrial_quality_inspection/error_analysis.py
  95. 114 0
      examples/industrial_quality_inspection/gpu_solution.md
  96. BIN=BIN
      examples/industrial_quality_inspection/image/after_clahe.png
  97. BIN=BIN
      examples/industrial_quality_inspection/image/allclasses_analysis_example.png
  98. BIN=BIN
      examples/industrial_quality_inspection/image/before_clahe.png
  99. BIN=BIN
      examples/industrial_quality_inspection/image/budaodian_analysis_example.png
  100. BIN=BIN
      examples/industrial_quality_inspection/image/cahua_analysis_example.png

+ 70 - 66
README.md

@@ -1,4 +1,5 @@
-简体中文| [English](./README_EN.md)
+[简体中文](./README_cn.md) | English
+
 
 
 
@@ -8,32 +9,36 @@
 </p>
 
 
-<p align= "center"> PaddleX -- 飞桨全流程开发套件,以低代码的形式支持开发者快速实现产业实际项目落地 </p>
+<p align= "center"> PaddleX -- PaddlePaddle End-to-End Development Toolkit,
+  enables developers to implement real industry projects in a low-code form quickly </p>
+
+[![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)
+ ![QQGroup](https://img.shields.io/badge/QQ_Group-1045148026-52B6EF?style=social&logo=tencent-qq&logoColor=000&logoWidth=20)
+
+:hugs:  PaddleX integrated the abilities of **Image classification**, **Object detection**, **Semantic segmentation**, and **Instance segmentation** in the Paddle CV toolkits, and get through the whole-process development from **Data preparation** and **Model training and optimization** to **Multi-end deployment**. At the same time, PaddleX provides **Succinct APIs** and a **Graphical Ueser Interface**. Developers can quickly complete the end-to-end process development of the Paddle in a form of **low-code**  without installing different libraries.
+
+**:factory: PaddleX** has been validated in a dozen of industry application scenarios such as **Quality Inspection**, **Security**, **Patrol Inspection**, **Remote Sensing**, **Retail**,  **Medical** etc.. In addition, it **provides a wealth of case practice tutorials**, to help developer could apply to actual cases easily.
 
-[![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)
-![QQGroup](https://img.shields.io/badge/QQ_Group-1045148026-52B6EF?style=social&logo=tencent-qq&logoColor=000&logoWidth=20)
 
-[完整PaddleX在线使用文档目录](https://paddlex.readthedocs.io/zh_CN/develop/index.html)
 
-集成飞桨智能视觉领域**图像分类**、**目标检测**、**语义分割**、**实例分割**任务能力,将深度学习开发全流程从**数据准备**、**模型训练与优化**到**多端部署**端到端打通,并提供**统一任务API接口**及**图形化开发界面Demo**。开发者无需分别安装不同套件,以**低代码**的形式即可快速完成飞桨全流程开发。
+:heart: **You can go to [Complete PaddleX Online Documentation Contents](https://paddlex.readthedocs.io/zh_CN/develop_en/index.html) for complete tutorial with the format of *Read the Doc* and better reading experience​** :heart:
 
-**PaddleX** 经过**质检**、**安防**、**巡检**、**遥感**、**零售**、**医疗**等十多个行业实际应用场景验证,沉淀产业实际经验,**并提供丰富的案例实践教程**,全程助力开发者产业实践落地。
 
-![](./docs/gui/images/paddlexoverview.png)
 
+![](./docs/gui/images/paddlexoverview_en.jpg)
 
-## 安装
 
-**PaddleX提供两种开发模式,满足用户的不同需求:**
 
-1. **Python开发模式:** 
+## Installation
 
-   通过简洁易懂的Python API,在兼顾功能全面性、开发灵活性、集成方便性的基础上,给开发者最流畅的深度学习开发体验。<br>
+**PaddleX has two development modes to meet different needs of users:**
+
+1.**Python development mode:**
+
+The design of PaddleX Python API taking into account of comprehensive functions, development flexibility, and integration convenience, giving developers the smoothest deep learning development experience.
+
+**Pre-dependence**
 
-  **前置依赖**
 > - paddlepaddle >= 1.8.4
 > - python >= 3.6
 > - cython
@@ -42,94 +47,93 @@
 ```
 pip install paddlex -i https://mirror.baidu.com/pypi/simple
 ```
-详细安装方法请参考[PaddleX安装](https://paddlex.readthedocs.io/zh_CN/develop/install.html)
-
+Please refer to the [PaddleX installation](https://paddlex.readthedocs.io/zh_CN/develop/install.html) for detailed installation method.
 
-2. **Padlde GUI模式:**
 
-   无代码开发的可视化客户端,应用Paddle API实现,使开发者快速进行产业项目验证,并为用户开发自有深度学习软件/应用提供参照。
+2. **Padlde GUI(Graphical Ueser Interface) mode:**
 
-- 前往[PaddleX官网](https://www.paddlepaddle.org.cn/paddle/paddlex),申请下载PaddleX GUI一键绿色安装包。
+It's a all-in-one client enable develops could implement deep learning projects without code.
 
-- 前往[PaddleX GUI使用教程](./docs/gui/how_to_use.md)了解PaddleX GUI使用详情。
+- Go to [PaddleX Official Website](https://www.paddlepaddle.org.cn/paddle/paddlex) to download the all-in-one client.
 
-- [PaddleX GUI安装环境说明](./docs/gui/download.md)
-  
+- Go to [PaddleX GUI tutorial](./docs/gui/how_to_use.md ) for details of using it.
 
-## 产品模块说明
+- [PaddleX GUI Environment Requirements for Installation](. /docs/gui/download.md)
 
-- **数据准备**:兼容ImageNet、VOC、COCO等常用数据协议,同时与Labelme、精灵标注助手、[EasyData智能数据服务平台](https://ai.baidu.com/easydata/)等无缝衔接,全方位助力开发者更快完成数据准备工作。
 
-- **数据预处理及增强**:提供极简的图像预处理和增强方法--Transforms,适配imgaug图像增强库,支持**上百种数据增强策略**,是开发者快速缓解小样本数据训练的问题。
+## Product Module Description
 
-- **模型训练**:集成[PaddleClas](https://github.com/PaddlePaddle/PaddleClas), [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection), [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg)视觉开发套件,提供大量精选的、经过产业实践的高质量预训练模型,使开发者更快实现工业级模型效果。
+- **Data preparation**: Compatible with common data protocols such as ImageNet, VOC, COCO, and seamlessly interconnecting with Labelme, Colabeler, and [EasyData intelligent data service platform](https://ai.baidu.com/easydata/), to help developers to quickly complete data preparations.
+- **Data pre-processing and enhancement**: Provides a minimalist image pre-processing and enhancement method--Transforms. Adapts imgaug which is a powerful image enhancement library, so that PaddleX could supports **Hundreds of data enhancement strategies**, which makes developers quickly alleviate the situation of traing with small sample dataset.
+- **Model training**: PaddleX integrates [PaddleClas](https://github.com/PaddlePaddle/PaddleClas), [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection), and [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg) etcs. So it provides a large number of selected, industry-proven, high-quality pre-trained models, enabling developers to achieve the industry requirements much more quickly.
+- **Model tuning**: Model-interpretability module and [VisualDL](https://github.com/PaddlePaddle/VisualDL) visual analysis tool are integrated as well. It allows developers to understand the model's feature extraction region and the change of the training process parameters more intuitively , so as to quickly optimize the model.
+- **Multi-End Secure Deployment**: The built-in model compression tool-- [PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim)  and **Model Encryption Deployment Module**, are seamlessly interconnected with native prediction library **Paddle Inference** and Multi-platform high performance deep learning inference engine-- [Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite) , to enable developers to quickly implement multi-end, high-performance, secure deployments of the model.
 
-- **模型调优**:内置模型可解释性模块、[VisualDL](https://github.com/PaddlePaddle/VisualDL)可视化分析工具。使开发者可以更直观的理解模型的特征提取区域、训练过程参数变化,从而快速优化模型。
 
-- **多端安全部署**:内置[PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim)模型压缩工具和**模型加密部署模块**,与飞桨原生预测库Paddle Inference及高性能端侧推理引擎[Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite) 无缝打通,使开发者快速实现模型的多端、高性能、安全部署。
 
-  
+## Full Documentation and API Description
 
-## 完整使用文档及API说明
+- [Complete PaddleX online documentation contents](https://paddlex.readthedocs.io/zh_CN/develop_en/):heart:
 
-- [完整PaddleX在线使用文档目录](https://paddlex.readthedocs.io/zh_CN/develop/index.html)
+- [10-Minute Quick Start Tutorial Series](https://paddlex.readthedocs.io/zh_CN/develop/quick_start.html)
+- [Collection of PaddleX Model Training Tutorials](https://paddlex.readthedocs.io/zh_CN/develop/train/index.html)
+- [PaddleX API Interface Description](https://paddlex.readthedocs.io/zh_CN/develop/apis/index.html)
 
-- [10分钟快速上手系列教程](https://paddlex.readthedocs.io/zh_CN/develop/quick_start.html)
-- [PaddleX模型训练教程集合](https://paddlex.readthedocs.io/zh_CN/develop/train/index.html)
-- [PaddleX API接口说明](https://paddlex.readthedocs.io/zh_CN/develop/apis/index.html)
+### Examples of Online Projects
 
-### 在线项目示例
+To get developers up to speed with the PaddleX API, we've created a complete series of sample tutorials that you can run PaddleX projects online through the **AIStudio** quickly.
 
-为了使开发者更快掌握PaddleX API,我们创建了一系列完整的示例教程,您可通过AIStudio一站式开发平台,快速在线运行PaddleX的项目。
+- [PaddleX Quick Start - CV Model Training](https://aistudio.baidu.com/aistudio/projectdetail/450925)
+- [PaddleX Quick Start - MobileNetV3-ssld Cosmetics Classification](https://aistudio.baidu.com/aistudio/projectdetail/450220)
+- [PaddleX Quick Start - Faster-RCNN AI Bug Recognition](https://aistudio.baidu.com/aistudio/projectdetail/439888)
+- [PaddleX Quick Start - DeepLabv3+ Semantic Segmentation](https://aistudio.baidu.com/aistudio/projectdetail/440197)
 
-- [PaddleX快速上手CV模型训练](https://aistudio.baidu.com/aistudio/projectdetail/450925)
-- [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)
 
 
-
-## 全流程产业应用案例
+## Full Process Industry Applications:star:
 
 (continue to be updated)
 
-* 工业巡检:
-  * [工业表计读数](https://paddlex.readthedocs.io/zh_CN/develop/examples/meter_reader.html)
-
-* 工业质检:
-  * 电池隔膜缺陷检测(Coming Soon)
-
-* [人像分割](https://paddlex.readthedocs.io/zh_CN/develop/examples/human_segmentation.html)
-
+* Industrial inspections:
+  - [Industrial Meter Readings](https://paddlex.readthedocs.io/zh_CN/develop_en/examples/meter_reader.html)
+* [Industrial quality control](https://paddlex.readthedocs.io/zh_CN/develop_en/examples/industrial_quality_inspection/README.html)
+* Satellite Image Understanding:
+  * [RGB Satellite Image Segmentation](https://paddlex.readthedocs.io/zh_CN/develop_en/examples/remote_sensing.html)
+  * [Multi-Channel Satellite Image Segmentation](https://paddlex.readthedocs.io/zh_CN/develop_en/examples/multi-channel_remote_sensing/README.html)
+  * [Land Parcel Change Detection](https://paddlex.readthedocs.io/zh_CN/develop_en/examples/change_detection.html)
+* [Portrait Segmentation](https://paddlex.readthedocs.io/zh_CN/develop_en/examples/human_segmentation.html)
+* Multi-platform Deployment with Encryption
+  - [CPU/GPU (Encryption) deployment](https://paddlex.readthedocs.io/zh_CN/develop_en/deploy/server/index.html)
+  - [Deployment with OpenVINO toolkit](https://paddlex.readthedocs.io/zh_CN/develop_en/deploy/openvino/index.html)
+  - [Deploy on Nvidia Jetson](https://paddlex.readthedocs.io/zh_CN/develop_en/deploy/nvidia-jetson.html)
+  - [Deploy on Raspberry Pi](https://paddlex.readthedocs.io/zh_CN/develop_en/deploy/raspberry/index.html)
 
 
-## [FAQ](./docs/gui/faq.md)
 
+## :question:[FAQ](./docs/gui/faq.md):question:
 
 
-## 交流与反馈
 
-- 项目官网:https://www.paddlepaddle.org.cn/paddle/paddlex
-
-- PaddleX用户交流群:957286141 (手机QQ扫描如下二维码快速加入)  
-  
-  <p align="center">
-    <img src="./docs/gui/images/QR2.jpg" width="250" height ="360" alt="QR" align="middle" />
-  </p>
+## Communication and Feedback
 
+- Project official website: https://www.paddlepaddle.org.cn/paddle/paddlex
+- PaddleX user group: 957286141 (Scan the following QR code on Mobile QQ to join quickly)
 
+<p align="center">
+  <img src="./docs/gui/images/QR2.jpg" width="250" height ="360" alt="QR" align="middle" />
+</p>
 
-## 更新日志
+## Release Note
 
-> [历史版本及更新内容](https://paddlex.readthedocs.io/zh_CN/develop/change_log.html)
+> [Complete Release Note](https://paddlex.readthedocs.io/zh_CN/develop/change_log.html)
+- 2020.12.20 v1.3.0
 - 2020.09.05 v1.2.0
 - 2020.07.13 v1.1.0
 - 2020.07.12 v1.0.8
 - 2020.05.20 v1.0.0
-- 2020.05.17 v0.1.8
 
 
 
-## 贡献代码
+## :hugs: Contribution :hugs:
 
-我们非常欢迎您为PaddleX贡献代码或者提供使用建议。如果您可以修复某个issue或者增加一个新功能,欢迎给我们提交Pull Requests。
+You are welcomed to contribute codes to PaddleX or provide suggestions. If you can fix an issue or add a new feature, please feel free to submit Pull Requests.

+ 0 - 126
README_EN.md

@@ -1,126 +0,0 @@
-[简体中文](./README.md) | English
-
-
-
-
-
-<p align="center">
-  <img src="./docs/gui/images/paddlex.png" width="360" height ="55" alt="PaddleX" align="middle" />
-</p>
-
-
-<p align= "center"> PaddleX -- PaddlePaddle End-to-End Development Toolkit, 
-  enables developers to implement real industry projects in a low-code form quickly </p>
-
-[![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)
-![QQGroup](https://img.shields.io/badge/QQ_Group-1045148026-52B6EF?style=social&logo=tencent-qq&logoColor=000&logoWidth=20)
-
-[Complete PaddleX Online Documentation Contents](https://paddlex.readthedocs.io/zh_CN/develop/index.html)
-
-It is integrated the abilities of **Image classification**, **Object detection**, **Semantic segmentation**, and **Instance segmentation** in the Paddle CV toolkits, and get through the whole-process development from **Data preparation** and **Model training and optimization** to **Multi-end deployment**. At the same time, PaddleX provides **Succinct APIs** and a **Graphical Ueser Interface**. Developers can quickly complete the end-to-end process development of the Paddle in a form of **low-code**  without installing different libraries.
-
-**PaddleX** has been validated in a dozen of industry application scenarios such as **Quality Inspection**, **Security**, **Patrol Inspection**, **Remote Sensing**, **Retail**,  **Medical** etc.. In addition, it **provides a wealth of case practice tutorials**, to help developer could apply to actual cases easily.
-
-![](./docs/gui/images/paddlexoverview_en.png)
-
-
-## Installation
-
-**PaddleX has two development modes to meet different needs of users:**
-
-1.**Python development mode:**
-
-The design of PaddleX Python API taking into account of comprehensive functions, development flexibility, and integration convenience, giving developers the smoothest deep learning development experience.
-
-**Pre-dependence**
-
-> - paddlepaddle >= 1.8.4
-> - python >= 3.6
-> - cython
-> - pycocotools
-
-```
-pip install paddlex -i https://mirror.baidu.com/pypi/simple
-```
-Please refer to the [PaddleX installation](https://paddlex.readthedocs.io/zh_CN/develop/install.html) for detailed installation method.
-
-
-2. **Padlde GUI(Graphical Ueser Interface) mode:**
-
-It's a all-in-one client enable develops could implement deep learning projects without code. 
-
-- Go to [PaddleX Official Website](https://www.paddlepaddle.org.cn/paddle/paddlex) to download the all-in-one client.
-
-- Go to [PaddleX GUI tutorial](./docs/gui/how_to_use.md ) for details of using it.
-
-- [PaddleX GUI Environment Requirements for Installation](. /docs/gui/download.md)
-
-
-## Product Module Description
-
-- **Data preparation**: Compatible with common data protocols such as ImageNet, VOC, COCO, and seamlessly interconnecting with Labelme, Colabeler, and [EasyData intelligent data service platform](https://ai.baidu.com/easydata/), to help developers to quickly complete data preparations.
-- **Data pre-processing and enhancement**: Provides a minimalist image pre-processing and enhancement method--Transforms. Adapts imgaug which is a powerful image enhancement library, so that PaddleX could supports **Hundreds of data enhancement strategies**, which makes developers quickly alleviate the situation of traing with small sample dataset.
-- **Model training**: PaddleX integrates [PaddleClas](https://github.com/PaddlePaddle/PaddleClas), [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection), and [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg) etcs. So it provides a large number of selected, industry-proven, high-quality pre-trained models, enabling developers to achieve the industry requirements much more quickly.
-- **Model tuning**: Model-interpretability module and [VisualDL](https://github.com/PaddlePaddle/VisualDL) visual analysis tool are integrated as well. It allows developers to understand the model's feature extraction region and the change of the training process parameters more intuitively , so as to quickly optimize the model.
-- **Multi-End Secure Deployment**: The built-in model compression tool-- [PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim)  and **Model Encryption Deployment Module**, are seamlessly interconnected with native prediction library **Paddle Inference** and Multi-platform high performance deep learning inference engine-- [Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite) , to enable developers to quickly implement multi-end, high-performance, secure deployments of the model.
-
-
-
-## Full Documentation and API Description
-
-- [Complete PaddleX online documentation contents](https://paddlex.readthedocs.io/zh_CN/develop/index.html)
-
-- [10-Minute Quick Start Tutorial Series](https://paddlex.readthedocs.io/zh_CN/develop/quick_start.html)
-- [Collection of PaddleX Model Training Tutorials](https://paddlex.readthedocs.io/zh_CN/develop/train/index.html)
-- [PaddleX API Interface Description](https://paddlex.readthedocs.io/zh_CN/develop/apis/index.html)
-
-### Examples of Online Projects
-
-To get developers up to speed with the PaddleX API, we've created a complete series of sample tutorials that you can run PaddleX projects online through the **AIStudio** quickly.
-
-- [PaddleX Quick Start - CV Model Training](https://aistudio.baidu.com/aistudio/projectdetail/450925)
-- [PaddleX Quick Start - MobileNetV3-ssld Cosmetics Classification](https://aistudio.baidu.com/aistudio/projectdetail/450220)
-- [PaddleX Quick Start - Faster-RCNN AI Bug Recognition](https://aistudio.baidu.com/aistudio/projectdetail/439888)
-- [PaddleX Quick Start - DeepLabv3+ Semantic Segmentation](https://aistudio.baidu.com/aistudio/projectdetail/440197)
-
-
-
-## Full Process Industry Applications
-
-(continue to be updated)
-
-* Industrial inspections:
-  - [Industrial Meter Readings](https://paddlex.readthedocs.io/zh_CN/develop/examples/meter_reader.html)
-* Industrial quality control:
-  - Battery separator defect detection (Coming Soon)
-* [Portrait Segmentation](https://paddlex.readthedocs.io/zh_CN/develop/examples/human_segmentation.html)
-
-
-
-## [FAQ](./docs/gui/faq.md)
-
-
-
-## Communication and Feedback
-
-- Project official website: https://www.paddlepaddle.org.cn/paddle/paddlex
-- PaddleX user group: 957286141 (Scan the following QR code on Mobile QQ to join quickly)
-
-<p align="center">
-  <img src="./docs/gui/images/QR2.jpg" width="250" height ="360" alt="QR" align="middle" />
-</p>
-
-## Release Note
-
-> [Complete Release Note](https://paddlex.readthedocs.io/zh_CN/develop/change_log.html)
-- 2020.09.05 v1.2.0
-- 2020.07.13 v1.1.0
-- 2020.07.12 v1.0.8
-- 2020.05.20 v1.0.0
-- 2020.05.17 v0.1.8
-
-
-
-## Contribution
-
-You are welcomed to contribute codes to PaddleX or provide suggestions. If you can fix an issue or add a new feature, please feel free to submit Pull Requests.

+ 168 - 0
README_cn.md

@@ -0,0 +1,168 @@
+简体中文| [English](./README.md)
+
+
+
+
+<p align="center">
+  <img src="./docs/gui/images/paddlex.png" width="360" height ="55" alt="PaddleX" align="middle" />
+</p>
+ <p align= "center"> PaddleX -- 飞桨全流程开发工具,以低代码的形式支持开发者快速实现产业实际项目落地 </p>
+
+[![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)
+ ![QQGroup](https://img.shields.io/badge/QQ_Group-1045148026-52B6EF?style=social&logo=tencent-qq&logoColor=000&logoWidth=20)
+
+:hugs: PaddleX 集成飞桨智能视觉领域**图像分类**、**目标检测**、**语义分割**、**实例分割**任务能力,将深度学习开发全流程从**数据准备**、**模型训练与优化**到**多端部署**端到端打通,并提供**统一任务API接口**及**图形化开发界面Demo**。开发者无需分别安装不同套件,以**低代码**的形式即可快速完成飞桨全流程开发。
+
+:factory: **PaddleX** 经过**质检**、**安防**、**巡检**、**遥感**、**零售**、**医疗**等十多个行业实际应用场景验证,沉淀产业实际经验,**并提供丰富的案例实践教程**,全程助力开发者产业实践落地。
+
+
+
+:heart:**您可以前往  [完整PaddleX在线使用文档目录](https://paddlex.readthedocs.io/zh_CN/develop/index.html)  查看完整*Read the Doc* 格式的文档,获得更好的阅读体验**:heart:
+
+
+
+![](./docs/gui/images/paddlexoverview.png)
+
+
+
+## 安装
+
+**PaddleX提供两种开发模式,满足用户的不同需求:**
+
+1. **Python开发模式:**
+
+   通过简洁易懂的Python API,在兼顾功能全面性、开发灵活性、集成方便性的基础上,给开发者最流畅的深度学习开发体验。<br>
+
+  **前置依赖**
+> - paddlepaddle >= 1.8.4
+> - python >= 3.6
+> - cython
+> - pycocotools
+
+```
+pip install paddlex -i https://mirror.baidu.com/pypi/simple
+```
+详细安装方法请参考[PaddleX安装](https://paddlex.readthedocs.io/zh_CN/develop/install.html)
+
+
+2. **Padlde GUI模式:**
+
+   无代码开发的可视化客户端,应用Paddle API实现,使开发者快速进行产业项目验证,并为用户开发自有深度学习软件/应用提供参照。
+
+- 前往[PaddleX官网](https://www.paddlepaddle.org.cn/paddle/paddlex),申请下载PaddleX GUI一键绿色安装包。
+
+- 前往[PaddleX GUI使用教程](./docs/gui/how_to_use.md)了解PaddleX GUI使用详情。
+
+- [PaddleX GUI安装环境说明](./docs/gui/download.md)
+
+3. **PaddleX Restful:**  
+  使用基于RESTful API开发的GUI与Web Demo实现远程的深度学习全流程开发;同时开发者也可以基于RESTful API开发个性化的可视化界面
+- 前往[PaddleX RESTful API使用教程](./docs/gui/restful/introduction.md)  
+
+
+## 产品模块说明
+
+- **数据准备**:兼容ImageNet、VOC、COCO等常用数据协议,同时与Labelme、精灵标注助手、[EasyData智能数据服务平台](https://ai.baidu.com/easydata/)等无缝衔接,全方位助力开发者更快完成数据准备工作。
+
+- **数据预处理及增强**:提供极简的图像预处理和增强方法--Transforms,适配imgaug图像增强库,支持**上百种数据增强策略**,是开发者快速缓解小样本数据训练的问题。
+
+- **模型训练**:集成[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)模型压缩工具和**模型加密部署模块**,与飞桨原生预测库Paddle Inference及高性能端侧推理引擎[Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite) 无缝打通,使开发者快速实现模型的多端、高性能、安全部署。
+
+
+
+## 完整使用文档及API说明
+
+- [完整PaddleX在线使用文档目录](https://paddlex.readthedocs.io/zh_CN/develop/index.html):heart:
+
+- [10分钟快速上手系列教程](https://paddlex.readthedocs.io/zh_CN/develop/quick_start.html)
+- [PaddleX模型训练教程集合](https://paddlex.readthedocs.io/zh_CN/develop/train/index.html)
+- [PaddleX API接口说明](https://paddlex.readthedocs.io/zh_CN/develop/apis/index.html)
+- [PaddleX RESTful API说明](https://paddlex.readthedocs.io/zh_CN/develop/gui/restful/introduction.html)
+
+### 在线项目示例
+
+为了使开发者更快掌握PaddleX API,我们创建了一系列完整的示例教程,您可通过AIStudio一站式开发平台,快速在线运行PaddleX的项目。
+
+- [PaddleX快速上手CV模型训练](https://aistudio.baidu.com/aistudio/projectdetail/450925)
+- [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)
+
+## 全流程产业应用案例:star:
+
+(continue to be updated)
+
+* 工业巡检:
+  * [工业表计读数](https://paddlex.readthedocs.io/zh_CN/develop/examples/meter_reader.html)
+* 工业质检:
+  * [铝材表面缺陷检测](https://paddlex.readthedocs.io/zh_CN/develop/examples/industrial_quality_inspection/README.html)
+* 卫星遥感:
+  * [RGB遥感影像分割](https://paddlex.readthedocs.io/zh_CN/develop/examples/remote_sensing.html)
+  * [多通道遥感影像分割](https://paddlex.readthedocs.io/zh_CN/develop/examples/multi-channel_remote_sensing/README.html)
+  * [地块变化检测](https://paddlex.readthedocs.io/zh_CN/develop/examples/multi-channel_remote_sensing/README.html)
+* [人像分割](https://paddlex.readthedocs.io/zh_CN/develop/examples/human_segmentation.html)
+* 模型多端安全部署
+  * [CPU/GPU(加密)部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/server/index.html)
+  * [OpenVINO加速部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/openvino/index.html)
+  * [Nvidia Jetson开发板部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/nvidia-jetson.html)
+  * [树莓派部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/raspberry/index.html)
+
+* [模型可解释性](https://paddlex.readthedocs.io/zh_CN/develop/appendix/interpret.html)
+
+## :question:[FAQ](./docs/gui/faq.md):question:
+
+## 交流与反馈
+
+- 项目官网:https://www.paddlepaddle.org.cn/paddle/paddlex
+
+- PaddleX用户交流群:957286141 (手机QQ扫描如下二维码快速加入)  
+
+  <p align="center">
+    <img src="./docs/gui/images/QR2.jpg" width="250" height ="360" alt="QR" align="middle" />
+  </p>
+
+
+
+## 更新日志
+
+> [历史版本及更新内容](https://paddlex.readthedocs.io/zh_CN/develop/change_log.html)
+- **2020.09.07 v1.2.0**
+
+  新增产业最实用目标检测模型PP-YOLO,FasterRCNN、MaskRCNN、YOLOv3、DeepLabv3p等模型新增内置COCO数据集预训练模型,适用于小模型精调。新增多种Backbone,优化体积及预测速度。优化OpenVINO、PaddleLite Android、服务端C++预测部署方案,新增树莓派部署方案等。
+
+- **2020.07.12 v1.1.0**
+
+  新增人像分割、工业标记读数案例。模型新增HRNet、FastSCNN、FasterRCNN,实例分割MaskRCNN新增Backbone HRNet。集成X2Paddle,PaddleX所有分类模型和语义分割模型支持导出为ONNX协议。新增模型加密Windows平台支持。新增Jetson、Paddle Lite模型部署预测方案。
+
+- **2020.05.20 v1.0.0**
+
+  新增C++和Python部署,模型加密部署,分类模型OpenVINO部署。新增模型可解释性接口
+
+- **2020.05.17 v0.1.8**
+
+  新增EasyData平台数据标注格式,支持imgaug数据增强库的pixel-level算子
+
+## 近期活动更新
+
+- 2020.12.16
+
+  《直击深度学习部署最后一公里 C#软件部署实战》b站直播中奖用户名单请点击[PaddleX直播中奖名单](./docs/luckydraw.md)查看~
+
+- 2020.12.09
+
+  往期直播《直击深度学习部署最后一公里 目标检测兴趣小组》回放链接:https://www.bilibili.com/video/BV1rp4y1q7ap?from=search&seid=105037779997274685
+
+## :hugs: 贡献代码:hugs:
+
+我们非常欢迎您为PaddleX贡献代码或者提供使用建议。如果您可以修复某个issue或者增加一个新功能,欢迎给我们提交Pull Requests。
+
+### 开发者贡献项目
+
+* [工业相机实时目标检测GUI](https://github.com/xmy0916/SoftwareofIndustrialCameraUsePaddle)
+(windows系统,基于pyqt5开发)
+* [工业相机实时目标检测GUI](https://github.com/LiKangyuLKY/PaddleXCsharp)
+(windows系统,基于C#开发)

+ 1 - 1
deploy/cpp/cmake/yaml-cpp.cmake

@@ -4,7 +4,7 @@ message("${CMAKE_BUILD_TYPE}")
 
 ExternalProject_Add(
         ext-yaml-cpp
-        URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip
+	URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip
         URL_MD5 9542d6de397d1fbd649ed468cb5850e6
         CMAKE_ARGS
         -DYAML_CPP_BUILD_TESTS=OFF

+ 6 - 2
deploy/cpp/demo/classifier.cpp

@@ -92,7 +92,9 @@ int main(int argc, char** argv) {
       for (int j = i; j < im_vec_size; ++j) {
         im_vec[j - i] = std::move(cv::imread(image_paths[j], 1));
       }
-      model.predict(im_vec, &results, thread_num);
+      if (!model.predict(im_vec, &results, thread_num)) {
+        return -1;
+      }
       for (int j = i; j < im_vec_size; ++j) {
         std::cout << "Path:" << image_paths[j]
                   << ", predict label: " << results[j - i].category
@@ -103,7 +105,9 @@ int main(int argc, char** argv) {
   } else {
     PaddleX::ClsResult result;
     cv::Mat im = cv::imread(FLAGS_image, 1);
-    model.predict(im, &result);
+    if (!model.predict(im, &result)) {
+      return -1;
+    }
     std::cout << "Predict label: " << result.category
               << ", label_id:" << result.category_id
               << ", score: " << result.score << std::endl;

+ 6 - 2
deploy/cpp/demo/detector.cpp

@@ -95,7 +95,9 @@ int main(int argc, char** argv) {
       for (int j = i; j < im_vec_size; ++j) {
         im_vec[j - i] = std::move(cv::imread(image_paths[j], 1));
       }
-      model.predict(im_vec, &results, thread_num);
+      if (!model.predict(im_vec, &results, thread_num)) {
+        return -1;
+      }
       // Output predicted bounding boxes
       for (int j = 0; j < im_vec_size - i; ++j) {
         for (int k = 0; k < results[j].boxes.size(); ++k) {
@@ -123,7 +125,9 @@ int main(int argc, char** argv) {
   } else {
     PaddleX::DetResult result;
     cv::Mat im = cv::imread(FLAGS_image, 1);
-    model.predict(im, &result);
+    if (!model.predict(im, &result)) {
+      return -1;
+    }
     // Output predicted bounding boxes
     for (int i = 0; i < result.boxes.size(); ++i) {
       std::cout << "image file: " << FLAGS_image << std::endl;

+ 6 - 2
deploy/cpp/demo/segmenter.cpp

@@ -91,7 +91,9 @@ int main(int argc, char** argv) {
       for (int j = i; j < im_vec_size; ++j) {
         im_vec[j - i] = std::move(cv::imread(image_paths[j], 1));
       }
-      model.predict(im_vec, &results, thread_num);
+      if (!model.predict(im_vec, &results, thread_num)) {
+        return -1;
+      }
       // Visualize results
       for (int j = 0; j < im_vec_size - i; ++j) {
         cv::Mat vis_img =
@@ -105,7 +107,9 @@ int main(int argc, char** argv) {
   } else {
     PaddleX::SegResult result;
     cv::Mat im = cv::imread(FLAGS_image, 1);
-    model.predict(im, &result);
+    if (!model.predict(im, &result)) {
+      return -1;
+    }
     // Visualize results
     cv::Mat vis_img = PaddleX::Visualize(im, result, model.labels);
     std::string save_path =

+ 4 - 2
deploy/cpp/demo/video_classifier.cpp

@@ -103,7 +103,7 @@ int main(int argc, char** argv) {
     if (FLAGS_use_camera) {
       video_fourcc = 828601953;
     } else {
-      video_fourcc = static_cast<int>(capture.get(CV_CAP_PROP_FOURCC));
+      video_fourcc = CV_FOURCC('M', 'J', 'P', 'G');
     }
 
     if (FLAGS_use_camera) {
@@ -140,7 +140,9 @@ int main(int argc, char** argv) {
       break;
     }
     // Begin to predict
-    model.predict(frame, &result);
+    if (!model.predict(frame, &result)) {
+      return -1;
+    }
     // Visualize results
     cv::Mat vis_img = frame.clone();
     auto colormap = PaddleX::GenerateColorMap(model.labels.size());

+ 4 - 2
deploy/cpp/demo/video_detector.cpp

@@ -104,7 +104,7 @@ int main(int argc, char** argv) {
     if (FLAGS_use_camera) {
       video_fourcc = 828601953;
     } else {
-      video_fourcc = static_cast<int>(capture.get(CV_CAP_PROP_FOURCC));
+      video_fourcc = CV_FOURCC('M', 'J', 'P', 'G');
     }
 
     if (FLAGS_use_camera) {
@@ -141,7 +141,9 @@ int main(int argc, char** argv) {
       break;
     }
     // Begin to predict
-    model.predict(frame, &result);
+    if (!model.predict(frame, &result)) {
+      return -1;
+    }
     // Visualize results
     cv::Mat vis_img =
         PaddleX::Visualize(frame, result, model.labels, FLAGS_threshold);

+ 4 - 2
deploy/cpp/demo/video_segmenter.cpp

@@ -103,7 +103,7 @@ int main(int argc, char** argv) {
     if (FLAGS_use_camera) {
       video_fourcc = 828601953;
     } else {
-      video_fourcc = static_cast<int>(capture.get(CV_CAP_PROP_FOURCC));
+      video_fourcc = CV_FOURCC('M', 'J', 'P', 'G');
     }
 
     if (FLAGS_use_camera) {
@@ -140,7 +140,9 @@ int main(int argc, char** argv) {
       break;
     }
     // Begin to predict
-    model.predict(frame, &result);
+    if (!model.predict(frame, &result)) {
+      return -1;
+    }
     // Visualize results
     cv::Mat vis_img = PaddleX::Visualize(frame, result, model.labels);
     if (FLAGS_show_result || FLAGS_use_camera) {

+ 6 - 0
deploy/cpp/include/paddlex/transforms.h

@@ -234,6 +234,12 @@ class Padding : public Transform {
     }
   }
   virtual bool Run(cv::Mat* im, ImageBlob* data);
+  virtual void GeneralPadding(cv::Mat* im,
+                              const std::vector<float> &padding_val,
+                              int padding_w, int padding_h);
+  virtual void MultichannelPadding(cv::Mat* im,
+                                   const std::vector<float> &padding_val,
+                                   int padding_w, int padding_h);
 
  private:
   int coarsest_stride_ = -1;

+ 2 - 2
deploy/cpp/scripts/jetson_build.sh

@@ -1,5 +1,5 @@
 # 是否使用GPU(即是否使用 CUDA)
-WITH_GPU=OFF
+WITH_GPU=ON
 # 使用MKL or openblas
 WITH_MKL=OFF
 # 是否集成 TensorRT(仅WITH_GPU=ON 有效)
@@ -7,7 +7,7 @@ WITH_TENSORRT=OFF
 # TensorRT 的路径,如果需要集成TensorRT,需修改为您实际安装的TensorRT路径
 TENSORRT_DIR=/root/projects/TensorRT/
 # Paddle 预测库路径, 请修改为您实际安装的预测库路径
-PADDLE_DIR=/root/projects/fluid_inference
+PADDLE_DIR=/root/projects/paddle_inference
 # Paddle 的预测库是否使用静态库来编译
 # 使用TensorRT时,Paddle的预测库通常为动态库
 WITH_STATIC_LIB=OFF

+ 4 - 1
deploy/cpp/src/paddlex.cpp

@@ -171,7 +171,10 @@ bool Model::predict(const cv::Mat& im, ClsResult* result) {
   inputs_.clear();
   if (type == "detector") {
     std::cerr << "Loading model is a 'detector', DetResult should be passed to "
-                 "function predict()!"
+                 "function predict()!" << std::endl;
+    return false;
+  } else if (type == "segmenter") {
+    std::cerr << "Loading model is a 'segmenter', SegResult should be passed "
                  "to function predict()!" << std::endl;
     return false;
   }

+ 51 - 13
deploy/cpp/src/transforms.cpp

@@ -36,9 +36,11 @@ bool Normalize::Run(cv::Mat* im, ImageBlob* data) {
 
   std::vector<cv::Mat> split_im;
   cv::split(*im, split_im);
+  #pragma omp parallel for num_threads(im->channels())
   for (int c = 0; c < im->channels(); c++) {
+    float range_val = max_val_[c] - min_val_[c];
     cv::subtract(split_im[c], cv::Scalar(min_val_[c]), split_im[c]);
-    cv::divide(split_im[c], cv::Scalar(range_val[c]), split_im[c]);
+    cv::divide(split_im[c], cv::Scalar(range_val), split_im[c]);
     cv::subtract(split_im[c], cv::Scalar(mean_[c]), split_im[c]);
     cv::divide(split_im[c], cv::Scalar(std_[c]), split_im[c]);
   }
@@ -92,6 +94,50 @@ bool CenterCrop::Run(cv::Mat* im, ImageBlob* data) {
   return true;
 }
 
+void Padding::GeneralPadding(cv::Mat* im,
+                             const std::vector<float> &padding_val,
+                             int padding_w, int padding_h) {
+  cv::Scalar value;
+  if (im->channels() == 1) {
+    value = cv::Scalar(padding_val[0]);
+  } else if (im->channels() == 2) {
+    value = cv::Scalar(padding_val[0], padding_val[1]);
+  } else if (im->channels() == 3) {
+    value = cv::Scalar(padding_val[0], padding_val[1], padding_val[2]);
+  } else if (im->channels() == 4) {
+    value = cv::Scalar(padding_val[0], padding_val[1], padding_val[2],
+                                  padding_val[3]);
+  }
+  cv::copyMakeBorder(
+  *im,
+  *im,
+  0,
+  padding_h,
+  0,
+  padding_w,
+  cv::BORDER_CONSTANT,
+  value);
+}
+
+void Padding::MultichannelPadding(cv::Mat* im,
+                                  const std::vector<float> &padding_val,
+                                  int padding_w, int padding_h) {
+  std::vector<cv::Mat> padded_im_per_channel(im->channels());
+  #pragma omp parallel for num_threads(im->channels())
+  for (size_t i = 0; i < im->channels(); i++) {
+    const cv::Mat per_channel = cv::Mat(im->rows + padding_h,
+                                        im->cols + padding_w,
+                                        CV_32FC1,
+                                        cv::Scalar(padding_val[i]));
+    padded_im_per_channel[i] = per_channel;
+  }
+  cv::Mat padded_im;
+  cv::merge(padded_im_per_channel, padded_im);
+  cv::Rect im_roi = cv::Rect(0, 0, im->cols, im->rows);
+  im->copyTo(padded_im(im_roi));
+  *im = padded_im;
+}
+
 bool Padding::Run(cv::Mat* im, ImageBlob* data) {
   data->im_size_before_resize_.push_back({im->rows, im->cols});
   data->reshape_order_.push_back("padding");
@@ -116,19 +162,11 @@ bool Padding::Run(cv::Mat* im, ImageBlob* data) {
               << ", but they should be greater than 0." << std::endl;
     return false;
   }
-  std::vector<cv::Mat> padded_im_per_channel;
-  for (size_t i = 0; i < im->channels(); i++) {
-    const cv::Mat per_channel = cv::Mat(im->rows + padding_h,
-                                        im->cols + padding_w,
-                                        CV_32FC1,
-                                        cv::Scalar(im_value_[i]));
-    padded_im_per_channel.push_back(per_channel);
+  if (im->channels() < 5) {
+    Padding::GeneralPadding(im, im_value_, padding_w, padding_h);
+  } else {
+    Padding::MultichannelPadding(im, im_value_, padding_w, padding_h);
   }
-  cv::Mat padded_im;
-  cv::merge(padded_im_per_channel, padded_im);
-  cv::Rect im_roi = cv::Rect(0, 0, im->cols, im->rows);
-  im->copyTo(padded_im(im_roi));
-  *im = padded_im;
   data->new_im_size_[0] = im->rows;
   data->new_im_size_[1] = im->cols;
 

+ 1 - 3
deploy/openvino/CMakeLists.txt

@@ -9,7 +9,6 @@ SET(OPENVINO_DIR "" CACHE PATH "Location of libraries")
 SET(OPENCV_DIR "" CACHE PATH "Location of libraries")
 SET(GFLAGS_DIR "" CACHE PATH "Location of libraries")
 SET(NGRAPH_LIB "" CACHE PATH "Location of libraries")
-SET(ARCH "" CACHE PATH "Location of libraries")
 
 include(cmake/yaml-cpp.cmake)
 
@@ -96,8 +95,7 @@ if(WIN32)
     set(DEPS ${OPENVINO_DIR}/lib/intel64/Release/inference_engine${CMAKE_STATIC_LIBRARY_SUFFIX})
     set(DEPS ${DEPS} ${OPENVINO_DIR}/lib/intel64/Release/inference_engine_legacy${CMAKE_STATIC_LIBRARY_SUFFIX})
 else()
-    if (ARCH STREQUAL "armv7")
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv7-a")
+    if (${ARCH} STREQUAL "armv7")
         if(WITH_STATIC_LIB)
             set(DEPS ${OPENVINO_DIR}/lib/armv7l/libinference_engine${CMAKE_STATIC_LIBRARY_SUFFIX})
             set(DEPS ${DEPS} ${OPENVINO_DIR}/lib/armv7l/libinference_engine_legacy${CMAKE_STATIC_LIBRARY_SUFFIX})

+ 1 - 2
deploy/openvino/cmake/yaml-cpp.cmake

@@ -5,8 +5,7 @@ message("${CMAKE_BUILD_TYPE}")
 
 ExternalProject_Add(
         ext-yaml-cpp
-        URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip
-        URL_MD5 9542d6de397d1fbd649ed468cb5850e6
+        URL ${CMAKE_CURRENT_SOURCE_DIR}/deps/yaml-cpp.zip
         CMAKE_ARGS
         -DYAML_CPP_BUILD_TESTS=OFF
         -DYAML_CPP_BUILD_TOOLS=OFF

+ 6 - 2
deploy/openvino/demo/classifier.cpp

@@ -59,7 +59,9 @@ int main(int argc, char** argv) {
     while (getline(inf, image_path)) {
       PaddleX::ClsResult result;
       cv::Mat im = cv::imread(image_path, 1);
-      model.predict(im, &result);
+      if (!model.predict(im, &result)) {
+        return -1;
+      }
       std::cout << "Predict label: " << result.category
                 << ", label_id:" << result.category_id
                 << ", score: " << result.score << std::endl;
@@ -67,7 +69,9 @@ int main(int argc, char** argv) {
   } else {
     PaddleX::ClsResult result;
     cv::Mat im = cv::imread(FLAGS_image, 1);
-    model.predict(im, &result);
+    if (!model.predict(im, &result)) {
+      return -1;
+    }
     std::cout << "Predict label: " << result.category
               << ", label_id:" << result.category_id
               << ", score: " << result.score << std::endl;

+ 6 - 2
deploy/openvino/demo/detector.cpp

@@ -70,7 +70,9 @@ int main(int argc, char** argv) {
     while (getline(inf, image_path)) {
       PaddleX::DetResult result;
       cv::Mat im = cv::imread(image_path, 1);
-      model.predict(im, &result);
+      if (!model.predict(im, &result)) {
+        return -1;
+      }
       if (FLAGS_save_dir != "") {
         cv::Mat vis_img = PaddleX::Visualize(
           im, result, model.labels, colormap, FLAGS_threshold);
@@ -83,7 +85,9 @@ int main(int argc, char** argv) {
   } else {
   PaddleX::DetResult result;
   cv::Mat im = cv::imread(FLAGS_image, 1);
-  model.predict(im, &result);
+  if (!model.predict(im, &result)) {
+    return -1;
+  }
   for (int i = 0; i < result.boxes.size(); ++i) {
       std::cout << "image file: " << FLAGS_image << std::endl;
       std::cout << ", predict label: " << result.boxes[i].category

+ 6 - 2
deploy/openvino/demo/segmenter.cpp

@@ -64,7 +64,9 @@ int main(int argc, char** argv) {
     while (getline(inf, image_path)) {
       PaddleX::SegResult result;
       cv::Mat im = cv::imread(image_path, 1);
-      model.predict(im, &result);
+      if (!model.predict(im, &result)) {
+        return -1;
+      }
       if (FLAGS_save_dir != "") {
       cv::Mat vis_img = PaddleX::Visualize(im, result, model.labels, colormap);
         std::string save_path =
@@ -76,7 +78,9 @@ int main(int argc, char** argv) {
   } else {
     PaddleX::SegResult result;
     cv::Mat im = cv::imread(FLAGS_image, 1);
-    model.predict(im, &result);
+    if (!model.predict(im, &result)) {
+      return -1;
+    }
     if (FLAGS_save_dir != "") {
       cv::Mat vis_img = PaddleX::Visualize(im, result, model.labels, colormap);
       std::string save_path =

+ 6 - 0
deploy/openvino/include/paddlex/transforms.h

@@ -213,6 +213,12 @@ class Padding : public Transform {
   }
 
   virtual bool Run(cv::Mat* im, ImageBlob* data);
+  virtual void GeneralPadding(cv::Mat* im,
+                              const std::vector<float> &padding_val,
+                              int padding_w, int padding_h);
+  virtual void MultichannelPadding(cv::Mat* im,
+                                   const std::vector<float> &padding_val,
+                                   int padding_w, int padding_h);
 
  private:
   int coarsest_stride_ = -1;

+ 18 - 7
deploy/openvino/scripts/build.sh

@@ -20,10 +20,21 @@ sh $(pwd)/scripts/install_third-party.sh
 rm -rf build
 mkdir -p build
 cd build
-cmake .. \
-    -DOPENCV_DIR=${OPENCV_DIR} \
-    -DGFLAGS_DIR=${GFLAGS_DIR} \
-    -DOPENVINO_DIR=${OPENVINO_DIR} \
-    -DNGRAPH_LIB=${NGRAPH_LIB} \
-    -DARCH=${ARCH}
-make
+if [ ${ARCH} = "x86" ];then
+  cmake .. \
+      -DOPENCV_DIR=${OPENCV_DIR} \
+      -DGFLAGS_DIR=${GFLAGS_DIR} \
+      -DOPENVINO_DIR=${OPENVINO_DIR} \
+      -DNGRAPH_LIB=${NGRAPH_LIB} \
+      -DARCH=${ARCH}
+  make
+else
+  cmake ..\
+      -DOPENCV_DIR=${OPENCV_DIR} \
+      -DGFLAGS_DIR=${GFLAGS_DIR} \
+      -DOPENVINO_DIR=${OPENVINO_DIR} \
+      -DNGRAPH_LIB=${NGRAPH_LIB} \
+      -DARCH=${ARCH} \
+      -DCMAKE_CXX_FLAGS="-march=armv7-a"
+  make
+fi

+ 10 - 1
deploy/openvino/scripts/install_third-party.sh

@@ -2,7 +2,7 @@
 if [ ! -d "./deps" ]; then
     mkdir deps
 fi
-if [ ! -d "./deps/gflag" ]; then
+if [ ! -d "./deps/gflags" ]; then
     cd deps
     git clone https://github.com/gflags/gflags
     cd gflags
@@ -12,6 +12,15 @@ if [ ! -d "./deps/gflag" ]; then
     cd ..
 fi
 
+# install yaml
+YAML_URL=https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip
+if [ ! -f "./deps/yaml-cpp.zip" ]; then
+    cd deps
+    wget -c ${YAML_URL}
+    cd ..
+fi
+
+
 if [ "$ARCH" = "x86" ]; then
     OPENCV_URL=https://bj.bcebos.com/paddlex/deploy/x86opencv/opencv.tar.bz2
 else

+ 8 - 3
deploy/openvino/src/paddlex.cpp

@@ -44,7 +44,7 @@ void Model::create_predictor(const std::string& model_dir,
     }
     if (device == "MYRIAD") {
       std::map<std::string, std::string> networkConfig;
-      networkConfig["VPU_HW_STAGES_OPTIMIZATION"] = "ON";
+      networkConfig["VPU_HW_STAGES_OPTIMIZATION"] = "NO";
       executable_network_ = ie.LoadNetwork(network_, device, networkConfig);
     } else {
       executable_network_ = ie.LoadNetwork(network_, device);
@@ -116,11 +116,16 @@ bool Model::predict(const cv::Mat& im, ClsResult* result) {
   output_ = infer_request.GetBlob(output_name);
   InferenceEngine::MemoryBlob::CPtr moutput =
     InferenceEngine::as<InferenceEngine::MemoryBlob>(output_);
+  InferenceEngine::TensorDesc blob_output = moutput->getTensorDesc();
+  std::vector<size_t> output_shape = blob_output.getDims();
   auto moutputHolder = moutput->rmap();
   float* outputs_data = moutputHolder.as<float *>();
-
+  int size = 1;
+  for (auto& i : output_shape) {
+    size *= static_cast<int>(i);
+  }
   // post process
-  auto ptr = std::max_element(outputs_data, outputs_data+sizeof(outputs_data));
+  auto ptr = std::max_element(outputs_data, outputs_data + size);
   result->category_id = std::distance(outputs_data, ptr);
   result->score = *ptr;
   result->category = labels[result->category_id];

+ 50 - 14
deploy/openvino/src/transforms.cpp

@@ -38,9 +38,11 @@ bool Normalize::Run(cv::Mat* im, ImageBlob* data) {
 
   std::vector<cv::Mat> split_im;
   cv::split(*im, split_im);
+  #pragma omp parallel for num_threads(im->channels())
   for (int c = 0; c < im->channels(); c++) {
+    float range_val = max_val_[c] - min_val_[c];
     cv::subtract(split_im[c], cv::Scalar(min_val_[c]), split_im[c]);
-    cv::divide(split_im[c], cv::Scalar(range_val[c]), split_im[c]);
+    cv::divide(split_im[c], cv::Scalar(range_val), split_im[c]);
     cv::subtract(split_im[c], cv::Scalar(mean_[c]), split_im[c]);
     cv::divide(split_im[c], cv::Scalar(std_[c]), split_im[c]);
   }
@@ -95,6 +97,49 @@ bool CenterCrop::Run(cv::Mat* im, ImageBlob* data) {
   return true;
 }
 
+void Padding::GeneralPadding(cv::Mat* im,
+                             const std::vector<float> &padding_val,
+                             int padding_w, int padding_h) {
+  cv::Scalar value;
+  if (im->channels() == 1) {
+    value = cv::Scalar(padding_val[0]);
+  } else if (im->channels() == 2) {
+    value = cv::Scalar(padding_val[0], padding_val[1]);
+  } else if (im->channels() == 3) {
+    value = cv::Scalar(padding_val[0], padding_val[1], padding_val[2]);
+  } else if (im->channels() == 4) {
+    value = cv::Scalar(padding_val[0], padding_val[1], padding_val[2],
+                                  padding_val[3]);
+  }
+  cv::copyMakeBorder(
+  *im,
+  *im,
+  0,
+  padding_h,
+  0,
+  padding_w,
+  cv::BORDER_CONSTANT,
+  value);
+}
+
+void Padding::MultichannelPadding(cv::Mat* im,
+                                  const std::vector<float> &padding_val,
+                                  int padding_w, int padding_h) {
+  std::vector<cv::Mat> padded_im_per_channel(im->channels());
+  #pragma omp parallel for num_threads(im->channels())
+  for (size_t i = 0; i < im->channels(); i++) {
+    const cv::Mat per_channel = cv::Mat(im->rows + padding_h,
+                                        im->cols + padding_w,
+                                        CV_32FC1,
+                                        cv::Scalar(padding_val[i]));
+    padded_im_per_channel[i] = per_channel;
+  }
+  cv::Mat padded_im;
+  cv::merge(padded_im_per_channel, padded_im);
+  cv::Rect im_roi = cv::Rect(0, 0, im->cols, im->rows);
+  im->copyTo(padded_im(im_roi));
+  *im = padded_im;
+}
 
 bool Padding::Run(cv::Mat* im, ImageBlob* data) {
   data->im_size_before_resize_.push_back({im->rows, im->cols});
@@ -120,19 +165,11 @@ bool Padding::Run(cv::Mat* im, ImageBlob* data) {
               << ", but they should be greater than 0." << std::endl;
     return false;
   }
-  std::vector<cv::Mat> padded_im_per_channel;
-  for (size_t i = 0; i < im->channels(); i++) {
-    const cv::Mat per_channel = cv::Mat(im->rows + padding_h,
-                                        im->cols + padding_w,
-                                        CV_32FC1,
-                                        cv::Scalar(im_value_[i]));
-    padded_im_per_channel.push_back(per_channel);
+  if (im->channels() < 5) {
+    Padding::GeneralPadding(im, im_value_, padding_w, padding_h);
+  } else {
+    Padding::MultichannelPadding(im, im_value_, padding_w, padding_h);
   }
-  cv::Mat padded_im;
-  cv::merge(padded_im_per_channel, padded_im);
-  cv::Rect im_roi = cv::Rect(0, 0, im->cols, im->rows);
-  im->copyTo(padded_im(im_roi));
-  *im = padded_im;
   data->new_im_size_[0] = im->rows;
   data->new_im_size_[1] = im->cols;
 
@@ -219,7 +256,6 @@ void Transforms::Init(
     if (name == "ArrangeYOLOv3") {
       continue;
     }
-    std::cout << "trans name: " << name << std::endl;
     std::shared_ptr<Transform> transform = CreateTransform(name);
     transform->Init(item.begin()->second);
     transforms_.push_back(transform);

+ 25 - 52
deploy/raspberry/CMakeLists.txt

@@ -4,11 +4,11 @@ project(PaddleX CXX C)
 
 option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static."   OFF)
 
+
 SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
 SET(LITE_DIR "" CACHE PATH "Location of libraries")
 SET(OPENCV_DIR "" CACHE PATH "Location of libraries")
-SET(NGRAPH_LIB "" CACHE PATH "Location of libraries")
-
+SET(GFLAGS_DIR "" CACHE PATH "Location of libraries")
 
 include(cmake/yaml-cpp.cmake)
 
@@ -17,16 +17,6 @@ link_directories("${CMAKE_CURRENT_BINARY_DIR}")
 include_directories("${CMAKE_CURRENT_BINARY_DIR}/ext/yaml-cpp/src/ext-yaml-cpp/include")
 link_directories("${CMAKE_CURRENT_BINARY_DIR}/ext/yaml-cpp/lib")
 
-macro(safe_set_static_flag)
-    foreach(flag_var
-        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
-        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
-      if(${flag_var} MATCHES "/MD")
-        string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
-      endif(${flag_var} MATCHES "/MD")
-    endforeach(flag_var)
-endmacro()
-
 if (NOT DEFINED LITE_DIR OR ${LITE_DIR} STREQUAL "")
 	message(FATAL_ERROR "please set LITE_DIR with -LITE_DIR=/path/influence_engine")
 endif()
@@ -39,9 +29,13 @@ if (NOT DEFINED GFLAGS_DIR OR ${GFLAGS_DIR} STREQUAL "")
     message(FATAL_ERROR "please set GFLAGS_DIR with -DGFLAGS_DIR=/path/gflags")
 endif()
 
+if (NOT DEFINED ARCH OR ${ARCH} STREQUAL "")
+    message(FATAL_ERROR "please set ARCH with ARCH=armv7-a or ARCH=armv8-a")
+endif()
 
-
-
+if (NOT DEFINED LITE OR ${LITE} STREQUAL "")
+    message(FATAL_ERROR "Please set LITE with LITE=light or LITE=full")
+endif()
 
 link_directories("${LITE_DIR}/lib")
 include_directories("${LITE_DIR}/include")
@@ -53,54 +47,33 @@ include_directories("${GFLAGS_DIR}/include")
 
 
 
-
-if (WIN32)
-  find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/build/ NO_DEFAULT_PATH)
-  unset(OpenCV_DIR CACHE)
-else ()
-	find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/share/OpenCV NO_DEFAULT_PATH)
-endif ()
-
+find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/share/OpenCV NO_DEFAULT_PATH)
 include_directories(${OpenCV_INCLUDE_DIRS})
 
-if (WIN32)
-    set(CMAKE_C_FLAGS_DEBUG   "${CMAKE_C_FLAGS_DEBUG} /bigobj /MTd")
-    set(CMAKE_C_FLAGS_RELEASE  "${CMAKE_C_FLAGS_RELEASE} /bigobj /MT")
-    set(CMAKE_CXX_FLAGS_DEBUG  "${CMAKE_CXX_FLAGS_DEBUG} /bigobj /MTd")
-    set(CMAKE_CXX_FLAGS_RELEASE   "${CMAKE_CXX_FLAGS_RELEASE} /bigobj /MT")
-    if (WITH_STATIC_LIB)
-        safe_set_static_flag()
-        add_definitions(-DSTATIC_LIB)
-    endif()
-else()
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon-vfpv4 -g -o2 -fopenmp -std=c++11")
+if (${ARCH} STREQUAL "armv7-a")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -mfloat-abi=hard -mfpu=neon-vfpv4 -g -o2 -fopenmp -std=c++11")
+    set(CMAKE_STATIC_LIBRARY_PREFIX "")
+elseif(${ARC}H STREQUAL "armv8-a")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -g -o2 -fopenmp -std=c++11")
     set(CMAKE_STATIC_LIBRARY_PREFIX "")
-endif()
-
-
-if(WITH_STATIC_LIB)
-	set(DEPS ${LITE_DIR}/lib/libpaddle_full_api_shared${CMAKE_STATIC_LIBRARY_SUFFIX})
 else()
-	set(DEPS ${LITE_DIR}/lib/libpaddle_full_api_shared${CMAKE_SHARED_LIBRARY_SUFFIX})
+    message(FATAL_ERROR "Unknown arch abi ${ARCH}, only support armv8 and armv7")
 endif()
 
-if (NOT WIN32)
-    set(DEPS ${DEPS}
-        gflags yaml-cpp
-        )
-else()
-    set(DEPS ${DEPS}
-        gflags_static libprotobuf zlibstatic xxhash libyaml-cppmt)
-    set(DEPS ${DEPS} libcmt shlwapi)
-endif(NOT WIN32)
-
 
-if (NOT WIN32)
-    set(EXTERNAL_LIB "-ldl -lrt -lgomp -lz -lm -lpthread")
-    set(DEPS ${DEPS} ${EXTERNAL_LIB})
+if(${LITE} STREQUAL "full")
+    set(DEPS ${LITE_DIR}/lib/libpaddle_full_api_shared${CMAKE_SHARED_LIBRARY_SUFFIX})
+elseif(${LITE} STREQUAL "light")
+    set(DEPS ${LITE_DIR}/lib/libpaddle_light_api_shared${CMAKE_SHARED_LIBRARY_SUFFIX})
+else()
+    message(FATAL_ERROR "Unkown LITE release ${LITE}, only support light and full")
 endif()
 
+set(DEPS ${DEPS} gflags yaml-cpp)
+set(EXTERNAL_LIB "-ldl -lrt -lgomp -lz -lm -lpthread")
+set(DEPS ${DEPS} ${EXTERNAL_LIB})
 set(DEPS ${DEPS} ${OpenCV_LIBS})
+
 add_executable(classifier demo/classifier.cpp src/transforms.cpp src/paddlex.cpp)
 ADD_DEPENDENCIES(classifier ext-yaml-cpp)
 target_link_libraries(classifier ${DEPS})

+ 2 - 2
deploy/raspberry/cmake/yaml-cpp.cmake

@@ -2,11 +2,11 @@
 include(ExternalProject)
 
 message("${CMAKE_BUILD_TYPE}")
+message(${CMAKE_CURRENT_SOURCE_DIR})
 
 ExternalProject_Add(
         ext-yaml-cpp
-        URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip
-        URL_MD5 9542d6de397d1fbd649ed468cb5850e6
+	URL ${CMAKE_CURRENT_SOURCE_DIR}/deps/yaml-cpp.zip
         CMAKE_ARGS
         -DYAML_CPP_BUILD_TESTS=OFF
         -DYAML_CPP_BUILD_TOOLS=OFF

+ 1 - 1
deploy/raspberry/include/paddlex/visualize.h

@@ -22,7 +22,7 @@
 #include <io.h>
 #else  // Linux/Unix
 #include <dirent.h>
-#include <sys/io.h>
+#include <sys/uio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>

+ 12 - 3
deploy/raspberry/scripts/build.sh

@@ -6,8 +6,15 @@ GFLAGS_DIR=$(pwd)/deps/gflags
 
 # opencv预编译库的路径, 如果使用自带预编译版本可不修改
 OPENCV_DIR=$(pwd)/deps/opencv
+
+# arm处理器架构,默认为armv7下ARCH=armv7-a,若CPU为armv8请修改为ARCH=armv8-a
+ARCH=armv7-a
+
+# 采用lite的版本,可选为full 与 light,默认为full版
+LITE=full
+
 # 下载自带预编译版本
-exec $(pwd)/scripts/install_third-party.sh
+bash $(pwd)/scripts/install_third-party.sh
 
 rm -rf build
 mkdir -p build
@@ -16,5 +23,7 @@ cmake .. \
     -DOPENCV_DIR=${OPENCV_DIR} \
     -DGFLAGS_DIR=${GFLAGS_DIR} \
     -DLITE_DIR=${LITE_DIR} \
-    -DCMAKE_CXX_FLAGS="-march=armv7-a"  
-make
+    -DARCH=${ARCH} \
+    -DLITE=${LITE} \
+    -DCMAKE_CXX_FLAGS="-march=${ARCH}"
+make -j4

+ 12 - 1
deploy/raspberry/scripts/install_third-party.sh

@@ -2,7 +2,8 @@
 if [ ! -d "./deps" ]; then
     mkdir deps
 fi
-if [ ! -d "./deps/gflag" ]; then
+
+if [ ! -d "./deps/gflags" ]; then
     cd deps
     git clone https://github.com/gflags/gflags
     cd gflags
@@ -11,6 +12,16 @@ if [ ! -d "./deps/gflag" ]; then
     cd ..
     cd ..
 fi
+
+# install yaml
+YAML_URL=https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip
+if [ ! -f "./deps/yaml-cpp.zip" ]; then
+    cd deps
+    wget -c ${YAML_URL}
+    cd ..
+fi
+
+# install opencv
 OPENCV_URL=https://bj.bcebos.com/paddlex/deploy/armlinux/opencv.tar.bz2
 if [ ! -d "./deps/opencv" ]; then
     cd deps

+ 7 - 4
deploy/raspberry/src/paddlex.cpp

@@ -90,10 +90,13 @@ bool Model::predict(const cv::Mat& im, ClsResult* result) {
   std::unique_ptr<const paddle::lite_api::Tensor> output_tensor(
     std::move(predictor_->GetOutput(0)));
   const float *outputs_data = output_tensor->mutable_data<float>();
-
-
+  auto output_shape = output_tensor->shape();
+  int64_t size = 1;
+  for (const auto& i : output_shape) {
+    size *= i;
+  }
   // postprocess
-  auto ptr = std::max_element(outputs_data, outputs_data+sizeof(outputs_data));
+  auto ptr = std::max_element(outputs_data, outputs_data + size);
   result->category_id = std::distance(outputs_data, ptr);
   result->score = *ptr;
   result->category = labels[result->category_id];
@@ -121,7 +124,7 @@ bool Model::predict(const cv::Mat& im, DetResult* result) {
   if (name == "YOLOv3") {
     std::unique_ptr<paddle::lite_api::Tensor> im_size_tensor(
       std::move(predictor_->GetInput(1)));
-    im_size_tensor->Resize({1,2});
+    im_size_tensor->Resize({1, 2});
     auto *im_size_data = im_size_tensor->mutable_data<int>();
     memcpy(im_size_data, inputs_.ori_im_size_.data(), 1*2*sizeof(int));
   }

+ 0 - 48
docs/apis/analysis.md

@@ -1,48 +0,0 @@
-# 数据集分析
-
-## paddlex.datasets.analysis.Seg
-```python
-paddlex.datasets.analysis.Seg(data_dir, file_list, label_list)
-```
-
-构建统计分析语义分类数据集的分析器。
-
-> **参数**
-> > * **data_dir** (str): 数据集所在的目录路径。  
-> > * **file_list** (str): 描述数据集图片文件和类别id的文件路径(文本内每行路径为相对`data_dir`的相对路径)。  
-> > * **label_list** (str): 描述数据集包含的类别信息文件路径。  
-
-### analysis
-```python
-analysis(self)
-```
-
-Seg分析器的分析接口,完成以下信息的分析统计:
-
-> * 图像数量
-> * 图像最大和最小的尺寸
-> * 图像通道数量
-> * 图像各通道的最小值和最大值
-> * 图像各通道的像素值分布
-> * 图像各通道归一化后的均值和方差
-> * 标注图中各类别的数量及比重
-
-[代码示例](https://github.com/PaddlePaddle/PaddleX/blob/develop/examples/multi-channel_remote_sensing/tools/analysis.py)
-
-[统计信息示例](../examples/multi-channel_remote_sensing/analysis.html#id2)
-
-### cal_clipped_mean_std
-```python
-cal_clipped_mean_std(self, clip_min_value, clip_max_value, data_info_file)
-```
-
-Seg分析器用于计算图像截断后的均值和方差的接口。
-
-> **参数**
-> > * **clip_min_value** (list):  截断的下限,小于min_val的数值均设为min_val。
-> > * **clip_max_value** (list): 截断的上限,大于max_val的数值均设为max_val。
-> > * **data_info_file** (str): 在analysis()接口中保存的分析结果文件(名为`train_information.pkl`)的路径。
-
-[代码示例](https://github.com/PaddlePaddle/PaddleX/blob/develop/examples/multi-channel_remote_sensing/tools/cal_clipped_mean_std.py)
-
-[计算结果示例](../../examples/multi-channel_remote_sensing/analysis.html#id4)

+ 18 - 0
docs/apis/datasets.md

@@ -41,6 +41,15 @@ paddlex.datasets.VOCDetection(data_dir, file_list, label_list, transforms=None,
 > > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
 > > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
 
+### add_negative_samples(self, image_dir)
+
+> **将背景图片加入训练**
+
+> > * **image_dir** (str): 背景图片所在的文件夹目录。
+
+> 示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/tree/develop/examples/industrial_quality_inspection/train_rcnn.py#L45)
+
+
 ## paddlex.datasets.CocoDetection
 > **用于实例分割/目标检测模型**  
 ```
@@ -61,6 +70,15 @@ paddlex.datasets.CocoDetection(data_dir, ann_file, transforms=None, num_workers=
 > > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。  
 > > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。  
 
+### add_negative_samples(self, image_dir)
+
+> **将背景图片加入训练**
+
+> > * **image_dir** (str): 背景图片所在的文件夹目录。
+
+> 示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/tree/develop/examples/industrial_quality_inspection/train_rcnn.py#L45)
+
+
 ## paddlex.datasets.SegDataset
 > **用于语义分割模型**  
 ```

BIN=BIN
docs/apis/images/detection_analysis.jpg


BIN=BIN
docs/apis/images/insect_bbox-allclass-allarea.png


+ 1 - 1
docs/apis/index.rst

@@ -6,7 +6,7 @@ API接口说明
 
    transforms/index.rst
    datasets.md
-   analysis.md
+   tools.md
    models/index.rst
    slim.md
    visualize.md

+ 1 - 1
docs/apis/models/classification.md

@@ -27,7 +27,7 @@ train(self, num_epochs, train_dataset, train_batch_size=64, eval_dataset=None, s
 > > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
 > > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代步数)。默认为2。
 > > - **save_dir** (str): 模型保存路径。
-> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为'IMAGENET'。
+> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为'IMAGENET'。若模型为'ResNet50_vd',则默认下载百度自研10万类预训练模型,即默认为'BAIDU10W'。
 > > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
 > > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.025。
 > > - **warmup_steps** (int): 默认优化器的warmup步数,学习率将在设定的步数内,从warmup_start_lr线性增长至设定的learning_rate,默认为0。

+ 28 - 10
docs/apis/models/detection.md

@@ -3,7 +3,7 @@
 ## paddlex.det.PPYOLO
 
 ```python
-paddlex.det.PPYOLO(num_classes=80, backbone='ResNet50_vd_ssld', with_dcn_v2=True, anchors=None, anchor_masks=None, use_coord_conv=True, use_iou_aware=True, use_spp=True, use_drop_block=True, scale_x_y=1.05, ignore_threshold=0.7, label_smooth=False, use_iou_loss=True, use_matrix_nms=True, nms_score_threshold=0.01, nms_topk=1000, nms_keep_topk=100, nms_iou_threshold=0.45, train_random_shapes=[320, 352, 384, 416, 448, 480, 512, 544, 576, 608])
+paddlex.det.PPYOLO(num_classes=80, backbone='ResNet50_vd_ssld', with_dcn_v2=True, anchors=None, anchor_masks=None, use_coord_conv=True, use_iou_aware=True, use_spp=True, use_drop_block=True, scale_x_y=1.05, ignore_threshold=0.7, label_smooth=False, use_iou_loss=True, use_matrix_nms=True, nms_score_threshold=0.01, nms_topk=1000, nms_keep_topk=100, nms_iou_threshold=0.45, train_random_shapes=[320, 352, 384, 416, 448, 480, 512, 544, 576, 608], input_channel=3)
 ```
 
 > 构建PPYOLO检测器。**注意在PPYOLO,num_classes不需要包含背景类,如目标包括human、dog两种,则num_classes设为2即可,这里与FasterRCNN/MaskRCNN有差别**
@@ -32,6 +32,7 @@ paddlex.det.PPYOLO(num_classes=80, backbone='ResNet50_vd_ssld', with_dcn_v2=True
 > > - **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]。
+> > - **input_channel** (int): 输入图像的通道数量。默认为3。
 
 ### train
 
@@ -85,7 +86,7 @@ evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_de
 > >
 >  **返回值**
 >
-> > - **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‘:真实标注框相关信息。
+> > - **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和gt两个关键字。其中关键字bbox的键值是一个列表,列表中每个元素代表一个预测结果,一个预测结果是一个由图像id,预测框类别id, 预测框坐标,预测框得分组成的列表。而关键字gt的键值是真实标注框的相关信息。
 
 ### predict
 
@@ -93,7 +94,7 @@ evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_de
 predict(self, img_file, transforms=None)
 ```
 
-> PPYOLO模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`YOLOv3.test_transforms`和`YOLOv3.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义`test_transforms`传入给`predict`接口
+> PPYOLO模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`PPYOLO.test_transforms`和`PPYOLO.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义`test_transforms`传入给`predict`接口
 
 > **参数**
 >
@@ -111,7 +112,7 @@ predict(self, img_file, transforms=None)
 batch_predict(self, img_file_list, transforms=None)
 ```
 
-> PPYOLO模型批量预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`YOLOv3.test_transforms`和`YOLOv3.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`batch_predict`接口时,用户需要再重新定义`test_transforms`传入给`batch_predict`接口
+> PPYOLO模型批量预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`PPYOLO.test_transforms`和`PPYOLO.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`batch_predict`接口时,用户需要再重新定义`test_transforms`传入给`batch_predict`接口
 
 > **参数**
 >
@@ -126,7 +127,7 @@ batch_predict(self, img_file_list, transforms=None)
 ## paddlex.det.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])
+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], input_channel=3)
 ```
 
 > 构建YOLOv3检测器。**注意在YOLOv3,num_classes不需要包含背景类,如目标包括human、dog两种,则num_classes设为2即可,这里与FasterRCNN/MaskRCNN有差别**
@@ -147,6 +148,7 @@ paddlex.det.YOLOv3(num_classes=80, backbone='MobileNetV1', anchors=None, anchor_
 > > - **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]。
+> > - **input_channel** (int): 输入图像的通道数量。默认为3。
 
 ### train
 
@@ -198,7 +200,7 @@ evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_de
 > >
 >  **返回值**
 >
-> > - **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‘:真实标注框相关信息。
+> > - **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和gt两个关键字。其中关键字bbox的键值是一个列表,列表中每个元素代表一个预测结果,一个预测结果是一个由图像id,预测框类别id, 预测框坐标,预测框得分组成的列表。而关键字gt的键值是真实标注框的相关信息。
 
 ### predict
 
@@ -240,8 +242,7 @@ batch_predict(self, img_file_list, transforms=None)
 ## paddlex.det.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])
-
+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], with_dcn=False, rpn_cls_loss='SigmoidCrossEntropy', rpn_focal_loss_alpha=0.25, rpn_focal_loss_gamma=2, rcnn_bbox_loss='SmoothL1Loss', rcnn_nms='MultiClassNMS', keep_top_k=100, nms_threshold=0.5, score_threshold=0.05, softnms_sigma=0.5, bbox_assigner='BBoxAssigner', fpn_num_channels=256, input_channel=3, rpn_batch_size_per_im=256, rpn_fg_fraction=0.5, test_pre_nms_top_n=None, test_post_nms_top_n=1000)
 ```
 
 > 构建FasterRCNN检测器。 **注意在FasterRCNN中,num_classes需要设置为类别数+背景类,如目标包括human、dog两种,则num_classes需设为3,多的一种为背景background类别**
@@ -249,10 +250,27 @@ paddlex.det.FasterRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspec
 > **参数**
 
 > > - **num_classes** (int): 包含了背景类的类别数。默认为81。
-> > - **backbone** (str): FasterRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd', 'HRNet_W18']。默认为'ResNet50'。
+> > - **backbone** (str): FasterRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd', 'HRNet_W18', 'ResNet50_vd_ssld']。默认为'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]。
+> > - **with_dcn** (bool): backbone网络中是否使用deformable convolution network v2。默认为False。
+> > - **rpn_cls_loss** (str): RPN部分的分类损失函数,取值范围为['SigmoidCrossEntropy', 'SigmoidFocalLoss']。当遇到模型误检了很多背景区域时,可以考虑使用'SigmoidFocalLoss',并调整适合的`rpn_focal_loss_alpha`和`rpn_focal_loss_gamma`。默认为'SigmoidCrossEntropy'。
+> > - **rpn_focal_loss_alpha** (float):当RPN的分类损失函数设置为'SigmoidFocalLoss'时,用于调整正样本和负样本的比例因子,默认为0.25。当PN的分类损失函数设置为'SigmoidCrossEntropy'时,`rpn_focal_loss_alpha`的设置不生效。
+> > - **rpn_focal_loss_gamma** (float): 当RPN的分类损失函数设置为'SigmoidFocalLoss'时,用于调整易分样本和难分样本的比例因子,默认为2。当RPN的分类损失函数设置为'SigmoidCrossEntropy'时,`rpn_focal_loss_gamma`的设置不生效。
+> > - **rcnn_bbox_loss** (str): RCNN部分的位置回归损失函数,取值范围为['SmoothL1Loss', 'CIoULoss']。默认为'SmoothL1Loss'。
+> > - **rcnn_nms** (str): RCNN部分的非极大值抑制的计算方法,取值范围为['MultiClassNMS', 'MultiClassSoftNMS','MultiClassCiouNMS']。默认为'MultiClassNMS'。当选择'MultiClassNMS'时,可以将`keep_top_k`设置成100、`nms_threshold`设置成0.5、`score_threshold`设置成0.05。当选择'MultiClassSoftNMS'时,可以将`keep_top_k`设置为300、`score_threshold`设置为0.01、`softnms_sigma`设置为0.5。当选择'MultiClassCiouNMS'时,可以将`keep_top_k`设置为100、`score_threshold`设置成0.05、`nms_threshold`设置成0.5。
+> > - **keep_top_k** (int): RCNN部分在进行非极大值抑制计算后,每张图像保留最多保存`keep_top_k`个检测框。默认为100。
+> > - **nms_threshold** (float): RCNN部分在进行非极大值抑制时,用于剔除检测框所需的IoU阈值。当`rcnn_nms`设置为`MultiClassSoftNMS`时,`nms_threshold`的设置不生效。默认为0.5。
+> > - **score_threshold** (float): RCNN部分在进行非极大值抑制前,用于过滤掉低置信度边界框所需的置信度阈值。默认为0.05。
+> > - **softnms_sigma** (float): 当`rcnn_nms`设置为`MultiClassSoftNMS`时,用于调整被抑制的检测框的置信度,调整公式为`score = score * weights, weights = exp(-(iou * iou) / softnms_sigma)`。默认设为0.5。
+> > - **bbox_assigner** (str): 训练阶段,RCNN部分生成正负样本的采样方式。可选范围为['BBoxAssigner', 'LibraBBoxAssigner']。当目标物体的区域只占原始图像的一小部分时,可以考虑采用[LibraRCNN](https://arxiv.org/abs/1904.02701)中提出的IoU-balanced Sampling采样方式来获取更多的难分负样本,设置为'LibraBBoxAssigner'即可。默认为'BBoxAssigner'。
+> > - **fpn_num_channels** (int): FPN部分特征层的通道数量。默认为256。
+> > - **input_channel** (int): 输入图像的通道数量。默认为3。
+> > - **rpn_batch_size_per_im** (int): 训练阶段,RPN部分每张图片的正负样本的数量总和。默认为256。
+> > - **rpn_fg_fraction** (float): 训练阶段,RPN部分每张图片的正负样本数量总和中正样本的占比。默认为0.5。
+> > - **test_pre_nms_top_n** (int):预测阶段,RPN部分做非极大值抑制计算的候选框的数量。若设置为None, 有FPN结构的话,`test_pre_nms_top_n`会被设置成6000, 无FPN结构的话,`test_pre_nms_top_n`会被设置成1000。默认为None。
+> > - **test_post_nms_top_n** (int): 预测阶段,RPN部分做完非极大值抑制后保留的候选框的数量。默认为1000。
 
 ### train
 
@@ -302,7 +320,7 @@ evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_de
 > >
 > **返回值**
 >
-> > - **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‘:真实标注框相关信息。
+> > - **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和gt两个关键字。其中关键字bbox的键值是一个列表,列表中每个元素代表一个预测结果,一个预测结果是一个由图像id,预测框类别id, 预测框坐标,预测框得分组成的列表。而关键字gt的键值是真实标注框的相关信息。
 
 ### predict
 

+ 24 - 5
docs/apis/models/instance_segmentation.md

@@ -3,7 +3,7 @@
 ## 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])
+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], with_dcn=False, rpn_cls_loss='SigmoidCrossEntropy', rpn_focal_loss_alpha=0.25, rpn_focal_loss_gamma=2, rcnn_bbox_loss='SmoothL1Loss', rcnn_nms='MultiClassNMS', keep_top_k=100, nms_threshold=0.5, score_threshold=0.05, softnms_sigma=0.5, bbox_assigner='BBoxAssigner', fpn_num_channels=256, input_channel=3, rpn_batch_size_per_im=256, rpn_fg_fraction=0.5, test_pre_nms_top_n=None, test_post_nms_top_n=1000)
 
 ```
 
@@ -12,10 +12,29 @@ paddlex.det.MaskRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_
 > **参数**
 
 > > - **num_classes** (int): 包含了背景类的类别数。默认为81。
-> > - **backbone** (str): MaskRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd', 'HRNet_W18']。默认为'ResNet50'。
+> > - **backbone** (str): MaskRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd', 'HRNet_W18', 'ResNet50_vd_ssld']。默认为'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]。
+> > - **with_dcn** (bool): backbone网络中是否使用deformable convolution network v2。默认为False。
+> > - **rpn_cls_loss** (str): RPN部分的分类损失函数,取值范围为['SigmoidCrossEntropy', 'SigmoidFocalLoss']。当遇到模型误检了很多背景区域时,可以考虑使用'SigmoidFocalLoss',并调整适合的`rpn_focal_loss_alpha`和`rpn_focal_loss_gamma`。默认为'SigmoidCrossEntropy'。
+> > - **rpn_focal_loss_alpha** (float):当RPN的分类损失函数设置为'SigmoidFocalLoss'时,用于调整正样本和负样本的比例因子,默认为0.25。当PN的分类损失函数设置为'SigmoidCrossEntropy'时,`rpn_focal_loss_alpha`的设置不生效。
+> > - **rpn_focal_loss_gamma** (float): 当RPN的分类损失函数设置为'SigmoidFocalLoss'时,用于调整易分样本和难分样本的比例因子,默认为2。当RPN的分类损失函数设置为'SigmoidCrossEntropy'时,`rpn_focal_loss_gamma`的设置不生效。
+> > - **rcnn_bbox_loss** (str): RCNN部分的位置回归损失函数,取值范围为['SmoothL1Loss', 'CIoULoss']。默认为'SmoothL1Loss'。
+> > - **rcnn_nms** (str): RCNN部分的非极大值抑制的计算方法,取值范围为['MultiClassNMS', 'MultiClassSoftNMS','MultiClassCiouNMS']。默认为'MultiClassNMS'。当选择'MultiClassNMS'时,可以将`keep_top_k`设置成100、`nms_threshold`设置成0.5、`score_threshold`设置成0.05。当选择'MultiClassSoftNMS'时,可以将`keep_top_k`设置为300、`score_threshold`设置为0.01、`softnms_sigma`设置为0.5。当选择'MultiClassCiouNMS'时,可以将`keep_top_k`设置为100、`score_threshold`设置成0.05、`nms_threshold`设置成0.5。
+> > - **keep_top_k** (int): RCNN部分在进行非极大值抑制计算后,每张图像保留最多保存`keep_top_k`个检测框。默认为100。
+> > - **nms_threshold** (float): RCNN部分在进行非极大值抑制时,用于剔除检测框所需的IoU阈值。当`rcnn_nms`设置为`MultiClassSoftNMS`时,`nms_threshold`的设置不生效。默认为0.5。
+> > - **score_threshold** (float): RCNN部分在进行非极大值抑制前,用于过滤掉低置信度边界框所需的置信度阈值。默认为0.05。
+> > - **softnms_sigma** (float): 当`rcnn_nms`设置为`MultiClassSoftNMS`时,用于调整被抑制的检测框的置信度,调整公式为`score = score * weights, weights = exp(-(iou * iou) / softnms_sigma)`。默认设为0.5。
+> > - **bbox_assigner** (str): 训练阶段,RCNN部分生成正负样本的采样方式。可选范围为['BBoxAssigner', 'LibraBBoxAssigner']。当目标物体的区域只占原始图像的一小部分时,可以考虑采用[LibraRCNN](https://arxiv.org/abs/1904.02701)中提出的IoU-balanced Sampling采样方式来获取更多的难分负样本,设置为'LibraBBoxAssigner'即可。默认为'BBoxAssigner'。
+> > - **fpn_num_channels** (int): FPN部分特征层的通道数量。默认为256。
+> > - **input_channel** (int): 输入图像的通道数量。默认为3。
+> > - **rpn_batch_size_per_im** (int): 训练阶段,RPN部分每张图片的正负样本的数量总和。默认为256。
+> > - **rpn_fg_fraction** (float): 训练阶段,RPN部分每张图片的正负样本数量总和中正样本的占比。默认为0.5。
+> > - **test_pre_nms_top_n** (int):预测阶段,RPN部分做非极大值抑制计算的候选框的数量。若设置为None, 有FPN结构的话,`test_pre_nms_top_n`会被设置成6000, 无FPN结构的话,`test_pre_nms_top_n`会被设置成1000。默认为None。
+> > - **test_post_nms_top_n** (int): 预测阶段,RPN部分做完非极大值抑制后保留的候选框的数量。默认为1000。
+
+
 
 #### train
 
@@ -65,7 +84,7 @@ evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_de
 > >
 > **返回值**
 >
-> > - **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‘:真实标注框和标注区域相关信息。
+> > - **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`、`mask`和`gt`三个关键字。其中关键字`bbox`的键值是一个列表,列表中每个元素代表一个预测结果,一个预测结果是一个由图像id,预测框类别id, 预测框坐标,预测框得分组成的列表。关键字`mask`的键值是一个列表,列表中每个元素代表各预测框内物体的分割结果,分割结果由图像id、预测框类别id、表示预测框内各像素点是否属于物体的二值图、预测框得分。而关键字gt的键值是真实标注框的相关信息。
 
 #### predict
 
@@ -73,7 +92,7 @@ evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_de
 predict(self, img_file, transforms=None)
 ```
 
-> MaskRCNN模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`FasterRCNN.test_transforms`和`FasterRCNN.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
+> MaskRCNN模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`MaskRCNN.test_transforms`和`MaskRCNN.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
 
 > **参数**
 >
@@ -91,7 +110,7 @@ predict(self, img_file, transforms=None)
 batch_predict(self, img_file_list, transforms=None)
 ```
 
-> MaskRCNN模型批量预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`FasterRCNN.test_transforms`和`FasterRCNN.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`batch_predict`接口时,用户需要再重新定义test_transforms传入给`batch_predict`接口。
+> MaskRCNN模型批量预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`MaskRCNN.test_transforms`和`MaskRCNN.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`batch_predict`接口时,用户需要再重新定义test_transforms传入给`batch_predict`接口。
 
 > **参数**
 >

+ 77 - 0
docs/apis/tools.md

@@ -0,0 +1,77 @@
+# 数据集工具
+
+## 数据集分析
+
+### paddlex.datasets.analysis.Seg
+```python
+paddlex.datasets.analysis.Seg(data_dir, file_list, label_list)
+```
+
+构建统计分析语义分类数据集的分析器。
+
+> **参数**
+> > * **data_dir** (str): 数据集所在的目录路径。  
+> > * **file_list** (str): 描述数据集图片文件和类别id的文件路径(文本内每行路径为相对`data_dir`的相对路径)。  
+> > * **label_list** (str): 描述数据集包含的类别信息文件路径。  
+
+#### analysis
+```python
+analysis(self)
+```
+
+Seg分析器的分析接口,完成以下信息的分析统计:
+
+> * 图像数量
+> * 图像最大和最小的尺寸
+> * 图像通道数量
+> * 图像各通道的最小值和最大值
+> * 图像各通道的像素值分布
+> * 图像各通道归一化后的均值和方差
+> * 标注图中各类别的数量及比重
+
+[代码示例](https://github.com/PaddlePaddle/PaddleX/blob/develop/examples/multi-channel_remote_sensing/tools/analysis.py)
+
+[统计信息示例](../../examples/multi-channel_remote_sensing/analysis.html#id2)
+
+#### cal_clipped_mean_std
+```python
+cal_clipped_mean_std(self, clip_min_value, clip_max_value, data_info_file)
+```
+
+Seg分析器用于计算图像截断后的均值和方差的接口。
+
+> **参数**
+> > * **clip_min_value** (list):  截断的下限,小于min_val的数值均设为min_val。
+> > * **clip_max_value** (list): 截断的上限,大于max_val的数值均设为max_val。
+> > * **data_info_file** (str): 在analysis()接口中保存的分析结果文件(名为`train_information.pkl`)的路径。
+
+[代码示例](https://github.com/PaddlePaddle/PaddleX/blob/develop/examples/multi-channel_remote_sensing/tools/cal_clipped_mean_std.py)
+
+[计算结果示例](../examples/multi-channel_remote_sensing/analysis.html#id4)
+
+## 数据集生成
+
+### paddlex.det.paste_objects
+```python
+paddlex.det.paste_objects(templates, background, save_dir='dataset_clone')
+```
+
+将目标物体粘贴在背景图片上生成新的图片和标注文件
+
+> **参数**
+> > * **templates** (list|tuple):可以将多张图像上的目标物体同时粘贴在同一个背景图片上,因此templates是一个列表,其中每个元素是一个dict,表示一张图片的目标物体。一张图片的目标物体有`image`和`annos`两个关键字,`image`的键值是图像的路径,或者是解码后的排列格式为(H, W, C)且类型为uint8且为BGR格式的数组。图像上可以有多个目标物体,因此`annos`的键值是一个列表,列表中每个元素是一个dict,表示一个目标物体的信息。该dict包含`polygon`和`category`两个关键字,其中`polygon`表示目标物体的边缘坐标,例如[[0, 0], [0, 1], [1, 1], [1, 0]],`category`表示目标物体的类别,例如'dog'。
+> > * **background** (dict): 背景图片可以有真值,因此background是一个dict,包含`image`和`annos`两个关键字,`image`的键值是背景图像的路径,或者是解码后的排列格式为(H, W, C)且类型为uint8且为BGR格式的数组。若背景图片上没有真值,则`annos`的键值是空列表[],若有,则`annos`的键值是由多个dict组成的列表,每个dict表示一个物体的信息,包含`bbox`和`category`两个关键字,`bbox`的键值是物体框左上角和右下角的坐标,即[x1, y1, x2, y2],`category`表示目标物体的类别,例如'dog'。
+> > * **save_dir** (str):新图片及其标注文件的存储目录。默认值为`dataset_clone`。
+
+> **代码示例**
+
+```python
+import paddlex as pdx
+templates = [{'image': 'dataset/JPEGImages/budaodian-10.jpg',
+              'annos': [{'polygon': [[146, 169], [909, 169], [909, 489], [146, 489]],
+                        'category': 'lou_di'},
+                        {'polygon': [[146, 169], [909, 169], [909, 489], [146, 489]],
+                        'category': 'lou_di'}]}]
+background = {'image': 'dataset/JPEGImages/budaodian-12.jpg', 'annos': []}
+pdx.det.paste_objects(templates, background, save_dir='dataset_clone')
+```

+ 14 - 3
docs/apis/transforms/det_transforms.md

@@ -32,13 +32,13 @@ paddlex.det.transforms.ResizeByShort(short_size=800, max_size=1333)
 
 根据图像的短边调整图像大小(resize)。  
 1. 获取图像的长边和短边长度。  
-2. 根据短边与short_size的比例,计算长边的目标长度,此时高、宽的resize比例为short_size/原图短边长度。  
+2. 根据短边与short_size的比例,计算长边的目标长度,此时高、宽的resize比例为short_size/原图短边长度。若short_size为数组,则随机从该数组中挑选一个数值作为short_size。
 3. 如果max_size>0,调整resize比例:
    如果长边的目标长度>max_size,则高、宽的resize比例为max_size/原图长边长度。
 4. 根据调整大小的比例对图像进行resize。
 
 ### 参数
-* **short_size** (int): 短边目标长度。默认为800。
+* **short_size** (int|list): 短边目标长度。默认为800。当需要做多尺度训练时,可以将`short_size`设置成数组,例如[500, 600, 700, 800]。
 * **max_size** (int): 长边目标长度的最大限制。默认为1333。
 
 ## Padding
@@ -122,7 +122,7 @@ paddlex.det.transforms.MixupImage(alpha=1.5, beta=1.5, mixup_epoch=-1)
 * **beta** (float): 随机beta分布的上限。默认为1.5。
 * **mixup_epoch** (int): 在前mixup_epoch轮使用mixup增强操作;当该参数为-1时,该策略不会生效。默认为-1。
 
-## RandomExpand
+## RandomExpand
 ```python
 paddlex.det.transforms.RandomExpand(ratio=4., prob=0.5, fill_value=[123.675, 116.28, 103.53])
 ```
@@ -168,6 +168,17 @@ paddlex.det.transforms.RandomCrop(aspect_ratio=[.5, 2.], thresholds=[.0, .1, .3,
 * **allow_no_crop** (bool): 是否允许未进行裁剪。默认值为True。
 * **cover_all_box** (bool): 是否要求所有的真实标注框都必须在裁剪区域内。默认值为False。
 
+## CLAHE
+```
+paddlex.det.transforms.CLAHE(clip_limit=2., tile_grid_size=(8, 8))
+```
+对图像进行对比度增强。
+
+### 参数
+
+* **clip_limit** (int|float): 颜色对比度的阈值,默认值为2.。
+* **tile_grid_size** (list|tuple): 进行像素均衡化的网格大小。默认值为(8, 8)。
+
 <!--
 ## ComposedRCNNTransforms
 ```python

+ 67 - 0
docs/apis/visualize.md

@@ -139,3 +139,70 @@ paddlex.transforms.visualize(dataset,
 >* **dataset** (paddlex.datasets): 数据集读取器。
 >* **img_count** (int): 需要进行数据预处理/增强的图像数目。默认为3。
 >* **save_dir** (str): 日志保存的路径。默认为'vdl_output'。
+
+## paddlex.det.coco_error_analysis
+> **分析模型预测错误的原因**
+
+```
+paddlex.det.coco_error_analysis(eval_details_file=None, gt=None, pred_bbox=None, pred_mask=None, save_dir='./output')
+```
+逐个分析模型预测错误的原因,并将分析结果以图表的形式展示。分析结果图表示例如下:
+
+![](images/detection_analysis.jpg)
+
+左图显示的是`person`类的分析结果,有图显示的是所有类别整体的分析结果。
+
+分析图表展示了7条Precision-Recall(PR)曲线,每一条曲线表示的Average Precision (AP)比它左边那条高,原因是逐步放宽了评估要求。以`person`类为例,各条PR曲线的评估要求解释如下:
+
+* C75: 在IoU设置为0.75时的PR曲线, AP为0.510。
+* C50: 在IoU设置为0.5时的PR曲线,AP为0.724。C50与C75之间的白色区域面积代表将IoU从0.75放宽至0.5带来的AP增益。
+* Loc: 在IoU设置为0.1时的PR曲线,AP为0.832。Loc与C50之间的蓝色区域面积代表将IoU从0.5放宽至0.1带来的AP增益。蓝色区域面积越大,表示越多的检测框位置不够精准。
+* Sim: 在Loc的基础上,如果检测框与真值框的类别不相同,但两者同属于一个亚类,则不认为该检测框是错误的,在这种评估要求下的PR曲线, AP为0.832。Sim与Loc之间的红色区域面积越大,表示子类间的混淆程度越高。
+* Oth: 在Sim的基础上,如果检测框与真值框的亚类不相同,则不认为该检测框是错误的,在这种评估要求下的PR曲线,AP为0.841。Oth与Sim之间的绿色区域面积越大,表示亚类间的混淆程度越高。
+* BG: 在Oth的基础上,背景区域上的检测框不认为是错误的,在这种评估要求下的PR曲线,AP为91.1。BG与Oth之间的紫色区域面积越大,表示背景区域被误检的数量越多。
+* FN: 在BG的基础上,漏检的真值框不认为是错误的,在这种评估要求下的PR曲线,AP为1.00。FN与BG之间的橙色区域面积越大,表示漏检的真值框数量越多。
+
+更为详细的说明参考[COCODataset官网给出分析工具说明](https://cocodataset.org/#detection-eval)
+
+### 参数
+> * **eval_details_file** (str): 模型评估结果的保存路径,包含真值信息和预测结果。默认值为None。
+> * **gt** (list): 数据集的真值信息。默认值为None。
+> * **pred_bbox** (list): 模型在数据集上的预测框。默认值为None。
+> * **pred_mask** (list): 模型在数据集上的预测mask。默认值为None。
+> * **save_dir** (str): 可视化结果保存路径。默认值为'./output'。
+
+**注意:**`eval_details_file`的优先级更高,只要`eval_details_file`不为None,就会从`eval_details_file`提取真值信息和预测结果做分析。当`eval_details_file`为None时,则用`gt`、`pred_mask`、`pred_mask`做分析。
+
+### 使用示例
+点击下载如下示例中的[模型](https://bj.bcebos.com/paddlex/models/insect_epoch_270.zip)和[数据集](https://bj.bcebos.com/paddlex/datasets/insect_det.tar.gz)
+
+> 方式一:分析训练过程中保存的模型文件夹中的评估结果文件`eval_details.json`,例如[模型](https://bj.bcebos.com/paddlex/models/insect_epoch_270.zip)中的`eval_details.json`。
+```
+import paddlex as pdx
+eval_details_file = 'insect_epoch_270/eval_details.json'
+pdx.det.coco_error_analysis(eval_details_file, save_dir='./insect')
+```
+> 方式二:分析模型评估函数返回的评估结果。
+
+```
+import os
+# 选择使用0号卡
+os.environ['CUDA_VISIBLE_DEVICES'] = '0'
+
+from paddlex.det import transforms
+import paddlex as pdx
+
+model = pdx.load_model('insect_epoch_270')
+eval_dataset = pdx.datasets.VOCDetection(
+    data_dir='insect_det',
+    file_list='insect_det/val_list.txt',
+    label_list='insect_det/labels.txt',
+    transforms=model.eval_transforms)
+metrics, evaluate_details = model.evaluate(eval_dataset, batch_size=8, return_details=True)
+gt = evaluate_details['gt']
+bbox = evaluate_details['bbox']
+pdx.det.coco_error_analysis(gt=gt, pred_bbox=bbox, save_dir='./insect')
+```
+所有类别整体的分析结果示例如下:
+
+![](./images/insect_bbox-allclass-allarea.png)

+ 20 - 0
docs/change_log.md

@@ -1,5 +1,25 @@
 # 更新日志
 
+**v1.3.0** 2020.12.20
+
+- 模型更新
+  > - 图像分类模型ResNet50_vd新增10万分类预训练模型 
+  > - 目标检测模型FasterRCNN新增模型裁剪支持
+  > - 目标检测模型新增多通道图像训练支持
+
+- 模型部署更新
+  > - 修复OpenVINO部署C++代码中部分Bug
+  > - 树莓派部署新增Arm V8支持
+
+- 产业案例更新
+ > - 新增工业质检产业案例,提供基于GPU和CPU两种部署场景下的工业质检方案,及与质检相关的优化策略 [详情链接](https://paddlex.readthedocs.io/zh_CN/develop/examples/industrial_quality_inspection)
+
+- **新增RestFUL API模块**
+新增RestFUL API模块,开发者可通过此模块快速开发基于PaddleX的训练平台
+ > - 增加基于RestFUL API的HTML Demo [详情链接](https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/gui/introduction.md#paddlex-web-demo)
+ > - 增加基于RestFUL API的Remote版可视化客户端 [详情链接](https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/gui/introduction.md#paddlex-remote-gui)
+新增模型通过OpenVINO的部署方案[详情链接](https://paddlex.readthedocs.io/zh_CN/develop/deploy/openvino/index.html)
+
 **v1.2.0** 2020.09.07
 - 模型更新
   > - 新增产业最实用目标检测模型PP-YOLO,深入考虑产业应用对精度速度的双重面诉求,COCO数据集精度45.2%,Tesla V100预测速度72.9FPS。[详情链接](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-ppyolo)

BIN=BIN
docs/deploy/images/container.png


BIN=BIN
docs/deploy/images/images.png


+ 1 - 1
docs/deploy/index.rst

@@ -9,8 +9,8 @@
    export_model.md
    hub_serving.md
    server/index
-   nvidia-jetson.md
    paddlelite/index
    openvino/index
    raspberry/index
+   jetson/index
    opencv.md

+ 10 - 0
docs/deploy/jetson/index.rst

@@ -0,0 +1,10 @@
+Jetson部署
+=======================================
+
+
+.. toctree::
+   :maxdepth: 1
+   :caption: 文档目录:
+
+   nvidia-jetson.md
+   jetson-docker.md

+ 121 - 0
docs/deploy/jetson/jetson-docker.md

@@ -0,0 +1,121 @@
+# Nvidia Jetson开发板Docker部署
+本文档介绍了如何用Docker在Jetson开发板上部署PaddleX模型,通过Docker的方式部署,用户可以有效的避免可能因为系统环境导致编译或者运行的错误  
+
+提供了在Jeston上用于编译或者运行PaddleX部署代码的Docker,主要有如下功能:
+- 编译PaddleX部署代码:用户可以通过Docker编译PaddleX部署代码
+- 部署PaddleX模型:通过Docker使用编译好的可执行文件部署
+
+**注意**:NVIDIA JetPack在v4.2.1版本以上(含v4.2.1)才能支持通过Docker部署
+
+## 准备工作
+在编译与运行之前的准备工作,主要是下载Docker与创建容器  
+
+### Step1: 下载Jetson开发板Docker
+运行如下命令下载Docker  
+
+```
+sudo docker pull paddlex/jetson:1.0
+```  
+
+下载成功后,通过如下命令查看docker的镜像
+
+```
+sudo docker images
+```
+可以看到,存在一个REPOSITORY为`paddlex/jetson`、TAG为`1.0`的docker镜像
+![](../images/images.png)  
+
+### Step2: 容器创建
+创建容器之前,需要先准备好需要编译的部署代码与训练好的PaddleX部署模型
+
+建议用户在HOME目录下创建infer文件夹,将需要部署的代码与模型拷贝到该目录下用于挂载到容器内  
+
+本文档以PaddleX提供的jetson部署代码为示例:
+```
+#通过如下命令下载代码,Jetson部署代码在 `PaddleX/deploy/cpp` 目录下面
+git clone https://github.com/PaddlePaddle/PaddleX.git
+
+#在HOME目录下创建infer文件夹,将cpp文件夹拷贝到infer目录下面
+mkdir ~/infer
+cp -r PaddleX/deploy/cpp ~/infer/
+```
+
+**创建容器**:通过如下命令创建容器,同时将HOME目录下包含部署代码的infer文件夹挂载到容器内
+ ```
+ sudo docker create -it -v ~/infer/:/infer -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY --net=host --name paddlex --runtime nvidia paddlex/jetson:1.0 /bin/bash
+ ```
+查看创建的容器
+ ```
+ sudo docker ps -a
+ ```  
+
+ ![](../images/container.png)  
+
+
+创建好容器后需要运行容器
+```
+sudo docker start paddlex
+```
+
+## 编译
+通过如下命令可以编译infer文件夹内的部署代码
+```
+sudo docker exec -it paddlex /bin/bash -c 'cd /infer/cpp && sh scripts/jetson_build.sh'
+```
+**注意**:
+- `cd /infer/cpp`表示进入到部署代码目录,用户需要根据实际情况自己修改
+
+
+## 部署
+对于图片预测,编译的可执行文件在`/infer/cpp/build/demo/detector`,`/infer/cpp/build/demo/classifier`,`/infer/cpp/build/demo/segmenter`,其主要命令参数说明如下:
+
+|  参数   | 说明  |
+|  ----  | ----  |
+| model_dir  | 导出的预测模型所在路径 |
+| image  | 要预测的图片文件路径 |
+| image_list  | 按行存储图片路径的.txt文件 |
+| use_gpu  | 是否使用 GPU 预测, 支持值为0或1(默认值为0) |
+| use_trt  | 是否使用 TensorRT 预测, 支持值为0或1(默认值为0) |
+| gpu_id  | GPU 设备ID, 默认值为0 |
+| save_dir | 保存可视化结果的路径, 默认值为"output",**classfier无该参数** |
+| batch_size | 预测的批量大小,默认为1 |
+| thread_num | 预测的线程数,默认为cpu处理器个数 |  
+
+对于视频预测,编译的可执行文件在`/infer/cpp/build/demo/video_detector`,`/infer/cpp/build/demo/video_classifier`,`/infer/cpp/build/demo/video_segmenter`,其主要命令参数说明如下:
+
+|  参数   | 说明  |
+|  ----  | ----  |
+| model_dir  | 导出的预测模型所在路径 |
+| use_camera | 是否使用摄像头预测,支持值为0或1(默认值为0) |
+| camera_id | 摄像头设备ID,默认值为0 |
+| video_path | 视频文件的路径 |
+| use_gpu  | 是否使用 GPU 预测, 支持值为0或1(默认值为0) |
+| use_trt  | 是否使用 TensorRT 预测, 支持值为0或1(默认值为0) |
+| gpu_id  | GPU 设备ID, 默认值为0 |
+| show_result | 对视频文件做预测时,是否在屏幕上实时显示预测可视化结果(因加入了延迟处理,故显示结果不能反映真实的帧率),支持值为0或1(默认值为0) |
+| save_result | 是否将每帧的预测可视结果保存为视频文件,支持值为0或1(默认值为1) |
+| save_dir | 保存可视化结果的路径, 默认值为"output" |
+
+**设置show_result为1之前请执行如下命令确保容器有显示权限**
+```
+sudo xhost +
+```  
+
+**注意:若系统无GUI,则不要将show_result设置为1。当使用摄像头预测时,按`ESC`键可关闭摄像头并推出预测程序。**
+
+**对于使用用户编译的可执行文件进行部署的命令如下:**  
+```
+sudo docker exec -it paddlex /bin/bash -c 'cd [部署代码目录] && .build/demo/[可执行文件名] [命令参数]'
+```
+
+### 样例
+在用户编译完部署代码后,可按如下流程运行测试模型样例
+
+- 1)下载PaddleX预训练模型及测试图片[下载地址](https://paddlex.readthedocs.io/zh_CN/develop/train/prediction.html),本文档下载了YOLOv3-MobileNetV1模型与测试图片  
+- 2)将模型导出为部署模型格式 [导出部署模型步骤](https://paddlex.readthedocs.io/zh_CN/develop/deploy/export_model.html)
+- 3)将部署模型和测试图片copy到`~/infer`文件夹
+- 4)使用如下命令,通过容器进行预测
+
+```
+sudo docker exec -it paddlex /bin/bash -c 'cd /infer/cpp && ./build/demo/detector --model_dir /infer/yolov3_mobilenetv1_coco --image /infer/yolov3_mobilenetv1_coco/test.jpg --use_gpu 1'
+```

+ 1 - 1
docs/deploy/nvidia-jetson.md → docs/deploy/jetson/nvidia-jetson.md

@@ -1,4 +1,4 @@
-# Nvidia Jetson开发板
+# Nvidia Jetson开发板本地部署
 
 ## 说明
 本文档在基于Nvidia Jetpack 4.4的`Linux`平台上使用`GCC 7.4`测试过,如需使用不同G++版本,则需要重新编译Paddle预测库,请参考: [NVIDIA Jetson嵌入式硬件预测库源码编译](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html#id12)。

+ 2 - 1
docs/deploy/openvino/export_openvino_model.md

@@ -7,7 +7,8 @@
 * PaddleX 1.2+
 * OpenVINO 2021.1+
 
-**说明**:PaddleX安装请参考[PaddleX](https://paddlex.readthedocs.io/zh_CN/develop/install.html) , OpenVINO安装请参考[OpenVINO](https://docs.openvinotoolkit.org/latest/index.html),ONNX请安装1.6.0以上版本否则会出现转模型错误。
+**说明**:PaddleX安装请参考[PaddleX](https://paddlex.readthedocs.io/zh_CN/develop/install.html) , OpenVINO安装请参考[OpenVINO](https://docs.openvinotoolkit.org/latest/index.html),ONNX请安装1.6.0以上版本否则会出现转模型错误。  
+**注意**:安装OpenVINO时请务必安装官网教程初始化OpenVINO运行环境,并安装相关依赖  
 
 请确保系统已经安装好上述基本软件,**下面所有示例以工作目录 `/root/projects/`演示**。
 

+ 3 - 1
docs/deploy/openvino/introduction.md

@@ -1,6 +1,8 @@
 # OpenVINO部署简介
 PaddleX支持将训练好的Paddle模型通过OpenVINO实现模型的预测加速,OpenVINO详细资料与安装流程请参考[OpenVINO](https://docs.openvinotoolkit.org/latest/index.html),本文档使用OpenVINO 2020.4与2021.1测试通过。  
-**注意**:由于PaddleX分割模型使用了ReSize-11 Op,OpenVINO 2021.1版本开始支持支持Resize-11 ,请务必下载OpenVINO 2021.1+版本  
+**注意**:
+- 由于PaddleX分割模型使用了ReSize-11 Op,OpenVINO 2021.1版本开始支持支持Resize-11 ,请务必下载OpenVINO 2021.1+版本  
+- 安装OpenVINO过程中请务必参考OpenVINO官网教程,初始化OpenVINO使用环境,以及安装OpenVINO相关依赖  
 
 
 ## 部署支持情况

+ 1 - 1
docs/deploy/openvino/python.md

@@ -18,7 +18,7 @@
 | --model_dir  | 模型转换生成的.xml文件路径,请保证模型转换生成的三个文件在同一路径下|
 | --img  | 要预测的图片文件路径 |
 | --image_list  | 按行存储图片路径的.txt文件 |
-| --device  | 运行的平台, 默认值为"CPU" |
+| --device  | 运行的平台,可选项{"CPU","MYRIAD"} ,默认值为"CPU",VPU下上请使用"MYRIAD" |
 | --cfg_file | PaddleX model 的.yml配置文件 |
 
 ### 样例

+ 91 - 0
docs/deploy/raspberry/NCS2.md

@@ -0,0 +1,91 @@
+# 神经计算棒2代  
+PaddleX支持在树莓派上插入NCS2(神经计算棒2代)通过OpenVINO部署PadlleX训练出来的分类模型  
+
+**注意**:目前仅支持分类模型、仅支持Armv7hf的树莓派  
+
+## 前置条件  
+* OS: Raspbian OS 
+* PaddleX 1.0+
+* OpenVINO 2020.3+  
+
+- Raspbian OS:树莓派操作操作系统下载与安装请参考[树莓派系统安装与环境配置](./Raspberry.md#硬件环境配置)  
+- PaddleX: PaddleX安装请参考[PaddleX](https://paddlex.readthedocs.io/zh_CN/develop/install.html)  
+- OpenVINO: OpenVINO的安装请参考[OpenVINO-Raspbian](https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_raspbian.html)  
+
+**注意**:安装完OpenVINO后需要初始化OpenVINO环境,并且需要对USB进行配置,请参考:  
+  
+```
+#初始化OpenVINO环境
+source /opt/intel/openvino/bin/setupvars.sh
+#将初始化OpenVINO环境的规则加入到bashrc中
+echo "source /opt/intel/openvino/bin/setupvars.sh" >> ~/.bashrc
+#配置USB
+sh /opt/intel/openvino/install_dependencies/install_NCS_udev_rules.sh
+```
+  
+## 部署流程  
+  
+部署流程主要分为模型转换与转换后模型部署两个步骤,下面以MobilnetV2模型为例,介绍如何将PaddleX训练好的模型通过OpenVINO部署到插入NCS2的树莓派  
+教程的示例项目训练MobilenetV2模型,请参考[PaddleX模型训练示例](https://aistudio.baidu.com/aistudio/projectdetail/439860)  
+
+## 模型转换
+  
+模型转换指的是将PaddleX训练出来的Paddle模型转换为OpenVINO的IR,对于模型转换教程可以参考[OpenVINO模型转换](../openvino/export_openvino_model.md)  
+
+**注意**:树莓派上面安装的OpenVINO是不带Model Optmizier模块的,不能在上面进行模型转换,请在Host下载与树莓派一直的OpenVINO版本,然后进行模型转换。  
+
+以转换训练好的MobileNetV2为示例,请参考以下命令:
+```
+#安装paddlex
+pip install paddlex
+
+#下载PaddleX代码
+git clone https://github.com/PaddlePaddle/PaddleX.git
+
+#进入模型转换脚本文件夹
+cd PaddleX/deploy/openvino/python
+
+#导出inference模型,执行命令前务必将训练好的MobileNetV2模型拷贝到当前目录,并命名为MobileNetV2
+paddlex --export_inference --model_dir ./MobileNetV2 --save_dir ./MobileNetV2 --fixed_input_shape [224,224]
+#完成导出后会在MobileNetV2文件夹下面出现,__model__、__params__、model.yml三个文件
+
+#转换Paddle inference模型到OpenVINO IR
+python converter.py --model_dir ./MobileNetV2 --save_dir ./MobileNetV2 --fixed_input_shape [224,224] --data_type FP16
+#转换成功后会在MobileNetV2目录下面出现 paddle2onnx.xml、paddle2onnx.mapping、paddle2onnx.bin三个文件
+```
+
+## 模型部署
+
+PaddleX支持Python和C++两种方式在树莓派上通过NCS2部署:  
+- C++:C++部署教程请参考[OpenVINO_Raspberry](../openvino/linux.md)
+- python:python部署教程请参考[OpenVINO_python](../openvino/python.md)  
+
+以转换好的MobileNetV2模型为示例  
+
+**准备工作**
+```
+#在树莓派上下载PaddleX代码
+git clone https://github.com/PaddlePaddle/PaddleX.git
+#进入OpenVINO部署代码
+cd PaddleX/deploy/openvino
+#将MobileNetV2转好的OpenVINO IR以及测试图片拷贝到树莓派上面,并以及MobileNetV2文件夹放到OpenVINO部署的代码的目录
+```
+  
+**C++部署**
+```
+#修改编译文件script/build.sh,将ARCH参数修改为armv7
+vim script/build.sh
+#编译代码
+sh script/build.sh
+#OpenVINO部署
+./build/classfier --model_dir MobileNetV2/paddle2onnx.xml --image [测试图片路径] --device MYRIAD --cfg_file MobileNetV2/model.yml --save_dir output
+```
+执行成功后会在output文件夹面保存测试图片的可视化结果  
+
+**python部署**
+```
+进入python部署代码目录
+cd python
+#python部署
+python demo.py --model_dir ../MobileNetV2/paddle2onnx.xml --img [测试图片路径] --device MYRIAD --cfg_file MobileNetV2/model.yml
+```

+ 19 - 11
docs/deploy/raspberry/Raspberry.md

@@ -44,35 +44,42 @@ git clone https://github.com/PaddlePaddle/PaddleX.git
 **说明**:其中C++预测代码在PaddleX/deploy/raspberry 目录,该目录不依赖任何PaddleX下其他目录,如果需要在python下预测部署请参考[Python预测部署](./python.md)。  
 
 #### Step2:Paddle-Lite预编译库下载
-提供了下载的opt工具对应的Paddle-Lite在ArmLinux下面的预编译库:[Paddle-Lite(ArmLinux)预编译库](https://bj.bcebos.com/paddlex/deploy/lite/inference_lite_2.6.1_armlinux.tar.bz2)。  
-建议用户使用预编译库,若需要自行编译,在树莓派上LX终端输入
+对于Armv7hf的用户提供了2.6.1版本的Paddle-Lite在架构为armv7hf的ArmLinux下面的Full版本预编译库:[Paddle-Lite(ArmLinux)预编译库](https://bj.bcebos.com/paddlex/deploy/lite/inference_lite_2.6.1_armlinux.tar.bz2)    
+对于Armv8的用户提供了2.6.3版本的Paddle-Lite在架构为armv8的ArmLinux下面的full版本预编译库:[Paddle-Lite(ArmLinux)与编译库](https://bj.bcebos.com/paddlex/paddle-lite/armlinux/paddle-Lite_armlinux_full_2.6.3.zip)  
+其他版本与arm架构的Paddle-Lite预测库请在官网[Releases](https://github.com/PaddlePaddle/Paddle-Lite/release)下载
+若用户需要在树莓派上自行编译Paddle-Lite,在树莓派上LX终端输入  
+
 ```
 git clone https://github.com/PaddlePaddle/Paddle-Lite.git
 cd Paddle-Lite
 sudo ./lite/tools/build.sh  --arm_os=armlinux --arm_abi=armv7hf --arm_lang=gcc  --build_extra=ON full_publish
-```  
-
+```
 预编库位置:`./build.lite.armlinux.armv7hf.gcc/inference_lite_lib.armlinux.armv7hf/cxx`  
 
-**注意**:预测库版本需要跟opt版本一致,更多Paddle-Lite编译内容请参考[Paddle-Lite编译](https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html);更多预编译Paddle-Lite预测库请参考[Paddle-Lite Release Note](https://github.com/PaddlePaddle/Paddle-Lite/releases)
+**注意**:预测库版本需要跟opt版本一致,检测与分割请使用Paddle-Lite的full版本预测库,更多Paddle-Lite编译内容请参考[Paddle-Lite编译](https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html);更多预编译Paddle-Lite预测库请参考[Paddle-Lite Release Note](https://github.com/PaddlePaddle/Paddle-Lite/releases)
 
 #### Step3 软件依赖
-提供了依赖软件的预编包或者一键编译,用户不需要单独下载或编译第三方依赖软件。若需要自行编译第三方依赖软件请参考:
+提供了依赖软件的预编包或者一键编译,对于armv7树莓派用户不需要单独下载或编译第三方依赖软件,对于armv8树莓派用户需要自行编译opencv,编译第三方依赖软件请参考:
 
 - gflags:编译请参考 [编译文档](https://gflags.github.io/gflags/#download)  
 
 - opencv: 编译请参考
-[编译文档](https://docs.opencv.org/master/d7/d9f/tutorial_linux_install.html)
+[编译文档](https://docs.opencv.org/master/d7/d9f/tutorial_linux_install.html)  
+**注意**:对于armv8树莓派用户,需要自行编译opencv  
 
 #### Step4: 编译
 编译`cmake`的命令在`scripts/build.sh`中,修改LITE_DIR为Paddle-Lite预测库目录,若自行编译第三方依赖软件请根据Step1中编译软件的实际情况修改主要参数,其主要内容说明如下:
 ```
 # Paddle-Lite预编译库的路径
 LITE_DIR=/path/to/Paddle-Lite/inference/lib
-# gflags预编译库的路径
+# gflags预编译库的路径,若没有自行编译无需修改
 GFLAGS_DIR=$(pwd)/deps/gflags
-# opencv预编译库的路径
+# opencv预编译库的路径,若自行编译请指定到对应路径
 OPENCV_DIR=$(pwd)/deps/opencv/
+# arm处理器架构 armv7-a或者armv8-a
+ARCH=armv7-a
+# Lite预测库版本 light或者full
+LITE=full
 ```
 执行`build`脚本:
  ```shell
@@ -86,7 +93,7 @@ OPENCV_DIR=$(pwd)/deps/opencv/
 
 |  参数   | 说明  |
 |  ----  | ----  |
-| --model_dir  | 模型转换生成的.xml文件路径,请保证模型转换生成的三个文件在同一路径下|
+| --model_dir  | 模型转换生成的.nb文件路径|
 | --image  | 要预测的图片文件路径 |
 | --image_list  | 按行存储图片路径的.txt文件 |
 | --thread_num | 预测的线程数,默认值为1 |
@@ -154,4 +161,5 @@ OPENCV_DIR=$(pwd)/deps/opencv/
 ## NCS2部署
 树莓派支持通过OpenVINO在NCS2上跑PaddleX模型预测,目前仅支持PaddleX的分类网络,基于NCS2的方式包含Paddle模型转OpenVINO IR以及部署IR在NCS2上进行预测两个步骤。
 - 模型转换请参考:[PaddleX模型转换为OpenVINO IR](../openvino/export_openvino_model.md),raspbian OS上的OpenVINO不支持模型转换,需要先在host侧转换FP16的IR。
-- 预测部署请参考[OpenVINO部署](../openvino/linux.md)中VPU在raspbian OS部署的部分
+- 预测部署请参考[OpenVINO部署](../openvino/linux.md)中VPU在raspbian OS部署的部分  
+- 目前仅支持armv7的树莓派

+ 6 - 2
docs/deploy/raspberry/export_nb_model.md

@@ -3,7 +3,11 @@
 ### Step1:导出inference模型
 PaddleX模型转Paddle-Lite模型之前需要先把PaddleX模型导出为inference格式模型,导出的模型将包括__model__、__params__和model.yml三个文件名。具体方法请参考[Inference模型导出](../export_model.md)。
 ### Step2:导出Paddle-Lite模型
-Paddle-Lite模型需要通过Paddle-Lite的opt工具转出模型,下载并解压: [模型优化工具opt(2.6.1-linux)](https://bj.bcebos.com/paddlex/deploy/Rasoberry/opt.zip),在Linux系统下运行:
+Paddle-Lite模型需要通过Paddle-Lite的opt工具转出模型
+- 对于armv7hf的用户下载并解压: [模型优化工具opt(2.6.1-linux)](https://bj.bcebos.com/paddlex/deploy/Rasoberry/opt.zip)
+- 对于armv8的用户下载:[模型优化工具opt(2.6.3-linux)](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.6.3/opt_linux)  
+
+在Linux系统下运行:
 ``` bash
 ./opt --model_file=<model_path> \
       --param_file=<param_path> \
@@ -30,4 +34,4 @@ Paddle-Lite模型需要通过Paddle-Lite的opt工具转出模型,下载并解
 
 更多详细的使用方法和参数含义请参考: [使用opt转化模型](https://paddle-lite.readthedocs.io/zh/latest/user_guides/opt/opt_bin.html),更多opt预编译版本请参考[Paddle-Lite Release Note](https://github.com/PaddlePaddle/Paddle-Lite/releases)
 
-**注意**:opt版本需要跟预测库版本保持一致,如使2.6.0版本预测库,请从上面Release Note中下载2.6.0版本的opt转换模型
+**注意**:opt版本需要跟预测库版本保持一致,使2.6.0版本预测库,请从上面Release Note中下载2.6.0版本的opt转换模型

+ 1 - 0
docs/deploy/raspberry/index.rst

@@ -9,3 +9,4 @@
    Raspberry.md
    python.md
    export_nb_model.md 
+   NCS2.md

+ 2 - 2
docs/deploy/raspberry/python.md

@@ -34,7 +34,7 @@ python -m pip install paddlelite
 ```
 cd /root/projects/python  
 
-python demo.py --model_dir /path/to/openvino_model --img /path/to/test_img.jpeg --cfg_file /path/to/PadlleX_model.yml --thread_num 4 
+python demo.py --model_dir /path/to/nb_model --img /path/to/test_img.jpeg --cfg_file /path/to/PadlleX_model.yml --thread_num 4 
 ```  
 
 样例二`:
@@ -51,5 +51,5 @@ python demo.py --model_dir /path/to/openvino_model --img /path/to/test_img.jpeg
 ```
 cd /root/projects/python  
 
-python demo.py --model_dir /path/to/models/openvino_model --image_list /root/projects/images_list.txt --cfg_file=/path/to/PadlleX_model.yml --thread_num 4 
+python demo.py --model_dir /path/to/models/nb_model --image_list /root/projects/images_list.txt --cfg_file=/path/to/PadlleX_model.yml --thread_num 4 
 ```

+ 1 - 0
docs/examples/index.rst

@@ -15,3 +15,4 @@ PaddleX精选飞桨视觉开发套件在产业实践中的成熟模型结构,
    multi-channel_remote_sensing/README.md
    remote_sensing.md
    change_detection.md
+   industrial_quality_inspection/README.md

+ 99 - 0
docs/examples/industrial_quality_inspection/README.md

@@ -0,0 +1,99 @@
+# 工业质检
+
+本案例面向工业质检场景里的铝材表面缺陷检测,提供了针对GPU端和CPU端两种部署场景下基于PaddleX的解决方案,希望通过梳理优化模型精度和性能的思路能帮助用户更高效地解决实际质检应用中的问题。
+
+## 1. GPU端解决方案
+
+### 1.1 数据集介绍
+
+本案例使用[天池铝材表面缺陷检测初赛](https://tianchi.aliyun.com/competition/entrance/231682/introduction)数据集,共有3005张图片,分别检测擦花、杂色、漏底、不导电、桔皮、喷流、漆泡、起坑、脏点和角位漏底10种缺陷,这10种缺陷的定义和示例可点击文档[天池铝材表面缺陷检测初赛数据集示例](./dataset.md)查看。
+
+将这3005张图片按9:1随机切分成2713张图片的训练集和292张图片的验证集。
+
+### 1.2 精度优化
+
+本小节侧重展示在模型迭代过程中优化精度的思路,在本案例中,有些优化策略获得了精度收益,而有些没有。在其他质检场景中,可根据实际情况尝试这些优化策略。点击文档[精度优化](./accuracy_improvement.md)查看。
+
+### 1.3 性能优化
+
+在完成模型精度优化之后,从以下两个方面对模型进行加速:
+
+#### (1) 减少FPN部分的通道数量
+
+将FPN部分的通道数量由原本的256减少至64,使用方式在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时设置参数`fpn_num_channels`为64即可,需要重新对模型进行训练。
+
+#### (2) 减少测试阶段的候选框数量
+
+将测试阶段RPN部分做非极大值抑制计算的候选框数量由原本的6000减少至500,将RPN部分做完非极大值抑制后保留的候选框数量由原本的1000减少至300。使用方式在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时设置参数`test_pre_nms_top_n`为500,`test_post_nms_top_n`为300。
+
+采用Fluid C++预测引擎在Tesla P40上测试模型的推理时间(输入数据拷贝至GPU的时间、计算时间、数据拷贝至CPU的时间),输入大小设置为800x1333,加速前后推理时间如下表所示:
+
+| 模型 | 推理时间 (ms/image)| VOC mAP (%) |
+| -- | -- | -- |
+| baseline | 66.51 | 88.87 |
+| + fpn channel=64 + test proposal=pre/post topk 500/300 | 46.08 | 87.72 |
+
+### 1.4 最终方案
+
+本案例面向GPU端的最终方案是选择二阶段检测模型FasterRCNN,其骨干网络选择加入了可变形卷积(DCN)的ResNet50_vd,训练时使用SSLD蒸馏方案训练得到的ResNet50_vd预训练模型,FPN部分的通道数量设置为64。使用复核过的数据集,训练阶段数据增强策略采用RandomHorizontalFlip、RandomDistort、RandomCrop,并加入背景图片。测试阶段的RPN部分做非极大值抑制计算的候选框数量由原本的6000减少至500、做完非极大值抑制后保留的候选框数量由原本的1000减少至300。模型在验证集上的VOC mAP为87.72%。
+
+在Tesla P40的Linux系统下,对于输入大小是800 x 1333的模型,图像预处理时长为30ms/image,模型的推理时间为46.08ms/image,包括输入数据拷贝至GPU的时间、计算时间、数据拷贝至CPU的时间。
+
+| 模型 | VOC mAP (%) | 推理时间 (ms/image)
+| -- | -- | -- |
+| FasterRCNN-ResNet50_vd_ssld | 81.05 | 48.62 |
+| + dcn | 88.09 | 66.51 |
+| + RandomHorizontalFlip/RandomDistort/RandomCrop | 90.23| 66.51 |
+| + background images | 88.87 | 66.51 |
+| + fpn channel=64 | 87.79 | 48.65 |
+| + test proposal=pre/post topk 500/300 | 87.72 | 46.08 |
+
+具体的训练和部署流程点击文档[GPU端最终解决方案](./gpu_solution.md)进行查看。
+
+## 2. CPU端解决方案
+
+为了实现高效的模型推理,面向CPU端的模型选择精度和效率皆优的单阶段检测模型YOLOv3,骨干网络选择基于PaddleClas中SSLD蒸馏方案训练得到的MobileNetv3_large。训练完成后,对模型做剪裁操作,以提升模型的性能。模型在验证集上的VOC mAP为79.02%。
+
+部署阶段,借助OpenVINO预测引擎完成在Intel(R) Core(TM) i9-9820X CPU @ 3.30GHz Windows系统下高效推理。对于输入大小是608 x 608的模型,图像预处理时长为38.69 ms/image,模型的推理时间为34.50ms/image,
+
+| 模型 | VOC mAP (%) | Inference Speed (ms/image)
+| -- | -- | -- |
+| YOLOv3-MobileNetv3_ssld | 78.52 | 56.71 |
+| pruned YOLOv3-MobileNetv3_ssld | 79.02 | 34.50 |
+
+### 模型训练
+
+[环境前置依赖](./gpu_solution.md#%E5%89%8D%E7%BD%AE%E4%BE%9D%E8%B5%96)、[下载PaddleX源码](./gpu_solution.md#1-%E4%B8%8B%E8%BD%BDpaddlex%E6%BA%90%E7%A0%81)、[下载数据集](./gpu_solution.md#2-%E4%B8%8B%E8%BD%BD%E6%95%B0%E6%8D%AE%E9%9B%86)与GPU端是一样的,可点击文档[GPU端最终解决方案](./gpu_solution.md)查看,在此不做赘述。
+
+如果不想再次训练模型,可以直接下载已经训练好的模型完成后面的模型测试和部署推理:
+
+```
+wget https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/models/yolov3_mobilenetv3_large_pruned.tar.gz
+tar xvf yolov3_mobilenetv3_large_pruned.tar.gz
+```
+
+运行以下代码进行模型训练,代码会自动下载数据集,如若事先下载了数据集,需将下载和解压铝材缺陷检测数据集的相关行注释掉。代码中默认使用0,1,2,3,4,5,6,7号GPU训练,可根据实际情况设置卡号并调整`batch_size`和`learning_rate`。
+
+```
+python train_yolov3.py
+```
+
+### 模型剪裁
+
+运行以下代码,分析在不同的精度损失下模型各层的剪裁比例:
+
+```
+python params_analysis.py
+```
+
+设置可允许的精度损失为0.05,对模型进行剪裁,剪裁后需要重新训练模型:
+
+```
+python train_pruned_yolov3.py
+```
+
+[分析预测错误的原因](./gpu_solution.md#4-%E5%88%86%E6%9E%90%E9%A2%84%E6%B5%8B%E9%94%99%E8%AF%AF%E7%9A%84%E5%8E%9F%E5%9B%A0)、[统计图片级召回率和误检率](./gpu_solution.md#5-%E7%BB%9F%E8%AE%A1%E5%9B%BE%E7%89%87%E7%BA%A7%E5%8F%AC%E5%9B%9E%E7%8E%87%E5%92%8C%E8%AF%AF%E6%A3%80%E7%8E%87)、[模型测试](./gpu_solution.md#6-%E6%A8%A1%E5%9E%8B%E6%B5%8B%E8%AF%95)这些步骤与GPU端是一样的,可点击文档[GPU端最终解决方案](./gpu_solution.md)查看,在此不做赘述。
+
+### 推理部署
+
+本案例采用C++部署方式,通过OpenVINO将模型部署在Intel(R) Core(TM) i9-9820X CPU @ 3.30GHz的Windows系统下,具体的部署流程请参考文档[PaddleX模型多端安全部署/OpenVINO部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/openvino/index.html)。

+ 97 - 0
docs/examples/industrial_quality_inspection/accuracy_improvement.md

@@ -0,0 +1,97 @@
+# 精度优化
+
+本小节侧重展示在模型迭代过程中优化精度的思路,在本案例中,有些优化策略获得了精度收益,而有些没有。在其他质检场景中,可根据实际情况尝试这些优化策略。
+
+## (1) 基线模型选择
+
+相较于单阶段检测模型,二阶段检测模型的精度更高但是速度更慢。考虑到是部署到GPU端,本案例选择二阶段检测模型FasterRCNN作为基线模型,其骨干网络选择ResNet50_vd,并使用基于PaddleClas中SSLD蒸馏方案训练得到的ResNet50_vd预训练模型(ImageNet1k验证集上Top1 Acc为82.39%)。训练完成后,模型在验证集上的精度VOC mAP为73.36%。
+
+## (2) 模型效果分析
+
+使用PaddleX提供的[paddlex.det.coco_error_analysis](https://paddlex.readthedocs.io/zh_CN/develop/apis/visualize.html#paddlex-det-coco-error-analysis)接口对模型在验证集上预测错误的原因进行分析,分析结果以图表的形式展示如下:
+
+| all classes| 擦花 | 杂色 | 漏底 | 不导电 | 桔皮 | 喷流 | 漆泡 | 起坑 | 脏点 | 角位漏底 |
+| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
+| ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/allclasses_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/cahua_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/zase_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/loudi_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/budaodian_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/jupi_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/penliu_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/qipao_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/qikeng_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/zangdian_analysis_example.png) | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/jiaoweiloudi_analysis_example.png) |
+
+分析图表展示了7条Precision-Recall(PR)曲线,每一条曲线表示的Average Precision (AP)比它左边那条高,原因是逐步放宽了评估要求。以擦花类为例,各条PR曲线的评估要求解释如下:
+
+* C75: 在IoU设置为0.75时的PR曲线, AP为0.001。
+* C50: 在IoU设置为0.5时的PR曲线,AP为0.622。C50与C75之间的白色区域面积代表将IoU从0.75放宽至0.5带来的AP增益。
+* Loc: 在IoU设置为0.1时的PR曲线,AP为0.740。Loc与C50之间的蓝色区域面积代表将IoU从0.5放宽至0.1带来的AP增益。蓝色区域面积越大,表示越多的检测框位置不够精准。
+* Sim: 在Loc的基础上,如果检测框与真值框的类别不相同,但两者同属于一个亚类,则不认为该检测框是错误的,在这种评估要求下的PR曲线, AP为0.742。Sim与Loc之间的红色区域面积越大,表示子类间的混淆程度越高。VOC格式的数据集所有的类别都属于同一个亚类。
+* Oth: 在Sim的基础上,如果检测框与真值框的亚类不相同,则不认为该检测框是错误的,在这种评估要求下的PR曲线,AP为0.742。Oth与Sim之间的绿色区域面积越大,表示亚类间的混淆程度越高。VOC格式的数据集中所有的类别都属于同一个亚类,故不存在亚类间的混淆。
+* BG: 在Oth的基础上,背景区域上的检测框不认为是错误的,在这种评估要求下的PR曲线,AP为92.1。BG与Oth之间的紫色区域面积越大,表示背景区域被误检的数量越多。
+* FN: 在BG的基础上,漏检的真值框不认为是错误的,在这种评估要求下的PR曲线,AP为1.00。FN与BG之间的橙色区域面积越大,表示漏检的真值框数量越多。
+
+从分析图表中可以看出,杂色、桔皮、起坑三类检测效果较好,角位漏底存在少许检测框没有达到IoU 0.5的情况,问题较多的是擦花、不导电、喷流、漆泡、脏点。擦花类最严重的问题是误检、位置不精准、漏检,不导电类最严重的问题是漏检、位置不精准,喷流类和漆泡类最严重的问题是位置不精准、误检,脏点类最严重的问题是误检、漏检。为进一步理解造成这些问题的原因,将验证集上的预测结果进行了可视化,然后发现数据集标注存在以下问题:
+
+* 轻微的缺陷不视为缺陷,但轻微的界定不明确,有些轻微的缺陷被标注了,造成误检较多
+* 不导电、漏底、角位漏底外观极其相似,肉眼难以区分,导致这三类极其容易混淆而使得评估时误检或漏检的产生
+* 有些轻微的擦花和脏点被标注了,有些明显的反而没有被标注,造成了这两类误检和漏检情况都较为严重
+* 喷流和漆泡多为连续性的缺陷,一处喷流,其水平线上还会有其他喷流,一个气泡,其水平线上还会有一排气泡。但有时候把这些连续性的缺陷标注成一个目标,有时候又单独地标注不同的部分。导致模型有时候检测单独部分,有时候又检测整体,造成这两类位置不精准、误检较多。
+
+## (3) 数据复核
+
+为了减少原始数据标注的诸多问题对模型优化的影响,需要对数据进行复核。复核准则示例如下:
+
+* 擦花:不明显的擦花不标注,面状擦花以同一个框表示,条状擦花一条擦花以一个框表示
+* 漏底、角位漏底、不导电:三者过于相似,归为一类
+* 桔皮:忽略不是大颗粒状的表面
+* 喷流:明显是一条喷流的就用一个框表示,不是的话用多个框表示
+* 漆泡:不要单独标一个点,一连串点标一个框
+* 脏点:忽略轻微脏点
+
+对数据集复核并重新标注后,将FasterRCNN-ResNet50_vd_ssld重新在训练集上进行训练,模型在验证集上的VOC mAP为81.05%。
+
+## (4) 可变形卷积加入
+
+由于喷流、漆泡的形态不规则,导致这两类的很多预测框位置不精准。为了解决该问题,选择在骨干网络ResNet50_vd中使用可变形卷积(DCN)。重新训练后,模型在验证集上的VOC mAP为88.09%,喷流的VOC AP由57.3%提升至78.7%,漆泡的VOC AP由74.7%提升至96.7%。
+
+## (5) 数据增强选择
+
+在(4)的基础上,选择加入一些数据增强策略来进一步提升模型的精度。本案例选择同时使用[RandomHorizontalFlip](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#randomhorizontalflip)、[RandomDistort](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#randomdistort)、[RandomCrop](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#randomcrop)这三种数据增强方法,重新训练后的模型在验证集上的VOC mAP为90.23%。
+
+除此之外,还可以尝试的数据增强方式有[MultiScaleTraining](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#resizebyshort)、[RandomExpand](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#randomexpand)。本案例使用的铝材表面缺陷检测数据集中,同一个类别的尺度变化不大,使用MultiScaleTraining或者RandomExpand反而使得原始数据分布发生改变。对此,本案例也进行了实验验证,使用RandomHorizontalFlip + RandomDistort + RandomCrop + MultiScaleTraining数据增强方式训练得到的模型在验证集上的VOC mAP为87.15%,使用RandomHorizontalFlip + RandomDistort + RandomCrop + RandomExpand数据增强方式训练得到的模型在验证集上的的VOC mAP为88.56%。
+
+## (6) 背景图片加入
+
+本案例将数据集中提供的背景图片按9:1切分成了1116张、135张两部分,并使用(5)中训练好的模型在135张背景图片上进行测试,发现图片级误检率高达21.5%。为了降低模型的误检率,使用[paddlex.datasets.VOCDetection.add_negative_samples](https://paddlex.readthedocs.io/zh_CN/develop/apis/datasets.html#add-negative-samples)接口将1116张背景图片加入到原本的训练集中,重新训练后图片级误检率降低至4%。为了不让训练被背景图片主导,本案例通过将`train_list.txt`中的文件路径多写了一遍,从而增加有目标图片的占比。
+
+| 模型 | VOC mAP (%) | 有缺陷图片级召回率 | 背景图片级误检率 |
+| -- | -- | -- | -- |
+| FasterRCNN-ResNet50_vd_ssld + DCN + RandomHorizontalFlip + RandomDistort + RandomCrop | 90.23 | 95.5 | 21.5 |
+| FasterRCNN-ResNet50_vd_ssld + DCN + RandomHorizontalFlip + RandomDistort + RandomCrop + 背景图片 | 88.87 | 95.2 | 4 |
+
+【名词解释】
+
+* 图片级别的召回率:只要在有目标的图片上检测出目标(不论框的个数),该图片被认为召回。批量有目标图片中被召回图片所占的比例,即为图片级别的召回率。
+* 图片级别的误检率:只要在无目标的图片上检测出目标(不论框的个数),该图片被认为误检。批量无目标图片中被误检图片所占的比例,即为图片级别的误检率。
+
+## (7) 分类损失函数选择
+
+降低误检率的措施除了(6)中提到的将背景图片加入训练,还可以将RPN部分的分类损失函数选择为`SigmoidFocalLoss`,将更多的anchors加入训练,增加难分样本的在损失函数的比重进而降低误检率。在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时将参数`rpn_cls_loss`设置为'SigmoidFocalLoss',同时需要调整参数`rpn_focal_loss_alpha`、`rpn_focal_loss_gamma`、`rpn_batch_size_per_im`、`rpn_fg_fraction`的设置。
+
+## (8) 位置回归损失函数选择
+
+RCNN部分的位置回归损失函数除了'SmoothL1Loss'以外,还可以选择'CIoULoss',使用方式在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时设置参数`rcnn_bbox_loss`即可。在本案例中,选择'CIoULoss'并没有带来精度收益,故还是选择'SmoothL1Loss'。其他质检场景下,也可尝试使用'CIoULoss'。
+
+## (9) 正负样本采样方式选择
+
+当目标物体的区域只占图像的一小部分时,可以考虑采用[LibraRCNN](https://arxiv.org/abs/1904.02701)中提出的IoU-balanced Sampling采样方式来获取更多的难分负样本。使用方式在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时将参数`bbox_assigner`设置为'LibraBBoxAssigner'即可。
+
+## (10) 预处理对比度增强
+
+工业界常用灰度相机采集图片,会存在目标与周围背景对比度不明显而无法被检测出的情况。在这种情况下,可以在定义预处理的时候使用[paddlex.det.transforms.CLAHE](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#clahe)对灰度图像的对比度进行增强。
+
+灰度图:
+
+![](../../../examples/industrial_quality_inspection/image/before_clahe.png)
+
+对比度增加后的灰度图:
+
+![](../../../examples/industrial_quality_inspection/image/after_clahe.png) |
+
+## (11) 样本生成
+
+对于数量较少的类别或者小目标,可以通过把这些目标物体粘贴在背景图片上来生成新的图片和标注文件,并把这些新的样本加入到训练中从而提升模型精度。目前PaddleX提供了实现该功能的接口,详细见[paddlex.det.paste_objects](https://paddlex.readthedocs.io/zh_CN/develop/apis/tools.html#paddlex-det-paste-objects),需要注意的是,前景目标颜色与背景颜色差异较大时生成的新图片才会比较逼真。

+ 14 - 0
docs/examples/industrial_quality_inspection/dataset.md

@@ -0,0 +1,14 @@
+# 天池铝材表面缺陷检测初赛数据集示例
+
+| 序号 | 瑕疵名称 | 瑕疵成因 | 瑕疵图片示例 | 图片数量 |
+| -- | -- | -- | -- | -- |
+| 1 | 擦花(擦伤)| 表面处理(喷涂)后有轻微擦到其它的东西,造成痕迹 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/ca_hua_example.png) | 128 |
+| 2 | 杂色 | 喷涂换颜料的时候,装颜料的容器未清洗干净,造成喷涂时有少量其它颜色掺入 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/za_se_example.png) |365 |
+| 3 | 漏底 | 喷粉效果不好,铝材大量底色露出 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/lou_di_example.png) | 538 |
+| 4 | 不导电 | 直接喷不到铝材表面上去 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/bu_dao_dian_example.png) | 390 |
+|5 | 桔皮 | 表面处理后涂层表面粗糙,大颗粒 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/ju_pi_example.png) | 173 |
+| 6 | 喷流| 喷涂时油漆稀从上流下来,有流动痕迹 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/pen_liu_example.png) | 86 |
+| 7 |漆泡 | 喷涂后表面起泡,小而多| ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/qi_pao_example.png) | 82 |
+| 8 | 起坑 | 型材模具问题,做出来的型材一整条都有一条凹下去的部分 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/qi_keng_example.png.png) | 407 |
+| 9 | 脏点 | 表面处理时,有灰尘或一些脏东西未能擦掉,导致涂层有颗粒比较突出 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/zang_dian_example.png) | 261 |
+| 10 | 角位漏底 | 在型材角落出现的露底 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/jiao_wei_lou_di_example.png) | 346 |

+ 116 - 0
docs/examples/industrial_quality_inspection/gpu_solution.md

@@ -0,0 +1,116 @@
+# GPU端最终解决方案
+
+本案例面向GPU端的最终方案是选择二阶段检测模型FasterRCNN,其骨干网络选择加入了可变形卷积(DCN)的ResNet50_vd,训练时使用SSLD蒸馏方案训练得到的ResNet50_vd预训练模型,FPN部分的通道数量设置为64,训练阶段数据增强策略采用RandomHorizontalFlip、RandomDistort、RandomCrop,并加入背景图片,测试阶段的RPN部分做非极大值抑制计算的候选框数量由原本的6000减少至500、做完非极大值抑制后保留的候选框数量由原本的1000减少至300。
+
+在Tesla P40的Linux系统下,对于输入大小是800 x 1333的模型,图像预处理时长为30ms/image,模型的推理时间为46.08ms/image,包括输入数据拷贝至GPU的时间、计算时间、数据拷贝至CPU的时间。
+
+| 模型 | VOC mAP (%) | 推理时间 (ms/image)
+| -- | -- | -- |
+| FasterRCNN-ResNet50_vd_ssld | 81.05 | 48.62 |
+| + dcn | 88.09 | 66.51 |
+| + RandomHorizontalFlip/RandomDistort/RandomCrop | 90.23| 66.51 |
+| + background images | 88.87 | 66.51 |
+| + fpn channel=64 | 87.79 | 48.65 |
+| + test proposal=pre/post topk 500/300 | 87.72 | 46.08 |
+
+## 前置依赖
+
+* Paddle paddle >= 1.8.0
+* Python >= 3.5
+* PaddleX >= 1.3.0
+
+## 模型训练
+
+### (1) 下载PaddleX源码
+
+```
+git clone https://github.com/PaddlePaddle/PaddleX
+
+cd PaddleX/examples/industrial_quality_inspection
+```
+
+### (2) 下载数据集
+
+因数据集较大,可运行以下代码提前将数据集下载并解压。训练代码中也会自动下载数据集,所以这一步不是必须的。
+
+```
+wget https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/aluminum_inspection.tar.gz
+tar xvf aluminum_inspection.tar.gz
+```
+### (3) 下载预先训练好的模型
+
+如果不想再次训练模型,可以直接下载已经训练好的模型完成后面的模型测试和部署推理:
+
+```
+wget https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/models/faster_rcnn_r50_vd_dcn.tar.gz
+tar xvf faster_rcnn_r50_vd_dcn.tar.gz
+```
+### (4) 训练
+
+运行以下代码进行模型训练,代码会自动下载数据集,如若事先下载了数据集,需将下载和解压铝材缺陷检测数据集的相关行注释掉。代码中默认使用0,1,2,3,4号GPU训练,可根据实际情况设置卡号并调整`batch_size`和`learning_rate`。
+
+```
+python train_rcnn.py
+```
+
+### (5) 分析预测错误的原因
+
+在模型迭代过程中,运行以下代码可完成模型效果的分析并生成分析结果图表:
+
+```
+python error_analysis.py
+```
+
+可参考[性能优化部分的模型效果分析](./accuracy_improvement.md#2-%E6%A8%A1%E5%9E%8B%E6%95%88%E6%9E%9C%E5%88%86%E6%9E%90)来理解当前模型预测错误的原因。
+
+运行以下代码,生成可视化真值和预测结果的对比图以进一步理解模型效果,代码中的置信度阈值可根据实际情况进行调整。
+
+```
+python compare.py
+```
+
+![](../../../examples/industrial_quality_inspection/image/compare_budaodian-116.jpg)
+
+左边是可视化真值,右边是可视化预测结果。
+
+### (6) 统计图片级召回率和误检率
+
+模型迭代完成后,计算不同置信度阈值下[图片级召回率](./accuracy_improvement.md#6-%E8%83%8C%E6%99%AF%E5%9B%BE%E7%89%87%E5%8A%A0%E5%85%A5)和[图片级误检率](./accuracy_improvement.md#6-%E8%83%8C%E6%99%AF%E5%9B%BE%E7%89%87%E5%8A%A0%E5%85%A5),找到符合要求的召回率和误检率,对应的置信度阈值用于后续模型预测阶段。
+
+```
+python cal_tp_fp.py
+```
+
+执行后会生成图表`image-level_tp_fp.png`和文件`tp_fp_list.txt`,示意如下:
+
+图表`image-level_tp_fp.png`:
+
+![](../../../examples/industrial_quality_inspection/image/image-level_tp_fp.png)
+
+文件[tp_fp_list.txt](tp_fp_list.md)
+
+图表`image-level_tp_fp.png`中左边子图,横坐标表示不同置信度阈值下计算得到的图片级召回率,纵坐标表示各图片级召回率对应的图片级误检率。右边子图横坐标表示图片级召回率,纵坐标表示各图片级召回率对应的置信度阈值。从图表中可较为直观地看出当前模型的图片级召回率和误检率的量级,从文件`tp_fp_list.txt`可以查到具体数值,例如在图片级召回率/图片级误检率为[0.9589,0.0074]这一组符合要求,就将对应的置信度阈值0.90选取为后续预测推理的阈值。
+
+### (7) 模型测试
+
+测试集因没有标注文件,这里单独下载测试集图片:
+
+```
+wget https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/aluminum_inspection_test.tar.gz
+tar xvf aluminum_inspection_test.tar.gz
+```
+
+加载训练好的模型,使用(5)选取的置信度阈值0.90对验证集图片或者测试集图片进行预测:
+
+```
+python predict.py
+```
+可视化预测结果示例如下:
+
+![](../../../examples/industrial_quality_inspection/image/visualize_budaodian-116.jpg)
+
+## 推理部署
+
+本案例采用C++部署方式将模型部署在Tesla P40的Linux系统下,具体的C++部署流程请参考文档[PaddleX模型多端安全部署/C++部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/server/cpp/index.html)。
+
+对于输入大小是800 x 1333的模型,图像预处理时长为30ms/image。值得一提的是预处理中的Normalize操作比较耗时,因此在设置预处理操作时,可以先进行Resize操作再做Normalize。模型的推理时间为46.08ms/image,包括输入数据拷贝至GPU的时间、计算时间、数据拷贝至CPU的时间。

+ 102 - 0
docs/examples/industrial_quality_inspection/tp_fp_list.md

@@ -0,0 +1,102 @@
+| score | recall rate | false-positive rate |
+| -- | -- | -- |
+| 0.000000 | 0.982877 | 0.022222 |
+| 0.010000 | 0.982877 | 0.022222 |
+| 0.020000 | 0.982877 | 0.022222 |
+| 0.030000 | 0.982877 | 0.022222 |
+| 0.040000 | 0.982877 | 0.022222 |
+| 0.050000 | 0.982877 | 0.022222 |
+| 0.060000 | 0.982877 | 0.022222 |
+| 0.070000 | 0.979452 | 0.022222 |
+| 0.080000 | 0.979452 | 0.022222 |
+| 0.090000 | 0.979452 | 0.022222 |
+| 0.100000 | 0.979452 | 0.022222 |
+| 0.110000 | 0.979452 | 0.022222 |
+| 0.120000 | 0.979452 | 0.022222 |
+| 0.130000 | 0.979452 | 0.022222 |
+| 0.140000 | 0.976027 | 0.022222 |
+| 0.150000 | 0.976027 | 0.022222 |
+| 0.160000 | 0.976027 | 0.022222 |
+| 0.170000 | 0.976027 | 0.022222 |
+| 0.180000 | 0.976027 | 0.022222 |
+| 0.190000 | 0.976027 | 0.022222 |
+| 0.200000 | 0.976027 | 0.022222 |
+| 0.210000 | 0.976027 | 0.022222 |
+| 0.220000 | 0.976027 | 0.022222 |
+| 0.230000 | 0.976027 | 0.022222 |
+| 0.240000 | 0.976027 | 0.022222 |
+| 0.250000 | 0.976027 | 0.022222 |
+| 0.260000 | 0.976027 | 0.014815 |
+| 0.270000 | 0.976027 | 0.014815 |
+| 0.280000 | 0.976027 | 0.014815 |
+| 0.290000 | 0.976027 | 0.014815 |
+| 0.300000 | 0.976027 | 0.014815 |
+| 0.310000 | 0.976027 | 0.014815 |
+| 0.320000 | 0.976027 | 0.014815 |
+| 0.330000 | 0.976027 | 0.014815 |
+| 0.340000 | 0.976027 | 0.014815 |
+| 0.350000 | 0.976027 | 0.014815 |
+| 0.360000 | 0.976027 | 0.014815 |
+| 0.370000 | 0.976027 | 0.014815 |
+| 0.380000 | 0.976027 | 0.014815 |
+| 0.390000 | 0.976027 | 0.014815 |
+| 0.400000 | 0.976027 | 0.014815 |
+| 0.410000 | 0.976027 | 0.014815 |
+| 0.420000 | 0.976027 | 0.014815 |
+| 0.430000 | 0.976027 | 0.014815 |
+| 0.440000 | 0.972603 | 0.014815 |
+| 0.450000 | 0.972603 | 0.014815 |
+| 0.460000 | 0.972603 | 0.014815 |
+| 0.470000 | 0.972603 | 0.014815 |
+| 0.480000 | 0.972603 | 0.014815 |
+| 0.490000 | 0.972603 | 0.014815 |
+| 0.500000 | 0.972603 | 0.014815 |
+| 0.510000 | 0.972603 | 0.014815 |
+| 0.520000 | 0.972603 | 0.014815 |
+| 0.530000 | 0.972603 | 0.014815 |
+| 0.540000 | 0.972603 | 0.014815 |
+| 0.550000 | 0.972603 | 0.014815 |
+| 0.560000 | 0.969178 | 0.014815 |
+| 0.570000 | 0.969178 | 0.014815 |
+| 0.580000 | 0.969178 | 0.014815 |
+| 0.590000 | 0.969178 | 0.014815 |
+| 0.600000 | 0.969178 | 0.014815 |
+| 0.610000 | 0.969178 | 0.014815 |
+| 0.620000 | 0.969178 | 0.014815 |
+| 0.630000 | 0.969178 | 0.014815 |
+| 0.640000 | 0.969178 | 0.014815 |
+| 0.650000 | 0.969178 | 0.014815 |
+| 0.660000 | 0.969178 | 0.014815 |
+| 0.670000 | 0.969178 | 0.014815 |
+| 0.680000 | 0.969178 | 0.014815 |
+| 0.690000 | 0.969178 | 0.014815 |
+| 0.700000 | 0.969178 | 0.014815 |
+| 0.710000 | 0.969178 | 0.014815 |
+| 0.720000 | 0.969178 | 0.014815 |
+| 0.730000 | 0.969178 | 0.014815 |
+| 0.740000 | 0.969178 | 0.014815 |
+| 0.750000 | 0.969178 | 0.014815 |
+| 0.760000 | 0.969178 | 0.014815 |
+| 0.770000 | 0.965753 | 0.014815 |
+| 0.780000 | 0.965753 | 0.014815 |
+| 0.790000 | 0.965753 | 0.014815 |
+| 0.800000 | 0.962329 | 0.014815 |
+| 0.810000 | 0.962329 | 0.014815 |
+| 0.820000 | 0.962329 | 0.014815 |
+| 0.830000 | 0.962329 | 0.014815 |
+| 0.840000 | 0.962329 | 0.014815 |
+| 0.850000 | 0.958904 | 0.014815 |
+| 0.860000 | 0.958904 | 0.014815 |
+| 0.870000 | 0.958904 | 0.014815 |
+| 0.880000 | 0.958904 | 0.014815 |
+| 0.890000 | 0.958904 | 0.014815 |
+| 0.900000 | 0.958904 | 0.007407 |
+| 0.910000 | 0.958904 | 0.007407 |
+| 0.920000 | 0.958904 | 0.007407 |
+| 0.930000 | 0.955479 | 0.007407 |
+| 0.940000 | 0.955479 | 0.007407 |
+| 0.950000 | 0.955479 | 0.007407 |
+| 0.960000 | 0.955479 | 0.007407 |
+| 0.970000 | 0.955479 | 0.007407 |
+| 0.980000 | 0.941781 | 0.000000 |
+| 0.990000 | 0.893836 | 0.000000 |

+ 35 - 0
docs/gui/FAQ.md

@@ -0,0 +1,35 @@
+# PaddleX客户端常见问题
+
+## 1. 训练出错,提示『训练任务异常中止,请查阅错误日志具体确认原因』?
+请按照以下步骤来查找原因
+
+- 1.首先根据提示,找到错误日志,根据日志提示判断原因
+- 2.如无法确定原因,测a)尝试重新训练,看是否能正常训练; b)调低batchsize(同时按比例调低学习率)排除是否是显存不足原因导致
+- 3.如第2步仍然失败,请前往GitHub提ISSUE,a) 描述清楚问题 b) 贴上训练参数截图 c) 附上错误日志   https://github.com/PaddlePaddle/PaddleX/issues
+- 4.如无Github帐号,则可加QQ群1045148026在线咨询工程师(咨询时请附上出错日志)
+
+## 2. 没有使用GPU,使用CPU,错误日志仍然提示"cuda error"
+部分Windows机型由于GPU型号或驱动较老,导致训练时无法使用GPU,还会导致使用不了CPU,针对此情况,可采取如下方式解决
+- 1.在PaddleX客户端安装目录下,删除"paddle"文件夹
+- 2.下载paddlepaddle-cpu(压缩文件可在[百度网盘](https://pan.baidu.com/s/1GrzLCuzuw-PAEx4BELnc0w)下载,提取码iaor,约57M),下载解压后,将目前中的paddle文件夹拷贝至PaddleX客户端安装目录下即可
+- 3.重新启动PaddleX客户端,替换后客户端仅支持使用CPU训练模型
+
+## 3. 如何升级PaddleX客户端
+PaddleX客户端目前需用户手动下载最新版升级,旧版本可直接删除原安装目录即可。升级前请备份好工作空间下的3个workspace.*.pb文件,避免升级过程可能导致项目信息丢失。
+
+PaddleX更新历史和下载地址: https://www.paddlepaddle.org.cn/paddlex/download
+
+## 4. 如何卸载PaddleX客户端
+客户端安装本质只是解压文件到相应目录,因此卸载直接删除安装目录和桌面快捷方式即可。
+
+## 5. 使用客户端训练检测模型在测试图片中出现很多目标框,甚至同一物体上出现多个目标框
+目标检测模型和实例分割模型,在模型预测阶段,会将所有可能的目标都输出,对于输出,我们需要可以按如下方式来处理
+- 1.观察预测出来的各个目标框,各框上应该还同时包含相应框的置信度分数
+- 2.设定一个threshold,过滤掉低置信度的目标框
+上面两个步骤,在客户端的评估界面,我们可以手动输入threshold后,重新再预测;而对于在实际使用,例如Python预测部署,则根据得到结果中的'score'进行过滤
+
+## 6. 使用CPU训练时,如何设置CPU_NUM多CPU卡进行训练
+Windows平台上由于缺少NCCL库,无法使用多GPU或多CPU训练。而对于v1.1.5版本及以下版本,当前无法设置多CPU进行训练(v1.1.5版本及以下版本,请勿在环境变量中设置CPU_NUM,可能会导致无法使用CPU进行模型训练)
+
+## 7. 如何查看GPU的使用情况
+Windows/Linux上都可以在打开命令终端后(Windows为CMD命令行)后,输入nvidia-smi命令查看GPU使用情况。不建议使用其它方式(如任务管理器等)。如若提示此命令不存在,可在网上搜索相应解决方法。

+ 0 - 46
docs/gui/faq.md

@@ -1,46 +0,0 @@
-
-
-1. **为什么训练速度这么慢?**
-
-   PaddleX完全采用您本地的硬件进行计算,深度学习任务确实对算力要求较高,为了使您能快速体验应用PaddleX进行开发,我们适配了CPU硬件,但强烈建议您使用GPU以提升训练速度和开发体验。
-
-   
-
-2. **我可以在服务器或云平台上部署PaddleX么?**
-
-   PaddleX GUI是一个适配本地单机安装的客户端,无法在服务器上直接进行部署,您可以直接使用PaddleX API,或采用飞桨核心框架进行服务器上的部署。如果您希望使用公有算力,强烈建议您尝试飞桨产品系列中的 [EasyDL](https://ai.baidu.com/easydl/) 或 [AI Studio](https://aistudio.baidu.com/aistudio/index)进行开发。
-
-   
-
-3. **PaddleX支持EasyData标注的数据吗?**
-
-   支持,PaddleX可顺畅读取EasyData标注的数据。但当前版本的PaddleX GUI暂时无法支持直接导入EasyData数据格式,您可以参照文档,将[数据集进行转换](https://paddlex.readthedocs.io/zh_CN/latest/appendix/how_to_convert_dataset.html)再导入PaddleX GUI进行后续开发。
-   同时,我们也在紧密开发PaddleX GUI可直接导入EasyData数据格式的功能。
-
-   
-
-4. **为什么模型裁剪分析耗时这么长?**
-
-   模型裁剪分析过程是对模型各卷积层的敏感度信息进行分析,根据各参数对模型效果的影响进行不同比例的裁剪。此过程需要重复多次直至FLOPS满足要求,最后再进行精调训练获得最终裁剪后的模型,因此耗时较长。有关模型裁剪的原理,可参见文档[剪裁原理介绍](https://paddlepaddle.github.io/PaddleSlim/algo/algo.html#2-%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%89%AA%E8%A3%81%E5%8E%9F%E7%90%86)
-
-   
-
-5. **如何调用后端代码?**
-
-   PaddleX 团队为您整理了相关的API接口文档,方便您学习和使用。具体请参见[PaddleX API说明文档](https://paddlex.readthedocs.io/zh_CN/latest/apis/index.html)
-   
-   
-   
-6. **如何在离线环境下使用PaddleX?**
-
-   PaddleX是支撑用户在本地离线环境中训练模型的,但是如果大家希望使用PaddleX团队为大家准备好的在标准数据集上训练的预训练模型,则需要在线环境进行下载。大家可以参照完整的无联网情况下进行模型训练的[文档](https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/appendix/how_to_offline_run.md)查看如何一键快速下载所有预训练模型。
-
-   
-
-7. **有没有行业应用案例,或者实现好的工程实例?**
-
-   有的,PaddleX提供丰富的行业应用案例和完整的示例项目,请参考[PaddleX产业案例集](https://paddlex.readthedocs.io/zh_CN/develop/examples/index.html)
-
-**如果您有任何问题或建议,欢迎以issue的形式,或加入PaddleX官方QQ群(1045148026)直接反馈您的问题和需求**
-
-![](./images/QR.jpg)

+ 20 - 0
docs/gui/first_meet.md

@@ -0,0 +1,20 @@
+# PaddleX可视化客户端
+
+感谢使用PaddleX可视化客户端,通过本客户端,您可以实现图像分类、目标检测、实例分割和语义分割四大视觉任务模型的训练,裁剪及量化,以及模型在移动端/服务端的发布。
+
+## 可视化客户端使用
+
+- [PaddleX可视化客户端使用](https://paddlex.readthedocs.io/zh_CN/develop/gui/)
+- [PaddleX模型部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/)
+
+## Python API使用
+除可视化客户端,PaddleX还提供了更灵活的API方式进行模型训练、裁剪、量化,以及一系列的模型效果分析接口,欢迎有需求的开发者使用。
+
+- [10分钟上手API训练模型](https://paddlex.readthedocs.io/zh_CN/develop/quick_start.html)
+- [更多模型训练示例](https://paddlex.readthedocs.io/zh_CN/develop/train/index.html)
+
+## 支持PaddleX
+
+当前GitHub Repo即为PaddleX的开源项目地址,**欢迎大家star(本页面右上角哦)支持PaddleX的开发者!**
+
+个人开发者或企业用户有相关需求及建议,欢迎在此Github上提ISSUE,或邮件至paddlex@baidu.com。

BIN=BIN
docs/gui/images/paddlexoverview_en.jpg


BIN=BIN
docs/gui/images/paddlexoverview_en.png


BIN=BIN
docs/gui/images/star.png


+ 28 - 0
docs/gui/index.rst

@@ -42,6 +42,30 @@ PaddleX GUI覆盖深度学习模型开发必经的 **数据处理** 、 **超参
 点选式选择模型发布平台、格式,一键导出预测模型,并匹配完善的模型预测部署说明文档,贴心助力产业端到端项目落地
 
 
+PaddleX RESTful
+=======================================
+
+PaddleX RESTful是基于PaddleX开发的RESTful API。
+
+对于开发者来说通过如下指令启动PaddleX RESTful服务,开启RESTful服务后可以通过下载Remote版本的GUI或者是web demo连接开启RESTful服务的服务端完成深度学习全流程开发。
+
+同样您还可以根据RESTful API来开发自己的可视化界面。
+
+**paddlex --start_restful --port [端口号] --workspace_dir [工作空间地址]**
+
+PaddleX Remote GUI
+---------------------------------------
+
+PaddleX Remote GUI是针对PaddleX RESTful开发的可视化客户端。开发者可以通过客户端连接开启RESTful服务的服务端,通过GUI实现深度学习全流程:**数据处理** 、 **超参配置** 、 **模型训练及优化** 、 **模型发布**,无需开发一行代码,即可得到高性深度学习推理模型。
+
+
+PaddleX RESTful API 二次开发
+---------------------------------------
+
+开发者可以使用PaddleX RESTful API 进行二次开发,按照自己的需求开发可视化界面
+
+
+
 .. toctree::
    :maxdepth: 2
    :caption: 文档目录
@@ -49,6 +73,7 @@ PaddleX GUI覆盖深度学习模型开发必经的 **数据处理** 、 **超参
    download.md
    usage/index
    faq.md
+   restful/index
 
 
 * PaddleX GUI版本: v1.0
@@ -57,3 +82,6 @@ PaddleX GUI覆盖深度学习模型开发必经的 **数据处理** 、 **超参
 * 官方QQ用户群: 1045148026  
 * GitHub Issue反馈: http://www.github.com/PaddlePaddle/PaddleX/issues
 
+
+
+

+ 191 - 0
docs/gui/restful/data_struct.md

@@ -0,0 +1,191 @@
+# 数据结构
+本文档用于说明PaddleX RESTful模块自定义的数据结构
+
+## Protobuf结构化数据
+```
+message Dataset {
+    string id = 1;
+    string name = 2;
+    string desc = 3;
+    // 'classification': 分类数据
+    // 'segmentation': 分割数据
+    // 'detection_voc': 检测数据(仅用于检测)
+    // 'detection_coco': 检测数据(用于检测,分割,实例分割)
+    string type = 4;
+    string path = 5;
+    string create_time = 6;
+}
+
+message Project {
+    string id = 1;
+    string name = 2;
+    string desc = 3;
+    // 'classification'
+    // 'segmentation'
+    // 'segmentation'
+    // 'instance_segmentation'
+    // 'remote_segmentation'
+    string type = 4;
+    string did = 5;
+    string path = 6;
+    string create_time = 7;
+}
+
+message Task {
+    string id = 1;
+    string name = 2;
+    string desc = 3;
+    string pid = 4;
+    string path = 5;
+    string create_time = 6;
+    //裁剪任务id
+    string parent_id = 7;
+}
+
+message PretrainedModel {
+    string id = 1;
+    string name = 2;
+    string model = 3;
+    string type = 4;
+    // 所属项目id
+    string pid = 5;
+    string tid = 6;
+    string create_time = 7;
+    string path = 8;
+}
+
+message ExportedModel {
+    string id = 1;
+    string name = 2;
+    string model = 3;
+    string type = 4;
+    // 所属项目id
+    string pid = 5;
+    string tid = 6;
+    string create_time = 7;
+    string path = 8;
+    int32 exported_type = 9;
+}
+
+message Workspace {
+    string version = 1;
+    string path = 2;
+    map<string, Dataset> datasets = 3;
+    map<string, Project> projects = 4;
+    map<string, Task> tasks = 5;
+    int32 max_dataset_id = 6;
+    int32 max_project_id = 7;
+    int32 max_task_id = 8;
+    string current_time = 9;
+
+    int32 max_pretrained_model_id = 10;
+    map<string, PretrainedModel> pretrained_models = 11;
+
+    int32 max_exported_model_id = 12;
+    map<string, ExportedModel> exported_models = 13;
+}
+
+```
+
+## 状态枚举变量
+### DatasetStatus(数据集状态变量)
+```
+DatasetStatus = Enum('DatasetStatus',  
+('XEMPTY', #空数据集  
+'XCHECKING', #正在验证数据集  
+'XCHECKFAIL', #数据集验证失败  
+'XCOPYING',  #正在导入数据集  
+'XCOPYDONE', #数据集导入成功  
+'XCOPYFAIL', #数据集导入失败  
+'XSPLITED' #数据集已经切分  
+),start=0)
+```
+
+### TaskStatus(任务状态变量)
+```
+TaskStatus = Enum('TaskStatus',
+('XUNINIT',#任务还未初始化
+'XINIT',#任务初始化
+'XDOWNLOADING',#正在下载预训练模型
+'XTRAINING',#任务正在运行中,改状态下任务不能被删除
+'XTRAINDONE',#任务完成运行
+'XEVALUATED',#任务评估完成
+'XEXPORTING',#任务正在导出inference模型
+'XEXPORTED',#任务已经导出模型
+'XTRAINEXIT', #任务运行中止
+'XDOWNLOADFAIL', #任务下载失败
+'XTRAINFAIL', #任务运行失败
+'XEVALUATING',#任务评估中
+'XEVALUATEFAIL', #任务评估失败
+'XEXPORTFAIL', #任务导出模型失败
+'XPRUNEING', #裁剪分析任务运行中
+'XPRUNETRAIN'#裁剪训练任务运行中
+),start=0)
+```
+### ProjectType(项目类型)
+
+```
+ProjectType = Enum('ProjectType',
+('classification',#分类
+'detection',#检测
+'segmentation',#分割
+'instance_segmentation',#实例分割
+'remote_segmentation'#摇杆分割
+),start=0)
+```
+
+### DownloadStatus(下载状态变量)
+
+```
+DownloadStatus = Enum('DownloadStatus',
+('XDDOWNLOADING',#下载中
+'XDDOWNLOADFAIL',#下载失败
+'XDDOWNLOADDONE',下载完成
+'XDDECOMPRESSED'解压完成
+),start=0)
+```
+
+
+### PruneStatus(裁剪状态变量)
+
+```
+PruneStatus = Enum('PruneStatus',
+('XSPRUNESTART',#启动裁剪任务
+'XSPRUNEING',#正在裁剪模型
+'XSPRUNEDONE',#已完成裁剪任务
+'XSPRUNEFAIL',#裁剪任务失败
+'XSPRUNEEXIT',#裁剪任务已经停止
+),start=0)
+```
+
+### PredictStatus(预测任务状态变量)
+
+```
+PredictStatus = Enum('PredictStatus',
+('XPRESTART',#预测开始
+'XPREDONE',#预测完成
+'XPREFAIL'#预测失败
+), start=0)
+```
+### PretrainedModelStatus(预训练模型状态变量)
+
+```
+PretrainedModelStatus = Enum('PretrainedModelStatus',
+('XPINIT', #初始化
+'XPSAVING', #正在保存
+'XPSAVEFAIL',#保存失败
+'XPSAVEDONE' #保存完成
+),start=0)
+```
+
+### ExportedModelType(模型导出状态变量)
+```
+ExportedModelType = Enum('ExportedModelType',
+('XQUANTMOBILE',#量化后的lite模型
+'XPRUNEMOBILE', #裁剪后的lite模型
+'XTRAINMOBILE',#lite模型
+'XQUANTSERVER', #量化后的inference模型
+'XPRUNESERVER', #裁剪后的inference模型
+'XTRAINSERVER'#inference模型
+),start=0)
+```

BIN=BIN
docs/gui/restful/img/classify_help.jpg


BIN=BIN
docs/gui/restful/img/detect_help.jpg


BIN=BIN
docs/gui/restful/img/framework.png


BIN=BIN
docs/gui/restful/img/gui_use.png


BIN=BIN
docs/gui/restful/img/ins_seg_help.jpg


BIN=BIN
docs/gui/restful/img/restful_api.png


BIN=BIN
docs/gui/restful/img/seg_help.jpg


BIN=BIN
docs/gui/restful/img/start_restful.png


BIN=BIN
docs/gui/restful/img/web_demo.png


+ 49 - 0
docs/gui/restful/index.rst

@@ -0,0 +1,49 @@
+
+PaddleX RESTful
+=======================================
+
+PaddleX RESTful是基于PaddleX开发的RESTful API。
+
+对于开发者来说通过如下指令启动PaddleX RESTful服务,开启RESTful服务后可以通过下载Remote版本的GUI或者是web demo连接开启RESTful服务的服务端完成深度学习全流程开发。
+
+同样您还可以根据RESTful API来开发自己的可视化界面。
+
+```
+paddlex --start_restful --port 8081 --workspace_dir D:\Workspace
+```
+
+**注意:请确保启动RESTful的端口未被防火墙限制**
+
+支持RESTful版本的GUI
+---------------------------------------
+
+支持RESTful版本的GUI是针对PaddleX RESTful开发的可视化客户端。开发者可以通过客户端连接开启RESTful服务的服务端,通过GUI远程的实现深度学习全流程:**数据处理** 、 **超参配置** 、 **模型训练及优化** 、 **模型发布**,无需开发一行代码,即可得到高性深度学习推理模型。
+
+
+支持RESTful版本Web Demo
+---------------------------------------
+
+支持RESTful版本Web Demo是针对PaddleX RESTful开发的网页版可视化客户端。开发者可以通过Web Demo连接开启RESTful服务的服务端,远程实现深度学习全流程:**数据处理** 、 **超参配置** 、 **模型训练及优化** 、 **模型发布**,无需开发一行代码,即可得到高性深度学习推理模型。
+
+PaddleX RESTful API 二次开发
+---------------------------------------
+
+开发者可以使用PaddleX RESTful API 进行二次开发,按照自己的需求开发可视化界面
+
+
+
+.. toctree::
+   :maxdepth: 1
+   :caption: 文档目录
+   
+   introduction.md
+   restful.md
+   quick_start.md
+   restful_api.md
+   data_struct.md
+   tree.md
+
+
+
+
+

+ 83 - 0
docs/gui/restful/introduction.md

@@ -0,0 +1,83 @@
+# 介绍与使用
+PaddleX RESTful是基于PaddleX开发的RESTful API。  
+
+对于开发者来说可以通过如下指令启动PaddleX RESTful服务  
+**paddlex --start_restful --port [端口号] --workspace_dir [工作空间地址]**  
+
+对于设置workspace在HOME目录的wk文件夹下,RESTful服务端口为8080的命令参考如下:
+![](./img/start_restful.png)  
+
+**注意:请确保启动RESTful的端口未被防火墙限制**
+
+开启RESTful服务后可以实现如下功能:
+
+- 通过下载基于RESTful API的GUI连接开启RESTful服务的服务端,实现远程深度学习全流程开发。
+- 通过使用web demo连接开启RESTful服务的服务端,实现远程深度学习全流程开发。
+- 根据RESTful API来开发您自己个性化的可视化界面。  
+
+
+
+## PaddleX Remote GUI
+PaddleX Remote GUI是针对PaddleX RESTful开发的可视化客户端。开发者可以通过客户端连接开启RESTful服务的服务端,通过GUI实现深度学习全流程:**数据处理** 、 **超参配置** 、 **模型训练及优化** 、 **模型发布**,无需开发一行代码,即可得到高性深度学习推理模型。  
+### 客户端下载地址
+- [MAC](https://bj.bcebos.com/paddlex/PaddleX_Remote_GUI/mac/PaddleX_Remote_GUI.zip)
+- [Windows](https://bj.bcebos.com/paddlex/PaddleX_Remote_GUI/windows/PaddleX_Remote_GUI.zip)
+
+### 客户端使用流程
+
+#### step1:安装PaddleX  
+```
+pip install paddlex
+```  
+**注意**:若需要使用GPU请安装pycuda
+```
+pip install pycuda
+```
+
+#### step2:开启RESTful 服务
+```
+paddlex --start_restful --port [端口号] --workspace_dir [工作空间地址]
+```
+
+#### setp3:根据上面的链接下载支持RESTful版本的GUI
+
+#### step4:运行客户端,如图所示填写开启RESTful后端的ip与端口,点击确定便可正常使用GUI
+![](./img/gui_use.png)
+
+
+## PaddleX Web Demo
+PaddleX Web Demo是针对PaddleX RESTful开发的Web可视化客户端。  
+[Wed demo传送门](https://github.com/PaddlePaddle/PaddleX/blob/develop/paddlex/restful/frontend_demo/paddlex_restful_demo.html)
+
+### Web DEMO使用流程
+
+#### step1:安装paddlex  
+```
+pip install paddlex
+```  
+**注意**:若需要使用GPU请安装pycuda
+```
+pip install pycuda
+```
+
+#### step2:开启RESTful 服务
+```
+paddlex --start_restful --port [端口号] --workspace_dir [工作空间地址]
+```
+
+#### step3:通过浏览器打开[Demo](https://github.com/PaddlePaddle/PaddleX/blob/develop/paddlex/restful/frontend_demo/paddlex_restful_demo.html)文件
+
+
+#### step4:点击设置服务器信息,填写正确的后端ip与端口
+![](./img/web_demo.png)
+
+## PaddleX RESTful API 二次开发
+开发者可以使用PaddleX RESTful API 进行二次开发,按照自己的需求开发可视化界面,详细请参考以下文档  
+
+[RESTful API 二次开发简介](./restful.md)  
+
+[快速开始](./quick_start.md)  
+
+[API 参考文档](./restful_api.md)  
+
+[自定义数据结构](./data_struct.md)

+ 222 - 0
docs/gui/restful/quick_start.md

@@ -0,0 +1,222 @@
+# 快速开始
+
+## 环境依赖  
+- paddlepaddle-gpu/paddlepaddle  
+- paddlex  
+- pycocotools  
+
+
+## 服务端启动PaddleX RESTful服务
+```
+ paddlex --start_restful --port [端口号] --workspace_dir [工作空间目录]
+```  
+
+## 客户端请求服务端
+```
+import requests
+url = "https://127.0.0.1:5000"
+```
+- url为实际服务端ip与端口
+- 所有的请求,通过ret.status_code是否为200,判断是否正确给Server执行
+- 在status_code为200的前提下,如果ret.json()['status']为-1,则表明出错,出错信息在ret.json()['message']里面,如果执行成功, status是1
+
+## 创建一个PaddleX的训练任务  
+**下面介绍如何通过API完成模型的训练、评估、预测与导出,对于每个RESTful API的详细介绍请参考[API 接口文档](./restful_api.md),对于示例中用到自定的数据结构请参考[数据结构](./data_struct.md)**
+
+### 流程
+对于通过RESTful API创建一个PaddleX的训练任务的主要流程如下
+- 1):创建并导入数据集
+- 2):创建项目并绑定数据集
+- 3):获取参数并创建任务
+- 4):开始训练
+- 5):评估任务
+- 6):导出模型
+
+
+### 数据集操作
+#### 创建数据集
+```
+# dataset_type: 支持"detection"/"classification"/"segmentation"/"instance_segmentation"
+params = {"name": "我的第一个数据集", "desc": "这里是数据集的描述文字", "dataset_type": "detection"}  
+ret = requests.post(url+"/dataset", json=params)  
+#获取数据集id
+did = ret.json()['id']
+```
+
+#### 导入数据集
+
+```
+# 导入数据集
+params = {'did' : did, 'path' : '/path/to/dataset'}
+ret = requests.put(url+"/dataset", json=params)
+
+# 数据集导入是一个异步操作,可以通过不断发送请求,获取导入的状态
+params = {"did": did}
+ret = requests.get(url+"/dataset", json=params)
+#导入状态获取,其中DatasetStatus为自定义枚举标量,用来表示数据集的状态,具体定义请参考数据结构部分
+import_status = DatasetStatus(ret.json['dataset_status'])
+if import_status == DatasetStatus.XCOPYDONE:
+    print("数据集导入成功")
+elif import_status == DatasetStatus.XCOPYING:
+    print("数据集正在导入中")
+elif import_status == DatasetStatus.XCHECKFAIL:
+    print("数据集格式校验未通过,请确定数据集格式是否正确)
+```
+
+#### 切分数据集
+```
+# 当数据集导入成功后,可以对数据集进行切分
+# 切分数据集按照训练集、验证集、测试集为:6:2:2的形式切分
+params = {'did' : did, 'val_split' : 0.2 , 'test_split' : 0.2}
+ret = requests.put(url+"/dataset/split', json=params)
+
+#切分数据集后需要获取具体切分情况
+params = {'did': did}  
+ret = requests.get(url+"/dataset/details', json=params)  
+#获取切分情况
+dataset_details = ret.json()
+```
+
+## 项目操作
+
+### 创建项目
+```
+# project_type: 支持detection/classification/segmentation/instance_segmentation
+params = {'name': '项目名称', 'desc': '项目描述文字', 'project_type' : 'detection'}
+ret = requests.post(url+'/project', json=params)
+# 获取项目id
+pid = ret.json['pid']
+```
+
+### 绑定数据集
+```
+# 修改project中的did属性
+# struct支持 project/dataset/task
+params = {'struct': 'project', 'id': pid, 'attr_dict': {'did':did}}
+ret = requests.put(url+'/workspace', json=params)
+```
+
+### 获取训练默认参数
+```
+params = {"pid", "P0001"}
+ret = requests.get(url+"/project/task/parmas", json=params)
+#获取默认训练参数
+train_params = ret.json()['train']
+```
+
+
+
+## 任务操作
+
+### 创建任务
+```
+#将训练参数json化
+params_json = json.dumps(train_params)
+#创建任务
+params = {'pid': 'P0001', 'train':params_json}
+ret = requests.post(url+'/task', json=params)
+#获取任务id
+tid = ret.json()['tid']
+```
+
+### 启动训练任务
+```
+params = {'tid' : tid}
+ret = requests.post(url+'/project/task/train', json=params)
+
+#训练任务是一个后台异步操作,可通过如下操作,获取任务训练的最新状态
+params = {'tid' : 'T0001', 'type': 'train'}
+ret = requests.get(url+'/project/task/metrics', json=params)
+ret.json()获取返回值:
+{'status': 1, 'train_log': 训练日志}
+```
+
+### 停止训练任务
+通过如下操作,停止正在训练的任务
+```
+params = {'tid': tid, 'act': 'stop'}
+ret = requests.put(url+'/project/task/train', json=params)
+```
+
+### 获取训练任务信息
+```
+params = {'tid': tid, 'type': 'train'}
+ret = requests.get(url+'/project/task/metrics', json=params)
+#任务训练信息
+train_log = ret.json()['train_log']
+```
+
+### 创建一个评估任务,并获取评估结果
+```
+#获取任务状态
+params = {'tid': tid}
+ret = requests.get(url+'/project/task', json=params)
+#判断是否训练完成
+if TaskStatus(ret.json()['task_status']) == TaskStatus.XTRAINDONE:
+    #创建一个评估任务,可以指定score_thresh
+    params = {'tid': tid, 'score_thresh', 0.3}
+    ret = requests.post(url+'/project/task/evaluate', json=params)
+#获取评估任务状态
+import time
+while:
+    params = {'tid': tid}
+    ret = requests.get(url+'/project/task/evaluate', json=params)
+    #判断是否评估完成
+    if TaskStatus(ret.json()['evaluate_status']) == TaskStatus.XEVALUATED:
+        break
+    else:
+        time.sleep(1)
+#获取评估结果
+result = ret.json()['result']
+```
+
+### 使用模型进行预测
+
+```
+import cv2
+import numpy as np
+#预测图片路径
+img_path = '/path/to/img'
+params = dict()
+#base64编码
+with open(img_path, 'rb') as f:
+    base64_data = base64.b64encode(f.read())
+    base64_str = str(base64_data,'utf-8')
+    params['image_data'] = base64_str
+params['tid'] = tid
+#单张推理
+ret = requests.post(url + 'project/task/predict', json=params)
+#获取结果保存地址
+result_path = ret.json()['path']
+#判断是否预测完成
+while:
+    params = {'tid': tid}
+    ret = requests.get(url+'/project/task/predict', json=params)
+    #判断是否评估完成
+    if PredictStatus(ret.json()['predict_status']) == PredictStatus.XPREDONE:
+        break
+    else:
+        time.sleep(1)
+# 获取结果
+params = {'path' : result_path}
+ret = requests.get(url+'/file', json=params)
+#图片based64数据
+img_data = ret.json()['img_data']
+#转换为numpy数据
+img_data = base64.b64decode(img_data)
+img_array = np.frombuffer(img_data, np.uint8)
+img = cv2.imdecode(img_array, cv2.COLOR_RGB2BGR)
+```
+
+### 导出inference模型
+
+```
+#导出inference模型
+#保存地址
+save_dir = '/path/to/save/inference/model'
+params = {'tid': tid ,'type': 'inference', 'save_dir' : save_dir}
+ret = requests.post(url+'/project/task/export', json=params)
+#workspace创建inference模型信息
+params = {'pid' : pid, 'tid': tid, 'name': 'my_inference_model', 'type': 'exported', 'path' : save_dir, 'exported_type': 0}
+ret = requests.post(url+'/model', json=params)
+```

+ 69 - 0
docs/gui/restful/restful.md

@@ -0,0 +1,69 @@
+# 二次开发简介
+如图,PaddleX RESTful主要由数据集(dataset),项目(project),任务(task),模型(model)组成。上述模块数据保存在指定的工作空间(workspace)内,相应的结构化信息通过protobuf保存,[workspace的protobuf消息定义](./data_struct.md)。  
+
+![](./img/framework.png)  
+
+**说明**:后续RESTful API通过`[HTTP request method] url`来表示  
+
+## 流程介绍
+对于通过RESTtful接口来进行二次开发,主要的流程如下:
+- 1):指定工作空间启动restful服务
+- 2):创建、导入并切分数据到数据集
+- 3):创建项目,绑定数据集到该项目,并根据项目类型获取训练的默认参数
+- 4):根据默认参数,在该项目下创建训练任务,调整参数(非必要),开始训练模型
+- 5):对训练好的模型进行裁剪、评估、测试(非必要)
+- 6):保存或者发布训练好的模型
+
+## 工作空间
+
+通过如下命令启动PaddleX的RESTful服务,同时会初始化工作空间,初始化工作空间主要做载入工作空间内已有的数据集、项目等模块的信息。初始化工作空间后就可以正常调用其他的RESTful API,所有新建的数据集、项目等数据都会保存在此工作空间目录下面  
+```
+ paddlex --start_restful --port [端口号] --workspace_dir [工作空间目录]
+```  
+
+
+## 数据集
+可以通过调用["[post] /dataset"](./restful_api.md)接口创建数据集、创建数据集后会在工作空间内创建相应的文件夹,按照workspace protobuf定义的变量保存数据集信息。创建数据集后可以通过["[put] \dataset"](./restful_api.md)接口导入数据集,目前仅支持从路径导入并且数据集需储存在后端服务器。目前支持图像分类、目标检测、语义分割与实例分割四种数据集,具体格式如下  
+### 图像分类
+如图所示
+- 文件夹名为需要分类的类名,输入限定为英文字符,不可包含:空格、中文或特殊字符;
+- 图片格式支持png,jpg,jpeg,bmp格式  
+
+![](./img/classify_help.jpg)
+
+### 目标检测
+如图所示
+- 图片文件名需要为"JPEGImages",标签文件夹命名需要为"Annotations"
+- 图片格式支持png,jpg,jpeg,bmp格式;标签文件格式为.xml  
+
+![](./img/detect_help.jpg)
+
+### 语义分割
+如图所示
+- 图片文件名需要为"JPEGImages",标签文件夹命名需要为"Annotations"
+- 图片格式支持png,jpg,jpeg,bmp格式
+- 标注需要与图片像素严格保持一一对应,格式只可为png。每个像素值需标注为[0,255]区间从0开始依序递增整数ID,除255外,标注ID值的增加不能跳跃。其中255表示模型中需忽略的像素,0为背景类标注。
+- (可选)可以提供一份命名为"labels.txt"的包含所有标注名的清单  
+
+![](./img/seg_help.jpg)
+
+
+### 实例分割
+如图所示
+- 图片文件名需要为"JPEGImages",标签文件名需要为"annotations.json"
+- 图片格式支持png,jpg,jpeg,bmp格式;标签文件格式为.json  
+
+![](./img/ins_seg_help.jpg)
+
+## 项目
+可以通过调用["[post] /project"](./restful_api.md)接口创建项目,目前支持的项目类型有分类(classification)、检测(detection)、语义分割(segmentation)、实例分割(instance_segmentation)。对于新建的项目首先需要绑定项目类型对应的数据集,通过["[post] \workspace"](./restful_api.md)可以实现;然后便可以在项目下创建任务,进行一系列任务相关的操作。  
+
+## 任务
+在创建项目后,首先需要通过["[get] /project/task/params"](./restful_api.md)获得默认的训练参数,可以通过调用["[post] /project/task"](./restful_api.md)接口在项目中创建任务,创建好任务后可以通过API实现以下功能:
+- 训练(train):进行模型的训练
+- 裁剪(prune):对训练好的模型模型进行裁剪
+- 评估(eval):对训练好的模型进行评估
+- 预测(predict):用训练好的模型进行预测,目前仅支持单张图片的预测
+
+## 模型
+目前PaddleX RESTful API支持将训练评估后的模型保存为预训练模型、导出inference模型、导出Padlle-Lite模型、同时能支持模型的量化,可以通过调用["[post] /model](./restful_api.md)接口来完成这些功能

+ 871 - 0
docs/gui/restful/restful_api.md

@@ -0,0 +1,871 @@
+# RestFUL API 参考文档
+## API 总览
+![](./img/restful_api.png)
+图片包含目前PaddleX RESTful模块提供所有的RESTful API:
+
+- /workspace: 工作空间相关
+- /dataset:数据集操作
+- /project: 项目操作
+- /project/task: 任务相关操作
+- /model: 模型相关操作
+- /file: 文件传输
+- /demo: 示例
+
+
+## API 接口文档
+**说明**:
+- 后续例子中HTTP请求通过requests完成,url代表运行PaddleX RESTful服务的主机ip与端口号
+- 所有的请求,通过ret.status_code是否为200,判断是否正确给Server执行
+- 在status_code为200的前提下,如果ret.json()['status']为-1,则表明出错,出错信息在ret.json()['message']里面,如果执行成功, status是1
+
+
+### /workspace [GET,PUT]
+主要是对工作空间的结构化信息进行操作,包括修改合和获取工作空间中数据集、项目、任务的属性
+- GET请求:获取workspace中数据集、项目、任务、模型的属性
+- PUT请求:修改workspace中数据集、项目、任务、模型的属性,对于创建项目之后我们需求通过该接口将数据集与项目绑定才能进行训练任务
+对于可以获取和修改的属性请参考[Protobuf结构化数据](./data_struct.md)  
+
+```
+methods=='GET':获取工作目录中项目、数据集、任务的属性
+	Args:
+		struct(str):结构类型,可以是'dataset', 'project'或'task',
+		id(str):结构类型对应的id
+		attr_list(list):需要获取的属性的列表
+	Return:
+		status
+		if Not Args:
+			'dirname' : RESTful服务初始化时指定的工作目录
+		else:
+			attr(dict):key为属性,value为属性的值
+
+	Example:
+		#获取任务id为'T0001'的任务对应的path的值
+		params = {'struct': 'task', 'id': 'T0001', 'attr_list': ['path']}
+		ret = requests.get(url + '/workspace', json=params)
+		if (ret.json()['status'] == 1):
+			task_path = ret.json()['attr']['path']
+		else:
+			print("failed to get path)
+
+methods=='PUT':修改工作目录中项目、数据集、任务的属性
+	Args:
+		struct(str):结构类型,可以是'dataset', 'project'或'task'
+		id(str):结构类型对应的id
+		attr_dict(dict):key:需要修改的属性,value:需要修改属性的值
+	Return:
+		status
+	Example
+		#为id为'P0001'的项目绑定id为'D0001'的数据集
+		attr_dict = {'did': 'D0001'}
+		params = {'struct': 'project', 'id': 'P0001', 'attr_dict': attr_dict}
+		ret = requests.post(url + '/workspace', json=params)
+```
+
+
+
+
+### /dataset [GET,POST,PUT,DELETE]
+对数据集进行操作,包括创建、导入、查询、删除数据集的功能
+- POST请求:创建数据集,创建时需要指定数据集类型可以是['classification', 'detection', 'segmentation','instance_segmentation']中的一种
+- GET请求:创建好数据集后,可以通过GET请求获取数据集信息,目前支持获取单个或者所有数据集的信息
+- PUT请求:导入数据集,创建数据集后并没有真实的数据与数据集关联,需要通过导入功能,将数据导入到工作空间内,需要导入的数据集必须按照
+- DELETE:删除一个数据集  
+DatasetStatus定义了数据集状态,具体请参考[数据集状态变量](./data_struct.md)  
+
+```
+methods=='GET':获取所有数据集或者单个数据集的信息
+	Args:
+		did(str, optional):数据集id(可选),如果存在就返回数据集id对应数据集的信息
+	Ruturn:
+		status
+		if 'did' in Args:
+			id(str):数据集id,
+			dataset_status(int):数据集状态(DatasetStatus)枚举变量的值
+			message(str):数据集状态信息
+			attr(dict):数据集属性
+		else:
+			datasets(list):所有数据集属性的列表
+    Example1:
+        #获取数据集id为'D0001'数据集的信息
+        params = {'did': 'D0001'}
+        ret = requests.get(url + '/dataset', json=params)
+        #状态码转换为Enum类型
+        ret.json()['dataset_status'] = DatasetStatus(ret.json()['dataset_status'])
+    Example2:
+        #获取所有数据集信息
+        ret = requests.get(url + '/dataset')
+    Ruturn中的自定数据结构:
+		数据集属性attr,为dict对于其中的key包括如下
+		attr{
+			'type'(str): 数据集类型
+			'id'(str): 数据集id
+			'name'(str): 数据集名字
+			'path'(str): 数据集路径
+			'desc'(str): 数据集描述
+			'create_time'(str): 数据集创建时间
+			'pids'(list): 数据集绑定的项目列表
+		}
+		所有数据集属性datasets,为list,dataset_list[idx]包含:
+		dataset_list[idx]{
+			"id": 数据集id
+			"attr": 数据集属性
+		}
+		其中数据集属性attr,为dict对于其中的key包括如下,注意与获取单个数据集的属性区分
+		attr{
+			"type": 数据集类型,
+            "id": 数据集id,
+            "name": 数据集名字,
+            "path": 数据集路径,
+            "desc": 数据集描述,
+            "create_time": 数据集创建时间
+			'dataset_status': 数据集状态(DatasetStatus)枚举变量的值
+            'message' : 数据集状态信息
+
+		}
+
+methods=='POST':创建一个新的数据集
+	Args:
+		name(str):数据集名字
+		desc(str):数据集描述
+		dataset_type(str):数据集类型,可以是['classification', 'detection', 'segmentation','instance_segmentation']
+	Return:
+		did(str):数据集id
+		status
+	Example:
+		#新建一个分类数据集
+		params = {'name' : '我的数据集', 'desc' : '数据集描述', 'dataset_type' : 'classification'}
+		ret = requests.post(url + '/dataset', json=params)
+		#获得数据集id
+		did = ret.json()['did']
+
+methods=='PUT':异步,向数据集导入数据,支持分类、检测、语义分割、实例分割、摇杆分割数据集类型
+	Args:
+		did(str):数据集id
+		path(str):数据集路径
+	Return:
+		status
+	Example:
+		#为id为'D0001'的数据集导入数据集
+		params = {'did':'D0001', 'path':'/path/to/dataset'}
+		ret = requests.put(url + '/dataset', json=params)
+
+methods=='DELETE':删除已有的某个数据集
+	Args:
+		did(str):数据集id
+	Return:
+		status
+	Example:
+		#删除数据集id为'D0001'的数据集
+		params = {'did':'D0001'}
+		ret = requests.delete(url + '/dataset', json=params)
+```
+
+### /dataset/split [PUT]
+按照比例切分一个已经导入数据的数据集  
+
+```
+methods=='PUT':切分某个数据集
+	Args:
+		did(str):数据集id
+		val_split(float): 验证集比例
+		test_split(float): 测试集比例
+	Return:
+		status
+	Example:
+		#按照训练集,验证集,测试集,7:2:1的形式切分D0001数据集
+		params = {'did':'D0001', 'val_split': 0.2, 'test_split': 0.1}
+		ret = requests.put(url + '/dataset/split', json=params)
+```
+
+### /dataset/details [GET]
+获取切分后数据集的具体信息  
+
+```
+methods=='GET':获取某个数据集的详细信息
+	Args:
+		did(str):数据集id
+	Return:
+		details(dict):数据集详细信息,
+		status
+	Example:
+		#获取数据集id为'D0001'的数据集的详细信息
+		params = {'did':'D0001'}
+		ret = requests.get(url + '/dataset/details', json=params)
+	Ruturn中的自定数据结构:
+		数据集详细信息(details),其中的key包括如下:
+		details{
+			'file_info'(dict): 全量数据集文件与标签映射表,key:图片相对于数据集地址的相对路径;value:标签文件相对于数据集地址的相对路径
+			'label_info'(dict): 标签与全量数据集文件映射表,key:标签的类别;value:标签文件相对于数据集地址的相对路径
+			'labels'(list): 标签列表
+			'train_files'(list): 训练集文件列表,相对于据集地址的相对路径
+			'val_files'(list): 验证集文件列表,相对于据集地址的相对路径
+			'test_files'(list): 测试集文件列表,相对于据集地址的相对路径
+			'class_train_file_list(dict)':类别与训练集映射表,key为类别、value为训练图片相对于据集地址的相对路径
+			'class_val_file_list(dict)':类别与评估集映射表,key为类别、value为评估图片相对于据集地址的相对路径
+			'class_test_file_list(dict)':类别与测试集映射表,key为类别、value为测试图片相对于据集地址的相对路径
+		}
+```
+
+### /file [GET]
+#用于文件传输,目前支持图片、xml格式文件、log或者txt格式文件,对于图片文件如果带有did参数则会返回带可视化label的图片数据  
+
+```
+methods=='GET':获取服务端的文件,目前支持图片、xml格式文件、log文件
+	Args:
+		'path'(str):文件在服务端的路径
+		'did'(str, optional):可选,数据集id仅在文件为图片时有效。若存在返回图片带label可视化。注意当前不支持分类数据集数据的标注可视化
+	Return:
+		#数据为图片
+		img_data(str): base64图片数据
+		status
+		#数据为xml文件
+		ret:数据流
+		#数据为log或者txt文件
+		ret:json数据
+	Example1:
+		#获取图片,目前支持的图片格式有:
+		#{'JPEG', 'jpeg', 'JPG', 'jpg', 'BMP', 'bmp', 'PNG', 'png'}
+		#图片通过based64编码
+		params = {'path' : '/path/to/img'}
+		ret = requests.get(url + '/file', json=params)
+		#图片数据
+		img_data = base64.b64decode(ret.json()['img_data'])
+		#图片解码
+		#opencv
+		img_array = np.frombuffer(img_data, np.uint8)
+        img = cv2.imdecode(img_array, cv2.COLOR_RGB2BGR)
+        #PIL
+        img = Image.open(BytesIO(img_data))
+	Example2:
+		#获取xml数据
+		params = {'path' : '/path/to/xml'}
+		ret = requests.get(url + '/file', json=params)
+		#xml数据
+		xml_file = ret.text
+```
+
+### /project [GET,POST,DELETE]
+项目相关操作,包括创建、删除、查询项目
+- POST请求:创建一个项目,支持分类、检测、语义分割、实例分割
+- GET请求:查询已经创建项目中的信息,可以是单个项目或者是所有项目
+- DELETE:删除一个项目,同时会删除项目里面所有task  
+
+```
+methods=='GET':获取指定项目id的信息
+	Args:
+		'id'(str, optional):项目id,可选,如果存在就返回项目id对应项目的信息
+	Return:
+		status,
+		if 'id' in Args:
+			attr(dict):项目属性
+		else:
+			projects(list):所有项目属性
+	Example1:
+		#获取id为P0001项目的信息
+		params = {'id' : 'P0001'}
+		ret = requests.get(url + '/project', json=params)
+	Example2:
+		#获取所有项目信息
+		ret = requests.get(url + '/project', json=params)
+	Ruturn中的自定数据结构:
+		单个项目属性attr(dict){
+			id(str):项目id,
+			name(str):项目名字,
+			desc(str):项目描述,
+			type(str):项目类型,
+			did(str):项目绑定的数据集id,
+			path(str):项目在服务端的路径,
+			create_time(str):项目创建时间,
+			tasks(list):项目中包含所有任务的任务状态变量的int值
+		}
+		多个项目的属性projects(list),对于list里面每一个元素表示了单个项目属性的字典project其数据结构如下
+		project(dict){
+			id(str):项目id,
+			attr(dict):项目属性字典,与单个项目属性一致
+		}
+
+methods=='POST':创建一个项目
+	Args:
+		name(str): 项目名
+		desc(str):项目描述
+		project_type(str):项目类型
+	Return:
+		pid(str):项目id
+		status
+	Example:
+		#创建一个新的项目,project_type支持{'classification', 'detection', 'segmentation', 'instance_segmentation'}
+		params = {'name' : '分类项目','desc': '一个新的项目','project_type' : 'classification'}
+		ret = requests.post(url + '/project', json=params)
+		#获取项目id
+		pid = ret.json()['pid']
+
+methods=='DELETE':删除一个项目,以及项目相关的task
+	Args:
+		pid(str):项目id
+	Return:
+		status
+	Example:
+		#删除id为'P0001'的项目
+		params = {'pid' : 'P0001'}
+		ret = requests.delete(url + '/project', json=params)
+```
+
+### /project/task [GET,POST,DELETE]
+任务相关,创建、获取、删除任务
+- POST请求:创建一个任务可以是训练任务也可以是剪裁任务,剪裁任务需要指定parent_id
+- GET请求: 获取单个任务、单个项目内所有任务、所有任务的信息,当tid存在时返回指定任务的信息,如果任务状态(TaskStatus)显示任务停止可以通过resume查询任务是否可以恢复训练以及保存的最大epoch;当pid存在时返回该项目下面所有任务信息
+- DELETE请求:删除任务  
+TaskStatus定义了任务状态,具体请参考[任务状态变量](./data_struct.md)  
+
+```
+methods=='GET':#获取某个任务的信息或者所有任务的信息
+	Args:
+		tid(str, optional):任务id,可选,若存在即返回id对应任务的信息
+		resume(str, optional):获取是否可以恢复训练的状态,可选,需在存在tid的情况下才生效
+		pid(str, optional):项目id,可选,若存在即返回该项目id下所有任务信息
+	Return:
+		status
+		if 'tid' in Args:
+			task_status(int):任务状态(TaskStatus)枚举变量的值
+			message(str):任务状态信息
+			type(str):任务类型包括{'classification', 'detection', 'segmentation', 'instance_segmentation'}
+			resumable(bool):仅Args中存在resume时返回,任务训练是否可以恢复
+			max_saved_epochs(int):仅Args中存在resume时返回,当前训练模型保存的最大epoch
+		else:
+			tasks(list):所有任务属性
+	Example1:
+		#获取任务id为"T0001"的信息
+		params = {'tid' : 'T0001'}
+		ret = requests.get(url + '/project/task', json=params)
+	Example2:
+		#获取所有任务的信息
+		ret = requests.get(url + '/project/task')
+	Ruturn中的自定数据结构:
+		所有任务属性(tasks),任务属性attr(dict)的list
+		attr{
+			'id'(str): 任务id
+			'name'(str): 任务名字
+			'desc'(str): 任务详细描述
+			'pid'(str): 任务所属的项目id
+			'path'(str): 任务在工作空间的路径
+			'create_time'(str): 任务创建时间
+			'status(int)':任务状态(TaskStatus)枚举变量的值
+			'type(str)':任务类型包括{'classification', 'detection', 'segmentation', 'instance_segmentation'}
+		}
+
+methods=='POST':#创建任务(训练或者裁剪)
+	Args:
+		pid(str):项目id
+		train(dict):训练参数
+		desc(str, optional):任务描述,可选
+		parent_id(str, optional):可选,若存在即表示新建的任务为裁剪任务,parent_id的值为裁剪任务对应的训练任务id
+	Return:
+		tid(str):任务id
+		status
+	Example:
+		#在P0001项目下创建一个任务
+		params = {'pid' : 'POOO1'}
+		ret = requests.post(url + '/project/task')
+		#获取任务id
+		tid = ret.json()['tid']
+
+methods=='DELETE':#删除任务
+	Args:
+		tid(str):任务id
+	Return:
+		status
+	Example:
+		#删除id为T0001的任务
+		params = {'tid' : 'T0001'}
+		ret = requests.delete(url + '/project/task')
+```
+
+### /project/task/params [GET,POST]
+获取和设置训练参数
+- GET请求:获取已有的参数信息或者默认的参数信息,当tid存在时获取该任务已有的参数信息、当pid存在时获取该项目的推荐参数给该任务,在创建任务之前需要先获取默认参数
+- POST请求:设置训练参数,用户修改训练参数后通过该接口设置训练参数,在workspace内会将训练参数保存为params.pkl文件  
+
+```
+methods=='GET':#获取任务id对应的参数,或者获取项目默认参数
+	Args:
+		tid(str, optional):获取任务对应的参数
+		pid(str,optional):获取项目对应的默认参数
+		model_type(str,optional):pid存在下有效,对应项目下获取指定模型的默认参数
+		gpu_list(list,optional):pid存在下有效,默认值为[0],使用指定的gpu并获取相应的默认参数
+	Return:
+		train(dict):训练或者裁剪的参数
+		status
+	Example1:
+		获取任务id为T0001的任务对应的参数
+		params = {'tid' : 'T0001'}
+		ret = requests.get(url + '/project/task/params',json=params)
+	Example2:
+		获取项目id为P0001的检测项目,PPYOLO模型的默认参数
+		params = {'pid' : 'P0001', 'model_type' : 'PPYOLO'}
+		ret = requests.get(url + '/project/task/params',json=params)
+		#获取参数dict
+		train_dict = ret.json()['train']
+		ret = requests.get(url + '/project/task/params',json=params)  
+
+methods=='POST':#设置任务参数,将前端用户设置训练参数dict保存在后端的pkl文件中
+	Args:
+		tid(str):任务id
+		train(dict):训练参数
+	Return:
+		status
+	Example:
+		#设置训练参数
+		params = {'tid': 'T0001', 'train': train_dict}
+		ret = requests.post(url + '/project/task/params',json=params)
+```
+
+### /project/task/train [POST,PUT]
+任务训练(包括剪裁任务训练),主要是启动和停止任务,需要先设置好训练参数
+-POST请求:启动一个训练任务,异步操作,启动前需要设置好训练的参数
+-PUT请求:暂停一个训练任务或者重启一个暂停的训练任务,重启训练任务可以设置重启的epoch数  
+
+```
+methods=='POST':#异步,启动训练或者裁剪任务
+	Args:
+		tid(str):任务id
+		eval_metric_loss(int,optional):可选,裁剪任务时可用,裁剪任务所需的评估loss
+	Return:
+		status
+	Example:
+		#启动任务id为T0001的任务的训练
+		params = {'tid':'T0001'}
+		ret = requests.post(url + '/project/task/train',json=params)
+
+methods=='PUT':#改变任务训练的状态,即终止训练或者恢复训练
+	Args:
+		tid(str):任务id
+		act(str):[stop,resume]暂停或者恢复
+		epoch(int):(resume下可以设置)恢复训练的起始轮数
+    Return:
+		status
+	Example:
+		#停止任务id为T0001的任务的训练
+		params = {'tid':'T0001', 'act': 'stop'}
+		ret = requests.put(url + '/project/task/train',json=params)
+```
+
+### /project/task/prune [GET,POST,PUT]
+创建、获取、停止剪裁任务分析;在启动剪裁任务训练之前需要通过此接口完成剪裁任务分析
+- GET请求:获取剪裁任务状态信息
+- POST请求:创建剪裁分析任务,异步操作
+- PUT请求:停止正在进行的剪裁分析任务  
+PruneStatus定义了裁剪分析任务状态,具体请参考[裁剪分析状态变量](./data_struct.md)  
+
+```
+methods=='GET':#获取剪裁任务的状态
+	Args:
+		tid(str):任务id
+	Return:
+		prune_status(int): 剪裁任务状态(PruneStatus)枚举变量的值
+		status
+	Example:
+		#启动任务id为T0001的任务的训练
+		params = {'tid':'T0001'}
+		ret = requests.get(url + '/project/task/prune',json=params)
+
+methods=='POST':#异步,创建一个剪裁分析,对于启动剪裁任务前需要先启动剪裁分析
+	Args:
+		tid(str):任务id
+	Return:
+		status
+	Example:
+		#对任务id为T0001的任务启动剪裁分析任务
+		params = {'tid':'T0001'}
+		ret = requests.post(url + '/project/task/prune',json=params)
+
+methods=='PUT':#改变裁剪分析任务的状态
+	Args:
+		tid(str):任务id
+		act(str):[stop],目前仅支持停止一个裁剪分析任务
+	Return
+		status
+	Example:
+		#停止T0001的任务的裁剪分析
+		params = {'tid':'T0001', 'act': 'stop'}
+		ret = requests.put(url + '/project/task/prune',json=params)
+```
+
+### /project/task/evaluate [GET,POST]
+创建、获取一个评估任务
+- POST请求:创建一个评估任务,需要模型训练好后调用,异步操作
+- GET请求: 获取评估任务的状态  
+
+```
+methods=='GET':#获取模型评估的结果
+	Args:
+		tid(str):任务id
+	Return:
+		evaluate_status(int): 任务状态(TaskStatus)枚举变量的值
+		message(str):描述评估任务的信息
+		result(dict):如果评估成功,返回评估结果的dict,否则为None
+		status
+	Example:
+		#获取任务id为T0001的任务的评估数据
+		params = {'tid':'T0001'}
+		ret = requests.get(url + '/project/task/evaluate',json=params)
+		result = ret.json()['result']
+
+methods=='POST':#异步,创建一个评估任务
+	Args:
+		tid(str):任务id
+		epoch(int,optional):需要评估的epoch,如果为None则会评估训练时指标最好的epoch
+		topk(int,optional):分类任务topk指标,如果为None默认输入为5
+		score_thresh(float):检测任务类别的score threshhold值,如果为None默认输入为0.5
+		overlap_thresh(float):实例分割任务IOU threshhold值,如果为None默认输入为0.3
+	Return:
+		status
+	Example:
+		#对任务id为T0001的分类任务进行评估,topk=5
+		params = {'tid':'T0001', 'epoch': None, 'topk': 5, 'score_thresh': None, 'overlap_thresh': None}
+		ret = requests.post(url + '/project/task/evaluate',json=params)
+```
+
+### /project/task/evaluate/file [GET]
+评估结果生成excel表格  
+- GET请求:评估完成的情况下,在服务器端生成评估结果的excel表格
+
+```
+methods=='GET':#评估结果生成excel表格
+	Args:
+		tid(str):任务id
+	Return:
+		path(str):评估结果excel表格在服务器端的路径
+		message(str):提示信息
+		status
+	Example:
+		#任务id为T0001的任务在服务器端生成评估excel表格
+		params = {'tid': 'T0001'}
+		ret = requests.get(url + '/project/task/evaluate/file',json=params)
+		#显示保存路径
+		print(ret.json()['path'])
+```
+
+### /project/task/metrics [GET]
+获取训练、评估、剪裁的日志和敏感度与模型裁剪率关系图
+- GET请求:通过type来确定需要获取的内容  
+
+```
+methods=='GET':#获取日志数据
+	Args:
+		tid(str):任务id
+		type(str):可以获取日志的类型,[train,eval,sensitivities,prune],包括训练,评估,敏感度与模型裁剪率关系图,裁剪的日志
+	Return:
+		status
+		if type == 'train':
+			train_log(dict): 训练日志
+		elif type == 'eval':
+			eval_metrics(dict): 评估结果
+		elif type == 'sensitivities':
+			sensitivities_loss_img(dict): 敏感度与模型裁剪率关系图
+		elif type == 'prune':
+			prune_log(dict):裁剪日志
+	Example:
+		#获取训练日志
+		paramas = {'tid': 'T0002', 'type': 'train'}
+		ret = requests.get(url + '/project/task/metrics',json=params)
+	Ruturn中的自定数据结构:
+		train_log(dict){
+			eta: 剩余时间,
+			train_metrics: 训练指标,
+			eval_metircs: 评估指标,
+			download_status: 下载模型状态,
+			eval_done: 是否已保存模型,
+			train_error: 训练错误原因
+		}
+```
+
+### /project/task/predict [GET, POST]
+创建、查询、停止一个预测任务
+- POST请求:创建一个预测任务、图片输入需要先进行base64编码、异步操作
+- GET请求:获取预测任务的状态
+- PUT请求:停止一个预测任务
+PredictStatus定义了预测任务状态变量,具体请参考[预测任务状态变量](./data_struct.md)  
+
+```
+methods=='GET':#获取预测状态
+	Args:
+		tid(str):任务id
+	Return:
+		predict_status(int): 预测任务状态(PredictStatus)枚举变量的值
+		message(str): 预测信息
+		status
+	Example:
+		#获取预测状态
+		paramas = {'tid': 'T0002'}
+		ret = requests.get(url + '/project/task/predict',json=params)
+		predict_status = PredictStatus(ret.json()['predict_status'])
+
+methods=='POST':#创建预测任务,目前仅支持单张图片的预测
+	Args:
+		tid(str):任务id
+		image_data(str):base64编码的image数据
+		score_thresh(float,optional):可选,检测任务时有效,检测类别的score threashold值默认是0.5
+		epoch(int,float,optional):可选,选择需要做预测的ephoch,默认为评估指标最好的那一个epoch
+	Return:
+		path(str):服务器上保存预测结果图片的路径
+		status
+	Example:
+		#对一张图片进行预测并取回预测结果
+		import base64
+		import cv2
+		#对图片进行base64编码
+		img_path = 'path to img need to be predict'
+		f = open(img_path, 'rb')
+		base64_data = base64.b64encode(f.read())
+		base64_str = str(base64_data,'utf-8')
+		params[tid: 'T0001', 'image_data', base64_str]
+		#进行预测
+		ret = requests.post(url + '/project/task/predict',json=params)
+		result_path = ret.json()['path']
+		#判断预测是否完成
+		paramas = {'tid': 'T0001'}
+		ret = requests.get(url + '/project/task/predict',json=params)
+		predict_status = PredictStatus(ret.json()['predict_status'])
+		if (predict_status == PredictStatus.XPREDONE):
+		#取回预测结果图片
+			params = {'path' : result_path}
+			ret = requests.get(url + '/file',json=params)
+			img_data = ret.json()['img_data']
+
+methods=='PUT':#停止一个预测任务
+	Args:
+		tid(str):任务id
+	Return:
+	    status
+		predict_status:评估的状态
+```
+
+### /project/task/export [GET,POST,PUT]
+创建、获取、停止模型装换或者导出、支持导出inference和lite的模型
+- POST请求:创建模型导出,可以通过type确定导出inference模型还是lite模型
+- GET请求:获取导出的结果日志、或者时导出状态
+- PUT请求:停止模型的导出  
+
+```
+methods=='GET':#获取导出模型的状态
+	Args:
+		tid(str):任务id
+		quant(str,optional)可选,[log,result],导出量模型导出状态,若值为log则返回量化的日志;若值为result则返回量化的结果
+	Return:
+		status
+		if quant == 'log':
+			quant_log(dict):量化日志
+		if quant == 'result'
+			quant_result(dict):量化结果
+		if quant not in Args:
+			export_status(int):模型导出状态(PredictStatus)枚举变量的值
+			message(str):模型导出提示信息
+	Example:
+		#获取模型导出状态信息
+		params = {'tid':'T0002'}
+		ret = requests.get(url + '/project/task/export',json=params)
+
+methods=='POST':#导出inference模型或者导出lite模型
+	Args:
+		tid(str):任务id
+		type(str):保存模型的类别[infer,lite],支持inference模型导出和lite的模型导出
+		save_dir(str):保存模型的路径
+		epoch(str,optional)可选,指定导出的epoch数默认为评估效果最好的epoch
+		quant(bool,optional)可选,type为infer有效,是否导出量化后的模型,默认为False
+		model_path(str,optional)可选,type为lite时有效,inference模型的地址
+	Return:
+		status
+		if type == 'infer':
+			save_dir:模型保存路径
+		if type == 'lite':
+			message:模型保存信息
+	Example:
+		#导出inference模型
+		params = {tid:'T0001', type:'infer', save_dir:'path to save', 'quant': False}
+		ret = requests.post(url + '/project/task/export',json=params)
+methods=='PUT':#停止导出模型
+	Args:
+		tid(str):任务id
+	Return:
+		export_status(int):模型导出状态(PredictStatus)枚举变量的值
+		message(str):停止模型导出提示信息
+		status
+	Example:
+		#停止导出模型
+		params = {tid:'T0001'}
+		ret = requests.put(url + '/project/task/export',json=params)
+```
+
+### /project/task/vdl [GET]
+打开任务的可视化分析工具(VisualDL)  
+- GET请求:打开任务的vdl  
+
+```
+methods=='GET':#打开某个任务的可视化分析工具(VisualDL)
+	Args:
+		tid(str):任务id
+	Return:
+		url(str):vdl地址
+		status
+	Example:
+		#打开任务T0002的vdl
+		params = {tid:'T0002'}
+		ret = requests.get(url + '/project/task/vdl',json=params)
+		#获取打开vdl的url
+		url = ret.json()['url']
+```
+
+### /system [GET]
+获取系统信息包括CPU、GPU信息
+- GET请求:获取系统信息、在paddlex启动restful时会自行调用此api、若需要使用GPU请确定已经安装好了pycuda包
+```
+methods=='GET':#获取系统GPU、CPU信息
+	Args:
+		type(str):[machine_info,gpu_memory_size]选择需要获取的系统信息
+	Return:
+		status
+		if type=='machine_info'
+			info(dict):服务端信息
+		if type=='gpu_memory_size'
+			gpu_mem_infos(list):GPU内存信息
+	Example1:
+		#获取服务器gpu与cpu信息
+		params = {'type': 'machine_info'}
+		ret = requests.get(url + 'system', json=params)
+		info  = ret.json()['info']
+	Example2:
+		#获取服务器gpu显存信息
+		params = {'type': 'gpu_memory_size'}
+		ret = requests.get(url + 'system', json=params)
+		gpu_mem_infos = ret.json()['gpu_mem_infos']
+#info(dict):服务端信息
+info={
+	message(str):获取提示信息
+	cpu_num(int):cpu个数
+	gpu_num(int):gpu个数
+	sysstr(str):服务器系统信息
+}
+#gpu_mem_infos(list):GPU内存信息,对于list里面第i个元素表示第i个GPU的显存信息,包含:
+	free:可用显存
+	used:已经使用的显存
+	total:总共的显存
+```
+
+### /demo [GET,POST,PUT]
+创建、获取、删除demo项目,
+- GET请求: 获取demo下载的进度
+- POST请求: 下载和载入demo项目
+- PUT请求: 停止下载demo项目  
+
+```
+methods=='GET':#获取demo下载进度
+	Args:
+		prj_type(str):项目类型可以是['classification', 'detection', 'segmentation','instance_segmentation']
+	Return:
+		status
+		attr(dict):demo下载信息
+	Example:
+		#分类项目示例demo下载
+		params = {'prj_type' = 'classification'}
+		ret = requests.get(url + 'demo', json=params)
+#attr(dict):demo下载信息,包含
+attr={
+	status(int):demo下载状态枚举变量DownloadStatus的int值
+	progress(float):demo下载进度
+}
+
+methods=='POST':#下载或创建demo工程
+	Args:
+		type(str):{download,load}下载或者创建样例
+		prj_type(int):项目类型ProjectType枚举变量的int值
+	Return:
+		status
+		if type=='load':
+			did:数据集id
+			pid:项目id
+	Example1:
+		#下载分类demo样例
+		params = {'type': 'download', 'prj_type': 0}
+		ret = requests.post(url + 'demo', json=params)
+	Example2:
+		#创建分类demo样例工程
+		params = {'type': 'load', 'prj_type': 0}
+		ret = requests.post(url + 'demo', json=params)
+
+methods=='PUT':#停止下载或创建demo工程
+	Args:
+		prj_type(int):项目类型ProjectType枚举变量的int值
+	Return:
+		status
+	Example:
+		#停止分类demo下载或者创建
+		params = {'prj_type': 0}
+		ret = requests.put(url + 'demo', json=params)
+```
+
+### /model [GET,POST,DELETE]
+- GET请求: 获取所有或者单个模型的信息,可以是预训练模型或者inference模型
+- POST请求: 在workspace中创建模型,对于inference模型需要先通过/project/task/export接口现在导出inference模型
+- DELETE请求: 删除一个模型
+
+```
+methods=='GET':#获取一个或者所有模型的信息
+	Args:
+		mid(str,optional)可选,若存在则返回某个模型的信息
+		type(str,optional)可选,[pretrained,exported].若存在则返回对应类型下所有的模型信息
+	Return:
+		status
+		if mid in Args:
+			dataset_attr(dict):数据集属性
+			task_params(dict):模型训练参数
+			eval_result(dict):模型评估结果
+		if type in Args and type == 'pretrained':
+			pretrained_models(list):所有预训练模型信息
+		if type in Args and type == 'exported':
+			exported_models(list):所有inference模型的信息
+	Example:
+		#获取所有保存的预训练模型信息
+		params = {'type': 'exported'}
+		ret = requests.get(url + 'model', json=params)
+
+methods=='POST':#创建一个模型
+	Args:
+		pid(str):项目id
+		tid(str):任务id
+		name(str):模型名字
+		type(str):创建模型的类型,[pretrained,exported],pretrained代表创建预训练模型、exported代表创建inference或者lite模型
+		source_path(str):仅type为pretrained时有效,训练好的模型的路径
+		path(str):仅type为exported时有效,inference或者lite模型的路径
+		exported_type(int):0为inference模型,1为lite模型
+		eval_results(dict,optional):可选,仅type为pretrained时有效,模型评估的指标
+	Return:
+		status
+		if type == 'pretrained':
+			pmid(str):预训练模型id
+		if type == 'exported':
+			emid(str):inference模型id
+	Exampe:
+		#创建一个预训练模型
+		params={
+			pid : 'P0001',
+			tid : 'T0001',
+			name : 'Pretrain_model',
+			type : 'pretrained',
+			source_path : '/path/to/pretrian_model',
+		}
+		ret = requests.post(url + 'model', json=params)
+
+methods=='DELETE':删除一个模型
+	Args:
+		type(str):删除模型的类型,[pretrained,exported],pretrained代表创建预训练模型、exported代表创建inference或者lite模型
+		if type='pretrained':
+			pmid:预训练模型id
+		if type='exported':
+			emid:inference或者lite模型id
+	Return:
+		status
+	Example:
+		#删除模型id为EM0001的inference模型
+		params = {'type': 'exported', 'emid': 'EM0001'}
+		ret = requests.delete(url + 'model', json=params)
+```

+ 55 - 0
docs/gui/restful/tree.md

@@ -0,0 +1,55 @@
+# RESTful目录结构  
+
+介绍了PaddleX RESTful的整体目录结构
+
+```
+restful
+|____system.py	// 处理/system 请求
+|____workspace_pb2.py
+|____dir.py
+|____dataset	// 数据集相关
+| |____datasetbase.py	// 数据集基类
+| |______init__.py
+| |____seg_dataset.py	// 分割数据集
+| |____cls_dataset.py	// 分类数据集
+| |____dataset.py	// 处理/dataset 请求
+| |____operate.py	// 数据集基础操作函数
+| |____utils.py		// 数据集基础工具函数
+| |____ins_seg_dataset.py	// 示例分割数据集
+| |____det_dataset.py	// 检测数据集
+|______init__.py
+|____model.py	// 处理/model 请求
+|____project	// 项目相关
+| |____task.py	// 处理/project/task 请求
+| |______init__.py
+| |____visualize.py	// 数据可视化
+| |____operate.py	// 任务基础操作函数
+| |____evaluate		// 模型评估
+| | |____detection.py	// 检测模型评估
+| | |____classification.py	// 分类模型评估
+| | |______init__.py
+| | |____draw_pred_result.py	// 评估与预测结果可视化
+| | |____segmentation.py	// 分割模型评估
+| |____train	//模型训练
+| | |____detection.py	// 检测模型训练
+| | |____params.py	// 模型参数
+| | |____classification.py	// 分类模型训练
+| | |______init__.py
+| | |____params_v2.py	// 模型参数V2版本
+| | |____segmentation.py	// 分割模型训练
+| |____prune	// 模型剪裁
+| | |____detection.py	// 检测模型剪裁
+| | |____classification.py	// 分类模型剪裁
+| | |______init__.py
+| | |____segmentation.py	// 分割模型剪裁
+| |____project.py	// 处理/project请求
+|____utils.py	// 基础工具函数
+|____app.py	// 创建flask app
+|____front_demo	// 前端demo
+|____workspace.py	// 处理/workspace请求
+|____demo.py	// 处理/demo 请求
+|____workspace.proto	// workspace 结构化信息
+|____frontend_demo // 前端demo
+| |____paddlex_restful_demo.html    //前端demo文件
+
+```

BIN=BIN
docs/gui/star.png


+ 5 - 1
docs/index.rst

@@ -50,7 +50,7 @@ PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习
    deploy/export_model.md
    deploy/hub_serving.md
    deploy/server/index
-   deploy/nvidia-jetson.md
+   deploy/jetson/index
    deploy/paddlelite/android.md
    deploy/raspberry/index
    deploy/openvino/index
@@ -64,6 +64,7 @@ PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习
    examples/remote_sensing.md
    examples/multi-channel_remote_sensing/README.md
    examples/change_detection.md
+   examples/industrial_quality_inspection/README.md
 
 .. toctree::
    :maxdepth: 1
@@ -72,6 +73,9 @@ PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习
    gui/introduce.md
    gui/download.md
    gui/how_to_use.md
+   gui/FAQ.md
+   gui/restful/index
+
 
 .. toctree::
    :maxdepth: 1

+ 79 - 0
docs/luckydraw.md

@@ -0,0 +1,79 @@
+
+# 获奖名单
+
+## 50元京东卡(5个)
+
+### 恭喜以下用户获得该奖品!!
+
+用户**QLXY**
+
+用户**innaturn**
+
+用户**Bainiu2**
+
+用户**524723028**
+
+用户**LoverHaHa**
+
+
+
+
+
+## 百度网盘会员月卡(5个)
+
+### 恭喜以下用户获得该奖品!!
+
+用户**ZEKAICHEN**
+
+用户**hustcong**
+
+用户**Gedule**
+
+用户**VegeFira**
+
+用户**yinghua8714**
+
+
+
+
+
+## 鼠标垫(5个)
+
+### 恭喜以下用户获得该奖品!!
+
+用户**IzzyPrime**
+
+用户**Attackzzw**
+
+用户**van224**
+
+用户**NomeChomsky**
+
+用户**Darki-luo**
+
+
+
+## 小度熊抱枕(2个)
+
+### 恭喜以下用户获得该奖品!!
+
+用户**zhanglinc**
+
+用户**hualinzhang**
+
+
+
+
+
+## 领奖方式
+
+**再次恭喜以上获奖小伙伴们,请大家扫描下方二维码将自己的Github ID、姓名、电话、详细地址填写完整,我们会尽快将奖品寄出~~**
+
+<p align="center">
+<img src="https://user-images.githubusercontent.com/75066115/102462196-6e943700-4084-11eb-99d9-1707b813a6e5.png" width="20%"/>
+</p>
+
+
+
+ 
+

+ 99 - 0
examples/industrial_quality_inspection/README.md

@@ -0,0 +1,99 @@
+# 工业质检
+
+本案例面向工业质检场景里的铝材表面缺陷检测,提供了针对GPU端和CPU端两种部署场景下基于PaddleX的解决方案,希望通过梳理优化模型精度和性能的思路能帮助用户更高效地解决实际质检应用中的问题。
+
+## 1. GPU端解决方案
+
+### 1.1 数据集介绍
+
+本案例使用[天池铝材表面缺陷检测初赛](https://tianchi.aliyun.com/competition/entrance/231682/introduction)数据集,共有3005张图片,分别检测擦花、杂色、漏底、不导电、桔皮、喷流、漆泡、起坑、脏点和角位漏底10种缺陷,这10种缺陷的定义和示例可点击文档[天池铝材表面缺陷检测初赛数据集示例](./dataset.md)查看。
+
+将这3005张图片按9:1随机切分成2713张图片的训练集和292张图片的验证集。
+
+### 1.2 精度优化
+
+本小节侧重展示在模型迭代过程中优化精度的思路,在本案例中,有些优化策略获得了精度收益,而有些没有。在其他质检场景中,可根据实际情况尝试这些优化策略。点击文档[精度优化](./accuracy_improvement.md)查看。
+
+### 1.3 性能优化
+
+在完成模型精度优化之后,从以下两个方面对模型进行加速:
+
+#### (1) 减少FPN部分的通道数量
+
+将FPN部分的通道数量由原本的256减少至64,使用方式在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时设置参数`fpn_num_channels`为64即可,需要重新对模型进行训练。
+
+#### (2) 减少测试阶段的候选框数量
+
+将测试阶段RPN部分做非极大值抑制计算的候选框数量由原本的6000减少至500,将RPN部分做完非极大值抑制后保留的候选框数量由原本的1000减少至300。使用方式在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时设置参数`test_pre_nms_top_n`为500,`test_post_nms_top_n`为300。
+
+采用Fluid C++预测引擎在Tesla P40上测试模型的推理时间(输入数据拷贝至GPU的时间、计算时间、数据拷贝至CPU的时间),输入大小设置为800x1333,加速前后推理时间如下表所示:
+
+| 模型 | 推理时间 (ms/image)| VOC mAP (%) |
+| -- | -- | -- |
+| baseline | 66.51 | 88.87 |
+| + fpn channel=64 + test proposal=pre/post topk 500/300 | 46.08 | 87.72 |
+
+### 1.4 最终方案
+
+本案例面向GPU端的最终方案是选择二阶段检测模型FasterRCNN,其骨干网络选择加入了可变形卷积(DCN)的ResNet50_vd,训练时使用SSLD蒸馏方案训练得到的ResNet50_vd预训练模型,FPN部分的通道数量设置为64。使用复核过的数据集,训练阶段数据增强策略采用RandomHorizontalFlip、RandomDistort、RandomCrop,并加入背景图片。测试阶段的RPN部分做非极大值抑制计算的候选框数量由原本的6000减少至500、做完非极大值抑制后保留的候选框数量由原本的1000减少至300。模型在验证集上的VOC mAP为87.72%。
+
+在Tesla P40的Linux系统下,对于输入大小是800 x 1333的模型,图像预处理时长为30ms/image,模型的推理时间为46.08ms/image,包括输入数据拷贝至GPU的时间、计算时间、数据拷贝至CPU的时间。
+
+| 模型 | VOC mAP (%) | 推理时间 (ms/image)
+| -- | -- | -- |
+| FasterRCNN-ResNet50_vd_ssld | 81.05 | 48.62 |
+| + dcn | 88.09 | 66.51 |
+| + RandomHorizontalFlip/RandomDistort/RandomCrop | 90.23| 66.51 |
+| + background images | 88.87 | 66.51 |
+| + fpn channel=64 | 87.79 | 48.65 |
+| + test proposal=pre/post topk 500/300 | 87.72 | 46.08 |
+
+具体的训练和部署流程点击文档[GPU端最终解决方案](./gpu_solution.md)进行查看。
+
+## 2. CPU端解决方案
+
+为了实现高效的模型推理,面向CPU端的模型选择精度和效率皆优的单阶段检测模型YOLOv3,骨干网络选择基于PaddleClas中SSLD蒸馏方案训练得到的MobileNetv3_large。训练完成后,对模型做剪裁操作,以提升模型的性能。模型在验证集上的VOC mAP为79.02%。
+
+部署阶段,借助OpenVINO预测引擎完成在Intel(R) Core(TM) i9-9820X CPU @ 3.30GHz Windows系统下高效推理。对于输入大小是608 x 608的模型,图像预处理时长为38.69 ms/image,模型的推理时间为34.50ms/image。
+
+| 模型 | VOC mAP (%) | Inference Speed (ms/image)
+| -- | -- | -- |
+| YOLOv3-MobileNetv3_ssld | 81.31 | 56.71 |
+| pruned YOLOv3-MobileNetv3_ssld | 78.60 | 34.50 |
+
+### 模型训练
+
+[环境前置依赖](./gpu_solution.md#%E5%89%8D%E7%BD%AE%E4%BE%9D%E8%B5%96)、[下载PaddleX源码](./gpu_solution.md#1-%E4%B8%8B%E8%BD%BDpaddlex%E6%BA%90%E7%A0%81)、[下载数据集](./gpu_solution.md#2-%E4%B8%8B%E8%BD%BD%E6%95%B0%E6%8D%AE%E9%9B%86)与GPU端是一样的,可点击文档[GPU端最终解决方案](./gpu_solution.md)查看,在此不做赘述。
+
+如果不想再次训练模型,可以直接下载已经训练好的模型完成后面的模型测试和部署推理:
+
+```
+wget https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/models/yolov3_mobilenetv3_large_pruned.tar.gz
+tar xvf yolov3_mobilenetv3_large_pruned.tar.gz
+```
+
+运行以下代码进行模型训练,代码会自动下载数据集,如若事先下载了数据集,需将下载和解压铝材缺陷检测数据集的相关行注释掉。代码中默认使用0,1,2,3,4,5,6,7号GPU训练,可根据实际情况设置卡号并调整`batch_size`和`learning_rate`。
+
+```
+python train_yolov3.py
+```
+
+### 模型剪裁
+
+运行以下代码,分析在不同的精度损失下模型各层的剪裁比例:
+
+```
+python params_analysis.py
+```
+
+设置可允许的精度损失为0.05,对模型进行剪裁,剪裁后需要重新训练模型:
+
+```
+python train_pruned_yolov3.py
+```
+
+[分析预测错误的原因](./gpu_solution.md#4-%E5%88%86%E6%9E%90%E9%A2%84%E6%B5%8B%E9%94%99%E8%AF%AF%E7%9A%84%E5%8E%9F%E5%9B%A0)、[统计图片级召回率和误检率](./gpu_solution.md#5-%E7%BB%9F%E8%AE%A1%E5%9B%BE%E7%89%87%E7%BA%A7%E5%8F%AC%E5%9B%9E%E7%8E%87%E5%92%8C%E8%AF%AF%E6%A3%80%E7%8E%87)、[模型测试](./gpu_solution.md#6-%E6%A8%A1%E5%9E%8B%E6%B5%8B%E8%AF%95)这些步骤与GPU端是一样的,可点击文档[GPU端最终解决方案](./gpu_solution.md)查看,在此不做赘述。
+
+### 推理部署
+
+本案例采用C++部署方式,通过OpenVINO将模型部署在Intel(R) Core(TM) i9-9820X CPU @ 3.30GHz的Windows系统下,具体的部署流程请参考文档[PaddleX模型多端安全部署/OpenVINO部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/openvino/index.html)。

+ 93 - 0
examples/industrial_quality_inspection/accuracy_improvement.md

@@ -0,0 +1,93 @@
+# 精度优化
+
+本小节侧重展示在模型迭代过程中优化精度的思路,在本案例中,有些优化策略获得了精度收益,而有些没有。在其他质检场景中,可根据实际情况尝试这些优化策略。
+
+## (1) 基线模型选择
+
+相较于单阶段检测模型,二阶段检测模型的精度更高但是速度更慢。考虑到是部署到GPU端,本案例选择二阶段检测模型FasterRCNN作为基线模型,其骨干网络选择ResNet50_vd,并使用基于PaddleClas中SSLD蒸馏方案训练得到的ResNet50_vd预训练模型(ImageNet1k验证集上Top1 Acc为82.39%)。训练完成后,模型在验证集上的精度VOC mAP为73.36%。
+
+## (2) 模型效果分析
+
+使用PaddleX提供的[paddlex.det.coco_error_analysis](https://paddlex.readthedocs.io/zh_CN/develop/apis/visualize.html#paddlex-det-coco-error-analysis)接口对模型在验证集上预测错误的原因进行分析,分析结果以图表的形式展示如下:
+
+| all classes| 擦花 | 杂色 | 漏底 | 不导电 | 桔皮 | 喷流 | 漆泡 | 起坑 | 脏点 | 角位漏底 |
+| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
+| ![](image/allclasses_analysis_example.png) | ![](image/cahua_analysis_example.png) | ![](image/zase_analysis_example.png) | ![](image/loudi_analysis_example.png) | ![](image/budaodian_analysis_example.png) | ![](image/jupi_analysis_example.png) | ![](image/penliu_analysis_example.png) | ![](image/qipao_analysis_example.png) | ![](image/qikeng_analysis_example.png) | ![](image/zangdian_analysis_example.png) | ![](image/jiaoweiloudi_analysis_example.png) |
+
+分析图表展示了7条Precision-Recall(PR)曲线,每一条曲线表示的Average Precision (AP)比它左边那条高,原因是逐步放宽了评估要求。以擦花类为例,各条PR曲线的评估要求解释如下:
+
+* C75: 在IoU设置为0.75时的PR曲线, AP为0.001。
+* C50: 在IoU设置为0.5时的PR曲线,AP为0.622。C50与C75之间的白色区域面积代表将IoU从0.75放宽至0.5带来的AP增益。
+* Loc: 在IoU设置为0.1时的PR曲线,AP为0.740。Loc与C50之间的蓝色区域面积代表将IoU从0.5放宽至0.1带来的AP增益。蓝色区域面积越大,表示越多的检测框位置不够精准。
+* Sim: 在Loc的基础上,如果检测框与真值框的类别不相同,但两者同属于一个亚类,则不认为该检测框是错误的,在这种评估要求下的PR曲线, AP为0.742。Sim与Loc之间的红色区域面积越大,表示子类间的混淆程度越高。VOC格式的数据集所有的类别都属于同一个亚类。
+* Oth: 在Sim的基础上,如果检测框与真值框的亚类不相同,则不认为该检测框是错误的,在这种评估要求下的PR曲线,AP为0.742。Oth与Sim之间的绿色区域面积越大,表示亚类间的混淆程度越高。VOC格式的数据集中所有的类别都属于同一个亚类,故不存在亚类间的混淆。
+* BG: 在Oth的基础上,背景区域上的检测框不认为是错误的,在这种评估要求下的PR曲线,AP为92.1。BG与Oth之间的紫色区域面积越大,表示背景区域被误检的数量越多。
+* FN: 在BG的基础上,漏检的真值框不认为是错误的,在这种评估要求下的PR曲线,AP为1.00。FN与BG之间的橙色区域面积越大,表示漏检的真值框数量越多。
+
+从分析图表中可以看出,杂色、桔皮、起坑三类检测效果较好,角位漏底存在少许检测框没有达到IoU 0.5的情况,问题较多的是擦花、不导电、喷流、漆泡、脏点。擦花类最严重的问题是误检、位置不精准、漏检,不导电类最严重的问题是漏检、位置不精准,喷流类和漆泡类最严重的问题是位置不精准、误检,脏点类最严重的问题是误检、漏检。为进一步理解造成这些问题的原因,将验证集上的预测结果进行了可视化,然后发现数据集标注存在以下问题:
+
+* 轻微的缺陷不视为缺陷,但轻微的界定不明确,有些轻微的缺陷被标注了,造成误检较多
+* 不导电、漏底、角位漏底外观极其相似,肉眼难以区分,导致这三类极其容易混淆而使得评估时误检或漏检的产生
+* 有些轻微的擦花和脏点被标注了,有些明显的反而没有被标注,造成了这两类误检和漏检情况都较为严重
+* 喷流和漆泡多为连续性的缺陷,一处喷流,其水平线上还会有其他喷流,一个气泡,其水平线上还会有一排气泡。但有时候把这些连续性的缺陷标注成一个目标,有时候又单独地标注不同的部分。导致模型有时候检测单独部分,有时候又检测整体,造成这两类位置不精准、误检较多。
+
+## (3) 数据复核
+
+为了减少原始数据标注的诸多问题对模型优化的影响,需要对数据进行复核。复核准则示例如下:
+
+* 擦花:不明显的擦花不标注,面状擦花以同一个框表示,条状擦花一条擦花以一个框表示
+* 漏底、角位漏底、不导电:三者过于相似,归为一类
+* 桔皮:忽略不是大颗粒状的表面
+* 喷流:明显是一条喷流的就用一个框表示,不是的话用多个框表示
+* 漆泡:不要单独标一个点,一连串点标一个框
+* 脏点:忽略轻微脏点
+
+对数据集复核并重新标注后,将FasterRCNN-ResNet50_vd_ssld重新在训练集上进行训练,模型在验证集上的VOC mAP为81.05%。
+
+## (4) 可变形卷积加入
+
+由于喷流、漆泡的形态不规则,导致这两类的很多预测框位置不精准。为了解决该问题,选择在骨干网络ResNet50_vd中使用可变形卷积(DCN)。重新训练后,模型在验证集上的VOC mAP为88.09%,喷流的VOC AP由57.3%提升至78.7%,漆泡的VOC AP由74.7%提升至96.7%。
+
+## (5) 数据增强选择
+
+在(4)的基础上,选择加入一些数据增强策略来进一步提升模型的精度。本案例选择同时使用[RandomHorizontalFlip](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#randomhorizontalflip)、[RandomDistort](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#randomdistort)、[RandomCrop](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#randomcrop)这三种数据增强方法,重新训练后的模型在验证集上的VOC mAP为90.23%。
+
+除此之外,还可以尝试的数据增强方式有[MultiScaleTraining](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#resizebyshort)、[RandomExpand](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#randomexpand)。本案例使用的铝材表面缺陷检测数据集中,同一个类别的尺度变化不大,使用MultiScaleTraining或者RandomExpand反而使得原始数据分布发生改变。对此,本案例也进行了实验验证,使用RandomHorizontalFlip + RandomDistort + RandomCrop + MultiScaleTraining数据增强方式训练得到的模型在验证集上的VOC mAP为87.15%,使用RandomHorizontalFlip + RandomDistort + RandomCrop + RandomExpand数据增强方式训练得到的模型在验证集上的的VOC mAP为88.56%。
+
+## (6) 背景图片加入
+
+本案例将数据集中提供的背景图片按9:1切分成了1116张、135张两部分,并使用(5)中训练好的模型在135张背景图片上进行测试,发现图片级误检率高达21.5%。为了降低模型的误检率,使用[paddlex.datasets.VOCDetection.add_negative_samples](https://paddlex.readthedocs.io/zh_CN/develop/apis/datasets.html#add-negative-samples)接口将1116张背景图片加入到原本的训练集中,重新训练后图片级误检率降低至4%。为了不让训练被背景图片主导,本案例通过将`train_list.txt`中的文件路径多写了一遍,从而增加有目标图片的占比。
+
+| 模型 | VOC mAP (%) | 有缺陷图片级召回率 | 背景图片级误检率 |
+| -- | -- | -- | -- |
+| FasterRCNN-ResNet50_vd_ssld + DCN + RandomHorizontalFlip + RandomDistort + RandomCrop | 90.23 | 95.5 | 21.5 |
+| FasterRCNN-ResNet50_vd_ssld + DCN + RandomHorizontalFlip + RandomDistort + RandomCrop + 背景图片 | 88.87 | 95.2 | 4 |
+
+【名词解释】
+
+* 图片级别的召回率:只要在有目标的图片上检测出目标(不论框的个数),该图片被认为召回。批量有目标图片中被召回图片所占的比例,即为图片级别的召回率。
+* 图片级别的误检率:只要在无目标的图片上检测出目标(不论框的个数),该图片被认为误检。批量无目标图片中被误检图片所占的比例,即为图片级别的误检率。
+
+## (7) 分类损失函数选择
+
+降低误检率的措施除了(6)中提到的将背景图片加入训练,还可以将RPN部分的分类损失函数选择为`SigmoidFocalLoss`,将更多的anchors加入训练,增加难分样本的在损失函数的比重进而降低误检率。在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时将参数`rpn_cls_loss`设置为'SigmoidFocalLoss',同时需要调整参数`rpn_focal_loss_alpha`、`rpn_focal_loss_gamma`、`rpn_batch_size_per_im`、`rpn_fg_fraction`的设置。
+
+## (8) 位置回归损失函数选择
+
+RCNN部分的位置回归损失函数除了'SmoothL1Loss'以外,还可以选择'CIoULoss',使用方式在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时设置参数`rcnn_bbox_loss`即可。在本案例中,选择'CIoULoss'并没有带来精度收益,故还是选择'SmoothL1Loss'。其他质检场景下,也可尝试使用'CIoULoss'。
+
+## (9) 正负样本采样方式选择
+
+当目标物体的区域只占图像的一小部分时,可以考虑采用[LibraRCNN](https://arxiv.org/abs/1904.02701)中提出的IoU-balanced Sampling采样方式来获取更多的难分负样本。使用方式在定义模型[FasterRCNN](https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-fasterrcnn)类时将参数`bbox_assigner`设置为'LibraBBoxAssigner'即可。
+
+## (10) 预处理对比度增强
+
+工业界常用灰度相机采集图片,会存在目标与周围背景对比度不明显而无法被检测出的情况。在这种情况下,可以在定义预处理的时候使用[paddlex.det.transforms.CLAHE](https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html#clahe)对灰度图像的对比度进行增强。
+
+| 灰度图 | 对比度增加后的灰度图 |
+| -- | -- |
+| ![](./image/before_clahe.png) | ![](./image/after_clahe.png) |
+
+## (11) 样本生成
+
+对于数量较少的类别或者小目标,可以通过把这些目标物体粘贴在背景图片上来生成新的图片和标注文件,并把这些新的样本加入到训练中从而提升模型精度。目前PaddleX提供了实现该功能的接口,详细见[paddlex.det.paste_objects](https://paddlex.readthedocs.io/zh_CN/develop/apis/tools.html#paddlex-det-paste-objects),需要注意的是,前景目标颜色与背景颜色差异较大时生成的新图片才会比较逼真。

+ 214 - 0
examples/industrial_quality_inspection/cal_tp_fp.py

@@ -0,0 +1,214 @@
+# coding: utf8
+# 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.
+
+# 环境变量配置,用于控制是否使用GPU
+# 说明文档:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html#gpu
+import argparse
+import os
+os.environ['CUDA_VISIBLE_DEVICES'] = '0'
+
+import os.path as osp
+import numpy as np
+import matplotlib
+matplotlib.use('Agg')
+import matplotlib.pyplot as plt
+import paddlex as pdx
+
+
+def cal_image_level_recall_rate(model, dataset_dir):
+    """计算置信度(Score)在[0, 1]内以间隔0.01递增取值时,模型在有目标的图像上的图片级召回率。
+
+    图片级召回率:只要在有目标的图片上检测出目标(不论框的个数),该图片被认为召回,
+       批量有目标图片中被召回的图片所占的比例,即为图片级别的召回率。
+
+    Args:
+        model (PaddleX model object): 已加载的PaddleX模型。
+        dataset_dir (str):数据集路径。
+
+    Returns:
+        numpy.array: 形状为101x1的数组,对应置信度从0到1按0.01递增取值时,计算所得图片级别的召回率。
+    """
+
+    print(
+        "Begin to calculate image-level recall rate of positive images. Please wait for a moment..."
+    )
+    file_list = osp.join(dataset_dir, 'val_list.txt')
+    tp = np.zeros((101, 1))
+    positive_num = 0
+    with open(file_list, 'r') as fr:
+        while True:
+            line = fr.readline()
+            if not line:
+                break
+            img_file, xml_file = [osp.join(dataset_dir, x) \
+                    for x in line.strip().split()[:2]]
+            if not osp.exists(img_file):
+                continue
+            if not osp.exists(xml_file):
+                continue
+
+            positive_num += 1
+            results = model.predict(img_file)
+            scores = list()
+            for res in results:
+                scores.append(res['score'])
+            if len(scores) > 0:
+                tp[0:int(np.round(max(scores) / 0.01)), 0] += 1
+    tp = tp / positive_num
+    return tp
+
+
+def cal_image_level_false_positive_rate(model, negative_dir):
+    """计算置信度(Score)在[0, 1]内以间隔0.01递增取值时,模型在无目标的图像上的图片级误检率。
+
+    图片级误检率:只要在无目标的图片上检测出目标(不论框的个数),该图片被认为误检,
+       批量无目标图片中被误检的图片所占的比例,即为图片级别的误检率。
+
+    Args:
+        model (PaddleX model object): 已加载的PaddleX模型。
+        negative_dir (str):无目标图片的文件夹路径。
+
+    Returns:
+        numpy.array: 形状为101x1的数组,对应置信度从0到1按0.01递增取值时,计算所得图片级别的误检率。
+    """
+
+    print(
+        "Begin to calculate image-level false positive rate of negative(background) images. Please wait for a moment..."
+    )
+    fp = np.zeros((101, 1))
+    negative_num = 0
+    for file in os.listdir(negative_dir):
+        file = osp.join(negative_dir, file)
+        results = model.predict(file)
+        negative_num += 1
+        scores = list()
+        for res in results:
+            scores.append(res['score'])
+        if len(scores) > 0:
+            fp[0:int(np.round(max(scores) / 0.01)), 0] += 1
+    fp = fp / negative_num
+    return fp
+
+
+def result2textfile(tp_list, fp_list, save_dir):
+    """将不同置信度阈值下的图片级召回率和图片级误检率保存为文本文件。
+
+    文本文件中内容按照| 置信度阈值 | 图片级召回率 | 图片级误检率 |的格式保存。
+
+    Args:
+        tp_list (numpy.array): 形状为101x1的数组,对应置信度从0到1按0.01递增取值时,计算所得图片级别的召回率。
+        fp_list (numpy.array): 形状为101x1的数组,对应置信度从0到1按0.01递增取值时,计算所得图片级别的误检率。
+        save_dir (str): 文本文件的保存路径。
+
+    """
+
+    tp_fp_list_file = osp.join(save_dir, 'tp_fp_list.txt')
+    with open(tp_fp_list_file, 'w') as f:
+        f.write("| score | recall rate | false-positive rate |\n")
+        f.write("| -- | -- | -- |\n")
+        for i in range(100):
+            f.write("| {:2f} | {:2f} | {:2f} |\n".format(0.01 * i, tp_list[
+                i, 0], fp_list[i, 0]))
+    print("The numerical score-recall_rate-false_positive_rate is saved as {}".
+          format(tp_fp_list_file))
+
+
+def result2imagefile(tp_list, fp_list, save_dir):
+    """将不同置信度阈值下的图片级召回率和图片级误检率保存为图片。
+
+    图片中左子图横坐标表示不同置信度阈值下计算得到的图片级召回率,纵坐标表示各图片级召回率对应的图片级误检率。
+        右边子图横坐标表示图片级召回率,纵坐标表示各图片级召回率对应的置信度阈值。
+
+    Args:
+        tp_list (numpy.array): 形状为101x1的数组,对应置信度从0到1按0.01递增取值时,计算所得图片级别的召回率。
+        fp_list (numpy.array): 形状为101x1的数组,对应置信度从0到1按0.01递增取值时,计算所得图片级别的误检率。
+        save_dir (str): 文本文件的保存路径。
+
+    """
+
+    plt.subplot(1, 2, 1)
+    plt.title("image-level false_positive-recall")
+    plt.xlabel("recall")
+    plt.ylabel("false_positive")
+    plt.xlim(0, 1)
+    plt.ylim(0, 1)
+    plt.grid(linestyle='--', linewidth=1)
+    plt.plot([0, 1], [0, 1], 'r--', linewidth=1)
+    my_x_ticks = np.arange(0, 1, 0.1)
+    my_y_ticks = np.arange(0, 1, 0.1)
+    plt.xticks(my_x_ticks, fontsize=5)
+    plt.yticks(my_y_ticks, fontsize=5)
+    plt.plot(tp_list, fp_list, color='b', label="image level", linewidth=1)
+    plt.legend(loc="lower left", fontsize=5)
+
+    plt.subplot(1, 2, 2)
+    plt.title("score-recall")
+    plt.xlabel('recall')
+    plt.ylabel('score')
+    plt.xlim(0, 1)
+    plt.ylim(0, 1)
+    plt.grid(linestyle='--', linewidth=1)
+    plt.xticks(my_x_ticks, fontsize=5)
+    plt.yticks(my_y_ticks, fontsize=5)
+    plt.plot(
+        tp_list,
+        np.arange(0, 1.01, 0.01),
+        color='b',
+        label="image level",
+        linewidth=1)
+    plt.legend(loc="lower left", fontsize=5)
+    tp_fp_chart_file = os.path.join(save_dir, "image-level_tp_fp.png")
+    plt.savefig(tp_fp_chart_file, dpi=800)
+    plt.close()
+    print(
+        "The diagrammatic score-recall_rate-false_positive_rate is saved as {}".
+        format(tp_fp_chart_file))
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument(
+        "--model_dir",
+        default="./output/faster_rcnn_r50_vd_dcn/best_model/",
+        type=str,
+        help="The model directory path.")
+    parser.add_argument(
+        "--dataset_dir",
+        default="./aluminum_inspection",
+        type=str,
+        help="The VOC-format dataset directory path.")
+    parser.add_argument(
+        "--background_image_dir",
+        default="./aluminum_inspection/val_wu_xia_ci",
+        type=str,
+        help="The directory path of background images.")
+    parser.add_argument(
+        "--save_dir",
+        default="./visualize/faster_rcnn_r50_vd_dcn",
+        type=str,
+        help="The directory path of result.")
+
+    args = parser.parse_args()
+
+    if not osp.exists(args.save_dir):
+        os.makedirs(args.save_dir)
+
+    model = pdx.load_model(args.model_dir)
+
+    tp_list = cal_image_level_recall_rate(model, args.dataset_dir)
+    fp_list = cal_image_level_false_positive_rate(model,
+                                                  args.background_image_dir)
+    result2textfile(tp_list, fp_list, args.save_dir)
+    result2imagefile(tp_list, fp_list, args.save_dir)

+ 160 - 0
examples/industrial_quality_inspection/compare.py

@@ -0,0 +1,160 @@
+# coding: utf8
+# 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.
+
+# 环境变量配置,用于控制是否使用GPU
+# 说明文档:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html#gpu
+import argparse
+import os
+os.environ['CUDA_VISIBLE_DEVICES'] = '0'
+
+import os.path as osp
+import cv2
+import re
+import xml.etree.ElementTree as ET
+import paddlex as pdx
+
+
+def parse_xml_file(xml_file):
+    tree = ET.parse(xml_file)
+    pattern = re.compile('<object>', re.IGNORECASE)
+    obj_match = pattern.findall(str(ET.tostringlist(tree.getroot())))
+    if len(obj_match) == 0:
+        return False
+    obj_tag = obj_match[0][1:-1]
+    objs = tree.findall(obj_tag)
+    pattern = re.compile('<size>', re.IGNORECASE)
+    size_tag = pattern.findall(str(ET.tostringlist(tree.getroot())))[0][1:-1]
+    size_element = tree.find(size_tag)
+    pattern = re.compile('<width>', re.IGNORECASE)
+    width_tag = pattern.findall(str(ET.tostringlist(size_element)))[0][1:-1]
+    im_w = float(size_element.find(width_tag).text)
+    pattern = re.compile('<height>', re.IGNORECASE)
+    height_tag = pattern.findall(str(ET.tostringlist(size_element)))[0][1:-1]
+    im_h = float(size_element.find(height_tag).text)
+    gt_bbox = []
+    gt_class = []
+    for i, obj in enumerate(objs):
+        pattern = re.compile('<name>', re.IGNORECASE)
+        name_tag = pattern.findall(str(ET.tostringlist(obj)))[0][1:-1]
+        cname = obj.find(name_tag).text.strip()
+        gt_class.append(cname)
+        pattern = re.compile('<difficult>', re.IGNORECASE)
+        diff_tag = pattern.findall(str(ET.tostringlist(obj)))[0][1:-1]
+        try:
+            _difficult = int(obj.find(diff_tag).text)
+        except Exception:
+            _difficult = 0
+        pattern = re.compile('<bndbox>', re.IGNORECASE)
+        box_tag = pattern.findall(str(ET.tostringlist(obj)))[0][1:-1]
+        box_element = obj.find(box_tag)
+        pattern = re.compile('<xmin>', re.IGNORECASE)
+        xmin_tag = pattern.findall(str(ET.tostringlist(box_element)))[0][1:-1]
+        x1 = float(box_element.find(xmin_tag).text)
+        pattern = re.compile('<ymin>', re.IGNORECASE)
+        ymin_tag = pattern.findall(str(ET.tostringlist(box_element)))[0][1:-1]
+        y1 = float(box_element.find(ymin_tag).text)
+        pattern = re.compile('<xmax>', re.IGNORECASE)
+        xmax_tag = pattern.findall(str(ET.tostringlist(box_element)))[0][1:-1]
+        x2 = float(box_element.find(xmax_tag).text)
+        pattern = re.compile('<ymax>', re.IGNORECASE)
+        ymax_tag = pattern.findall(str(ET.tostringlist(box_element)))[0][1:-1]
+        y2 = float(box_element.find(ymax_tag).text)
+        x1 = max(0, x1)
+        y1 = max(0, y1)
+        if im_w > 0.5 and im_h > 0.5:
+            x2 = min(im_w - 1, x2)
+            y2 = min(im_h - 1, y2)
+        gt_bbox.append([x1, y1, x2, y2])
+    gts = []
+    for bbox, name in zip(gt_bbox, gt_class):
+        x1, y1, x2, y2 = bbox
+        w = x2 - x1 + 1
+        h = y2 - y1 + 1
+        gt = {
+            'category_id': 0,
+            'category': name,
+            'bbox': [x1, y1, w, h],
+            'score': 1
+        }
+        gts.append(gt)
+
+    return gts
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument(
+        "--model_dir",
+        default="./output/faster_rcnn_r50_vd_dcn/best_model/",
+        type=str,
+        help="The model directory path.")
+    parser.add_argument(
+        "--dataset_dir",
+        default="./aluminum_inspection",
+        type=str,
+        help="The VOC-format dataset directory path.")
+    parser.add_argument(
+        "--save_dir",
+        default="./visualize/compare",
+        type=str,
+        help="The directory path of result.")
+    parser.add_argument(
+        "--score_threshold",
+        default=0.1,
+        type=float,
+        help="The predicted bbox whose score is lower than score_threshold is filtered."
+    )
+
+    args = parser.parse_args()
+
+    if not os.path.exists(args.save_dir):
+        os.makedirs(args.save_dir)
+    file_list = osp.join(args.dataset_dir, 'val_list.txt')
+
+    model = pdx.load_model(args.model_dir)
+
+    with open(file_list, 'r') as fr:
+        while True:
+            line = fr.readline()
+            if not line:
+                break
+            img_file, xml_file = [osp.join(args.dataset_dir, x) \
+                    for x in line.strip().split()[:2]]
+            if not osp.exists(img_file):
+                continue
+            if not osp.exists(xml_file):
+                continue
+
+            res = model.predict(img_file)
+            gts = parse_xml_file(xml_file)
+
+            det_vis = pdx.det.visualize(
+                img_file, res, threshold=args.score_threshold, save_dir=None)
+            if gts == False:
+                gts = cv2.imread(img_file)
+            else:
+                gt_vis = pdx.det.visualize(
+                    img_file,
+                    gts,
+                    threshold=args.score_threshold,
+                    save_dir=None)
+            vis = cv2.hconcat([gt_vis, det_vis])
+            cv2.imwrite(
+                os.path.join(args.save_dir, os.path.split(img_file)[-1]), vis)
+            print('The comparison has been made for {}'.format(img_file))
+
+    print(
+        "The visualized ground-truths and predictions are saved in {}. Ground-truth is on the left, prediciton is on the right".
+        format(save_dir))

+ 14 - 0
examples/industrial_quality_inspection/dataset.md

@@ -0,0 +1,14 @@
+# 天池铝材表面缺陷检测初赛数据集示例
+
+| 序号 | 瑕疵名称 | 瑕疵成因 | 瑕疵图片示例 | 图片数量 |
+| -- | -- | -- | -- | -- |
+| 1 | 擦花(擦伤)| 表面处理(喷涂)后有轻微擦到其它的东西,造成痕迹 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/ca_hua_example.png) | 128 |
+| 2 | 杂色 | 喷涂换颜料的时候,装颜料的容器未清洗干净,造成喷涂时有少量其它颜色掺入 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/za_se_example.png) |365 |
+| 3 | 漏底 | 喷粉效果不好,铝材大量底色露出 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/lou_di_example.png) | 538 |
+| 4 | 不导电 | 直接喷不到铝材表面上去 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/bu_dao_dian_example.png) | 390 |
+|5 | 桔皮 | 表面处理后涂层表面粗糙,大颗粒 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/ju_pi_example.png) | 173 |
+| 6 | 喷流| 喷涂时油漆稀从上流下来,有流动痕迹 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/pen_liu_example.png) | 86 |
+| 7 |漆泡 | 喷涂后表面起泡,小而多| ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/qi_pao_example.png) | 82 |
+| 8 | 起坑 | 型材模具问题,做出来的型材一整条都有一条凹下去的部分 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/qi_keng_example.png.png) | 407 |
+| 9 | 脏点 | 表面处理时,有灰尘或一些脏东西未能擦掉,导致涂层有颗粒比较突出 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/zang_dian_example.png) | 261 |
+| 10 | 角位漏底 | 在型材角落出现的露底 | ![](https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/jiao_wei_lou_di_example.png) | 346 |

+ 26 - 0
examples/industrial_quality_inspection/error_analysis.py

@@ -0,0 +1,26 @@
+# coding: utf8
+# 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 os
+import os.path as osp
+import paddlex as pdx
+
+model_dir = 'output/faster_rcnn_r50_vd_dcn/best_model/'
+save_dir = 'visualize/faster_rcnn_r50_vd_dcn'
+if not osp.exists(save_dir):
+    os.makedirs(save_dir)
+
+eval_details_file = osp.join(model_dir, 'eval_details.json')
+pdx.det.coco_error_analysis(eval_details_file, save_dir=save_dir)

+ 114 - 0
examples/industrial_quality_inspection/gpu_solution.md

@@ -0,0 +1,114 @@
+# GPU端最终解决方案
+
+本案例面向GPU端的最终方案是选择二阶段检测模型FasterRCNN,其骨干网络选择加入了可变形卷积(DCN)的ResNet50_vd,训练时使用SSLD蒸馏方案训练得到的ResNet50_vd预训练模型,FPN部分的通道数量设置为64,训练阶段数据增强策略采用RandomHorizontalFlip、RandomDistort、RandomCrop,并加入背景图片,测试阶段的RPN部分做非极大值抑制计算的候选框数量由原本的6000减少至500、做完非极大值抑制后保留的候选框数量由原本的1000减少至300。
+
+在Tesla P40的Linux系统下,对于输入大小是800 x 1333的模型,图像预处理时长为30ms/image,模型的推理时间为46.08ms/image,包括输入数据拷贝至GPU的时间、计算时间、数据拷贝至CPU的时间。
+
+| 模型 | VOC mAP (%) | 推理时间 (ms/image)
+| -- | -- | -- |
+| FasterRCNN-ResNet50_vd_ssld | 81.05 | 48.62 |
+| + dcn | 88.09 | 66.51 |
+| + RandomHorizontalFlip/RandomDistort/RandomCrop | 90.23| 66.51 |
+| + background images | 88.87 | 66.51 |
+| + fpn channel=64 | 87.79 | 48.65 |
+| + test proposal=pre/post topk 500/300 | 87.72 | 46.08 |
+
+## 前置依赖
+
+* Paddle paddle >= 1.8.0
+* Python >= 3.5
+* PaddleX >= 1.3.0
+
+## 模型训练
+
+### (1) 下载PaddleX源码
+
+```
+git clone https://github.com/PaddlePaddle/PaddleX
+
+cd PaddleX/examples/industrial_quality_inspection
+```
+
+### (2) 下载数据集
+
+因数据集较大,可运行以下代码提前将数据集下载并解压。训练代码中也会自动下载数据集,所以这一步不是必须的。
+
+```
+wget https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/aluminum_inspection.tar.gz
+tar xvf aluminum_inspection.tar.gz
+```
+### (3) 下载预先训练好的模型
+
+如果不想再次训练模型,可以直接下载已经训练好的模型完成后面的模型测试和部署推理:
+
+```
+wget https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/models/faster_rcnn_r50_vd_dcn.tar.gz
+tar xvf faster_rcnn_r50_vd_dcn.tar.gz
+```
+### (4) 训练
+
+运行以下代码进行模型训练,代码会自动下载数据集,如若事先下载了数据集,需将下载和解压铝材缺陷检测数据集的相关行注释掉。代码中默认使用0,1,2,3,4号GPU训练,可根据实际情况设置卡号并调整`batch_size`和`learning_rate`。
+
+```
+python train_rcnn.py
+```
+
+### (5) 分析预测错误的原因
+
+在模型迭代过程中,运行以下代码可完成模型效果的分析并生成分析结果图表:
+
+```
+python error_analysis.py
+```
+
+可参考[性能优化部分的模型效果分析](./accuracy_improvement.md#2-%E6%A8%A1%E5%9E%8B%E6%95%88%E6%9E%9C%E5%88%86%E6%9E%90)来理解当前模型预测错误的原因。
+
+运行以下代码,生成可视化真值和预测结果的对比图以进一步理解模型效果,代码中的置信度阈值可根据实际情况进行调整。
+
+```
+python compare.py
+```
+
+![](image/compare_budaodian-116.jpg)
+
+左边是可视化真值,右边是可视化预测结果。
+
+### (6) 统计图片级召回率和误检率
+
+模型迭代完成后,计算不同置信度阈值下[图片级召回率](./accuracy_improvement.md#6-%E8%83%8C%E6%99%AF%E5%9B%BE%E7%89%87%E5%8A%A0%E5%85%A5)和[图片级误检率](./accuracy_improvement.md#6-%E8%83%8C%E6%99%AF%E5%9B%BE%E7%89%87%E5%8A%A0%E5%85%A5),找到符合要求的召回率和误检率,对应的置信度阈值用于后续模型预测阶段。
+
+```
+python cal_tp_fp.py
+```
+
+执行后会生成图表`image-level_tp_fp.png`和文件`tp_fp_list.txt`,示意如下:
+
+| 图表`image-level_tp_fp.png` | 文件`tp_fp_list.txt` |
+| -- | -- |
+| ![](./image/image-level_tp_fp.png) | [tp_fp_list.txt](tp_fp_list.md) |
+
+图表`image-level_tp_fp.png`中左边子图,横坐标表示不同置信度阈值下计算得到的图片级召回率,纵坐标表示各图片级召回率对应的图片级误检率。右边子图横坐标表示图片级召回率,纵坐标表示各图片级召回率对应的置信度阈值。从图表中可较为直观地看出当前模型的图片级召回率和误检率的量级,从文件`tp_fp_list.txt`可以查到具体数值,例如在图片级召回率/图片级误检率为[0.9589,0.0074]这一组符合要求,就将对应的置信度阈值0.90选取为后续预测推理的阈值。
+
+### (7) 模型测试
+
+测试集因没有标注文件,这里单独下载测试集图片:
+
+```
+wget https://bj.bcebos.com/paddlex/examples/industrial_quality_inspection/datasets/aluminum_inspection_test.tar.gz
+tar xvf aluminum_inspection_test.tar.gz
+```
+
+加载训练好的模型,使用(5)选取的置信度阈值0.90对验证集图片或者测试集图片进行预测:
+
+```
+python predict.py
+```
+可视化预测结果示例如下:
+
+![](image/visualize_budaodian-116.jpg)
+
+## 推理部署
+
+本案例采用C++部署方式将模型部署在Tesla P40的Linux系统下,具体的C++部署流程请参考文档[PaddleX模型多端安全部署/C++部署](https://paddlex.readthedocs.io/zh_CN/develop/deploy/server/cpp/index.html)。
+
+对于输入大小是800 x 1333的模型,图像预处理时长为30ms/image。值得一提的是预处理中的Normalize操作比较耗时,因此在设置预处理操作时,可以先进行Resize操作再做Normalize。模型的推理时间为46.08ms/image,包括输入数据拷贝至GPU的时间、计算时间、数据拷贝至CPU的时间。

BIN=BIN
examples/industrial_quality_inspection/image/after_clahe.png


BIN=BIN
examples/industrial_quality_inspection/image/allclasses_analysis_example.png


BIN=BIN
examples/industrial_quality_inspection/image/before_clahe.png


BIN=BIN
examples/industrial_quality_inspection/image/budaodian_analysis_example.png


BIN=BIN
examples/industrial_quality_inspection/image/cahua_analysis_example.png


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio