未验证 提交 15e57db2 编写于 作者: S SunAhong1993 提交者: GitHub

Merge pull request #3 from PaddlePaddle/develop

00
- repo: local - repo: https://github.com/PaddlePaddle/mirrors-yapf.git
sha: 0d79c0c469bab64f7229c9aca2b1186ef47f0e37
hooks: hooks:
- id: yapf - id: yapf
name: yapf
entry: yapf
language: system
args: [-i, --style .style.yapf]
files: \.py$ files: \.py$
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
sha: a11d9314b22d8f8c7556443875b731ef05965464 sha: a11d9314b22d8f8c7556443875b731ef05965464
hooks: hooks:
......
<img src="./paddlex.png" width = "300" height = "47" alt="PaddleX" align=center /> <p align="center">
<img src="./docs/images/paddlex.png" width="360" height ="60" alt="PaddleX" align="middle" />
</p>
[![License](https://img.shields.io/badge/license-Apache%202-red.svg)](LICENSE) [![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) [![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) ![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) ![support os](https://img.shields.io/badge/os-linux%2C%20win%2C%20mac-yellow.svg)
PaddleX是基于飞桨开发套件和工具组件的深度学习全流程开发工具。具备易集成,易使用,全流程等特点。PaddleX作为深度学习开发工具,不仅提供了开源的内核代码,可供用户灵活使用或集成,同时也提供了配套的前端可视化客户端套件,让用户以可视化的方式进行模型开发,免去代码开发过程 PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习全流程开发工具。具备**全流程打通****融合产业实践****易用易集成**三大特点
访问[PaddleX官网](https://www.paddlepaddle.org.cn/paddle/paddlex)获取更多细节。 ## 特点
## 快速安装 - **全流程打通**
- 数据准备:支持LabelMe,精灵标注等主流数据标注工具协议,同时无缝集成[EasyData智能数据服务平台](https://ai.baidu.com/easydata/), 助力开发者高效获取AI开发所需高质量数据。
- 模型训练:基于飞桨核心框架集成[PaddleClas](https://github.com/PaddlePaddle/PaddleClas), [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection), [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg)视觉开发套件,[VisualDL](https://github.com/PaddlePaddle/VisualDL)可视化分析组件,高效完成模型训练。
- 多端部署:内置[PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim)模型压缩工具和AES模型加密SDK,结合Paddle Inference和[Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite)便捷完成高性能且可靠的多端部署。
PaddleX提供两种使用模式,满足不同的场景和用户需求: - **融合产业实践**
- **开发模式:** pip安装后,开发者可通过Python API调用方式更灵活地完成模型的训练与软件集成 - 精选飞桨产业实践的成熟模型结构,开放案例实践教程,加速开发者产业落地
- **可视化模式:** 通过绿色安装的跨平台软件包,用户即可开箱即用,以可视化方式快速体验飞桨深度学习的全流程 - 通过[PaddleHub](https://github.com/PaddlePaddle/Paddle)内置丰富的飞桨高质量预训练模型,助力开发者高效实现飞桨Master模式
### 开发模式 - **易用易集成**
- PadldeX提供简洁易用的全流程API,几行代码即可实现上百种数据增强、模型可解释性、C++模型部署等功能。
- 提供以PaddleX API为核心集成的跨平台GUI界面,降低深度学习全流程应用门槛。
## 安装
PaddleX提供两种开发模式,满足不同场景和用户需求:
- **Python开发模式:** 通过Python API方式完成全流程使用或集成,该模型提供全面、灵活、开放的深度学习功能,有更高的定制化空间。
- **GUI开发模式:** 以PaddleX API为核心集成的跨平台GUI客户端,支持`Python开发模式`下的常用功能,以更低门槛的方式快速完成产业验证的模型训练。
开发者可根据自身需要按需选择不同的模式进行安装使用。
### Python开发模式安装
**前置依赖** **前置依赖**
* paddlepaddle >= 1.7.0 * paddlepaddle >= 1.8.0
* python >= 3.5 * python >= 3.5
* cython * cython
* pycocotools * pycocotools
...@@ -27,36 +48,39 @@ PaddleX提供两种使用模式,满足不同的场景和用户需求: ...@@ -27,36 +48,39 @@ PaddleX提供两种使用模式,满足不同的场景和用户需求:
pip install paddlex -i https://mirror.baidu.com/pypi/simple pip install paddlex -i https://mirror.baidu.com/pypi/simple
``` ```
### 可视化模式 ### GUI开发模式安装
进入PaddleX官网[下载使用](https://www.paddlepaddle.org.cn/paddle/paddlex),申请下载绿色安装包,开箱即用。 进入PaddleX官网[下载使用](https://www.paddlepaddle.org.cn/paddle/paddlex),申请下载绿色安装包,开箱即用。
GUI模式的使用教程可参考[PaddleX GUI模式使用教程](https://paddlex.readthedocs.io/zh_CN/latest/paddlex_gui/index.html)
## 文档 ## 使用文档
推荐访问[PaddleX在线使用文档](https://paddlex.readthedocs.io/zh_CN/latest/index.html),快速查阅读使用教程和API文档说明。 推荐访问[PaddleX在线使用文档](https://paddlex.readthedocs.io/zh_CN/latest/index.html),快速查阅读使用教程和API文档说明。
- [10分钟快速上手PaddleX模型训练](docs/quick_start.md) - [10分钟快速上手](https://paddlex.readthedocs.io/zh_CN/latest/quick_start.html)
- [PaddleX使用教程](docs/tutorials) - [PaddleX模型训练](https://paddlex.readthedocs.io/zh_CN/latest/tutorials/train/index.html#id1)
- [PaddleX模型库](docs/model_zoo.md) - [PaddleX模型压缩](https://paddlex.readthedocs.io/zh_CN/latest/slim/index.html#id1)
- [模型多端部署](docs/deploy.md) - [PaddleX模型库](https://paddlex.readthedocs.io/zh_CN/latest/model_zoo.html#id1)
- [PaddleX可视化模式进行模型训练](docs/client_use.md) - [PaddleX多端部署](docs/deploy.md)
## 在线教程
基于AIStudio平台,快速在线体验PaddleX的Python开发模式教程。
- [PaddleX快速上手——MobileNetV3-ssld 化妆品分类](https://aistudio.baidu.com/aistudio/projectdetail/450220)
- [PaddleX快速上手——Faster-RCNN AI识虫](https://aistudio.baidu.com/aistudio/projectdetail/439888)
- [PaddleX快速上手——DeepLabv3+ 视盘分割](https://aistudio.baidu.com/aistudio/projectdetail/440197)
## 反馈 ## 交流与反馈
- 项目官网: https://www.paddlepaddle.org.cn/paddle/paddlex - 项目官网: https://www.paddlepaddle.org.cn/paddle/paddlex
- PaddleX用户QQ群: 1045148026 (手机QQ扫描如下二维码快速加入) - PaddleX用户QQ群: 1045148026 (手机QQ扫描如下二维码快速加入)
<img src="./QQGroup.jpeg" width="195" height="300" alt="QQGroup" align=center /> <img src="./docs/images/QQGroup.jpeg" width="195" height="300" alt="QQGroup" align="center" />
## FAQ
## 飞桨技术生态 ## 更新日志
PaddleX全流程开发工具依赖以下飞桨开发套件与工具组件 ## 贡献代码
- [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection) 我们非常欢迎您为PaddleX贡献代码或者提供使用建议。如果您可以修复某个issue或者增加一个新功能,欢迎给我们提交Pull Requests.
- [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg)
- [PaddleClas](https://github.com/PaddlePaddle/PaddleClas)
- [PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim)
- [PaddleHub](https://github.com/PaddlePaddle/PaddleHub)
- [Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite)
- [VisualDL](https://github.com/PaddlePaddle/VisualDL)
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
本目录为PaddleX模型部署代码, 编译和使用的教程参考: 本目录为PaddleX模型部署代码, 编译和使用的教程参考:
- [C++部署文档](../docs/deploy/deploy.md#C部署) - [C++部署文档](../docs/tutorials/deploy/deploy.md#C部署)
- [OpenVINO部署文档](../docs/tutorials/deploy/deploy.md#openvino部署)
...@@ -5,12 +5,29 @@ option(WITH_MKL "Compile demo with MKL/OpenBlas support,defaultuseMKL." ...@@ -5,12 +5,29 @@ option(WITH_MKL "Compile demo with MKL/OpenBlas support,defaultuseMKL."
option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." ON) option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." ON)
option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." OFF) option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." OFF)
option(WITH_TENSORRT "Compile demo with TensorRT." OFF) option(WITH_TENSORRT "Compile demo with TensorRT." OFF)
option(WITH_ENCRYPTION "Compile demo with encryption tool." OFF)
SET(TENSORRT_DIR "" CACHE PATH "Compile demo with TensorRT") SET(TENSORRT_DIR "" CACHE PATH "Location of libraries")
SET(PADDLE_DIR "" CACHE PATH "Location of libraries") SET(PADDLE_DIR "" CACHE PATH "Location of libraries")
SET(OPENCV_DIR "" CACHE PATH "Location of libraries") SET(OPENCV_DIR "" CACHE PATH "Location of libraries")
SET(ENCRYPTION_DIR"" CACHE PATH "Location of libraries")
SET(CUDA_LIB "" CACHE PATH "Location of libraries") SET(CUDA_LIB "" CACHE PATH "Location of libraries")
if (NOT WIN32)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/demo)
else()
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/paddlex_inference)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/paddlex_inference)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/paddlex_inference)
endif()
if (NOT WIN32)
SET(YAML_BUILD_TYPE ON CACHE BOOL "yaml build shared library.")
else()
SET(YAML_BUILD_TYPE OFF CACHE BOOL "yaml build shared library.")
endif()
include(cmake/yaml-cpp.cmake) include(cmake/yaml-cpp.cmake)
include_directories("${CMAKE_SOURCE_DIR}/") include_directories("${CMAKE_SOURCE_DIR}/")
...@@ -27,6 +44,11 @@ macro(safe_set_static_flag) ...@@ -27,6 +44,11 @@ macro(safe_set_static_flag)
endforeach(flag_var) endforeach(flag_var)
endmacro() endmacro()
if (WITH_ENCRYPTION)
add_definitions( -DWITH_ENCRYPTION=${WITH_ENCRYPTION})
endif()
if (WITH_MKL) if (WITH_MKL)
ADD_DEFINITIONS(-DUSE_MKL) ADD_DEFINITIONS(-DUSE_MKL)
endif() endif()
...@@ -183,6 +205,7 @@ else() ...@@ -183,6 +205,7 @@ else()
set(DEPS ${DEPS} set(DEPS ${DEPS}
${MATH_LIB} ${MKLDNN_LIB} ${MATH_LIB} ${MKLDNN_LIB}
glog gflags_static libprotobuf zlibstatic xxhash libyaml-cppmt) glog gflags_static libprotobuf zlibstatic xxhash libyaml-cppmt)
set(DEPS ${DEPS} libcmt shlwapi) set(DEPS ${DEPS} libcmt shlwapi)
if (EXISTS "${PADDLE_DIR}/third_party/install/snappy/lib") if (EXISTS "${PADDLE_DIR}/third_party/install/snappy/lib")
set(DEPS ${DEPS} snappy) set(DEPS ${DEPS} snappy)
...@@ -207,21 +230,35 @@ if(WITH_GPU) ...@@ -207,21 +230,35 @@ if(WITH_GPU)
endif() endif()
endif() endif()
if(WITH_ENCRYPTION)
if(NOT WIN32)
include_directories("${ENCRYPTION_DIR}/include")
link_directories("${ENCRYPTION_DIR}/lib")
set(DEPS ${DEPS} ${ENCRYPTION_DIR}/lib/libpmodel-decrypt${CMAKE_SHARED_LIBRARY_SUFFIX})
else()
message(FATAL_ERROR "Encryption Tool don't support WINDOWS")
endif()
endif()
if (NOT WIN32) if (NOT WIN32)
set(EXTERNAL_LIB "-ldl -lrt -lgomp -lz -lm -lpthread") set(EXTERNAL_LIB "-ldl -lrt -lgomp -lz -lm -lpthread")
set(DEPS ${DEPS} ${EXTERNAL_LIB}) set(DEPS ${DEPS} ${EXTERNAL_LIB})
endif() endif()
set(DEPS ${DEPS} ${OpenCV_LIBS}) set(DEPS ${DEPS} ${OpenCV_LIBS})
add_executable(classifier src/classifier.cpp src/transforms.cpp src/paddlex.cpp) add_library(paddlex_inference SHARED src/visualize src/transforms.cpp src/paddlex.cpp)
ADD_DEPENDENCIES(paddlex_inference ext-yaml-cpp)
target_link_libraries(paddlex_inference ${DEPS})
add_executable(classifier demo/classifier.cpp src/transforms.cpp src/paddlex.cpp)
ADD_DEPENDENCIES(classifier ext-yaml-cpp) ADD_DEPENDENCIES(classifier ext-yaml-cpp)
target_link_libraries(classifier ${DEPS}) target_link_libraries(classifier ${DEPS})
add_executable(detector src/detector.cpp src/transforms.cpp src/paddlex.cpp src/visualize.cpp) add_executable(detector demo/detector.cpp src/transforms.cpp src/paddlex.cpp src/visualize.cpp)
ADD_DEPENDENCIES(detector ext-yaml-cpp) ADD_DEPENDENCIES(detector ext-yaml-cpp)
target_link_libraries(detector ${DEPS}) target_link_libraries(detector ${DEPS})
add_executable(segmenter src/segmenter.cpp src/transforms.cpp src/paddlex.cpp src/visualize.cpp) add_executable(segmenter demo/segmenter.cpp src/transforms.cpp src/paddlex.cpp src/visualize.cpp)
ADD_DEPENDENCIES(segmenter ext-yaml-cpp) ADD_DEPENDENCIES(segmenter ext-yaml-cpp)
target_link_libraries(segmenter ${DEPS}) target_link_libraries(segmenter ${DEPS})
...@@ -252,3 +289,14 @@ if (WIN32 AND WITH_MKL) ...@@ -252,3 +289,14 @@ if (WIN32 AND WITH_MKL)
) )
endif() endif()
file(COPY "${CMAKE_SOURCE_DIR}/include/paddlex/visualize.h"
DESTINATION "${CMAKE_BINARY_DIR}/include/" )
file(COPY "${CMAKE_SOURCE_DIR}/include/paddlex/config_parser.h"
DESTINATION "${CMAKE_BINARY_DIR}/include/" )
file(COPY "${CMAKE_SOURCE_DIR}/include/paddlex/transforms.h"
DESTINATION "${CMAKE_BINARY_DIR}/include/" )
file(COPY "${CMAKE_SOURCE_DIR}/include/paddlex/results.h"
DESTINATION "${CMAKE_BINARY_DIR}/include/" )
file(COPY "${CMAKE_SOURCE_DIR}/include/paddlex/paddlex.h"
DESTINATION "${CMAKE_BINARY_DIR}/include/" )
...@@ -14,7 +14,7 @@ ExternalProject_Add( ...@@ -14,7 +14,7 @@ ExternalProject_Add(
-DYAML_CPP_INSTALL=OFF -DYAML_CPP_INSTALL=OFF
-DYAML_CPP_BUILD_CONTRIB=OFF -DYAML_CPP_BUILD_CONTRIB=OFF
-DMSVC_SHARED_RT=OFF -DMSVC_SHARED_RT=OFF
-DBUILD_SHARED_LIBS=OFF -DBUILD_SHARED_LIBS=${YAML_BUILD_TYPE}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG} -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG}
......
...@@ -25,6 +25,7 @@ DEFINE_string(model_dir, "", "Path of inference model"); ...@@ -25,6 +25,7 @@ DEFINE_string(model_dir, "", "Path of inference model");
DEFINE_bool(use_gpu, false, "Infering with GPU or CPU"); DEFINE_bool(use_gpu, false, "Infering with GPU or CPU");
DEFINE_bool(use_trt, false, "Infering with TensorRT"); DEFINE_bool(use_trt, false, "Infering with TensorRT");
DEFINE_int32(gpu_id, 0, "GPU card id"); DEFINE_int32(gpu_id, 0, "GPU card id");
DEFINE_string(key, "", "key of encryption");
DEFINE_string(image, "", "Path of test image file"); DEFINE_string(image, "", "Path of test image file");
DEFINE_string(image_list, "", "Path of test image list file"); DEFINE_string(image_list, "", "Path of test image list file");
...@@ -43,7 +44,7 @@ int main(int argc, char** argv) { ...@@ -43,7 +44,7 @@ int main(int argc, char** argv) {
// 加载模型 // 加载模型
PaddleX::Model model; PaddleX::Model model;
model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id); model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id, FLAGS_key);
// 进行预测 // 进行预测
if (FLAGS_image_list != "") { if (FLAGS_image_list != "") {
......
...@@ -26,6 +26,7 @@ DEFINE_string(model_dir, "", "Path of inference model"); ...@@ -26,6 +26,7 @@ DEFINE_string(model_dir, "", "Path of inference model");
DEFINE_bool(use_gpu, false, "Infering with GPU or CPU"); DEFINE_bool(use_gpu, false, "Infering with GPU or CPU");
DEFINE_bool(use_trt, false, "Infering with TensorRT"); DEFINE_bool(use_trt, false, "Infering with TensorRT");
DEFINE_int32(gpu_id, 0, "GPU card id"); DEFINE_int32(gpu_id, 0, "GPU card id");
DEFINE_string(key, "", "key of encryption");
DEFINE_string(image, "", "Path of test image file"); DEFINE_string(image, "", "Path of test image file");
DEFINE_string(image_list, "", "Path of test image list file"); DEFINE_string(image_list, "", "Path of test image list file");
DEFINE_string(save_dir, "output", "Path to save visualized image"); DEFINE_string(save_dir, "output", "Path to save visualized image");
...@@ -45,7 +46,7 @@ int main(int argc, char** argv) { ...@@ -45,7 +46,7 @@ int main(int argc, char** argv) {
// 加载模型 // 加载模型
PaddleX::Model model; PaddleX::Model model;
model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id); model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id, FLAGS_key);
auto colormap = PaddleX::GenerateColorMap(model.labels.size()); auto colormap = PaddleX::GenerateColorMap(model.labels.size());
std::string save_dir = "output"; std::string save_dir = "output";
...@@ -74,7 +75,7 @@ int main(int argc, char** argv) { ...@@ -74,7 +75,7 @@ int main(int argc, char** argv) {
// 可视化 // 可视化
cv::Mat vis_img = cv::Mat vis_img =
PaddleX::VisualizeDet(im, result, model.labels, colormap, 0.5); PaddleX::Visualize(im, result, model.labels, colormap, 0.5);
std::string save_path = std::string save_path =
PaddleX::generate_save_path(FLAGS_save_dir, image_path); PaddleX::generate_save_path(FLAGS_save_dir, image_path);
cv::imwrite(save_path, vis_img); cv::imwrite(save_path, vis_img);
...@@ -97,7 +98,7 @@ int main(int argc, char** argv) { ...@@ -97,7 +98,7 @@ int main(int argc, char** argv) {
// 可视化 // 可视化
cv::Mat vis_img = cv::Mat vis_img =
PaddleX::VisualizeDet(im, result, model.labels, colormap, 0.5); PaddleX::Visualize(im, result, model.labels, colormap, 0.5);
std::string save_path = std::string save_path =
PaddleX::generate_save_path(FLAGS_save_dir, FLAGS_image); PaddleX::generate_save_path(FLAGS_save_dir, FLAGS_image);
cv::imwrite(save_path, vis_img); cv::imwrite(save_path, vis_img);
......
...@@ -26,6 +26,7 @@ DEFINE_string(model_dir, "", "Path of inference model"); ...@@ -26,6 +26,7 @@ DEFINE_string(model_dir, "", "Path of inference model");
DEFINE_bool(use_gpu, false, "Infering with GPU or CPU"); DEFINE_bool(use_gpu, false, "Infering with GPU or CPU");
DEFINE_bool(use_trt, false, "Infering with TensorRT"); DEFINE_bool(use_trt, false, "Infering with TensorRT");
DEFINE_int32(gpu_id, 0, "GPU card id"); DEFINE_int32(gpu_id, 0, "GPU card id");
DEFINE_string(key, "", "key of encryption");
DEFINE_string(image, "", "Path of test image file"); DEFINE_string(image, "", "Path of test image file");
DEFINE_string(image_list, "", "Path of test image list file"); DEFINE_string(image_list, "", "Path of test image list file");
DEFINE_string(save_dir, "output", "Path to save visualized image"); DEFINE_string(save_dir, "output", "Path to save visualized image");
...@@ -45,7 +46,7 @@ int main(int argc, char** argv) { ...@@ -45,7 +46,7 @@ int main(int argc, char** argv) {
// 加载模型 // 加载模型
PaddleX::Model model; PaddleX::Model model;
model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id); model.Init(FLAGS_model_dir, FLAGS_use_gpu, FLAGS_use_trt, FLAGS_gpu_id, FLAGS_key);
auto colormap = PaddleX::GenerateColorMap(model.labels.size()); auto colormap = PaddleX::GenerateColorMap(model.labels.size());
// 进行预测 // 进行预测
...@@ -62,7 +63,7 @@ int main(int argc, char** argv) { ...@@ -62,7 +63,7 @@ int main(int argc, char** argv) {
model.predict(im, &result); model.predict(im, &result);
// 可视化 // 可视化
cv::Mat vis_img = cv::Mat vis_img =
PaddleX::VisualizeSeg(im, result, model.labels, colormap); PaddleX::Visualize(im, result, model.labels, colormap);
std::string save_path = std::string save_path =
PaddleX::generate_save_path(FLAGS_save_dir, image_path); PaddleX::generate_save_path(FLAGS_save_dir, image_path);
cv::imwrite(save_path, vis_img); cv::imwrite(save_path, vis_img);
...@@ -74,7 +75,7 @@ int main(int argc, char** argv) { ...@@ -74,7 +75,7 @@ int main(int argc, char** argv) {
cv::Mat im = cv::imread(FLAGS_image, 1); cv::Mat im = cv::imread(FLAGS_image, 1);
model.predict(im, &result); model.predict(im, &result);
// 可视化 // 可视化
cv::Mat vis_img = PaddleX::VisualizeSeg(im, result, model.labels, colormap); cv::Mat vis_img = PaddleX::Visualize(im, result, model.labels, colormap);
std::string save_path = std::string save_path =
PaddleX::generate_save_path(FLAGS_save_dir, FLAGS_image); PaddleX::generate_save_path(FLAGS_save_dir, FLAGS_image);
cv::imwrite(save_path, vis_img); cv::imwrite(save_path, vis_img);
......
...@@ -28,9 +28,14 @@ ...@@ -28,9 +28,14 @@
#include "paddle_inference_api.h" // NOLINT #include "paddle_inference_api.h" // NOLINT
#include "include/paddlex/config_parser.h" #include "config_parser.h"
#include "include/paddlex/results.h" #include "results.h"
#include "include/paddlex/transforms.h" #include "transforms.h"
#ifdef WITH_ENCRYPTION
#include "paddle_model_decrypt.h"
#include "model_code.h"
#endif
namespace PaddleX { namespace PaddleX {
...@@ -39,14 +44,16 @@ class Model { ...@@ -39,14 +44,16 @@ class Model {
void Init(const std::string& model_dir, void Init(const std::string& model_dir,
bool use_gpu = false, bool use_gpu = false,
bool use_trt = false, bool use_trt = false,
int gpu_id = 0) { int gpu_id = 0,
create_predictor(model_dir, use_gpu, use_trt, gpu_id); std::string key = "") {
create_predictor(model_dir, use_gpu, use_trt, gpu_id, key);
} }
void create_predictor(const std::string& model_dir, void create_predictor(const std::string& model_dir,
bool use_gpu = false, bool use_gpu = false,
bool use_trt = false, bool use_trt = false,
int gpu_id = 0); int gpu_id = 0,
std::string key = "");
bool load_config(const std::string& model_dir); bool load_config(const std::string& model_dir);
......
...@@ -46,13 +46,13 @@ namespace PaddleX { ...@@ -46,13 +46,13 @@ namespace PaddleX {
// Generate visualization colormap for each class // Generate visualization colormap for each class
std::vector<int> GenerateColorMap(int num_class); std::vector<int> GenerateColorMap(int num_class);
cv::Mat VisualizeDet(const cv::Mat& img, cv::Mat Visualize(const cv::Mat& img,
const DetResult& results, const DetResult& results,
const std::map<int, std::string>& labels, const std::map<int, std::string>& labels,
const std::vector<int>& colormap, const std::vector<int>& colormap,
float threshold = 0.5); float threshold = 0.5);
cv::Mat VisualizeSeg(const cv::Mat& img, cv::Mat Visualize(const cv::Mat& img,
const SegResult& result, const SegResult& result,
const std::map<int, std::string>& labels, const std::map<int, std::string>& labels,
const std::vector<int>& colormap); const std::vector<int>& colormap);
......
...@@ -16,6 +16,11 @@ CUDA_LIB=/path/to/cuda/lib/ ...@@ -16,6 +16,11 @@ CUDA_LIB=/path/to/cuda/lib/
# CUDNN 的 lib 路径 # CUDNN 的 lib 路径
CUDNN_LIB=/path/to/cudnn/lib/ CUDNN_LIB=/path/to/cudnn/lib/
# 是否加载加密后的模型
WITH_ENCRYPTION=OFF
# 加密工具的路径
ENCRYPTION_DIR=/path/to/encryption_tool/
# OPENCV 路径, 如果使用自带预编译版本可不修改 # OPENCV 路径, 如果使用自带预编译版本可不修改
OPENCV_DIR=$(pwd)/deps/opencv3gcc4.8/ OPENCV_DIR=$(pwd)/deps/opencv3gcc4.8/
sh $(pwd)/scripts/bootstrap.sh sh $(pwd)/scripts/bootstrap.sh
...@@ -28,10 +33,12 @@ cmake .. \ ...@@ -28,10 +33,12 @@ cmake .. \
-DWITH_GPU=${WITH_GPU} \ -DWITH_GPU=${WITH_GPU} \
-DWITH_MKL=${WITH_MKL} \ -DWITH_MKL=${WITH_MKL} \
-DWITH_TENSORRT=${WITH_TENSORRT} \ -DWITH_TENSORRT=${WITH_TENSORRT} \
-DWITH_ENCRYPTION=${WITH_ENCRYPTION} \
-DTENSORRT_DIR=${TENSORRT_DIR} \ -DTENSORRT_DIR=${TENSORRT_DIR} \
-DPADDLE_DIR=${PADDLE_DIR} \ -DPADDLE_DIR=${PADDLE_DIR} \
-DWITH_STATIC_LIB=${WITH_STATIC_LIB} \ -DWITH_STATIC_LIB=${WITH_STATIC_LIB} \
-DCUDA_LIB=${CUDA_LIB} \ -DCUDA_LIB=${CUDA_LIB} \
-DCUDNN_LIB=${CUDNN_LIB} \ -DCUDNN_LIB=${CUDNN_LIB} \
-DENCRYPTION_DIR=${ENCRYPTION_DIR} \
-DOPENCV_DIR=${OPENCV_DIR} -DOPENCV_DIR=${OPENCV_DIR}
make make
...@@ -19,7 +19,8 @@ namespace PaddleX { ...@@ -19,7 +19,8 @@ namespace PaddleX {
void Model::create_predictor(const std::string& model_dir, void Model::create_predictor(const std::string& model_dir,
bool use_gpu, bool use_gpu,
bool use_trt, bool use_trt,
int gpu_id) { int gpu_id,
std::string key) {
// 读取配置文件 // 读取配置文件
if (!load_config(model_dir)) { if (!load_config(model_dir)) {
std::cerr << "Parse file 'model.yml' failed!" << std::endl; std::cerr << "Parse file 'model.yml' failed!" << std::endl;
...@@ -28,7 +29,14 @@ void Model::create_predictor(const std::string& model_dir, ...@@ -28,7 +29,14 @@ void Model::create_predictor(const std::string& model_dir,
paddle::AnalysisConfig config; paddle::AnalysisConfig config;
std::string model_file = model_dir + OS_PATH_SEP + "__model__"; std::string model_file = model_dir + OS_PATH_SEP + "__model__";
std::string params_file = model_dir + OS_PATH_SEP + "__params__"; std::string params_file = model_dir + OS_PATH_SEP + "__params__";
config.SetModel(model_file, params_file); #ifdef WITH_ENCRYPTION
if (key != ""){
paddle_security_load_model(&config, key.c_str(), model_file.c_str(), params_file.c_str());
}
#endif
if (key == ""){
config.SetModel(model_file, params_file);
}
if (use_gpu) { if (use_gpu) {
config.EnableUseGpu(100, gpu_id); config.EnableUseGpu(100, gpu_id);
} else { } else {
......
...@@ -31,7 +31,7 @@ std::vector<int> GenerateColorMap(int num_class) { ...@@ -31,7 +31,7 @@ std::vector<int> GenerateColorMap(int num_class) {
return colormap; return colormap;
} }
cv::Mat VisualizeDet(const cv::Mat& img, cv::Mat Visualize(const cv::Mat& img,
const DetResult& result, const DetResult& result,
const std::map<int, std::string>& labels, const std::map<int, std::string>& labels,
const std::vector<int>& colormap, const std::vector<int>& colormap,
...@@ -105,7 +105,7 @@ cv::Mat VisualizeDet(const cv::Mat& img, ...@@ -105,7 +105,7 @@ cv::Mat VisualizeDet(const cv::Mat& img,
return vis_img; return vis_img;
} }
cv::Mat VisualizeSeg(const cv::Mat& img, cv::Mat Visualize(const cv::Mat& img,
const SegResult& result, const SegResult& result,
const std::map<int, std::string>& labels, const std::map<int, std::string>& labels,
const std::vector<int>& colormap) { const std::vector<int>& colormap) {
......
cmake_minimum_required(VERSION 3.0)
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(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")
include(cmake/yaml-cpp.cmake)
include_directories("${CMAKE_SOURCE_DIR}/")
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 OPENVINO_DIR OR ${OPENVINO_DIR} STREQUAL "")
message(FATAL_ERROR "please set OPENVINO_DIR with -DOPENVINO_DIR=/path/influence_engine")
endif()
if (NOT DEFINED OPENCV_DIR OR ${OPENCV_DIR} STREQUAL "")
message(FATAL_ERROR "please set OPENCV_DIR with -DOPENCV_DIR=/path/opencv")
endif()
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 NGRAPH_LIB OR ${NGRAPH_LIB} STREQUAL "")
message(FATAL_ERROR "please set NGRAPH_DIR with -DNGRAPH_DIR=/path/ngraph")
endif()
include_directories("${OPENVINO_DIR}")
link_directories("${OPENVINO_DIR}/lib")
include_directories("${OPENVINO_DIR}/include")
link_directories("${OPENVINO_DIR}/external/tbb/lib")
include_directories("${OPENVINO_DIR}/external/tbb/include/tbb")
link_directories("${GFLAGS_DIR}/lib")
include_directories("${GFLAGS_DIR}/include")
link_directories("${NGRAPH_LIB}")
link_directories("${NGRAPH_LIB}/lib")
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 ()
include_directories(${OpenCV_INCLUDE_DIRS})
if (WIN32)
add_definitions("/DGOOGLE_GLOG_DLL_DECL=")
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} -g -o2 -fopenmp -std=c++11")
set(CMAKE_STATIC_LIBRARY_PREFIX "")
endif()
if(WITH_STATIC_LIB)
set(DEPS ${OPENVINO_DIR}/lib/intel64/libinference_engine${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENVINO_DIR}/lib/intel64/libinference_engine_legacy${CMAKE_STATIC_LIBRARY_SUFFIX})
else()
set(DEPS ${OPENVINO_DIR}/lib/intel64/libinference_engine${CMAKE_SHARED_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENVINO_DIR}/lib/intel64/libinference_engine_legacy${CMAKE_SHARED_LIBRARY_SUFFIX})
endif()
if (NOT WIN32)
set(DEPS ${DEPS}
glog gflags z yaml-cpp
)
else()
set(DEPS ${DEPS}
glog 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})
endif()
set(DEPS ${DEPS} ${OpenCV_LIBS})
add_executable(classifier src/classifier.cpp src/transforms.cpp src/paddlex.cpp)
ADD_DEPENDENCIES(classifier ext-yaml-cpp)
target_link_libraries(classifier ${DEPS})
{
"configurations": [
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"variables": [
{
"name": "OPENCV_DIR",
"value": "C:/projects/opencv",
"type": "PATH"
},
{
"name": "OPENVINO_LIB",
"value": "C:/projetcs/inference_engine",
"type": "PATH"
}
]
}
]
}
find_package(Git REQUIRED)
include(ExternalProject)
message("${CMAKE_BUILD_TYPE}")
ExternalProject_Add(
ext-yaml-cpp
URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip
URL_MD5 9542d6de397d1fbd649ed468cb5850e6
CMAKE_ARGS
-DYAML_CPP_BUILD_TESTS=OFF
-DYAML_CPP_BUILD_TOOLS=OFF
-DYAML_CPP_INSTALL=OFF
-DYAML_CPP_BUILD_CONTRIB=OFF
-DMSVC_SHARED_RT=OFF
-DBUILD_SHARED_LIBS=OFF
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG}
-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE}
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}/ext/yaml-cpp/lib
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}/ext/yaml-cpp/lib
PREFIX "${CMAKE_BINARY_DIR}/ext/yaml-cpp"
# Disable install step
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
LOG_BUILD 1
)
// 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.
#pragma once
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "yaml-cpp/yaml.h"
#ifdef _WIN32
#define OS_PATH_SEP "\\"
#else
#define OS_PATH_SEP "/"
#endif
namespace PaddleX {
// Inference model configuration parser
class ConfigPaser {
public:
ConfigPaser() {}
~ConfigPaser() {}
bool load_config(const std::string& model_dir,
const std::string& cfg = "model.yml") {
// Load as a YAML::Node
YAML::Node config;
config = YAML::LoadFile(model_dir + OS_PATH_SEP + cfg);
if (config["Transforms"].IsDefined()) {
YAML::Node transforms_ = config["Transforms"];
} else {
std::cerr << "There's no field 'Transforms' in model.yml" << std::endl;
return false;
}
return true;
}
YAML::Node Transforms_;
};
} // namespace PaddleDetection
// 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.
#pragma once
#include <functional>
#include <iostream>
#include <numeric>
#include "yaml-cpp/yaml.h"
#ifdef _WIN32
#define OS_PATH_SEP "\\"
#else
#define OS_PATH_SEP "/"
#endif
#include <inference_engine.hpp>
#include "include/paddlex/config_parser.h"
#include "include/paddlex/results.h"
#include "include/paddlex/transforms.h"
using namespace InferenceEngine;
namespace PaddleX {
class Model {
public:
void Init(const std::string& model_dir,
const std::string& cfg_dir,
std::string device) {
create_predictor(model_dir, cfg_dir, device);
}
void create_predictor(const std::string& model_dir,
const std::string& cfg_dir,
std::string device);
bool load_config(const std::string& model_dir);
bool preprocess(cv::Mat* input_im);
bool predict(const cv::Mat& im, ClsResult* result);
std::string type;
std::string name;
std::vector<std::string> labels;
Transforms transforms_;
Blob::Ptr inputs_;
Blob::Ptr output_;
CNNNetwork network_;
ExecutableNetwork executable_network_;
};
} // namespce of PaddleX
// 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.
#pragma once
#include <iostream>
#include <string>
#include <vector>
namespace PaddleX {
template <class T>
struct Mask {
std::vector<T> data;
std::vector<int> shape;
void clear() {
data.clear();
shape.clear();
}
};
struct Box {
int category_id;
std::string category;
float score;
std::vector<float> coordinate;
Mask<float> mask;
};
class BaseResult {
public:
std::string type = "base";
};
class ClsResult : public BaseResult {
public:
int category_id;
std::string category;
float score;
std::string type = "cls";
};
class DetResult : public BaseResult {
public:
std::vector<Box> boxes;
int mask_resolution;
std::string type = "det";
void clear() { boxes.clear(); }
};
class SegResult : public BaseResult {
public:
Mask<int64_t> label_map;
Mask<float> score_map;
void clear() {
label_map.clear();
score_map.clear();
}
};
} // namespce of PaddleX
// 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.
#pragma once
#include <yaml-cpp/yaml.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <inference_engine.hpp>
using namespace InferenceEngine;
namespace PaddleX {
// Abstraction of preprocessing opration class
class Transform {
public:
virtual void Init(const YAML::Node& item) = 0;
virtual bool Run(cv::Mat* im) = 0;
};
class Normalize : public Transform {
public:
virtual void Init(const YAML::Node& item) {
mean_ = item["mean"].as<std::vector<float>>();
std_ = item["std"].as<std::vector<float>>();
}
virtual bool Run(cv::Mat* im);
private:
std::vector<float> mean_;
std::vector<float> std_;
};
class ResizeByShort : public Transform {
public:
virtual void Init(const YAML::Node& item) {
short_size_ = item["short_size"].as<int>();
if (item["max_size"].IsDefined()) {
max_size_ = item["max_size"].as<int>();
} else {
max_size_ = -1;
}
};
virtual bool Run(cv::Mat* im);
private:
float GenerateScale(const cv::Mat& im);
int short_size_;
int max_size_;
};
class CenterCrop : public Transform {
public:
virtual void Init(const YAML::Node& item) {
if (item["crop_size"].IsScalar()) {
height_ = item["crop_size"].as<int>();
width_ = item["crop_size"].as<int>();
} else if (item["crop_size"].IsSequence()) {
std::vector<int> crop_size = item["crop_size"].as<std::vector<int>>();
width_ = crop_size[0];
height_ = crop_size[1];
}
}
virtual bool Run(cv::Mat* im);
private:
int height_;
int width_;
};
class Transforms {
public:
void Init(const YAML::Node& node, bool to_rgb = true);
std::shared_ptr<Transform> CreateTransform(const std::string& name);
bool Run(cv::Mat* im, Blob::Ptr blob);
private:
std::vector<std::shared_ptr<Transform>> transforms_;
bool to_rgb_ = true;
};
} // namespace PaddleX
# download pre-compiled opencv lib
OPENCV_URL=https://paddleseg.bj.bcebos.com/deploy/docker/opencv3gcc4.8.tar.bz2
if [ ! -d "./deps/opencv3gcc4.8" ]; then
mkdir -p deps
cd deps
wget -c ${OPENCV_URL}
tar xvfj opencv3gcc4.8.tar.bz2
rm -rf opencv3gcc4.8.tar.bz2
cd ..
fi
# openvino预编译库的路径
OPENVINO_DIR=/path/to/inference_engine/
# gflags预编译库的路径
GFLAGS_DIR=/path/to/gflags
# ngraph lib的路径,编译openvino时通常会生成
NGRAPH_LIB=/path/to/ngraph/lib/
# opencv预编译库的路径, 如果使用自带预编译版本可不修改
OPENCV_DIR=$(pwd)/deps/opencv3gcc4.8/
# 下载自带预编译版本
sh $(pwd)/scripts/bootstrap.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}
make
// 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.
#include <glog/logging.h>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "include/paddlex/paddlex.h"
DEFINE_string(model_dir, "", "Path of inference model");
DEFINE_string(cfg_dir, "", "Path of inference model");
DEFINE_string(device, "CPU", "Device name");
DEFINE_string(image, "", "Path of test image file");
DEFINE_string(image_list, "", "Path of test image list file");
int main(int argc, char** argv) {
// Parsing command-line
google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_model_dir == "") {
std::cerr << "--model_dir need to be defined" << std::endl;
return -1;
}
if (FLAGS_cfg_dir == "") {
std::cerr << "--cfg_dir need to be defined" << std::endl;
return -1;
}
if (FLAGS_image == "" & FLAGS_image_list == "") {
std::cerr << "--image or --image_list need to be defined" << std::endl;
return -1;
}
// 加载模型
PaddleX::Model model;
model.Init(FLAGS_model_dir, FLAGS_cfg_dir, FLAGS_device);
// 进行预测
if (FLAGS_image_list != "") {
std::ifstream inf(FLAGS_image_list);
if (!inf) {
std::cerr << "Fail to open file " << FLAGS_image_list << std::endl;
return -1;
}
std::string image_path;
while (getline(inf, image_path)) {
PaddleX::ClsResult result;
cv::Mat im = cv::imread(image_path, 1);
model.predict(im, &result);
std::cout << "Predict label: " << result.category
<< ", label_id:" << result.category_id
<< ", score: " << result.score << std::endl;
}
} else {
PaddleX::ClsResult result;
cv::Mat im = cv::imread(FLAGS_image, 1);
model.predict(im, &result);
std::cout << "Predict label: " << result.category
<< ", label_id:" << result.category_id
<< ", score: " << result.score << std::endl;
}
return 0;
}
// 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.
#include "include/paddlex/paddlex.h"
using namespace InferenceEngine;
namespace PaddleX {
void Model::create_predictor(const std::string& model_dir,
const std::string& cfg_dir,
std::string device) {
Core ie;
network_ = ie.ReadNetwork(model_dir, model_dir.substr(0, model_dir.size() - 4) + ".bin");
network_.setBatchSize(1);
InputInfo::Ptr input_info = network_.getInputsInfo().begin()->second;
input_info->getPreProcess().setResizeAlgorithm(RESIZE_BILINEAR);
input_info->setLayout(Layout::NCHW);
input_info->setPrecision(Precision::FP32);
executable_network_ = ie.LoadNetwork(network_, device);
load_config(cfg_dir);
}
bool Model::load_config(const std::string& cfg_dir) {
YAML::Node config = YAML::LoadFile(cfg_dir);
type = config["_Attributes"]["model_type"].as<std::string>();
name = config["Model"].as<std::string>();
bool to_rgb = true;
if (config["TransformsMode"].IsDefined()) {
std::string mode = config["TransformsMode"].as<std::string>();
if (mode == "BGR") {
to_rgb = false;
} else if (mode != "RGB") {
std::cerr << "[Init] Only 'RGB' or 'BGR' is supported for TransformsMode"
<< std::endl;
return false;
}
}
// 构建数据处理流
transforms_.Init(config["Transforms"], to_rgb);
// 读入label list
labels.clear();
labels = config["_Attributes"]["labels"].as<std::vector<std::string>>();
return true;
}
bool Model::preprocess(cv::Mat* input_im) {
if (!transforms_.Run(input_im, inputs_)) {
return false;
}
return true;
}
bool Model::predict(const cv::Mat& im, ClsResult* result) {
if (type == "detector") {
std::cerr << "Loading model is a 'detector', DetResult should be passed to "
"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;
}
// 处理输入图像
InferRequest infer_request = executable_network_.CreateInferRequest();
std::string input_name = network_.getInputsInfo().begin()->first;
inputs_ = infer_request.GetBlob(input_name);
auto im_clone = im.clone();
if (!preprocess(&im_clone)) {
std::cerr << "Preprocess failed!" << std::endl;
return false;
}
infer_request.Infer();
std::string output_name = network_.getOutputsInfo().begin()->first;
output_ = infer_request.GetBlob(output_name);
MemoryBlob::CPtr moutput = as<MemoryBlob>(output_);
auto moutputHolder = moutput->rmap();
float* outputs_data = moutputHolder.as<float *>();
// 对模型输出结果进行后处理
auto ptr = std::max_element(outputs_data, outputs_data+sizeof(outputs_data));
result->category_id = std::distance(outputs_data, ptr);
result->score = *ptr;
result->category = labels[result->category_id];
//for (int i=0;i<sizeof(outputs_data);i++){
// std::cout << labels[i] << std::endl;
// std::cout << outputs_[i] << std::endl;
// }
}
} // namespce of PaddleX
// 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.
#include <iostream>
#include <string>
#include <vector>
#include "include/paddlex/transforms.h"
namespace PaddleX {
std::map<std::string, int> interpolations = {{"LINEAR", cv::INTER_LINEAR},
{"NEAREST", cv::INTER_NEAREST},
{"AREA", cv::INTER_AREA},
{"CUBIC", cv::INTER_CUBIC},
{"LANCZOS4", cv::INTER_LANCZOS4}};
bool Normalize::Run(cv::Mat* im){
for (int h = 0; h < im->rows; h++) {
for (int w = 0; w < im->cols; w++) {
im->at<cv::Vec3f>(h, w)[0] =
(im->at<cv::Vec3f>(h, w)[0] / 255.0 - mean_[0]) / std_[0];
im->at<cv::Vec3f>(h, w)[1] =
(im->at<cv::Vec3f>(h, w)[1] / 255.0 - mean_[1]) / std_[1];
im->at<cv::Vec3f>(h, w)[2] =
(im->at<cv::Vec3f>(h, w)[2] / 255.0 - mean_[2]) / std_[2];
}
}
return true;
}
bool CenterCrop::Run(cv::Mat* im) {
int height = static_cast<int>(im->rows);
int width = static_cast<int>(im->cols);
if (height < height_ || width < width_) {
std::cerr << "[CenterCrop] Image size less than crop size" << std::endl;
return false;
}
int offset_x = static_cast<int>((width - width_) / 2);
int offset_y = static_cast<int>((height - height_) / 2);
cv::Rect crop_roi(offset_x, offset_y, width_, height_);
*im = (*im)(crop_roi);
return true;
}
float ResizeByShort::GenerateScale(const cv::Mat& im) {
int origin_w = im.cols;
int origin_h = im.rows;
int im_size_max = std::max(origin_w, origin_h);
int im_size_min = std::min(origin_w, origin_h);
float scale =
static_cast<float>(short_size_) / static_cast<float>(im_size_min);
if (max_size_ > 0) {
if (round(scale * im_size_max) > max_size_) {
scale = static_cast<float>(max_size_) / static_cast<float>(im_size_max);
}
}
return scale;
}
bool ResizeByShort::Run(cv::Mat* im) {
float scale = GenerateScale(*im);
int width = static_cast<int>(scale * im->cols);
int height = static_cast<int>(scale * im->rows);
cv::resize(*im, *im, cv::Size(width, height), 0, 0, cv::INTER_LINEAR);
return true;
}
void Transforms::Init(const YAML::Node& transforms_node, bool to_rgb) {
transforms_.clear();
to_rgb_ = to_rgb;
for (const auto& item : transforms_node) {
std::string name = item.begin()->first.as<std::string>();
std::cout << "trans name: " << name << std::endl;
std::shared_ptr<Transform> transform = CreateTransform(name);
transform->Init(item.begin()->second);
transforms_.push_back(transform);
}
}
std::shared_ptr<Transform> Transforms::CreateTransform(
const std::string& transform_name) {
if (transform_name == "Normalize") {
return std::make_shared<Normalize>();
} else if (transform_name == "CenterCrop") {
return std::make_shared<CenterCrop>();
} else if (transform_name == "ResizeByShort") {
return std::make_shared<ResizeByShort>();
} else {
std::cerr << "There's unexpected transform(name='" << transform_name
<< "')." << std::endl;
exit(-1);
}
}
bool Transforms::Run(cv::Mat* im, Blob::Ptr blob) {
// 按照transforms中预处理算子顺序处理图像
if (to_rgb_) {
cv::cvtColor(*im, *im, cv::COLOR_BGR2RGB);
}
(*im).convertTo(*im, CV_32FC3);
for (int i = 0; i < transforms_.size(); ++i) {
if (!transforms_[i]->Run(im)) {
std::cerr << "Apply transforms to image failed!" << std::endl;
return false;
}
}
// 将图像由NHWC转为NCHW格式
// 同时转为连续的内存块存储到Blob
SizeVector blobSize = blob->getTensorDesc().getDims();
const size_t width = blobSize[3];
const size_t height = blobSize[2];
const size_t channels = blobSize[1];
MemoryBlob::Ptr mblob = InferenceEngine::as<MemoryBlob>(blob);
auto mblobHolder = mblob->wmap();
float *blob_data = mblobHolder.as<float *>();
for (size_t c = 0; c < channels; c++) {
for (size_t h = 0; h < height; h++) {
for (size_t w = 0; w < width; w++) {
blob_data[c * width * height + h * width + w] =
im->at<cv::Vec3f>(h, w)[c];
}
}
}
return true;
}
} // namespace PaddleX
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
{% extends "!layout.html" %}
{% block footer %} {{ super() }}
<style>
.wy-nav-content { max-width: 1080px; }
</style>
{% endblock %}
# 数据集-datasets
## ImageNet类
```
paddlex.datasets.ImageNet(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
```
读取ImageNet格式的分类数据集,并对样本进行相应的处理。ImageNet数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/classification/mobilenetv2.py#L25)
### 参数
> * **data_dir** (str): 数据集所在的目录路径。
> * **file_list** (str): 描述数据集图片文件和类别id的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> * **label_list** (str): 描述数据集包含的类别信息文件路径。
> * **transforms** (paddlex.cls.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.cls.transforms](./transforms/cls_transforms.md)。
> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## VOCDetection类
```
paddlex.datasets.VOCDetection(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
```
读取PascalVOC格式的检测数据集,并对样本进行相应的处理。PascalVOC数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/detection/yolov3_mobilenetv1.py#L29)
### 参数
> * **data_dir** (str): 数据集所在的目录路径。
> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> * **label_list** (str): 描述数据集包含的类别信息文件路径。
> * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。
> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## CocoDetection类
```
paddlex.datasets.CocoDetection(data_dir, ann_file, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
```
读取MSCOCO格式的检测数据集,并对样本进行相应的处理,该格式的数据集同样可以应用到实例分割模型的训练中。MSCOCO数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/detection/mask_rcnn_r50_fpn.py#L27)
### 参数
> * **data_dir** (str): 数据集所在的目录路径。
> * **ann_file** (str): 数据集的标注文件,为一个独立的json格式文件。
> * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。
> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## SegDataset类
```
paddlex.datasets.SegDataset(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
```
读取语分分割任务数据集,并对样本进行相应的处理。语义分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/segmentation/unet.py#L27)
### 参数
> * **data_dir** (str): 数据集所在的目录路径。
> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> * **label_list** (str): 描述数据集包含的类别信息文件路径。
> * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.seg.transforms](./transforms/seg_transforms.md)。
> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## EasyDataCls类
```
paddlex.datasets.SegDataset(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
```
读取EasyData图像分类数据集,并对样本进行相应的处理。EasyData图像分类任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
### 参数
> * **data_dir** (str): 数据集所在的目录路径。
> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> * **label_list** (str): 描述数据集包含的类别信息文件路径。
> * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.cls.transforms](./transforms/cls_transforms.md)。
> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## EasyDataDet类
```
paddlex.datasets.EasyDataDet(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
```
读取EasyData目标检测格式数据集,并对样本进行相应的处理,该格式的数据集同样可以应用到实例分割模型的训练中。EasyData目标检测或实例分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
### 参数
> * **data_dir** (str): 数据集所在的目录路径。
> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> * **label_list** (str): 描述数据集包含的类别信息文件路径。
> * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。
> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## EasyDataSeg类
```
paddlex.datasets.EasyDataSeg(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
```
读取EasyData语分分割任务数据集,并对样本进行相应的处理。EasyData语义分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
### 参数
> * **data_dir** (str): 数据集所在的目录路径。
> * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> * **label_list** (str): 描述数据集包含的类别信息文件路径。
> * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.seg.transforms](./transforms/seg_transforms.md)。
> * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
\ No newline at end of file
# 图像分类数据集
## ImageNet类
```
paddlex.datasets.ImageNet(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
```
读取ImageNet格式的分类数据集,并对样本进行相应的处理。ImageNet数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/classification/mobilenetv2.py#L25)
> **参数**
> > * **data_dir** (str): 数据集所在的目录路径。
> > * **file_list** (str): 描述数据集图片文件和类别id的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> > * **label_list** (str): 描述数据集包含的类别信息文件路径。
> > * **transforms** (paddlex.cls.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.cls.transforms](./transforms/cls_transforms.md)。
> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## EasyDataCls类
```
paddlex.datasets.EasyDatasetCls(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
```
> 读取EasyData平台标注图像分类数据集,并对样本进行相应的处理。EasyData图像分类任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)。
> **参数**
> > * **data_dir** (str): 数据集所在的目录路径。
> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> > * **label_list** (str): 描述数据集包含的类别信息文件路径。
> > * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.cls.transforms](./transforms/cls_transforms.md)。
> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
# 检测和实例分割数据集
## VOCDetection类
```
paddlex.datasets.VOCDetection(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
```
> 仅用于**目标检测**。读取PascalVOC格式的检测数据集,并对样本进行相应的处理。PascalVOC数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
> 示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/detection/yolov3_mobilenetv1.py#L29)
> **参数**
> > * **data_dir** (str): 数据集所在的目录路径。
> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> > * **label_list** (str): 描述数据集包含的类别信息文件路径。
> > * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。
> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## CocoDetection类
```
paddlex.datasets.CocoDetection(data_dir, ann_file, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
```
> 用于**目标检测或实例分割**。读取MSCOCO格式的检测数据集,并对样本进行相应的处理,该格式的数据集同样可以应用到实例分割模型的训练中。MSCOCO数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
> 示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/detection/mask_rcnn_r50_fpn.py#L27)
> **参数**
> > * **data_dir** (str): 数据集所在的目录路径。
> > * **ann_file** (str): 数据集的标注文件,为一个独立的json格式文件。
> > * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。
> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## EasyDataDet类
```
paddlex.datasets.EasyDataDet(data_dir, file_list, label_list, transforms=None, num_workers=‘auto’, buffer_size=100, parallel_method='thread', shuffle=False)
```
> 用于**目标检测或实例分割**。读取EasyData目标检测格式数据集,并对样本进行相应的处理,该格式的数据集同样可以应用到实例分割模型的训练中。EasyData目标检测或实例分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
> **参数**
> > * **data_dir** (str): 数据集所在的目录路径。
> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> > * **label_list** (str): 描述数据集包含的类别信息文件路径。
> > * **transforms** (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.det.transforms](./transforms/det_transforms.md)。
> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
数据集-datasets
============================
PaddleX目前支持主流的CV数据集格式和 `EasyData <https://ai.baidu.com/easydata/>`_ 数据标注平台的标注数据格式,此外PaddleX也提升了数据格式转换工具API,支持包括LabelMe,精灵标注助手和EasyData平台数据格式的转换,可以参考PaddleX的tools API文档。
下表为各数据集格式与相应任务的对应关系,
+------------------------+------------+----------+----------+----------+
| 数据集格式 | 图像分类 | 目标检测 | 实例分割 | 语义分割 |
+========================+============+==========+==========+==========+
| ImageNet | √ | - | - | - |
+------------------------+------------+----------+----------+----------+
| VOCDetection | - | √ | - | - |
+------------------------+------------+----------+----------+----------+
| CocoDetection | - | √ | √ | - |
+------------------------+------------+----------+----------+----------+
| SegDataset | - | - | - | √ |
+------------------------+------------+----------+----------+----------+
| EasyDataCls | √ | - | - | - |
+------------------------+------------+----------+----------+----------+
| EasyDataDet | - | √ | √ | - |
+------------------------+------------+----------+----------+----------+
| EasyDataSeg | - | - | - | √ |
+------------------------+------------+----------+----------+----------+
.. toctree::
:maxdepth: 2
classification.md
detection.md
semantic_segmentation.md
# 语义分割数据集
## SegDataset类
```
paddlex.datasets.SegDataset(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
```
> 读取语义分割任务数据集,并对样本进行相应的处理。语义分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
> 示例:[代码文件](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/train/segmentation/unet.py#L27)
> **参数**
> > * **data_dir** (str): 数据集所在的目录路径。
> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> > * **label_list** (str): 描述数据集包含的类别信息文件路径。
> > * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.seg.transforms](./transforms/seg_transforms.md)。
> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
## EasyDataSeg类
```
paddlex.datasets.EasyDataSeg(data_dir, file_list, label_list, transforms=None, num_workers='auto', buffer_size=100, parallel_method='thread', shuffle=False)
```
> 读取EasyData语义分割任务数据集,并对样本进行相应的处理。EasyData语义分割任务数据集格式的介绍可查看文档:[数据集格式说明](../datasets.md)
> **参数**
> > * **data_dir** (str): 数据集所在的目录路径。
> > * **file_list** (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对`data_dir`的相对路径)。
> > * **label_list** (str): 描述数据集包含的类别信息文件路径。
> > * **transforms** (paddlex.seg.transforms): 数据集中每个样本的预处理/增强算子,详见[paddlex.seg.transforms](./transforms/seg_transforms.md)。
> > * **num_workers** (int|str):数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据系统的实际CPU核数设置`num_workers`: 如果CPU核数的一半大于8,则`num_workers`为8,否则为CPU核数的一半。
> > * **buffer_size** (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。
> > * **parallel_method** (str): 数据集中样本在预处理过程中并行处理的方式,支持'thread'线程和'process'进程两种方式。默认为'process'(Windows和Mac下会强制使用thread,该参数无效)。
> > * **shuffle** (bool): 是否需要对数据集中样本打乱顺序。默认为False。
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
接口说明 PaddleX API说明文档
============================ ============================
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
transforms/index.rst transforms/index.rst
datasets.md datasets/index.rst
models.md models/index.rst
slim.md slim.md
load_model.md load_model.md
visualize.md visualize.md
文件模式从 100644 更改为 100755
# 模型-models
## 分类模型
### ResNet50类
```python
paddlex.cls.ResNet50(num_classes=1000)
```
构建ResNet50分类器,并实现其训练、评估和预测。
#### **参数:**
> - **num_classes** (int): 类别数。默认为1000。
#### 分类器训练函数接口
> ```python
> train(self, num_epochs, train_dataset, train_batch_size=64, eval_dataset=None, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.025, lr_decay_epochs=[30, 60, 90], lr_decay_gamma=0.1, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
> ```
>
> **参数:**
>
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认值为64。
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代步数)。默认为2。
> > - **save_dir** (str): 模型保存路径。
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为'IMAGENET'。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.025。
> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[30, 60, 90]。
> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
#### 分类器评估函数接口
> ```python
> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False)
> ```
>
> **参数:**
>
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **batch_size** (int): 验证数据批大小。默认为1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **return_details** (bool): 是否返回详细信息,默认False。
>
> **返回值:**
>
> > - **dict**: 当return_details为False时,返回dict, 包含关键字:'acc1'、'acc5',分别表示最大值的accuracy、前5个最大值的accuracy。
> > - **tuple** (metrics, eval_details): 当`return_details`为True时,增加返回dict,包含关键字:'true_labels'、'pred_scores',分别代表真实类别id、每个类别的预测得分。
#### 分类器预测函数接口
> ```python
> predict(self, img_file, transforms=None, topk=5)
> ```
>
> **参数:**
>
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.cls.transforms): 数据预处理操作。
> > - **topk** (int): 预测时前k个最大值。
> **返回值:**
>
> > - **list**: 其中元素均为字典。字典的关键字为'category_id'、'category'、'score',
> > 分别对应预测类别id、预测类别标签、预测得分。
### 其它分类器类
`ResNet50`外,`paddlex.cls`下还提供了`ResNet18``ResNet34``ResNet101``ResNet50_vd``ResNet101_vd``ResNet50_vd_ssld``ResNet101_vd_ssld``DarkNet53``MobileNetV1``MobileNetV2``MobileNetV3_small``MobileNetV3_large``MobileNetV3_small_ssld``MobileNetV3_large_ssld``Xception41``Xception65``Xception71``ShuffleNetV2`, 使用方式(包括函数接口和参数)均与`ResNet50`一致,各模型效果可参考[模型库](../model_zoo.md)中列表。
## 检测模型
### YOLOv3类
```python
paddlex.det.YOLOv3(num_classes=80, backbone='MobileNetV1', anchors=None, anchor_masks=None, ignore_threshold=0.7, nms_score_threshold=0.01, nms_topk=1000, nms_keep_topk=100, nms_iou_threshold=0.45, label_smooth=False, train_random_shapes=[320, 352, 384, 416, 448, 480, 512, 544, 576, 608])
```
构建YOLOv3检测器,并实现其训练、评估和预测。 **注意在YOLOv3,num_classes不需要包含背景类,如目标包括human、dog两种,则num_classes设为2即可,这里与FasterRCNN/MaskRCNN有差别**
**参数:**
> - **num_classes** (int): 类别数。默认为80。
> - **backbone** (str): YOLOv3的backbone网络,取值范围为['DarkNet53', 'ResNet34', 'MobileNetV1', 'MobileNetV3_large']。默认为'MobileNetV1'。
> - **anchors** (list|tuple): anchor框的宽度和高度,为None时表示使用默认值
> [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
> [59, 119], [116, 90], [156, 198], [373, 326]]。
> - **anchor_masks** (list|tuple): 在计算YOLOv3损失时,使用anchor的mask索引,为None时表示使用默认值
> [[6, 7, 8], [3, 4, 5], [0, 1, 2]]。
> - **ignore_threshold** (float): 在计算YOLOv3损失时,IoU大于`ignore_threshold`的预测框的置信度被忽略。默认为0.7。
> - **nms_score_threshold** (float): 检测框的置信度得分阈值,置信度得分低于阈值的框应该被忽略。默认为0.01。
> - **nms_topk** (int): 进行NMS时,根据置信度保留的最大检测框数。默认为1000。
> - **nms_keep_topk** (int): 进行NMS后,每个图像要保留的总检测框数。默认为100。
> - **nms_iou_threshold** (float): 进行NMS时,用于剔除检测框IOU的阈值。默认为0.45。
> - **label_smooth** (bool): 是否使用label smooth。默认值为False。
> - **train_random_shapes** (list|tuple): 训练时从列表中随机选择图像大小。默认值为[320, 352, 384, 416, 448, 480, 512, 544, 576, 608]。
#### YOLOv3训练函数接口
> ```python
> train(self, num_epochs, train_dataset, train_batch_size=8, eval_dataset=None, save_interval_epochs=20, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=1.0/8000, warmup_steps=1000, warmup_start_lr=0.0, lr_decay_epochs=[213, 240], lr_decay_gamma=0.1, metric=None, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
> ```
>
> **参数:**
>
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认值为8。
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为20。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认值为'output'。
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
> > - **learning_rate** (float): 默认优化器的学习率。默认为1.0/8000。
> > - **warmup_steps** (int): 默认优化器进行warmup过程的步数。默认为1000。
> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为0.0。
> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[213, 240]。
> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在PascalVOC数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
#### YOLOv3评估函数接口
> ```python
> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
> ```
>
> **参数:**
>
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **batch_size** (int): 验证数据批大小。默认为1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC';如为COCODetection,则`metric`为'COCO'默认为None。
> > - **return_details** (bool): 是否返回详细信息。默认值为False。
> >
> **返回值:**
>
> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当`return_details`为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'或者’bbox_map‘,分别表示平均准确率平均值在各个阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;’gt‘:真实标注框相关信息。
#### YOLOv3预测函数接口
> ```python
> predict(self, img_file, transforms=None)
> ```
>
> **参数:**
>
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
>
> **返回值:**
>
> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key'bbox', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
### FasterRCNN类
```python
paddlex.det.FasterRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_ratios=[0.5, 1.0, 2.0], anchor_sizes=[32, 64, 128, 256, 512])
```
构建FasterRCNN检测器,并实现其训练、评估和预测。 **注意在FasterRCNN中,num_classes需要设置为类别数+背景类,如目标包括human、dog两种,则num_classes需设为3,多的一种为背景background类别**
**参数:**
> - **num_classes** (int): 包含了背景类的类别数。默认为81。
> - **backbone** (str): FasterRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd']。默认为'ResNet50'。
> - **with_fpn** (bool): 是否使用FPN结构。默认为True。
> - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
> - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
#### FasterRCNN训练函数接口
> ```python
> train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, save_interval_epochs=1, log_interval_steps=2,save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.0025, warmup_steps=500, warmup_start_lr=1.0/1200, lr_decay_epochs=[8, 11], lr_decay_gamma=0.1, metric=None, use_vdl=False, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
>
> ```
>
> **参数:**
>
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认为2。
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认值为'output'。
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.0025。
> > - **warmup_steps** (int): 默认优化器进行warmup过程的步数。默认为500。
> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为1.0/1200。
> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[8, 11]。
> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
#### FasterRCNN评估函数接口
> ```python
> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
>
> ```
>
> **参数:**
>
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **batch_size** (int): 验证数据批大小。默认为1。当前只支持设置为1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC'; 如为COCODetection,则`metric`为'COCO'。
> > - **return_details** (bool): 是否返回详细信息。默认值为False。
> >
> **返回值:**
>
> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当`return_details`为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'或者’bbox_map‘,分别表示平均准确率平均值在各个IoU阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;’gt‘:真实标注框相关信息。
#### FasterRCNN预测函数接口
> ```python
> predict(self, img_file, transforms=None)
>
> ```
>
> **参数:**
>
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
>
> **返回值:**
>
> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key'bbox', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
### MaskRCNN类
```python
paddlex.det.MaskRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_ratios=[0.5, 1.0, 2.0], anchor_sizes=[32, 64, 128, 256, 512])
```
构建MaskRCNN检测器,并实现其训练、评估和预测。**注意在MaskRCNN中,num_classes需要设置为类别数+背景类,如目标包括human、dog两种,则num_classes需设为3,多的一种为背景background类别**
**参数:**
> - **num_classes** (int): 包含了背景类的类别数。默认为81。
> - **backbone** (str): MaskRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd']。默认为'ResNet50'。
> - **with_fpn** (bool): 是否使用FPN结构。默认为True。
> - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
> - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
#### MaskRCNN训练函数接口
> ```python
> train(self, num_epochs, train_dataset, train_batch_size=1, eval_dataset=None, save_interval_epochs=1, log_interval_steps=20, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=1.0/800, warmup_steps=500, warmup_start_lr=1.0 / 2400, lr_decay_epochs=[8, 11], lr_decay_gamma=0.1, metric=None, use_vdl=False, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
>
> ```
>
> **参数:**
>
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认为1。
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认值为'output'。
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.00125。
> > - **warmup_steps** (int): 默认优化器进行warmup过程的步数。默认为500。
> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为1.0/2400。
> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[8, 11]。
> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
#### MaskRCNN评估函数接口
> ```python
> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
>
> ```
>
> **参数:**
>
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **batch_size** (int): 验证数据批大小。默认为1。当前只支持设置为1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC'; 如为COCODetection,则`metric`为'COCO'。
> > - **return_details** (bool): 是否返回详细信息。默认值为False。
> >
> **返回值:**
>
> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当return_details为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'和'segm_mmap'或者’bbox_map‘和'segm_map',分别表示预测框和分割区域平均准确率平均值在各个IoU阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测框结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;'mask',对应元素预测区域结果列表,每个预测结果由图像id、预测区域类别id、预测区域坐标、预测区域得分;’gt‘:真实标注框和标注区域相关信息。
#### MaskRCNN预测函数接口
> ```python
> predict(self, img_file, transforms=None)
>
> ```
>
> **参数:**
>
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
>
> **返回值:**
>
> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key'bbox', 'mask', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、Mask信息,类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
## 分割模型
### DeepLabv3p类
```python
paddlex.seg.DeepLabv3p(num_classes=2, backbone='MobileNetV2_x1.0', output_stride=16, aspp_with_sep_conv=True, decoder_use_sep_conv=True, encoder_with_aspp=True, enable_decoder=True, use_bce_loss=False, use_dice_loss=False, class_weight=None, ignore_index=255)
```
构建DeepLabv3p分割器,并实现其训练、评估和预测。
**参数:**
> - **num_classes** (int): 类别数。
> - **backbone** (str): DeepLabv3+的backbone网络,实现特征图的计算,取值范围为['Xception65', 'Xception41', 'MobileNetV2_x0.25', 'MobileNetV2_x0.5', 'MobileNetV2_x1.0', 'MobileNetV2_x1.5', 'MobileNetV2_x2.0'],'MobileNetV2_x1.0'。
> - **output_stride** (int): backbone 输出特征图相对于输入的下采样倍数,一般取值为8或16。默认16。
> - **aspp_with_sep_conv** (bool): decoder模块是否采用separable convolutions。默认True。
> - **decoder_use_sep_conv** (bool): decoder模块是否采用separable convolutions。默认True。
> - **encoder_with_aspp** (bool): 是否在encoder阶段采用aspp模块。默认True。
> - **enable_decoder** (bool): 是否使用decoder模块。默认True。
> - **use_bce_loss** (bool): 是否使用bce loss作为网络的损失函数,只能用于两类分割。可与dice loss同时使用。默认False。
> - **use_dice_loss** (bool): 是否使用dice loss作为网络的损失函数,只能用于两类分割,可与bce loss同时使用,当`use_bce_loss`和`use_dice_loss`都为False时,使用交叉熵损失函数。默认False。
> - **class_weight** (list/str): 交叉熵损失函数各类损失的权重。当`class_weight`为list的时候,长度应为`num_classes`。当`class_weight`为str时, weight.lower()应为'dynamic',这时会根据每一轮各类像素的比重自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,即平时使用的交叉熵损失函数。
> - **ignore_index** (int): label上忽略的值,label为`ignore_index`的像素不参与损失函数的计算。默认255。
#### DeepLabv3训练函数接口
> ```python
> train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, eval_batch_size=1, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.01, lr_decay_power=0.9, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None):
>
> ```
>
> **参数:**
> >
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认2。
> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认'output'
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认'IMAGENET'。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认的优化器:使用fluid.optimizer.Momentum优化方法,polynomial的学习率衰减策略。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认0.01。
> > - **lr_decay_power** (float): 默认优化器学习率衰减指数。默认0.9。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认False。
> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
#### DeepLabv3评估函数接口
> ```python
> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False):
> ```
> **参数:**
> >
> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
> > - **batch_size** (int): 评估时的batch大小。默认1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **return_details** (bool): 是否返回详细信息。默认False。
> **返回值:**
> >
> > - **dict**: 当`return_details`为False时,返回dict。包含关键字:'miou'、'category_iou'、'macc'、
> > 'category_acc'和'kappa',分别表示平均iou、各类别iou、平均准确率、各类别准确率和kappa系数。
> > - **tuple** (metrics, eval_details):当`return_details`为True时,增加返回dict (eval_details),
> > 包含关键字:'confusion_matrix',表示评估的混淆矩阵。
#### DeepLabv3预测函数接口
> ```
> predict(self, im_file, transforms=None):
> ```
> **参数:**
> >
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.seg.transforms): 数据预处理操作。
> **返回值:**
> >
> > - **dict**: 包含关键字'label_map'和'score_map', 'label_map'存储预测结果灰度图,像素值表示对应的类别,'score_map'存储各类别的概率,shape=(h, w, num_classes)。
### UNet类
```python
paddlex.seg.UNet(num_classes=2, upsample_mode='bilinear', use_bce_loss=False, use_dice_loss=False, class_weight=None, ignore_index=255)
```
构建UNet分割器,并实现其训练、评估和预测。
**参数:**
> - **num_classes** (int): 类别数。
> - **upsample_mode** (str): UNet decode时采用的上采样方式,取值为'bilinear'时利用双线行差值进行上菜样,当输入其他选项时则利用反卷积进行上菜样,默认为'bilinear'。
> - **use_bce_loss** (bool): 是否使用bce loss作为网络的损失函数,只能用于两类分割。可与dice loss同时使用。默认False。
> - **use_dice_loss** (bool): 是否使用dice loss作为网络的损失函数,只能用于两类分割,可与bce loss同时使用。当use_bce_loss和use_dice_loss都为False时,使用交叉熵损失函数。默认False。
> - **class_weight** (list/str): 交叉熵损失函数各类损失的权重。当`class_weight`为list的时候,长度应为`num_classes`。当`class_weight`为str时, weight.lower()应为'dynamic',这时会根据每一轮各类像素的比重自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,即平时使用的交叉熵损失函数。
> - **ignore_index** (int): label上忽略的值,label为`ignore_index`的像素不参与损失函数的计算。默认255。
#### Unet训练函数接口
> ```python
> train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, eval_batch_size=1, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='COCO', optimizer=None, learning_rate=0.01, lr_decay_power=0.9, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None):
> ```
>
> **参数:**
> >
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认2。
> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认'output'
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在COCO图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认'COCO'。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认的优化器:使用fluid.optimizer.Momentum优化方法,polynomial的学习率衰减策略。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认0.01。
> > - **lr_decay_power** (float): 默认优化器学习率衰减指数。默认0.9。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认False。
> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
#### Unet评估函数接口
> ```
> evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False):
> ```
> **参数:**
> >
> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
> > - **batch_size** (int): 评估时的batch大小。默认1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **return_details** (bool): 是否返回详细信息。默认False。
> **返回值:**
> >
> > - **dict**: 当return_details为False时,返回dict。包含关键字:'miou'、'category_iou'、'macc'、
> > 'category_acc'和'kappa',分别表示平均iou、各类别iou、平均准确率、各类别准确率和kappa系数。
> > - **tuple** (metrics, eval_details):当return_details为True时,增加返回dict (eval_details),
> > 包含关键字:'confusion_matrix',表示评估的混淆矩阵。
#### Unet预测函数接口
> ```
> predict(self, im_file, transforms=None):
> ```
> **参数:**
> >
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.seg.transforms): 数据预处理操作。
> **返回值:**
> >
> > - **dict**: 包含关键字'label_map'和'score_map', 'label_map'存储预测结果灰度图,像素值表示对应的类别,'score_map'存储各类别的概率,shape=(h, w, num_classes)。
# 图像分类
## ResNet50类
```python
paddlex.cls.ResNet50(num_classes=1000)
```
> 构建ResNet50分类器,并实现其训练、评估和预测。
**参数**
> - **num_classes** (int): 类别数。默认为1000。
### train 训练接口
```python
train(self, num_epochs, train_dataset, train_batch_size=64, eval_dataset=None, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.025, lr_decay_epochs=[30, 60, 90], lr_decay_gamma=0.1, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
```
>
> **参数**
>
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认值为64。
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代步数)。默认为2。
> > - **save_dir** (str): 模型保存路径。
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为'IMAGENET'。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.025。
> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[30, 60, 90]。
> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
### evaluate 评估接口
```python
evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False)
```
>
> **参数**
>
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **batch_size** (int): 验证数据批大小。默认为1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **return_details** (bool): 是否返回详细信息,默认False。
>
> **返回值**
>
> > - **dict**: 当return_details为False时,返回dict, 包含关键字:'acc1'、'acc5',分别表示最大值的accuracy、前5个最大值的accuracy。
> > - **tuple** (metrics, eval_details): 当`return_details`为True时,增加返回dict,包含关键字:'true_labels'、'pred_scores',分别代表真实类别id、每个类别的预测得分。
### predict 预测接口
```python
predict(self, img_file, transforms=None, topk=5)
```
> 分类模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`ResNet50.test_transforms`和`ResNet50.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
> **参数**
>
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.cls.transforms): 数据预处理操作。
> > - **topk** (int): 预测时前k个最大值。
> **返回值**
>
> > - **list**: 其中元素均为字典。字典的关键字为'category_id'、'category'、'score',
> > 分别对应预测类别id、预测类别标签、预测得分。
## 其它分类器类
PaddleX提供了共计22种分类器,所有分类器均提供同`ResNet50`相同的训练`train`,评估`evaluate`和预测`predict`接口,各模型效果可参考[模型库](../appendix/model_zoo.md)
### ResNet18
```python
paddlex.cls.ResNet18(num_classes=1000)
```
### ResNet34
```python
paddlex.cls.ResNet34(num_classes=1000)
```
### ResNet50
```python
paddlex.cls.ResNet50(num_classes=1000)
```
### ResNet50_vd
```python
paddlex.cls.ResNet50_vd(num_classes=1000)
```
### ResNet50_vd_ssld
```python
paddlex.cls.ResNet50_vd_ssld(num_classes=1000)
```
### ResNet101
```python
paddlex.cls.ResNet101(num_classes=1000)
```
### ResNet101_vd
```python
paddlex.cls.ResNet101_vdnum_classes=1000)
```
### ResNet101_vd_ssld
```python
paddlex.cls.ResNet101_vd_ssld(num_classes=1000)
```
### DarkNet53
```python
paddlex.cls.DarkNet53(num_classes=1000)
```
### MobileNetV1
```python
paddlex.cls.MobileNetV1(num_classes=1000)
```
### MobileNetV2
```python
paddlex.cls.MobileNetV2(num_classes=1000)
```
### MobileNetV3_small
```python
paddlex.cls.MobileNetV3_small(num_classes=1000)
```
### MobileNetV3_small_ssld
```python
paddlex.cls.MobileNetV3_small_ssld(num_classes=1000)
```
### MobileNetV3_large
```python
paddlex.cls.MobileNetV3_large(num_classes=1000)
```
### MobileNetV3_large_ssld
```python
paddlex.cls.MobileNetV3_large_ssld(num_classes=1000)
```
### Xception65
```python
paddlex.cls.Xception65(num_classes=1000)
```
### Xception71
```python
paddlex.cls.Xception71(num_classes=1000)
```
### ShuffleNetV2
```python
paddlex.cls.ShuffleNetV2(num_classes=1000)
```
### DenseNet121
```python
paddlex.cls.DenseNet121(num_classes=1000)
```
### DenseNet161
```python
paddlex.cls.DenseNet161(num_classes=1000)
```
### DenseNet201
```python
paddlex.cls.DenseNet201(num_classes=1000)
```
# 目标检测
## YOLOv3类
```python
paddlex.det.YOLOv3(num_classes=80, backbone='MobileNetV1', anchors=None, anchor_masks=None, ignore_threshold=0.7, nms_score_threshold=0.01, nms_topk=1000, nms_keep_topk=100, nms_iou_threshold=0.45, label_smooth=False, train_random_shapes=[320, 352, 384, 416, 448, 480, 512, 544, 576, 608])
```
> 构建YOLOv3检测器。**注意在YOLOv3,num_classes不需要包含背景类,如目标包括human、dog两种,则num_classes设为2即可,这里与FasterRCNN/MaskRCNN有差别**
> **参数**
>
> > - **num_classes** (int): 类别数。默认为80。
> > - **backbone** (str): YOLOv3的backbone网络,取值范围为['DarkNet53', 'ResNet34', 'MobileNetV1', 'MobileNetV3_large']。默认为'MobileNetV1'。
> > - **anchors** (list|tuple): anchor框的宽度和高度,为None时表示使用默认值
> > [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
> [59, 119], [116, 90], [156, 198], [373, 326]]。
> > - **anchor_masks** (list|tuple): 在计算YOLOv3损失时,使用anchor的mask索引,为None时表示使用默认值
> > [[6, 7, 8], [3, 4, 5], [0, 1, 2]]。
> > - **ignore_threshold** (float): 在计算YOLOv3损失时,IoU大于`ignore_threshold`的预测框的置信度被忽略。默认为0.7。
> > - **nms_score_threshold** (float): 检测框的置信度得分阈值,置信度得分低于阈值的框应该被忽略。默认为0.01。
> > - **nms_topk** (int): 进行NMS时,根据置信度保留的最大检测框数。默认为1000。
> > - **nms_keep_topk** (int): 进行NMS后,每个图像要保留的总检测框数。默认为100。
> > - **nms_iou_threshold** (float): 进行NMS时,用于剔除检测框IOU的阈值。默认为0.45。
> > - **label_smooth** (bool): 是否使用label smooth。默认值为False。
> > - **train_random_shapes** (list|tuple): 训练时从列表中随机选择图像大小。默认值为[320, 352, 384, 416, 448, 480, 512, 544, 576, 608]。
### train 训练接口
```python
train(self, num_epochs, train_dataset, train_batch_size=8, eval_dataset=None, save_interval_epochs=20, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=1.0/8000, warmup_steps=1000, warmup_start_lr=0.0, lr_decay_epochs=[213, 240], lr_decay_gamma=0.1, metric=None, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
```
> YOLOv3模型的训练接口,函数内置了`piecewise`学习率衰减策略和`momentum`优化器。
> **参数**
>
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认值为8。
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为20。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认值为'output'。
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
> > - **learning_rate** (float): 默认优化器的学习率。默认为1.0/8000。
> > - **warmup_steps** (int): 默认优化器进行warmup过程的步数。默认为1000。
> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为0.0。
> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[213, 240]。
> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在PascalVOC数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
### evaluate 评估接口
```python
evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
```
> YOLOv3模型的评估接口,模型评估后会返回在验证集上的指标`box_map`(metric指定为'VOC'时)或`box_mmap`(metric指定为`COCO`时)。
> **参数**
>
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **batch_size** (int): 验证数据批大小。默认为1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC';如为COCODetection,则`metric`为'COCO'默认为None, 如为EasyData类型数据集,同时也会使用'VOC'。
> > - **return_details** (bool): 是否返回详细信息。默认值为False。
> >
> **返回值**
>
> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当`return_details`为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'或者’bbox_map‘,分别表示平均准确率平均值在各个阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;’gt‘:真实标注框相关信息。
### predict 预测接口
```python
predict(self, img_file, transforms=None)
```
> YOLOv3模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`YOLOv3.test_transforms`和`YOLOv3.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义`test_transforms`传入给`predict`接口
> **参数**
>
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
>
> **返回值**
>
> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key包括'bbox', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
## FasterRCNN类
```python
paddlex.det.FasterRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_ratios=[0.5, 1.0, 2.0], anchor_sizes=[32, 64, 128, 256, 512])
```
> 构建FasterRCNN检测器。 **注意在FasterRCNN中,num_classes需要设置为类别数+背景类,如目标包括human、dog两种,则num_classes需设为3,多的一种为背景background类别**
> **参数**
> > - **num_classes** (int): 包含了背景类的类别数。默认为81。
> > - **backbone** (str): FasterRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd']。默认为'ResNet50'。
> > - **with_fpn** (bool): 是否使用FPN结构。默认为True。
> > - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
> > - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
### train 训练接口
```python
train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, save_interval_epochs=1, log_interval_steps=2,save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.0025, warmup_steps=500, warmup_start_lr=1.0/1200, lr_decay_epochs=[8, 11], lr_decay_gamma=0.1, metric=None, use_vdl=False, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
```
> FasterRCNN模型的训练接口,函数内置了`piecewise`学习率衰减策略和`momentum`优化器。
> **参数**
>
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认为2。
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认值为'output'。
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.0025。
> > - **warmup_steps** (int): 默认优化器进行warmup过程的步数。默认为500。
> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为1.0/1200。
> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[8, 11]。
> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
### evaluate 接口
```python
evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
```
> FasterRCNN模型的评估接口,模型评估后会返回在验证集上的指标box_map(metric指定为’VOC’时)或box_mmap(metric指定为COCO时)。
> **参数**
>
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **batch_size** (int): 验证数据批大小。默认为1。当前只支持设置为1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC'; 如为COCODetection,则`metric`为'COCO'。
> > - **return_details** (bool): 是否返回详细信息。默认值为False。
> >
> **返回值**
>
> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当`return_details`为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'或者’bbox_map‘,分别表示平均准确率平均值在各个IoU阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;’gt‘:真实标注框相关信息。
### predict 预测接口
```python
predict(self, img_file, transforms=None)
```
> FasterRCNN模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`FasterRCNN.test_transforms`和`FasterRCNN.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
> **参数**
>
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
>
> **返回值**
>
> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key包括'bbox', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
模型集-models
============================
PaddleX目前支持 `四种视觉任务解决方案 <../../cv_solutions.html>`_ ,包括图像分类、目标检测、实例分割和语义分割。对于每种视觉任务,PaddleX又提供了1种或多种模型,用户可根据需求及应用场景选取。
.. toctree::
:maxdepth: 2
classification.md
detection.md
instance_segmentation.md
semantic_segmentation.md
# 实例分割
## MaskRCNN类
```python
paddlex.det.MaskRCNN(num_classes=81, backbone='ResNet50', with_fpn=True, aspect_ratios=[0.5, 1.0, 2.0], anchor_sizes=[32, 64, 128, 256, 512])
```
> 构建MaskRCNN检测器。**注意在MaskRCNN中,num_classes需要设置为类别数+背景类,如目标包括human、dog两种,则num_classes需设为3,多的一种为背景background类别**
> **参数**
> > - **num_classes** (int): 包含了背景类的类别数。默认为81。
> > - **backbone** (str): MaskRCNN的backbone网络,取值范围为['ResNet18', 'ResNet50', 'ResNet50_vd', 'ResNet101', 'ResNet101_vd']。默认为'ResNet50'。
> > - **with_fpn** (bool): 是否使用FPN结构。默认为True。
> > - **aspect_ratios** (list): 生成anchor高宽比的可选值。默认为[0.5, 1.0, 2.0]。
> > - **anchor_sizes** (list): 生成anchor大小的可选值。默认为[32, 64, 128, 256, 512]。
#### train 训练接口
```python
train(self, num_epochs, train_dataset, train_batch_size=1, eval_dataset=None, save_interval_epochs=1, log_interval_steps=20, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=1.0/800, warmup_steps=500, warmup_start_lr=1.0 / 2400, lr_decay_epochs=[8, 11], lr_decay_gamma=0.1, metric=None, use_vdl=False, early_stop=False, early_stop_patience=5, resume_checkpoint=None)
```
> MaskRCNN模型的训练接口,函数内置了`piecewise`学习率衰减策略和`momentum`优化器。
> **参数**
>
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认为1。
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认值为'output'。
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为None。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认为0.00125。
> > - **warmup_steps** (int): 默认优化器进行warmup过程的步数。默认为500。
> > - **warmup_start_lr** (int): 默认优化器warmup的起始学习率。默认为1.0/2400。
> > - **lr_decay_epochs** (list): 默认优化器的学习率衰减轮数。默认为[8, 11]。
> > - **lr_decay_gamma** (float): 默认优化器的学习率衰减率。默认为0.1。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认值为None。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认值为False。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
#### evaluate 评估接口
```python
evaluate(self, eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)
```
> MaskRCNN模型的评估接口,模型评估后会返回在验证集上的指标box_mmap(metric指定为COCO时)和相应的seg_mmap。
> **参数**
>
> > - **eval_dataset** (paddlex.datasets): 验证数据读取器。
> > - **batch_size** (int): 验证数据批大小。默认为1。当前只支持设置为1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **metric** (bool): 训练过程中评估的方式,取值范围为['COCO', 'VOC']。默认为None,根据用户传入的Dataset自动选择,如为VOCDetection,则`metric`为'VOC'; 如为COCODetection,则`metric`为'COCO'。
> > - **return_details** (bool): 是否返回详细信息。默认值为False。
> >
> **返回值**
>
> > - **tuple** (metrics, eval_details) | **dict** (metrics): 当`return_details`为True时,返回(metrics, eval_details),当return_details为False时,返回metrics。metrics为dict,包含关键字:'bbox_mmap'和'segm_mmap'或者’bbox_map‘和'segm_map',分别表示预测框和分割区域平均准确率平均值在各个IoU阈值下的结果取平均值的结果(mmAP)、平均准确率平均值(mAP)。eval_details为dict,包含关键字:'bbox',对应元素预测框结果列表,每个预测结果由图像id、预测框类别id、预测框坐标、预测框得分;'mask',对应元素预测区域结果列表,每个预测结果由图像id、预测区域类别id、预测区域坐标、预测区域得分;’gt‘:真实标注框和标注区域相关信息。
#### predict 预测接口
```python
predict(self, img_file, transforms=None)
```
> MaskRCNN模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在FasterRCNN.test_transforms和FasterRCNN.eval_transforms中。如未在训练时定义eval_dataset,那在调用预测predict接口时,用户需要再重新定义test_transforms传入给predict接口。
> **参数**
>
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.det.transforms): 数据预处理操作。
>
> **返回值**
>
> > - **list**: 预测结果列表,列表中每个元素均为一个dict,key'bbox', 'mask', 'category', 'category_id', 'score',分别表示每个预测目标的框坐标信息、Mask信息,类别、类别id、置信度,其中框坐标信息为[xmin, ymin, w, h],即左上角x, y坐标和框的宽和高。
# 语义分割
## DeepLabv3p类
```python
paddlex.seg.DeepLabv3p(num_classes=2, backbone='MobileNetV2_x1.0', output_stride=16, aspp_with_sep_conv=True, decoder_use_sep_conv=True, encoder_with_aspp=True, enable_decoder=True, use_bce_loss=False, use_dice_loss=False, class_weight=None, ignore_index=255)
```
> 构建DeepLabv3p分割器。
> **参数**
> > - **num_classes** (int): 类别数。
> > - **backbone** (str): DeepLabv3+的backbone网络,实现特征图的计算,取值范围为['Xception65', 'Xception41', 'MobileNetV2_x0.25', 'MobileNetV2_x0.5', 'MobileNetV2_x1.0', 'MobileNetV2_x1.5', 'MobileNetV2_x2.0'],'MobileNetV2_x1.0'。
> > - **output_stride** (int): backbone 输出特征图相对于输入的下采样倍数,一般取值为8或16。默认16。
> > - **aspp_with_sep_conv** (bool): decoder模块是否采用separable convolutions。默认True。
> > - **decoder_use_sep_conv** (bool): decoder模块是否采用separable convolutions。默认True。
> > - **encoder_with_aspp** (bool): 是否在encoder阶段采用aspp模块。默认True。
> > - **enable_decoder** (bool): 是否使用decoder模块。默认True。
> > - **use_bce_loss** (bool): 是否使用bce loss作为网络的损失函数,只能用于两类分割。可与dice loss同时使用。默认False。
> > - **use_dice_loss** (bool): 是否使用dice loss作为网络的损失函数,只能用于两类分割,可与bce loss同时使用,当`use_bce_loss`和`use_dice_loss`都为False时,使用交叉熵损失函数。默认False。
> > - **class_weight** (list/str): 交叉熵损失函数各类损失的权重。当`class_weight`为list的时候,长度应为`num_classes`。当`class_weight`为str时, weight.lower()应为'dynamic',这时会根据每一轮各类像素的比重自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,即平时使用的交叉熵损失函数。
> > - **ignore_index** (int): label上忽略的值,label为`ignore_index`的像素不参与损失函数的计算。默认255。
### train 训练接口
```python
train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, eval_batch_size=1, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='IMAGENET', optimizer=None, learning_rate=0.01, lr_decay_power=0.9, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None):
```
> DeepLabv3p模型的训练接口,函数内置了`polynomial`学习率衰减策略和`momentum`优化器。
> **参数**
> >
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认2。
> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认'output'
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认'IMAGENET'。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认的优化器:使用fluid.optimizer.Momentum优化方法,polynomial的学习率衰减策略。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认0.01。
> > - **lr_decay_power** (float): 默认优化器学习率衰减指数。默认0.9。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认False。
> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
### evaluate 评估接口
```python
evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False):
```
> DeepLabv3p模型评估接口。
> **参数**
> >
> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
> > - **batch_size** (int): 评估时的batch大小。默认1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **return_details** (bool): 是否返回详细信息。默认False。
> **返回值**
> >
> > - **dict**: 当`return_details`为False时,返回dict。包含关键字:'miou'、'category_iou'、'macc'、
> > 'category_acc'和'kappa',分别表示平均iou、各类别iou、平均准确率、各类别准确率和kappa系数。
> > - **tuple** (metrics, eval_details):当`return_details`为True时,增加返回dict (eval_details),
> > 包含关键字:'confusion_matrix',表示评估的混淆矩阵。
### predict 预测接口
```
predict(self, im_file, transforms=None):
```
> DeepLabv3p模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`DeepLabv3p.test_transforms`和`DeepLabv3p.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
> **参数**
> >
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.seg.transforms): 数据预处理操作。
> **返回值**
> >
> > - **dict**: 包含关键字'label_map'和'score_map', 'label_map'存储预测结果灰度图,像素值表示对应的类别,'score_map'存储各类别的概率,shape=(h, w, num_classes)。
## UNet类
```python
paddlex.seg.UNet(num_classes=2, upsample_mode='bilinear', use_bce_loss=False, use_dice_loss=False, class_weight=None, ignore_index=255)
```
> 构建UNet分割器。
> **参数**
> > - **num_classes** (int): 类别数。
> > - **upsample_mode** (str): UNet decode时采用的上采样方式,取值为'bilinear'时利用双线行差值进行上菜样,当输入其他选项时则利用反卷积进行上菜样,默认为'bilinear'。
> > - **use_bce_loss** (bool): 是否使用bce loss作为网络的损失函数,只能用于两类分割。可与dice loss同时使用。默认False。
> > - **use_dice_loss** (bool): 是否使用dice loss作为网络的损失函数,只能用于两类分割,可与bce loss同时使用。当use_bce_loss和use_dice_loss都为False时,使用交叉熵损失函数。默认False。
> > - **class_weight** (list/str): 交叉熵损失函数各类损失的权重。当`class_weight`为list的时候,长度应为`num_classes`。当`class_weight`为str时, weight.lower()应为'dynamic',这时会根据每一轮各类像素的比重自行计算相应的权重,每一类的权重为:每类的比例 * num_classes。class_weight取默认值None是,各类的权重1,即平时使用的交叉熵损失函数。
> > - **ignore_index** (int): label上忽略的值,label为`ignore_index`的像素不参与损失函数的计算。默认255。
### train 训练接口
```python
train(self, num_epochs, train_dataset, train_batch_size=2, eval_dataset=None, eval_batch_size=1, save_interval_epochs=1, log_interval_steps=2, save_dir='output', pretrain_weights='COCO', optimizer=None, learning_rate=0.01, lr_decay_power=0.9, use_vdl=False, sensitivities_file=None, eval_metric_loss=0.05, early_stop=False, early_stop_patience=5, resume_checkpoint=None):
```
> UNet模型训练接口。
> **参数**
> >
> > - **num_epochs** (int): 训练迭代轮数。
> > - **train_dataset** (paddlex.datasets): 训练数据读取器。
> > - **train_batch_size** (int): 训练数据batch大小。同时作为验证数据batch大小。默认2。
> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
> > - **save_interval_epochs** (int): 模型保存间隔(单位:迭代轮数)。默认为1。
> > - **log_interval_steps** (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
> > - **save_dir** (str): 模型保存路径。默认'output'
> > - **pretrain_weights** (str): 若指定为路径时,则加载路径下预训练模型;若为字符串'IMAGENET',则自动下载在COCO图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认'COCO'。
> > - **optimizer** (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认的优化器:使用fluid.optimizer.Momentum优化方法,polynomial的学习率衰减策略。
> > - **learning_rate** (float): 默认优化器的初始学习率。默认0.01。
> > - **lr_decay_power** (float): 默认优化器学习率衰减指数。默认0.9。
> > - **use_vdl** (bool): 是否使用VisualDL进行可视化。默认False。
> > - **sensitivities_file** (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串'DEFAULT',则自动下载在ImageNet图片数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
> > - **eval_metric_loss** (float): 可容忍的精度损失。默认为0.05。
> > - **early_stop** (float): 是否使用提前终止训练策略。默认值为False。
> > - **early_stop_patience** (int): 当使用提前终止训练策略时,如果验证集精度在`early_stop_patience`个epoch内连续下降或持平,则终止训练。默认值为5。
> > - **resume_checkpoint** (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
#### evaluate 评估接口
```
evaluate(self, eval_dataset, batch_size=1, epoch_id=None, return_details=False):
```
> UNet模型评估接口。
> **参数**
> >
> > - **eval_dataset** (paddlex.datasets): 评估数据读取器。
> > - **batch_size** (int): 评估时的batch大小。默认1。
> > - **epoch_id** (int): 当前评估模型所在的训练轮数。
> > - **return_details** (bool): 是否返回详细信息。默认False。
> **返回值**
> >
> > - **dict**: 当return_details为False时,返回dict。包含关键字:'miou'、'category_iou'、'macc'、
> > 'category_acc'和'kappa',分别表示平均iou、各类别iou、平均准确率、各类别准确率和kappa系数。
> > - **tuple** (metrics, eval_details):当return_details为True时,增加返回dict (eval_details),
> > 包含关键字:'confusion_matrix',表示评估的混淆矩阵。
#### predict 预测接口
```
predict(self, im_file, transforms=None):
```
> UNet模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在`UNet.test_transforms`和`UNet.eval_transforms`中。如未在训练时定义eval_dataset,那在调用预测`predict`接口时,用户需要再重新定义test_transforms传入给`predict`接口。
> **参数**
> >
> > - **img_file** (str): 预测图像路径。
> > - **transforms** (paddlex.seg.transforms): 数据预处理操作。
> **返回值**
> >
> > - **dict**: 包含关键字'label_map'和'score_map', 'label_map'存储预测结果灰度图,像素值表示对应的类别,'score_map'存储各类别的概率,shape=(h, w, num_classes)。
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
## 计算参数敏感度 ## 计算参数敏感度
``` ```
paddlex.slim.cal_params_sensetives(model, save_file, eval_dataset, batch_size=8) paddlex.slim.cal_params_sensitivities(model, save_file, eval_dataset, batch_size=8)
``` ```
计算模型中可裁剪参数在验证集上的敏感度,并将敏感度信息保存至文件`save_file` 计算模型中可裁剪参数在验证集上的敏感度,并将敏感度信息保存至文件`save_file`
1. 获取模型中可裁剪卷积Kernel的名称。 1. 获取模型中可裁剪卷积Kernel的名称。
......
# 数据增强与imgaug支持
数据增强操作可用于在模型训练时,增加训练样本的多样性,从而提升模型的泛化能力。
## PaddleX内置增强操作
PaddleX对于图像分类、目标检测、实例分割和语义分割内置了部分常见的数据增强操作,如下表所示,
| 任务类型 | 增强方法 |
| :------- | :------------|
| 图像分类 | [RandomCrop](cls_transforms.html#randomcrop)[RandomHorizontalFlip](cls_transforms.html#randomhorizontalflip)[RandomVerticalFlip](cls_transforms.html#randomverticalflip)<br> [RandomRotate](cls_transforms.html#randomratate)[RandomDistort](cls_transforms.html#randomdistort) |
|目标检测<br>实例分割| [RandomHorizontalFlip](det_transforms.html#randomhorizontalflip)[RandomDistort](det_transforms.html#randomdistort)[RandomCrop](det_transforms.html#randomcrop)<br> [[MixupImage](det_transforms.html#mixupimage)(仅支持YOLOv3模型)、RandomExpand](det_transforms.html#randomexpand) |
|语义分割 | [RandomHorizontalFlip](seg_transforms.html#randomhorizontalflip)[RandomVerticalFlip](seg_transforms.html#randomverticalflip)[RandomRangeScaling](seg_transforms.html#randomrangescaling)<br> [RandomStepScaling](seg_transforms.html#randomstepscaling)[RandomPaddingCrop](seg_transforms.html#randompaddingcrop)[RandomBlur](seg_transforms.html#randomblur)<br> [RandomRotation](seg_transforms.html#randomrotation)[RandomScaleAspect](seg_transforms.html#randomscaleaspect)[RandomDistort](seg_transforms.html#randomdistort) |
## imgaug增强库的支持
PaddleX目前已适配imgaug图像增强库,用户可以直接在PaddleX构造`transforms`时,调用imgaug的方法, 如下示例
```
import paddlex as pdx
from paddlex.cls import transforms
import imgaug.augmenters as iaa
train_transforms = transforms.Compose([
# 随机在[0.0 3.0]中选值对图像进行模糊
iaa.blur.GaussianBlur(sigma=(0.0, 3.0)),
transforms.RandomCrop(crop_size=224),
transforms.Normalize()
])
```
除了上述用法,`Compose`接口中也支持imgaug的`Someof``Sometimes``Sequential``Oneof`等操作,开发者可以通过这些方法随意组合出增强流程。由于imgaug对于标注信息(目标检测框和实例分割mask)与PaddleX模型训练逻辑有部分差异,**目前在检测和分割中,只支持pixel-level的增强方法,(即在增强时,不对图像的大小和方向做改变) 其它方法仍在适配中**,详情可见下表,
| 增强方法 | 图像分类 | 目标检测<br> 实例分割 | 语义分割 | 备注 |
| :------ | :------- | :-------------------- | :------- | :--- |
| [imgaug.augmenters.arithmetic](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_arithmetic.html) |√ |√ |√ | Cutout, DropoutJpegCompression等|
| [imgaug.augmenters.artistic](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_artistic.html) |√ |√ |√ | 图像卡通化|
| [imgaug.augmenters.blur](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_blur.html) |√ |√ |√ | GaussianBlur, AverageBlur等|
| [imgaug.augmenters.collections](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_collections.html) |√ | | |提供了RandAugment方法 |
| [imgaug.augmenters.color](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_color.html) |√ |√ |√ | Brightness, Hue等色调的增强方法|
| [imgaug.augmenters.contrast](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_contrast.html) |√ |√ |√ | 多种对比度增强方式|
| [imgaug.augmenters.convolutional](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_convolutional.html) |√ |√ |√ | 应用卷积kernel到图像 |
| [imgaug.augmenters.edges](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_edges.html) |√ |√ |√ | 图像边缘化等方法|
| [imgaug.augmenters.flip](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_flip.html) |√ | | | Fliplr和Flipud翻转方法|
| [imgaug.augmenters.geometric](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_geometric.html) |√ | | | Affine、Rotate等增强方法|
| [imgaug.augmenters.imgcorruptlike](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_imgcorruptlike.html) |√ |√ |√ | GaussianNoise等图像噪声增强方法|
| [imgaug.augmenters.pillike](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_pillike.html) |√ | | | |
| [imgaug.augmenters.pooling](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_pooling.html) |√ | | |应用pooling操作到图像 |
| [imgaug.augmenters.segmentation](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_segmentation.html) |√ | | | 应用分割方法到图像|
| [imgaug.augmenters.size](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_size.html) |√ | | | Reisze、Crop、Pad等操作|
| [imgaug.augmenters.weather](https://imgaug.readthedocs.io/en/latest/source/api_augmenters_weather.html) |√ |√ |√ | 多种模拟天气等增强方法|
需要注意的是,imgaug的基础方法中,如`imgaug.augmenters.blur`仅为图像处理操作,并无概率设置,而在CV模型训练中,增强操作往往是以一定概率应用在样本上,因此我们可以通过imgaug的`Someof``Sometimes``Sequential``Oneof`等操作来组合实现,如下代码所示,
> - `Someof` 执行定义增强方法列表中的部分方法
> - `Sometimes` 以一定概率执行定义的增强方法列表
> - `Sequential` 按顺序执行定义的增强方法列表
```
image imgaug.augmenters as iaa
from paddlex.cls import transforms
# 以0.6的概率对图像样本进行模糊
img_augmenters = iaa.Sometimes(0.6, [
iaa.blur.GaussianBlur(sigma=(0.0, 3.0))
])
train_transforms = transforms.Compose([
img_augmenters,
transforms.RandomCrop(crop_size=224),
transforms.Normalize()
])
```
# 分类-paddlex.cls.transforms # 图像分类-cls.transforms
对图像分类任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。 对图像分类任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。
......
# 检测-paddlex.det.transforms # 检测和实例分割-det.transforms
对目标检测任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。 对目标检测任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。
......
...@@ -9,3 +9,4 @@ transforms为PaddleX的模型训练提供了数据的预处理和数据增强接 ...@@ -9,3 +9,4 @@ transforms为PaddleX的模型训练提供了数据的预处理和数据增强接
cls_transforms.md cls_transforms.md
det_transforms.md det_transforms.md
seg_transforms.md seg_transforms.md
augment.md
# 分割-paddlex.seg.transforms # 语义分割-seg.transforms
对用于分割任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。 对用于分割任务的数据进行操作。可以利用[Compose](#compose)类将图像预处理/增强操作进行组合。
......
文件模式从 100644 更改为 100755
...@@ -3,11 +3,12 @@ Anaconda是一个开源的Python发行版本,其包含了conda、Python等180 ...@@ -3,11 +3,12 @@ Anaconda是一个开源的Python发行版本,其包含了conda、Python等180
## Windows安装Anaconda ## Windows安装Anaconda
### 第一步 下载 ### 第一步 下载
在Anaconda官网[(https://www.anaconda.com/products/individual)](https://www.anaconda.com/products/individual)选择下载Windows Python3.7 64-Bit版本 - 在Anaconda官网[(https://www.anaconda.com/products/individual)](https://www.anaconda.com/products/individual)选择下载Windows Python3.7 64-Bit版本
- 确保已经安装`Visual C++ Build Tools`(可以在开始菜单中找到),如未安装,请[点击下载](https://go.microsoft.com/fwlink/?LinkId=691126)安装。
### 第二步 安装 ### 第二步 安装
运行下载的安装包(以.exe为后辍),根据引导完成安装, 用户可自行修改安装目录(如下图) 运行下载的安装包(以.exe为后辍),根据引导完成安装, 用户可自行修改安装目录(如下图)
![](./images/anaconda_windows.png) ![](../images/anaconda_windows.png)
### 第三步 使用 ### 第三步 使用
- 点击Windows系统左下角的Windows图标,打开:所有程序->Anaconda3/2(64-bit)->Anaconda Prompt - 点击Windows系统左下角的Windows图标,打开:所有程序->Anaconda3/2(64-bit)->Anaconda Prompt
...@@ -21,7 +22,7 @@ conda activate my_paddlex ...@@ -21,7 +22,7 @@ conda activate my_paddlex
conda install git conda install git
# 安装pycocotools # 安装pycocotools
pip install cython pip install cython
pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI pip install git+https://gitee.com/jiangjiajun/philferriere-cocoapi.git#subdirectory=PythonAPI
# 安装paddlepaddle-gpu # 安装paddlepaddle-gpu
pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
# 安装paddlex # 安装paddlex
......
附录
=======================================
.. toctree::
:maxdepth: 1
:caption: 目录:
model_zoo.md
metrics.md
* PaddleX版本: v0.1.7
* 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex
* 项目GitHub: https://github.com/PaddlePaddle/PaddleX/tree/develop
* 官方QQ用户群: 1045148026
* GitHub Issue反馈: http://www.github.com/PaddlePaddle/PaddleX/issues
# PaddleX指标及日志
PaddleX在模型训练、评估过程中,都会有相应的日志和指标反馈,本文档用于说明这些日志和指标的含义。
## 训练通用统计信息
PaddleX所有模型在训练过程中,输出的日志信息都包含了6个通用的统计信息,用于辅助用户进行模型训练,例如**分割模型**的训练日志,如下图所示。
![](../images/seg_train.png)
各字段含义如下:
| 字段 | 字段值示例 | 含义 |
| -------------- | -------------------- | ------------------------------------------------------------ |
| Epoch | Epoch=4/20 | [迭代轮数]所有训练数据会被训练20轮,当前处于第4轮 |
| Step | Step=62/66 | [迭代步数]所有训练数据被训练一轮所需要的迭代步数为66,当前处于第62步 |
| loss | loss=0.007226 | [损失函数值]参与当前迭代步数的训练样本的平均损失函数值loss,loss值越低,表明模型在训练集上拟合的效果越好(如上日志中第1行表示第4个epoch的第62个Batch的loss值为0.007226) |
| lr | lr=0.008215 | [学习率]当前模型迭代过程中的学习率 |
| time_each_step | time_each_step=0.41s | [每步迭代时间]训练过程计算得到的每步迭代平均用时 |
| eta | eta=0:9:44 | [剩余时间]模型训练完成所需剩余时间预估为0小时9分钟44秒 |
| | | |
不同模型的日志中除了上述通用字段外,还有其它字段,这些字段含义可见文档后面对各任务模型的描述。
## 评估通用统计信息
PaddleX所有模型在训练过程中会根据用户设定的`save_interval_epochs`参数,每间隔一定轮数进行评估和保存。例如**分类模型**的评估日志,如下图所示。
![](../images/cls_eval.png)
上图中第1行表明验证数据集中样本数为240,需要迭代8步才能评估完所有验证数据;第5行用于表明第2轮的模型已经完成保存操作;第6行则表明当前保存的模型中,第2轮的模型在验证集上指标最优(分类任务看`acc1`,此时`acc1`值为0.258333),最优模型会保存在`best_model`目录中。
## 分类特有统计信息
### 训练日志字段
分类任务的训练日志除了通用统计信息外,还包括`acc1``acc5`两个特有字段。
> 注: acck准确率是针对一张图片进行计算的:把模型在各个类别上的预测得分按从高往低进行排序,取出前k个预测类别,若这k个预测类别包含了真值类,则认为该图片分类正确。
![](../images/cls_train.png)
上图中第1行中的`acc1`表示参与当前迭代步数的训练样本的平均top1准确率,值越高代表模型越优;`acc5`表示参与当前迭代步数的训练样本的平均top5(若类别数n少于5,则为topn)准确率,值越高代表模型越优。第4行中的`loss`表示整个训练集的平均损失函数值,`acc1`表示整个训练集的平均top1准确率,`acc5`表示整个训练集的平均top5准确率。
### 评估日志字段
![](../images/cls_eval.png)
上图中第3行中的`acc1`表示整个验证集的平均top1准确率,`acc5`表示整个验证集的平均top5准确率。
## 检测特有统计信息
### 训练日志字段
#### YOLOv3
YOLOv3的训练日志只包括训练通用统计信息(见上文训练通用统计信息)。
![](../images/yolo_train.png)
上图中第5行`loss`表示整个训练集的平均损失函数loss值。
#### FasterRCNN
FasterRCNN的训练日志除了通用统计信息外,还包括`loss_cls``loss_bbox``loss_rpn_cls``loss_rpn_bbox`,这些字段的含义如下:
| 字段 | 含义 |
| -------------- | --------------------------------------------- |
| loss_cls | RCNN子网络中分类损失函数值 |
| loss_bbox | RCNN子网络中检测框回归损失函数值 |
| loss_rpn_cls | RPN子网络中分类损失函数值 |
| loss_rpn_bbox | RPN子网络中检测框回归损失函数值 |
| loss | 所有子网络损失函数值之和 |
![](../images/faster_train.png)
上图中第1行`loss`, `loss_cls``loss_bbox``loss_rpn_clss``loss_rpn_bbox`都是参与当前迭代步数的训练样本的损失值,而第7行是针整个训练集的损失函数值。
#### MaskRCNN
MaskRCNN的训练日志除了通用统计信息外,还包括`loss_cls``loss_bbox``loss_mask``loss_rpn_cls``loss_rpn_bbox`,这些字段的含义如下:
| 字段 | 含义 |
| -------------- | --------------------------------------------- |
| loss_cls | RCNN子网络中分类损失函数值 |
| loss_bbox | RCNN子网络中检测框回归损失函数值 |
| loss_mask | RCNN子网络中Mask回归损失函数值 |
| loss_rpn_cls | RPN子网络中分类损失函数值 |
| loss_rpn_bbox | RPN子网络中检测框回归损失函数值 |
| loss | 所有子网络损失函数值之和 |
![](../images/mask_train.png)
上图中第1行`loss`, `loss_cls``loss_bbox``loss_mask``loss_rpn_clss``loss_rpn_bbox`都是参与当前迭代步数的训练样本的损失值,而第7行是针整个训练集的损失函数值。
### 评估日志字段
检测可以使用两种评估标准:VOC评估标准和COCO评估标准。
#### VOC评估标准
![](../images/voc_eval.png)
> 注:`map`为平均准确率的平均值,即IoU(Intersection Over Union)取0.5时各个类别的准确率-召回率曲线下面积的平均值。
上图中第3行`bbox_map`表示检测任务中整个验证集的平均准确率平均值。
#### COCO评估标准
> 注:COCO评估指标可参见[COCO官网解释](http://cocodataset.org/#detection-eval)。PaddleX主要反馈`mmAP`,即AP at IoU=.50:.05:.95这项指标,为在各个IoU阈值下平均准确率平均值(mAP)的平均值。
COCO格式的数据集不仅可以用于训练目标检测模型,也可以用于训练实例分割模型。在目标检测中,PaddleX主要反馈针对检测框的`bbox_mmAP`指标;在实例分割中,还包括针对Mask的`seg_mmAP`指标。如下所示,第一张日志截图为目标检测的评估结果,第二张日志截图为实例分割的评估结果。
![](../images/faster_eval.png)
上图中红框标注的`bbox_mmap`表示整个验证集的检测框平均准确率平均值。
![](../images/mask_eval.png)
上图中红框标注的`bbox_mmap``seg_mmap`分别表示整个验证集的检测框平均准确率平均值、Mask平均准确率平均值。
## 分割特有统计信息
### 训练日志字段
语义分割的训练日志只包括训练通用统计信息(见上文训练通用统计信息)。
![](../images/seg_train.png)
### 评估日志字段
语义分割的评估日志包括了`miou``category_iou``macc``category_acc``kappa`,这些字段的含义如下:
| 字段 | 含义 |
| -------------- | --------------------------------------------- |
| miou | 各类IoU(Intersection Over Union)的平均值 |
| category_iou | 各类别的IoU |
| macc | 平均准确率,即预测正确的像素数/总像素数 |
| category_acc | 各类别的准确率,即各类别预测正确的像素数/预测为该类别的总像素数 |
| kappa | kappa系数,用于一致性检验 |
![](../images/seg_eval.png)
# PaddleX模型库
## 图像分类模型
> 表中模型相关指标均为在ImageNet数据集上使用PaddlePaddle Python预测接口测试得到(测试GPU型号为Nvidia Tesla P40),预测速度为每张图片预测用时(不包括预处理和后处理),表中符号`-`表示相关指标暂未测试。
| 模型 | 模型大小 | 预测速度(毫秒) | Top1准确率(%) | Top5准确率(%) |
| :----| :------- | :----------- | :--------- | :--------- |
| ResNet18| 46.9MB | 1.499 | 71.0 | 89.9 |
| ResNet34| 87.5MB | 2.272 | 74.6 | 92.1 |
| ResNet50| 102.7MB | 2.939 | 76.5 | 93.0 |
| ResNet101 |179.1MB | 5.314 | 77.6 | 93.6 |
| ResNet50_vd |102.8MB | 3.165 | 79.1 | 94.4 |
| ResNet101_vd| 179.2MB | 5.252 | 80.2 | 95.0 |
| ResNet50_vd_ssld |102.8MB | 3.165 | 82.4 | 96.1 |
| ResNet101_vd_ssld| 179.2MB | 5.252 | 83.7 | 96.7 |
| DarkNet53|166.9MB | 3.139 | 78.0 | 94.1 |
| MobileNetV1 | 16.0MB | 32.523 | 71.0 | 89.7 |
| MobileNetV2 | 14.0MB | 23.318 | 72.2 | 90.7 |
| MobileNetV3_large| 21.0MB | 19.308 | 75.3 | 93.2 |
| MobileNetV3_small | 12.0MB | 6.546 | 68.2 | 88.1 |
| MobileNetV3_large_ssld| 21.0MB | 19.308 | 79.0 | 94.5 |
| MobileNetV3_small_ssld | 12.0MB | 6.546 | 71.3 | 90.1 |
| Xception41 |92.4MB | 4.408 | 79.6 | 94.4 |
| Xception65 | 144.6MB | 6.464 | 80.3 | 94.5 |
| DenseNet121 | 32.8MB | 4.371 | 75.7 | 92.6 |
| DenseNet161|116.3MB | 8.863 | 78.6 | 94.1 |
| DenseNet201| 84.6MB | 8.173 | 77.6 | 93.7 |
| ShuffleNetV2 | 9.0MB | 10.941 | 68.8 | 88.5 |
## 目标检测模型
> 表中模型相关指标均为在MSCOCO数据集上使用PaddlePaddle Python预测接口测试得到(测试GPU型号为Nvidia Tesla V100测试得到,表中符号`-`表示相关指标暂未测试。
| 模型 | 模型大小 | 预测时间(毫秒) | BoxAP(%) |
|:-------|:-----------|:-------------|:----------|
|FasterRCNN-ResNet50|135.6MB| 78.450 | 35.2 |
|FasterRCNN-ResNet50_vd| 135.7MB | 79.523 | 36.4 |
|FasterRCNN-ResNet101| 211.7MB | 107.342 | 38.3 |
|FasterRCNN-ResNet50-FPN| 167.2MB | 44.897 | 37.2 |
|FasterRCNN-ResNet50_vd-FPN|168.7MB | 45.773 | 38.9 |
|FasterRCNN-ResNet101-FPN| 251.7MB | 55.782 | 38.7 |
|FasterRCNN-ResNet101_vd-FPN |252MB | 58.785 | 40.5 |
|YOLOv3-DarkNet53|252.4MB | 21.944 | 38.9 |
|YOLOv3-MobileNetv1 |101.2MB | 12.771 | 29.3 |
|YOLOv3-MobileNetv3|94.6MB | - | 31.6 |
| YOLOv3-ResNet34|169.7MB | 15.784 | 36.2 |
## 实例分割模型
> 表中模型相关指标均为在MSCOCO数据集上测试得到。
# 使用PaddleX客户端进行模型训练
**第一步:下载PaddleX客户端**
您需要前往 [官网](https://www.paddlepaddle.org.cn/paddle/paddlex)填写基本信息后下载试用PaddleX客户端
**第二步:准备数据**
在开始模型训练前,您需要根据不同的任务类型,将数据标注为相应的格式。目前PaddleX支持【图像分类】、【目标检测】、【语义分割】、【实例分割】四种任务类型。不同类型任务的数据处理方式可查看[数据标注方式](https://github.com/PaddlePaddle/PaddleX/tree/master/DataAnnotation/AnnotationNote)
**第三步:导入我的数据集**
① 数据标注完成后,您需要根据不同的任务,将数据和标注文件,按照客户端提示更名并保存到正确的文件中。
② 在客户端新建数据集,选择与数据集匹配的任务类型,并选择数据集对应的路径,将数据集导入。
![](./images/00_loaddata.png)
③ 选定导入数据集后,客户端会自动校验数据及标注文件是否合规,校验成功后,您可根据实际需求,将数据集按比例划分为训练集、验证集、测试集。
④ 您可在「数据分析」模块按规则预览您标注的数据集,双击单张图片可放大查看。
![](./images/01_datasplit.png)
**第四步:创建项目**
① 在完成数据导入后,您可以点击「新建项目」创建一个项目。
② 您可根据实际任务需求选择项目的任务类型,需要注意项目所采用的数据集也带有任务类型属性,两者需要进行匹配。
![](./images/02_newproject.png)
**第五步:项目开发**
**数据选择**:项目创建完成后,您需要选择已载入客户端并校验后的数据集,并点击下一步,进入参数配置页面。
![](./images/03_choosedata.png)
**参数配置**:主要分为**模型参数****训练参数****优化策略**三部分。您可根据实际需求选择模型结构及对应的训练参数、优化策略,使得任务效果最佳。
![](./images/04_parameter.png)
参数配置完成后,点击启动训练,模型开始训练并进行效果评估。
**训练可视化**
在训练过程中,您可通过VisualDL查看模型训练过程时的参数变化、日志详情,及当前最优的训练集和验证集训练指标。模型在训练过程中通过点击"终止训练"随时终止训练过程。
![](./images/05_train.png)
![](./images/06_VisualDL.png)
模型训练结束后,点击”下一步“,进入模型评估页面。
**模型评估**
在模型评估页面,您可将训练后的模型应用在切分时留出的「验证数据集」以测试模型在验证集上的效果。评估方法包括混淆矩阵、精度、召回率等。在这个页面,您也可以直接查看模型在测试数据集上的预测效果。
根据评估结果,您可决定进入模型发布页面,或返回先前步骤调整参数配置重新进行训练。
![](./images/07_evaluate.png)
**模型发布**
当模型效果满意后,您可根据实际的生产环境需求,选择将模型发布为需要的版本。
![](./images/08_deploy.png)
文件模式从 100644 更改为 100755
# 模型转换
## 转ONNX模型
PaddleX基于[Paddle2ONNX工具](https://github.com/PaddlePaddle/paddle2onnx),提供了便捷的API,支持用户将PaddleX训练保存的模型导出为ONNX模型。
通过如下示例代码,用户即可将PaddleX训练好的MobileNetV2模型导出
```
import paddlex as pdx
pdx.convertor.to_onnx(model_dir='paddle_mobilenet', save_dir='onnx_mobilenet')
```
## 转PaddleLite模型
PaddleX可支持导出为[PaddleLite](https://github.com/PaddlePaddle/Paddle-Lite)支持的模型格式,用于支持用户将模型部署更多硬件设备。
通过如下示例代码,用户即可将PaddleX训练好的MobileNetV2模型导出
```
import paddlex as pdx
pdx.convertor.to_lite(model_dir='paddle_mobilenet', save_dir='lite_mobilnet', terminal='arm')
```
# PaddleX视觉方案介绍
PaddleX目前提供了4种视觉任务解决方案,分别为图像分类、目标检测、实例分割和语义分割。用户可以根据自己的任务类型按需选取。
## 图像分类
图像分类任务指的是输入一张图片,模型预测图片的类别,如识别为风景、动物、车等。
![](./images/image_classification.png)
对于图像分类任务,针对不同的应用场景,PaddleX提供了百度改进的模型,见下表所示
| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | 准确率 | 备注 |
| :--------- | :------ | :---------- | :-----------| :------------- | :----- | :--- |
| MobileNetV3_small_ssld | 12M | ? | ? | ? | 71.3% |适用于移动端场景 |
| MobileNetV3_large_ssld | 21M | ? | ? | ? | 79.0% | 适用于移动端/服务端场景 |
| ResNet50_vd_ssld | 102.8MB | ? | ? | ? | 82.4% | 适用于服务端场景 |
| ResNet101_vd_ssld | 179.2MB | ? | ? | ? |83.7% | 适用于服务端场景 |
除上述模型外,PaddleX还支持近20种图像分类模型,模型列表可参考[PaddleX模型库](../appendix/model_zoo.md)
## 目标检测
目标检测任务指的是输入图像,模型识别出图像中物体的位置(用矩形框框出来,并给出框的位置),和物体的类别,如在手机等零件质检中,用于检测外观上的瑕疵等。
![](./images/object_detection.png)
对于目标检测,针对不同的应用场景,PaddleX提供了主流的YOLOv3模型和Faster-RCNN模型,见下表所示
| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 |ARM芯片预测速度 | BoxMAP | 备注 |
| :------- | :------- | :--------- | :---------- | :------------- | :----- | :--- |
| YOLOv3-MobileNetV1 | 101.2M | ? | ? | ? | 29.3 | |
| YOLOv3-MobileNetV3 | 94.6M | ? | ? | ? | 31.6 | |
| YOLOv3-ResNet34 | 169.7M | ? | ? | ? | 36.2 | |
| YOLOv3-DarkNet53 | 252.4 | ? | ? | ? | 38.9 | |
除YOLOv3模型外,PaddleX同时也支持FasterRCNN模型,支持FPN结构和5种backbone网络,详情可参考[PaddleX模型库](../appendix/model_zoo.md)
## 实例分割
在目标检测中,模型识别出图像中物体的位置和物体的类别。而实例分割则是在目标检测的基础上,做了像素级的分类,将框内的属于目标物体的像素识别出来。
![](./images/instance_segmentation.png)
PaddleX目前提供了实例分割MaskRCNN模型,支持5种不同的backbone网络,详情可参考[PaddleX模型库](../appendix/model_zoo.md)
| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | BoxMAP | SegMAP | 备注 |
| :---- | :------- | :---------- | :---------- | :------------- | :----- | :----- | :--- |
| MaskRCNN-ResNet50_vd-FPN | 185.5M | ? | ? | ? | 39.8 | 35.4 | |
| MaskRCNN-ResNet101_vd-FPN | 268.6M | ? | ? | ? | 41.4 | 36.8 | |
## 语义分割
语义分割用于对图像做像素级的分类,应用在人像分类、遥感图像识别等场景。
![](./images/semantic_segmentation.png)
对于语义分割,PaddleX也针对不同的应用场景,提供了不同的模型选择,如下表所示
| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | mIOU | 备注 |
| :---- | :------- | :---------- | :---------- | :------------- | :----- | :----- |
| DeepLabv3p-MobileNetV2_x0.25 | | ? | ? | ? | ? | ? |
| DeepLabv3p-MobileNetV2_x1.0 | | ? | ? | ? | ? | ? |
| DeepLabv3p-Xception65 | | ? | ? | ? | ? | ? |
| UNet | | ? | ? | ? | ? | ? |
...@@ -41,8 +41,8 @@ labelA ...@@ -41,8 +41,8 @@ labelA
labelB labelB
... ...
``` ```
[点击这里](https://bj.bcebos.com/paddlex/datasets/vegetables_cls.tar.gz),下载蔬菜分类分类数据集 [点击这里](https://bj.bcebos.com/paddlex/datasets/vegetables_cls.tar.gz),下载蔬菜分类分类数据集
在PaddleX中,使用`paddlex.cv.datasets.ImageNet`([API说明](./apis/datasets.html#imagenet))加载分类数据集 在PaddleX中,使用`paddlex.cv.datasets.ImageNet`([API说明](./apis/datasets.html#imagenet))加载分类数据集
## 目标检测VOC ## 目标检测VOC
目标检测VOC数据集包含图像文件夹、标注信息文件夹、标签文件及图像列表文件。 目标检测VOC数据集包含图像文件夹、标注信息文件夹、标签文件及图像列表文件。
...@@ -81,8 +81,8 @@ labelA ...@@ -81,8 +81,8 @@ labelA
labelB labelB
... ...
``` ```
[点击这里](https://bj.bcebos.com/paddlex/datasets/insect_det.tar.gz),下载昆虫检测数据集 [点击这里](https://bj.bcebos.com/paddlex/datasets/insect_det.tar.gz),下载昆虫检测数据集
在PaddleX中,使用`paddlex.cv.datasets.VOCDetection`([API说明](./apis/datasets.html#vocdetection))加载目标检测VOC数据集 在PaddleX中,使用`paddlex.cv.datasets.VOCDetection`([API说明](./apis/datasets.html#vocdetection))加载目标检测VOC数据集
## 目标检测和实例分割COCO ## 目标检测和实例分割COCO
目标检测和实例分割COCO数据集包含图像文件夹及图像标注信息文件。 目标检测和实例分割COCO数据集包含图像文件夹及图像标注信息文件。
...@@ -135,7 +135,7 @@ labelB ...@@ -135,7 +135,7 @@ labelB
] ]
} }
``` ```
其中,每个字段的含义如下所示: 每个字段的含义如下所示:
| 域名 | 字段名 | 含义 | 数据类型 | 备注 | | 域名 | 字段名 | 含义 | 数据类型 | 备注 |
|:-----|:--------|:------------|------|:-----| |:-----|:--------|:------------|------|:-----|
...@@ -155,8 +155,8 @@ labelB ...@@ -155,8 +155,8 @@ labelB
| categories | supercategory | 类别父类的标签名 | str | | | categories | supercategory | 类别父类的标签名 | str | |
[点击这里](https://bj.bcebos.com/paddlex/datasets/garbage_ins_det.tar.gz),下载垃圾实例分割数据集 [点击这里](https://bj.bcebos.com/paddlex/datasets/garbage_ins_det.tar.gz),下载垃圾实例分割数据集
在PaddleX中,使用`paddlex.cv.datasets.COCODetection`([API说明](./apis/datasets.html#cocodetection))加载COCO格式数据集 在PaddleX中,使用`paddlex.cv.datasets.COCODetection`([API说明](./apis/datasets.html#cocodetection))加载COCO格式数据集
## 语义分割数据 ## 语义分割数据
语义分割数据集包含原图、标注图及相应的文件列表文件。 语义分割数据集包含原图、标注图及相应的文件列表文件。
...@@ -191,176 +191,14 @@ images/xxx2.png annotations/xxx2.png ...@@ -191,176 +191,14 @@ images/xxx2.png annotations/xxx2.png
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示: `labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
``` ```
background
labelA labelA
labelB labelB
... ...
``` ```
标注图像为单通道图像,像素值即为对应的类别,像素标注类别需要从0开始递增(一般第一个类别为`background` 标注图像为单通道图像,像素值即为对应的类别,像素标注类别需要从0开始递增,
例如0,1,2,3表示有4种类别,标注类别最多为256类。其中可以指定特定的像素值用于表示该值的像素不参与训练和评估(默认为255)。 例如0,1,2,3表示有4种类别,标注类别最多为256类。其中可以指定特定的像素值用于表示该值的像素不参与训练和评估(默认为255)。
[点击这里](https://bj.bcebos.com/paddlex/datasets/optic_disc_seg.tar.gz),下载视盘语义分割数据集 [点击这里](https://bj.bcebos.com/paddlex/datasets/optic_disc_seg.tar.gz),下载视盘语义分割数据集
在PaddleX中,使用`paddlex.cv.datasets.SegReader`([API说明](./apis/datasets.html#segreader))加载语义分割数据集 在PaddleX中,使用`paddlex.cv.datasets.SegReader`([API说明](./apis/datasets.html#segreader))加载语义分割数据集
## 图像分类EasyDataCls
图像分类EasyDataCls数据集包含存放图像和json文件的文件夹、标签文件及图像列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录
|--easydata # 存放图像和json文件的文件夹
| |--0001.jpg
| |--0001.json
| |--0002.jpg
| |--0002.json
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表文件
```
其中,图像文件名应与json文件名一一对应。
每个json文件存储于`labels`相关的信息。如下所示:
```
{"labels": [{"name": "labelA"}]}
```
其中,`name`字段代表对应图像的类别。
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为json文件相对于dataset的相对路径。如下所示:
```
easydata/0001.jpg easydata/0001.json
easydata/0002.jpg easydata/0002.json
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
labelA
labelB
...
```
[点击这里](https://ai.baidu.com/easydata/),可以标注图像分类EasyDataCls数据集。
在PaddleX中,使用`paddlex.cv.datasets.EasyDataCls`([API说明](./apis/datasets.html#easydatacls))加载分类数据集。
## 目标检测和实例分割EasyDataDet
目标检测和实例分割EasyDataDet数据集包含存放图像和json文件的文件夹、标签文件及图像列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录ß
|--easydata # 存放图像和json文件的文件夹
| |--0001.jpg
| |--0001.json
| |--0002.jpg
| |--0002.json
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表文件
```
其中,图像文件名应与json文件名一一对应。
每个json文件存储于`labels`相关的信息。如下所示:
```
"labels": [{"y1": 18, "x2": 883, "x1": 371, "y2": 404, "name": "labelA",
"mask": "kVfc0`0Zg0<F7J7I5L5K4L4L4L3N3L3N3L3N2N3M2N2N2N2N2N2N1O2N2O1N2N1O2O1N101N1O2O1N101N10001N101N10001N10001O0O10001O000O100000001O0000000000000000000000O1000001O00000O101O000O101O0O101O0O2O0O101O0O2O0O2N2O0O2O0O2N2O1N1O2N2N2O1N2N2N2N2N2N2M3N3M2M4M2M4M3L4L4L4K6K5J7H9E\\iY1"},
{"y1": 314, "x2": 666, "x1": 227, "y2": 676, "name": "labelB",
"mask": "mdQ8g0Tg0:G8I6K5J5L4L4L4L4M2M4M2M4M2N2N2N3L3N2N2N2N2O1N1O2N2N2O1N1O2N2O0O2O1N1O2O0O2O0O2O001N100O2O000O2O000O2O00000O2O000000001N100000000000000000000000000000000001O0O100000001O0O10001N10001O0O101N10001N101N101N101N101N2O0O2N2O0O2N2N2O0O2N2N2N2N2N2N2N2N2N3L3N2N3L3N3L4M2M4L4L5J5L5J7H8H;BUcd<"},
...]}
```
其中,list中的每个元素代表一个标注信息,标注信息中字段的含义如下所示:
| 字段名 | 含义 | 数据类型 | 备注 |
|:--------|:------------|------|:-----|
| x1 | 标注框左下角横坐标 | int | |
| y1 | 标注框左下角纵坐标 | int | |
| x2 | 标注框右上角横坐标 | int | |
| y2 | 标注框右上角纵坐标 | int | |
| name | 标注框中物体类标 | str | |
| mask | 分割区域布尔型numpy编码后的字符串 | str | 该字段可以不存在,当不存在时只能进行目标检测 |
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为json文件相对于dataset的相对路径。如下所示:
```
easydata/0001.jpg easydata/0001.json
easydata/0002.jpg easydata/0002.json
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
labelA
labelB
...
```
[点击这里](https://ai.baidu.com/easydata/),可以标注图像分类EasyDataDet数据集。
在PaddleX中,使用`paddlex.cv.datasets.EasyDataDet`([API说明](./apis/datasets.html#easydatadet))加载分类数据集。
## 语义分割EasyDataSeg
语义分割EasyDataSeg数据集包含存放图像和json文件的文件夹、标签文件及图像列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录ß
|--easydata # 存放图像和json文件的文件夹
| |--0001.jpg
| |--0001.json
| |--0002.jpg
| |--0002.json
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表文件
```
其中,图像文件名应与json文件名一一对应。
每个json文件存储于`labels`相关的信息。如下所示:
```
"labels": [{"y1": 18, "x2": 883, "x1": 371, "y2": 404, "name": "labelA",
"mask": "kVfc0`0Zg0<F7J7I5L5K4L4L4L3N3L3N3L3N2N3M2N2N2N2N2N2N1O2N2O1N2N1O2O1N101N1O2O1N101N10001N101N10001N10001O0O10001O000O100000001O0000000000000000000000O1000001O00000O101O000O101O0O101O0O2O0O101O0O2O0O2N2O0O2O0O2N2O1N1O2N2N2O1N2N2N2N2N2N2M3N3M2M4M2M4M3L4L4L4K6K5J7H9E\\iY1"},
{"y1": 314, "x2": 666, "x1": 227, "y2": 676, "name": "labelB",
"mask": "mdQ8g0Tg0:G8I6K5J5L4L4L4L4M2M4M2M4M2N2N2N3L3N2N2N2N2O1N1O2N2N2O1N1O2N2O0O2O1N1O2O0O2O0O2O001N100O2O000O2O000O2O00000O2O000000001N100000000000000000000000000000000001O0O100000001O0O10001N10001O0O101N10001N101N101N101N101N2O0O2N2O0O2N2N2O0O2N2N2N2N2N2N2N2N2N3L3N2N3L3N3L4M2M4L4L5J5L5J7H8H;BUcd<"},
...]}
```
其中,list中的每个元素代表一个标注信息,标注信息中字段的含义如下所示:
| 字段名 | 含义 | 数据类型 | 备注 |
|:--------|:------------|------|:-----|
| x1 | 标注框左下角横坐标 | int | |
| y1 | 标注框左下角纵坐标 | int | |
| x2 | 标注框右上角横坐标 | int | |
| y2 | 标注框右上角纵坐标 | int | |
| name | 标注框中物体类标 | str | |
| mask | 分割区域布尔型numpy编码后的字符串 | str | 该字段必须存在 |
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为json文件相对于dataset的相对路径。如下所示:
```
easydata/0001.jpg easydata/0001.json
easydata/0002.jpg easydata/0002.json
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
labelA
labelB
...
```
[点击这里](https://ai.baidu.com/easydata/),可以标注图像分类EasyDataSeg数据集。
在PaddleX中,使用`paddlex.cv.datasets.EasyDataSeg`([API说明](./apis/datasets.html#easydataseg))加载分类数据集。
\ No newline at end of file
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
docs/images/vdl1.jpg

405.9 KB | W: | H:

docs/images/vdl1.jpg

47.0 KB | W: | H:

docs/images/vdl1.jpg
docs/images/vdl1.jpg
docs/images/vdl1.jpg
docs/images/vdl1.jpg
  • 2-up
  • Swipe
  • Onion skin
docs/images/vdl2.jpg

354.6 KB | W: | H:

docs/images/vdl2.jpg

28.2 KB | W: | H:

docs/images/vdl2.jpg
docs/images/vdl2.jpg
docs/images/vdl2.jpg
docs/images/vdl2.jpg
  • 2-up
  • Swipe
  • Onion skin
docs/images/vdl3.jpg

347.8 KB | W: | H:

docs/images/vdl3.jpg

29.8 KB | W: | H:

docs/images/vdl3.jpg
docs/images/vdl3.jpg
docs/images/vdl3.jpg
docs/images/vdl3.jpg
  • 2-up
  • Swipe
  • Onion skin
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
欢迎使用PaddleX! 欢迎使用PaddleX!
======================================= =======================================
PaddleX是基于飞桨技术生态的深度学习全流程开发工具。具备易集成,易使用,全流程等特点。PaddleX作为深度学习开发工具,不仅提供了开源的内核代码,可供用户灵活使用或集成,同时也提供了配套的前端可视化客户端套件,让用户以可视化地方式进行模型开发,相关细节可查阅PaddleX官网 PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习全流程开发工具。具备 **全流程打通** 、**融合产业实践** 、**易用易集成** 三大特点
本文档为PaddleX内核代码使用手册
全流程打通
| - **数据准备**: 支持LabelMe,精灵标注等主流数据标注工具协议,同时无缝集成 `EasyData智能数据服务平台 <https://ai.baidu.com/easydata/>`_ ,助力开发者高效获取AI开发所需高质量数据。
| - **模型训练**: 基于飞桨核心框架集成 `PaddleClas <https://github.com/PaddlePaddle/PaddleClas>`_ ,`PaddleDetection <https://github.com/PaddlePaddle/PaddleDetection>`_ ,`PaddleSeg <https://github.com/PaddlePaddle/PaddleSeg>`_ 视觉开发套件 ,`VisualDL <https://github.com/PaddlePaddle/VisualDL>`_ 可视化分析组件,高效完成模型训练。
| _ **多端部署**: 内置 `PaddleSlim <https://github.com/PaddlePaddle/PaddleSlim>`_ 模型压缩工具和AES模型加密SDK,结合Paddle Inference和 `Paddle Lite <https://github.com/PaddlePaddle/Paddle-Lite>`_ 便捷完成高性能且可靠的多端部署。
融合产业实践
| - 精选飞桨产业实践的成熟模型结构,开放案例实践教程,加速开发者产业落地。
| - 通过 `PaddleHub <https://github.com/PaddlePaddle/PaddleHub>`_ 内置丰富的飞桨高质量预训练模型,助力开发者高效实现飞桨Master模式。
易用易集成
| - PadldeX提供简洁易用的全流程API,几行代码即可实现上百种数据增强、模型可解释性、C++模型部署等功能。
| - 提供以PaddleX API为核心集成的跨平台GUI界面,降低深度学习全流程应用门槛。
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 2
:caption: 目录: :caption: 文档目录:
quick_start.md quick_start.md
install.md install.md
model_zoo.md
slim/index
apis/index
datasets.md
gpu_configure.md
tutorials/index.rst tutorials/index.rst
metrics.md cv_solutions.md
deploy.md apis/index.rst
client_use.md paddlex_gui/index.rst
update.md
FAQ.md FAQ.md
appendix/index.rst
* PaddleX版本: v0.1.7 * PaddleX版本: v0.1.7
* 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex * 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex
......
# 安装 # 快速安装
以下安装过程默认用户已安装好**paddlepaddle-gpu或paddlepaddle(版本大于或等于1.7.1)**,paddlepaddle安装方式参照[飞桨官网](https://www.paddlepaddle.org.cn/install/quick) 以下安装过程默认用户已安装好**paddlepaddle-gpu或paddlepaddle(版本大于或等于1.7.1)**,paddlepaddle安装方式参照[飞桨官网](https://www.paddlepaddle.org.cn/install/quick)
> 推荐使用Anaconda Python环境,Anaconda下安装PaddleX参考文档[Anaconda安装使用](./anaconda_install.md) > 推荐使用Anaconda Python环境,Anaconda下安装PaddleX参考文档[Anaconda安装使用](../appendix/anaconda_install.md)
## Github代码安装 ## pip安装
github代码会跟随开发进度不断更新
> 注意其中pycocotools在Windows安装较为特殊,可参考下面的Windows安装命令 > 注意其中pycocotools在Windows安装较为特殊,可参考下面的Windows安装命令
```
pip install paddlex -i https://mirror.baidu.com/pypi/simple
```
## Github代码安装
github代码会跟随开发进度不断更新
``` ```
git clone https://github.com/PaddlePaddle/PaddleX.git git clone https://github.com/PaddlePaddle/PaddleX.git
cd PaddleX cd PaddleX
...@@ -16,19 +23,16 @@ git checkout develop ...@@ -16,19 +23,16 @@ git checkout develop
python setup.py install python setup.py install
``` ```
## pip安装
```
pip install paddlex -i https://mirror.baidu.com/pypi/simple
```
## 安装问题 ## 安装问题
### 1. pycocotools安装问题 ### 1. pycocotools安装问题
> PaddleX依赖pycocotools包,如安装pycocotools失败,可参照如下方式安装pycocotools > PaddleX依赖pycocotools包,如安装pycocotools失败,可参照如下方式安装pycocotools
**Windows** **Windows**
> Windows安装时可能会提示缺少`Microsoft Visual C++ 2015 build tools`,[点击下载](https://go.microsoft.com/fwlink/?LinkId=691126)安装再执行如下pip命令
``` ```
pip install cython pip install cython
pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI pip install git+https://gitee.com/jiangjiajun/philferriere-cocoapi.git#subdirectory=PythonAPI
``` ```
**Linux/Mac安装** **Linux/Mac安装**
......
文件模式从 100644 更改为 100755
# 指标及日志含义 本页面已移至 [这里](./appendix/metrics.md)
PaddleX在模型训练、评估过程中,都会有相应的日志和指标反馈,本文档用于说明这些日志和指标的含义。
## 训练通用统计信息
PaddleX所有模型在训练过程中,输出的日志信息都包含了6个通用的统计信息,用于辅助用户进行模型训练,例如**分割模型**的训练日志,如下图所示。
![](./images/seg_train.png)
各字段含义如下:
| 字段 | 字段值示例 | 含义 |
| -------------- | -------------------- | ------------------------------------------------------------ |
| Epoch | Epoch=4/20 | [迭代轮数]所有训练数据会被训练20轮,当前处于第4轮 |
| Step | Step=62/66 | [迭代步数]所有训练数据被训练一轮所需要的迭代步数为66,当前处于第62步 |
| loss | loss=0.007226 | [损失函数值]参与当前迭代步数的训练样本的平均损失函数值loss,loss值越低,表明模型在训练集上拟合的效果越好(如上日志中第1行表示第4个epoch的第62个Batch的loss值为0.007226) |
| lr | lr=0.008215 | [学习率]当前模型迭代过程中的学习率 |
| time_each_step | time_each_step=0.41s | [每步迭代时间]训练过程计算得到的每步迭代平均用时 |
| eta | eta=0:9:44 | [剩余时间]模型训练完成所需剩余时间预估为0小时9分钟44秒 |
| | | |
不同模型的日志中除了上述通用字段外,还有其它字段,这些字段含义可见文档后面对各任务模型的描述。
## 评估通用统计信息
PaddleX所有模型在训练过程中会根据用户设定的`save_interval_epochs`参数,每间隔一定轮数进行评估和保存。例如**分类模型**的评估日志,如下图所示。
![](images/cls_eval.png)
上图中第1行表明验证数据集中样本数为240,需要迭代8步才能评估完所有验证数据;第5行用于表明第2轮的模型已经完成保存操作;第6行则表明当前保存的模型中,第2轮的模型在验证集上指标最优(分类任务看`acc1`,此时`acc1`值为0.258333),最优模型会保存在`best_model`目录中。
## 分类特有统计信息
### 训练日志字段
分类任务的训练日志除了通用统计信息外,还包括`acc1``acc5`两个特有字段。
> 注: acck准确率是针对一张图片进行计算的:把模型在各个类别上的预测得分按从高往低进行排序,取出前k个预测类别,若这k个预测类别包含了真值类,则认为该图片分类正确。
![](images/cls_train.png)
上图中第1行中的`acc1`表示参与当前迭代步数的训练样本的平均top1准确率,值越高代表模型越优;`acc5`表示参与当前迭代步数的训练样本的平均top5(若类别数n少于5,则为topn)准确率,值越高代表模型越优。第4行中的`loss`表示整个训练集的平均损失函数值,`acc1`表示整个训练集的平均top1准确率,`acc5`表示整个训练集的平均top5准确率。
### 评估日志字段
![](images/cls_eval.png)
上图中第3行中的`acc1`表示整个验证集的平均top1准确率,`acc5`表示整个验证集的平均top5准确率。
## 检测特有统计信息
### 训练日志字段
#### YOLOv3
YOLOv3的训练日志只包括训练通用统计信息(见上文训练通用统计信息)。
![](images/yolo_train.png)
上图中第5行`loss`表示整个训练集的平均损失函数loss值。
#### FasterRCNN
FasterRCNN的训练日志除了通用统计信息外,还包括`loss_cls``loss_bbox``loss_rpn_cls``loss_rpn_bbox`,这些字段的含义如下:
| 字段 | 含义 |
| -------------- | --------------------------------------------- |
| loss_cls | RCNN子网络中分类损失函数值 |
| loss_bbox | RCNN子网络中检测框回归损失函数值 |
| loss_rpn_cls | RPN子网络中分类损失函数值 |
| loss_rpn_bbox | RPN子网络中检测框回归损失函数值 |
| loss | 所有子网络损失函数值之和 |
![](images/faster_train.png)
上图中第1行`loss`, `loss_cls``loss_bbox``loss_rpn_clss``loss_rpn_bbox`都是参与当前迭代步数的训练样本的损失值,而第7行是针整个训练集的损失函数值。
#### MaskRCNN
MaskRCNN的训练日志除了通用统计信息外,还包括`loss_cls``loss_bbox``loss_mask``loss_rpn_cls``loss_rpn_bbox`,这些字段的含义如下:
| 字段 | 含义 |
| -------------- | --------------------------------------------- |
| loss_cls | RCNN子网络中分类损失函数值 |
| loss_bbox | RCNN子网络中检测框回归损失函数值 |
| loss_mask | RCNN子网络中Mask回归损失函数值 |
| loss_rpn_cls | RPN子网络中分类损失函数值 |
| loss_rpn_bbox | RPN子网络中检测框回归损失函数值 |
| loss | 所有子网络损失函数值之和 |
![](images/mask_train.png)
上图中第1行`loss`, `loss_cls``loss_bbox``loss_mask``loss_rpn_clss``loss_rpn_bbox`都是参与当前迭代步数的训练样本的损失值,而第7行是针整个训练集的损失函数值。
### 评估日志字段
检测可以使用两种评估标准:VOC评估标准和COCO评估标准。
#### VOC评估标准
![](images/voc_eval.png)
> 注:`map`为平均准确率的平均值,即IoU(Intersection Over Union)取0.5时各个类别的准确率-召回率曲线下面积的平均值。
上图中第3行`bbox_map`表示检测任务中整个验证集的平均准确率平均值。
#### COCO评估标准
> 注:COCO评估指标可参见[COCO官网解释](http://cocodataset.org/#detection-eval)。PaddleX主要反馈`mmAP`,即AP at IoU=.50:.05:.95这项指标,为在各个IoU阈值下平均准确率平均值(mAP)的平均值。
COCO格式的数据集不仅可以用于训练目标检测模型,也可以用于训练实例分割模型。在目标检测中,PaddleX主要反馈针对检测框的`bbox_mmAP`指标;在实例分割中,还包括针对Mask的`seg_mmAP`指标。如下所示,第一张日志截图为目标检测的评估结果,第二张日志截图为实例分割的评估结果。
![](images/faster_eval.png)
上图中红框标注的`bbox_mmap`表示整个验证集的检测框平均准确率平均值。
![](images/mask_eval.png)
上图中红框标注的`bbox_mmap``seg_mmap`分别表示整个验证集的检测框平均准确率平均值、Mask平均准确率平均值。
## 分割特有统计信息
### 训练日志字段
语义分割的训练日志只包括训练通用统计信息(见上文训练通用统计信息)。
![](images/seg_train.png)
### 评估日志字段
语义分割的评估日志包括了`miou``category_iou``macc``category_acc``kappa`,这些字段的含义如下:
| 字段 | 含义 |
| -------------- | --------------------------------------------- |
| miou | 各类IoU(Intersection Over Union)的平均值 |
| category_iou | 各类别的IoU |
| macc | 平均准确率,即预测正确的像素数/总像素数 |
| category_acc | 各类别的准确率,即各类别预测正确的像素数/预测为该类别的总像素数 |
| kappa | kappa系数,用于一致性检验 |
![](images/seg_eval.png)
# 模型库 本页面已移至 [这里](./appendix/model_zoo.md)
本文档梳理了PaddleX v0.1.0支持的模型,同时也提供了在各个数据集上的预训练模型和对应验证集上的指标。用户也可自行下载对应的代码,在安装PaddleX后,即可使用相应代码训练模型。
表中相关模型也可下载好作为相应模型的预训练模型,通过`pretrain_weights`指定目录加载使用。
## 图像分类模型
> 表中模型相关指标均为在ImageNet数据集上使用PaddlePaddle Python预测接口测试得到(测试GPU型号为Nvidia Tesla P40),预测速度为每张图片预测用时(不包括预处理和后处理),表中符号`-`表示相关指标暂未测试。
| 模型 | 模型大小 | 预测速度(毫秒) | Top1准确率(%) | Top5准确率(%) |
| :----| :------- | :----------- | :--------- | :--------- |
| ResNet18| 46.9MB | 1.499 | 71.0 | 89.9 |
| ResNet34| 87.5MB | 2.272 | 74.6 | 92.1 |
| ResNet50| 102.7MB | 2.939 | 76.5 | 93.0 |
| ResNet101 |179.1MB | 5.314 | 77.6 | 93.6 |
| ResNet50_vd |102.8MB | 3.165 | 79.1 | 94.4 |
| ResNet101_vd| 179.2MB | 5.252 | 80.2 | 95.0 |
| ResNet50_vd_ssld |102.8MB | 3.165 | 82.4 | 96.1 |
| ResNet101_vd_ssld| 179.2MB | 5.252 | 83.7 | 96.7 |
| DarkNet53|166.9MB | 3.139 | 78.0 | 94.1 |
| MobileNetV1 | 16.0MB | 32.523 | 71.0 | 89.7 |
| MobileNetV2 | 14.0MB | 23.318 | 72.2 | 90.7 |
| MobileNetV3_large| 21.0MB | 19.308 | 75.3 | 93.2 |
| MobileNetV3_small | 12.0MB | 6.546 | 68.2 | 88.1 |
| MobileNetV3_large_ssld| 21.0MB | 19.308 | 79.0 | 94.5 |
| MobileNetV3_small_ssld | 12.0MB | 6.546 | 71.3 | 90.1 |
| Xception41 |92.4MB | 4.408 | 79.6 | 94.4 |
| Xception65 | 144.6MB | 6.464 | 80.3 | 94.5 |
| DenseNet121 | 32.8MB | 4.371 | 75.7 | 92.6 |
| DenseNet161|116.3MB | 8.863 | 78.6 | 94.1 |
| DenseNet201| 84.6MB | 8.173 | 77.6 | 93.7 |
| ShuffleNetV2 | 9.0MB | 10.941 | 68.8 | 88.5 |
## 目标检测模型
> 表中模型相关指标均为在MSCOCO数据集上使用PaddlePaddle Python预测接口测试得到(测试GPU型号为Nvidia Tesla V100测试得到,表中符号`-`表示相关指标暂未测试。
| 模型 | 模型大小 | 预测时间(毫秒) | BoxAP(%) |
|:-------|:-----------|:-------------|:----------|
|FasterRCNN-ResNet50|135.6MB| 78.450 | 35.2 |
|FasterRCNN-ResNet50_vd| 135.7MB | 79.523 | 36.4 |
|FasterRCNN-ResNet101| 211.7MB | 107.342 | 38.3 |
|FasterRCNN-ResNet50-FPN| 167.2MB | 44.897 | 37.2 |
|FasterRCNN-ResNet50_vd-FPN|168.7MB | 45.773 | 38.9 |
|FasterRCNN-ResNet101-FPN| 251.7MB | 55.782 | 38.7 |
|FasterRCNN-ResNet101_vd-FPN |252MB | 58.785 | 40.5 |
|YOLOv3-DarkNet53|252.4MB | 21.944 | 38.9 |
|YOLOv3-MobileNetv1 |101.2MB | 12.771 | 29.3 |
|YOLOv3-MobileNetv3|94.6MB | - | 31.6 |
| YOLOv3-ResNet34|169.7MB | 15.784 | 36.2 |
## 实例分割模型
> 表中模型相关指标均为在MSCOCO数据集上测试得到。
| 模型 |模型大小 | 预测时间(毫秒) | BoxAP | SegAP(%) |
|:---------|:---------|:----------|:---------|:--------|
|MaskRCNN-ResNet50|51.2MB| 86.096 | 36.5 |32.2|
|MaskRCNN-ResNet50-FPN|184.6MB | 65.859 | 37.9 |34.2|
|MaskRCNN-ResNet50_vd-FPN |185.5MB | 63.191 | 39.8 |35.4|
|MaskRCNN-ResNet101-FPN|268.6MB | 77.024 | 39.5 |35.2|
|MaskRCNN-ResNet101vd-FPN |268.6MB | 76.307 | 41.4 |36.8|
## 语义分割模型
> 表中符号`-`表示相关指标暂未测试。
| 模型| 模型大小 | 预测速度 | mIOU |
|:--------|:----------|:----------|:----------|
| UNet|53.7M | - |-|
| DeepLabv3+/Xception65| 165.1M |- | 0.7930 |
| DeepLabv3+/MobileNetV2 | 7.4M | - | 0.6981 |
# PaddleX GUI下载安装
# PaddleX GUI如何训练模型
PaddleX GUI使用文档
=======================================
PaddleX GUI是基于PaddleX开发实现的可视化模型训练套件,可以让开发者免去代码开发的步骤,通过点选式地操作就可以快速完成模型的训练开发。PaddleXGUI具有 **数据集可视化分析** 、**模型参数自动推荐** 、**跨平台使用** 三大特点。
数据集可视化分析
| PaddleX支持导入常见的图像分类、目标检测、实例分割和语义分割数据集,并对数据集的样本分布,标注结果进行可视化展示,数据集的情况一目了然!
模型参数自动推荐
| 根据用户的电脑配置和数据集情况,自动推荐模型训练参数,免去用户查看文档,被各种参数所烦的忧心事!
跨平台使用
| PaddleX GUI完全跨平台,支持Linux、Windows和Mac三大主流系统!
.. toctree::
:maxdepth: 2
:caption: 文档目录:
download.md
how_to_use.md
xx.md
* PaddleX版本: v0.1.7
* 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex
* 项目GitHub: https://github.com/PaddlePaddle/PaddleX/tree/develop
* 官方QQ用户群: 1045148026
* GitHub Issue反馈: http://www.github.com/PaddlePaddle/PaddleX/issues
...@@ -2,22 +2,31 @@ ...@@ -2,22 +2,31 @@
本文档在一个小数据集上展示了如何通过PaddleX进行训练,您可以阅读PaddleX的**使用教程**来了解更多模型任务的训练使用方式。本示例同步在AIStudio上,可直接[在线体验模型训练](https://aistudio.baidu.com/aistudio/projectdetail/439860) 本文档在一个小数据集上展示了如何通过PaddleX进行训练,您可以阅读PaddleX的**使用教程**来了解更多模型任务的训练使用方式。本示例同步在AIStudio上,可直接[在线体验模型训练](https://aistudio.baidu.com/aistudio/projectdetail/439860)
## 1. 准备蔬菜分类数据集
## 1. 安装PaddleX
> 安装相关过程和问题可以参考PaddleX的[安装文档](./install.md)。
``` ```
wget https://bj.bcebos.com/paddlex/datasets/vegetables_cls.tar.gz pip install paddlex -i https://mirror.baidu.com/pypi/simple
tar xzvf vegetables_cls.tar.gz
``` ```
## 2. 训练代码开发 ## 2. 准备蔬菜分类数据集
通过如下`train.py`代码进行训练
> 设置使用0号GPU卡
``` ```
import os wget https://bj.bcebos.com/paddlex/datasets/vegetables_cls.tar.gz
os.environ['CUDA_VISIBLE_DEVICES'] = '0' tar xzvf vegetables_cls.tar.gz
import paddlex as pdx
``` ```
> 定义训练和验证时的数据处理流程, 在`train_transforms`中加入了`RandomCrop`和`RandomHorizontalFlip`两种数据增强方式 ## 3. 训练代码开发
PaddleX的所有模型训练和预测均只涉及到5个API接口,分别是
> - [transforms](apis/transforms/index.html) 图像数据处理
> - [datasets](apis/datasets/classification.md) 数据集加载
> - [models](apis/models/classification.md) 模型类型定义
> - [train](apis/models/classification.html#train) 开始训练
> - [predict](apis/models/classification.html#predict) 模型预测
在本示例,通过如下`train.py`代码进行训练, 训练环境为1张Tesla P40 GPU卡。
### 3.1 定义`transforms`数据处理流程
由于训练时数据增强操作的加入,因此模型在训练和验证过程中,数据处理流程需要分别进行定义。如下所示,代码在`train_transforms`中加入了[RandomCrop](apis/transforms/cls_transforms.html#RandomCrop)[RandomHorizontalFlip](apis/transforms/cls_transforms.html#RandomHorizontalFlip)两种数据增强方式, 更多方法可以参考[数据增强文档](apis/transforms/augment.md)
``` ```
from paddlex.cls import transforms from paddlex.cls import transforms
train_transforms = transforms.Compose([ train_transforms = transforms.Compose([
...@@ -32,7 +41,8 @@ eval_transforms = transforms.Compose([ ...@@ -32,7 +41,8 @@ eval_transforms = transforms.Compose([
]) ])
``` ```
> 定义数据集,`pdx.datasets.ImageNet`表示读取ImageNet格式的分类数据集 ### 3.2 定义`dataset`加载数据集
定义数据集,`pdx.datasets.ImageNet`表示读取ImageNet格式的分类数据集, 更多数据集细节可以查阅[数据集格式说明](datasets.md)[ImageNet接口文档](apis/datasets/classification.md)
``` ```
train_dataset = pdx.datasets.ImageNet( train_dataset = pdx.datasets.ImageNet(
data_dir='vegetables_cls', data_dir='vegetables_cls',
...@@ -46,11 +56,17 @@ eval_dataset = pdx.datasets.ImageNet( ...@@ -46,11 +56,17 @@ eval_dataset = pdx.datasets.ImageNet(
label_list='vegetables_cls/labels.txt', label_list='vegetables_cls/labels.txt',
transforms=eval_transforms) transforms=eval_transforms)
``` ```
> 模型训练
### 3.3 定义分类模型
本文档中使用百度基于蒸馏方法得到的MobileNetV3预训练模型,模型结构与MobileNetV3一致,但精度更高。PaddleX内置了20多种分类模型,查阅[PaddleX模型库](appendix/model_zoo.md)了解更多分类模型。
``` ```
num_classes = len(train_dataset.labels) num_classes = len(train_dataset.labels)
model = pdx.cls.MobileNetV2(num_classes=num_classes) model.pdx.cls.MobileNetV3_small_ssld(num_classes=num_classes)
```
### 3.4 定义训练参数
定义好模型后,即可直接调用`train`接口,定义训练时的参数,分类模型内置了`piecewise_decay`学习率衰减策略,相关参数见[分类train接口文档](apis/models/classification.html#train)
```
model.train(num_epochs=10, model.train(num_epochs=10,
train_dataset=train_dataset, train_dataset=train_dataset,
train_batch_size=32, train_batch_size=32,
...@@ -61,19 +77,21 @@ model.train(num_epochs=10, ...@@ -61,19 +77,21 @@ model.train(num_epochs=10,
use_vdl=True) use_vdl=True)
``` ```
## 3. 模型训练 ## 4. 模型开始训练
> `train.py`与解压后的数据集目录`vegetables_cls`放在同一目录下,在此目录下运行`train.py`即可开始训练。如果您的电脑上有GPU,这将会在10分钟内训练完成,如果为CPU也大概会在30分钟内训练完毕。 `train.py`与解压后的数据集目录`vegetables_cls`放在同一目录下,在此目录下运行`train.py`即可开始训练。如果您的电脑上有GPU,这将会在10分钟内训练完成,如果为CPU也大概会在30分钟内训练完毕。
``` ```
python train.py python train.py
``` ```
## 4. 训练过程中查看训练指标
> 模型在训练过程中,所有的迭代信息将以标注输出流的形式,输出到命令执行的终端上,用户也可通过visualdl以可视化的方式查看训练指标的变化,通过如下方式启动visualdl后,在浏览器打开https://0.0.0.0:8001即可。 ## 5. 训练过程中查看训练指标
模型在训练过程中,所有的迭代信息将以标注输出流的形式,输出到命令执行的终端上,用户也可通过visualdl以可视化的方式查看训练指标的变化,通过如下方式启动visualdl后,在浏览器打开https://0.0.0.0:8001 (或 https://localhost:8001)即可。
``` ```
visualdl --logdir output/mobilenetv2/vdl_log --port 8000 visualdl --logdir output/mobilenetv2/vdl_log --port 8000
``` ```
![](./images/vdl1.jpg) ![](./images/vdl1.jpg)
## 5. 训练完成使用模型进行测试
> 如使用训练过程中第8轮保存的模型进行测试 ## 6. 训练完成使用模型进行测试
如下代码使用训练过程中第8轮保存的模型进行测试。
``` ```
import paddlex as pdx import paddlex as pdx
model = pdx.load_model('output/mobilenetv2/epoch_8') model = pdx.load_model('output/mobilenetv2/epoch_8')
......
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
# 数据准备
## 数据标注
## 主流标注软件支持
## EasyData数据标注支持
# 数据集格式说明
---
## 图像分类ImageNet
图像分类ImageNet数据集包含对应多个标签的图像文件夹、标签文件及图像列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录
|--labelA # 标签为labelA的图像目录
| |--a1.jpg
| |--...
| └--...
|
|--...
|
|--labelZ # 标签为labelZ的图像目录
| |--z1.jpg
| |--...
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表文件
```
其中,相应的文件名可根据需要自行定义。
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为图像文件对应的标签id(从0开始)。如下所示:
```
labelA/a1.jpg 0
labelZ/z1.jpg 25
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
labelA
labelB
...
```
[点击这里](https://bj.bcebos.com/paddlex/datasets/vegetables_cls.tar.gz),下载蔬菜分类分类数据集。
在PaddleX中,使用`paddlex.cv.datasets.ImageNet`([API说明](./apis/datasets.html#imagenet))加载分类数据集。
## 目标检测VOC
目标检测VOC数据集包含图像文件夹、标注信息文件夹、标签文件及图像列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录
|--JPEGImages # 图像目录
| |--xxx1.jpg
| |--...
| └--...
|
|--Annotations # 标注信息目录
| |--xxx1.xml
| |--...
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表文件
```
其中,相应的文件名可根据需要自行定义。
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为标注文件相对于dataset的相对路径。如下所示:
```
JPEGImages/xxx1.jpg Annotations/xxx1.xml
JPEGImages/xxx2.jpg Annotations/xxx2.xml
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
labelA
labelB
...
```
[点击这里](https://bj.bcebos.com/paddlex/datasets/insect_det.tar.gz),下载昆虫检测数据集。
在PaddleX中,使用`paddlex.cv.datasets.VOCDetection`([API说明](./apis/datasets.html#vocdetection))加载目标检测VOC数据集。
## 目标检测和实例分割COCO
目标检测和实例分割COCO数据集包含图像文件夹及图像标注信息文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录
|--JPEGImages # 图像目录
| |--xxx1.jpg
| |--...
| └--...
|
|--train.json # 训练相关信息文件
|
└--val.json # 验证相关信息文件
```
其中,相应的文件名可根据需要自行定义。
`train.json``val.json`存储与标注信息、图像文件相关的信息。如下所示:
```
{
"annotations": [
{
"iscrowd": 0,
"category_id": 1,
"id": 1,
"area": 33672.0,
"image_id": 1,
"bbox": [232, 32, 138, 244],
"segmentation": [[32, 168, 365, 117, ...]]
},
...
],
"images": [
{
"file_name": "xxx1.jpg",
"height": 512,
"id": 267,
"width": 612
},
...
]
"categories": [
{
"name": "labelA",
"id": 1,
"supercategory": "component"
}
]
}
```
其中,每个字段的含义如下所示:
| 域名 | 字段名 | 含义 | 数据类型 | 备注 |
|:-----|:--------|:------------|------|:-----|
| annotations | id | 标注信息id | int | 从1开始 |
| annotations | iscrowd | 标注框是否为一组对象 | int | 只有0、1两种取值 |
| annotations | category_id | 标注框类别id | int | |
| annotations | area | 标注框的面积 | float | |
| annotations | image_id | 当前标注信息所在图像的id | int | |
| annotations | bbox | 标注框坐标 | list | 长度为4,分别代表x,y,w,h |
| annotations | segmentation | 标注区域坐标 | list | list中有至少1个list,每个list由每个小区域坐标点的横纵坐标(x,y)组成 |
| images | id | 图像id | int | 从1开始 |
| images | file_name | 图像文件名 | str | |
| images | height | 图像高度 | int | |
| images | width | 图像宽度 | int | |
| categories | id | 类别id | int | 从1开始 |
| categories | name | 类别标签名 | str | |
| categories | supercategory | 类别父类的标签名 | str | |
[点击这里](https://bj.bcebos.com/paddlex/datasets/garbage_ins_det.tar.gz),下载垃圾实例分割数据集。
在PaddleX中,使用`paddlex.cv.datasets.COCODetection`([API说明](./apis/datasets.html#cocodetection))加载COCO格式数据集。
## 语义分割数据
语义分割数据集包含原图、标注图及相应的文件列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录
|--images # 原图目录
| |--xxx1.png
| |--...
| └--...
|
|--annotations # 标注图目录
| |--xxx1.png
| |--...
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表
```
其中,相应的文件名可根据需要自行定义。
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为标注图像文件相对于dataset的相对路径。如下所示:
```
images/xxx1.png annotations/xxx1.png
images/xxx2.png annotations/xxx2.png
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
background
labelA
labelB
...
```
标注图像为单通道图像,像素值即为对应的类别,像素标注类别需要从0开始递增(一般第一个类别为`background`),
例如0,1,2,3表示有4种类别,标注类别最多为256类。其中可以指定特定的像素值用于表示该值的像素不参与训练和评估(默认为255)。
[点击这里](https://bj.bcebos.com/paddlex/datasets/optic_disc_seg.tar.gz),下载视盘语义分割数据集。
在PaddleX中,使用`paddlex.cv.datasets.SegReader`([API说明](./apis/datasets.html#segreader))加载语义分割数据集。
## 图像分类EasyDataCls
图像分类EasyDataCls数据集包含存放图像和json文件的文件夹、标签文件及图像列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录
|--easydata # 存放图像和json文件的文件夹
| |--0001.jpg
| |--0001.json
| |--0002.jpg
| |--0002.json
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表文件
```
其中,图像文件名应与json文件名一一对应。
每个json文件存储于`labels`相关的信息。如下所示:
```
{"labels": [{"name": "labelA"}]}
```
其中,`name`字段代表对应图像的类别。
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为json文件相对于dataset的相对路径。如下所示:
```
easydata/0001.jpg easydata/0001.json
easydata/0002.jpg easydata/0002.json
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
labelA
labelB
...
```
[点击这里](https://ai.baidu.com/easydata/),可以标注图像分类EasyDataCls数据集。
在PaddleX中,使用`paddlex.cv.datasets.EasyDataCls`([API说明](./apis/datasets.html#easydatacls))加载分类数据集。
## 目标检测和实例分割EasyDataDet
目标检测和实例分割EasyDataDet数据集包含存放图像和json文件的文件夹、标签文件及图像列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录ß
|--easydata # 存放图像和json文件的文件夹
| |--0001.jpg
| |--0001.json
| |--0002.jpg
| |--0002.json
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表文件
```
其中,图像文件名应与json文件名一一对应。
每个json文件存储于`labels`相关的信息。如下所示:
```
"labels": [{"y1": 18, "x2": 883, "x1": 371, "y2": 404, "name": "labelA",
"mask": "kVfc0`0Zg0<F7J7I5L5K4L4L4L3N3L3N3L3N2N3M2N2N2N2N2N2N1O2N2O1N2N1O2O1N101N1O2O1N101N10001N101N10001N10001O0O10001O000O100000001O0000000000000000000000O1000001O00000O101O000O101O0O101O0O2O0O101O0O2O0O2N2O0O2O0O2N2O1N1O2N2N2O1N2N2N2N2N2N2M3N3M2M4M2M4M3L4L4L4K6K5J7H9E\\iY1"},
{"y1": 314, "x2": 666, "x1": 227, "y2": 676, "name": "labelB",
"mask": "mdQ8g0Tg0:G8I6K5J5L4L4L4L4M2M4M2M4M2N2N2N3L3N2N2N2N2O1N1O2N2N2O1N1O2N2O0O2O1N1O2O0O2O0O2O001N100O2O000O2O000O2O00000O2O000000001N100000000000000000000000000000000001O0O100000001O0O10001N10001O0O101N10001N101N101N101N101N2O0O2N2O0O2N2N2O0O2N2N2N2N2N2N2N2N2N3L3N2N3L3N3L4M2M4L4L5J5L5J7H8H;BUcd<"},
...]}
```
其中,list中的每个元素代表一个标注信息,标注信息中字段的含义如下所示:
| 字段名 | 含义 | 数据类型 | 备注 |
|:--------|:------------|------|:-----|
| x1 | 标注框左下角横坐标 | int | |
| y1 | 标注框左下角纵坐标 | int | |
| x2 | 标注框右上角横坐标 | int | |
| y2 | 标注框右上角纵坐标 | int | |
| name | 标注框中物体类标 | str | |
| mask | 分割区域布尔型numpy编码后的字符串 | str | 该字段可以不存在,当不存在时只能进行目标检测 |
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为json文件相对于dataset的相对路径。如下所示:
```
easydata/0001.jpg easydata/0001.json
easydata/0002.jpg easydata/0002.json
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
labelA
labelB
...
```
[点击这里](https://ai.baidu.com/easydata/),可以标注图像分类EasyDataDet数据集。
在PaddleX中,使用`paddlex.cv.datasets.EasyDataDet`([API说明](./apis/datasets.html#easydatadet))加载分类数据集。
## 语义分割EasyDataSeg
语义分割EasyDataSeg数据集包含存放图像和json文件的文件夹、标签文件及图像列表文件。
参考数据文件结构如下:
```
./dataset/ # 数据集根目录ß
|--easydata # 存放图像和json文件的文件夹
| |--0001.jpg
| |--0001.json
| |--0002.jpg
| |--0002.json
| └--...
|
|--train_list.txt # 训练文件列表文件
|
|--val_list.txt # 验证文件列表文件
|
└--labels.txt # 标签列表文件
```
其中,图像文件名应与json文件名一一对应。
每个json文件存储于`labels`相关的信息。如下所示:
```
"labels": [{"y1": 18, "x2": 883, "x1": 371, "y2": 404, "name": "labelA",
"mask": "kVfc0`0Zg0<F7J7I5L5K4L4L4L3N3L3N3L3N2N3M2N2N2N2N2N2N1O2N2O1N2N1O2O1N101N1O2O1N101N10001N101N10001N10001O0O10001O000O100000001O0000000000000000000000O1000001O00000O101O000O101O0O101O0O2O0O101O0O2O0O2N2O0O2O0O2N2O1N1O2N2N2O1N2N2N2N2N2N2M3N3M2M4M2M4M3L4L4L4K6K5J7H9E\\iY1"},
{"y1": 314, "x2": 666, "x1": 227, "y2": 676, "name": "labelB",
"mask": "mdQ8g0Tg0:G8I6K5J5L4L4L4L4M2M4M2M4M2N2N2N3L3N2N2N2N2O1N1O2N2N2O1N1O2N2O0O2O1N1O2O0O2O0O2O001N100O2O000O2O000O2O00000O2O000000001N100000000000000000000000000000000001O0O100000001O0O10001N10001O0O101N10001N101N101N101N101N2O0O2N2O0O2N2N2O0O2N2N2N2N2N2N2N2N2N3L3N2N3L3N3L4M2M4L4L5J5L5J7H8H;BUcd<"},
...]}
```
其中,list中的每个元素代表一个标注信息,标注信息中字段的含义如下所示:
| 字段名 | 含义 | 数据类型 | 备注 |
|:--------|:------------|------|:-----|
| x1 | 标注框左下角横坐标 | int | |
| y1 | 标注框左下角纵坐标 | int | |
| x2 | 标注框右上角横坐标 | int | |
| y2 | 标注框右上角纵坐标 | int | |
| name | 标注框中物体类标 | str | |
| mask | 分割区域布尔型numpy编码后的字符串 | str | 该字段必须存在 |
`train_list.txt``val_list.txt`文本以空格为分割符分为两列,第一列为图像文件相对于dataset的相对路径,第二列为json文件相对于dataset的相对路径。如下所示:
```
easydata/0001.jpg easydata/0001.json
easydata/0002.jpg easydata/0002.json
...
```
`labels.txt`: 每一行为一个单独的类别,相应的行号即为类别对应的id(行号从0开始),如下所示:
```
labelA
labelB
...
```
[点击这里](https://ai.baidu.com/easydata/),可以标注图像分类EasyDataSeg数据集。
在PaddleX中,使用`paddlex.cv.datasets.EasyDataSeg`([API说明](./apis/datasets.html#easydataseg))加载分类数据集。
\ No newline at end of file
...@@ -39,6 +39,39 @@ C++部署方案位于目录`deploy/cpp/`下,且独立于PaddleX其他模块。 ...@@ -39,6 +39,39 @@ C++部署方案位于目录`deploy/cpp/`下,且独立于PaddleX其他模块。
- Linux平台:[linux](deploy_cpp_linux.md) - Linux平台:[linux](deploy_cpp_linux.md)
- window平台:[windows](deploy_cpp_win_vs2019.md) - window平台:[windows](deploy_cpp_win_vs2019.md)
### OpenVINO部署demo
OpenVINO部署demo位于目录`deploy/openvino/`下,且独立于PaddleX其他模块,该demo目前支持在 Linux 完成编译和部署运行。目前PaddleX到OpenVINO的部署流程如下:
graph LR
PaddleX --> ONNX --> OpenVINO IR --> OpenVINO Inference Engine
#### step1
PaddleX输出ONNX模型方法如下:
```
paddlex --export_onnx --model_dir=./xiaoduxiong_epoch_12 --save_dir=./onnx_model
```
|目前支持的模型|
|-----|
|ResNet18|
|ResNet34|
|ResNet50|
|ResNet101|
|ResNet50_vd|
|ResNet101_vd|
|ResNet50_vd_ssld|
|ResNet101_vd_ssld
|DarkNet53|
|MobileNetV1|
|MobileNetV2|
|DenseNet121|
|DenseNet161|
|DenseNet201|
得到ONNX模型后,OpenVINO的部署参考:[OpenVINO部署](deploy_openvino.md)
### 预测性能对比 ### 预测性能对比
#### 测试环境 #### 测试环境
......
...@@ -95,7 +95,7 @@ make ...@@ -95,7 +95,7 @@ make
``` ```
### Step5: 预测及可视化 ### Step5: 预测及可视化
编译成功后,预测demo的可执行程序分别为`build/detector``build/classifer``build/segmenter`,用户可根据自己的模型类型选择,其主要命令参数说明如下: 编译成功后,预测demo的可执行程序分别为`build/demo/detector``build/demo/classifer``build/demo/segmenter`,用户可根据自己的模型类型选择,其主要命令参数说明如下:
| 参数 | 说明 | | 参数 | 说明 |
| ---- | ---- | | ---- | ---- |
...@@ -116,7 +116,7 @@ make ...@@ -116,7 +116,7 @@ make
不使用`GPU`测试图片 `/path/to/xiaoduxiong.jpeg` 不使用`GPU`测试图片 `/path/to/xiaoduxiong.jpeg`
```shell ```shell
./build/detector --model_dir=/path/to/inference_model --image=/path/to/xiaoduxiong.jpeg --save_dir=output ./build/demo/detector --model_dir=/path/to/inference_model --image=/path/to/xiaoduxiong.jpeg --save_dir=output
``` ```
图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
...@@ -131,6 +131,6 @@ make ...@@ -131,6 +131,6 @@ make
/path/to/images/xiaoduxiongn.jpeg /path/to/images/xiaoduxiongn.jpeg
``` ```
```shell ```shell
./build/detector --model_dir=/path/to/models/inference_model --image_list=/root/projects/images_list.txt --use_gpu=1 --save_dir=output ./build/demo/detector --model_dir=/path/to/models/inference_model --image_list=/root/projects/images_list.txt --use_gpu=1 --save_dir=output
``` ```
图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
...@@ -106,7 +106,7 @@ d: ...@@ -106,7 +106,7 @@ d:
cd D:\projects\PaddleX\deploy\cpp\out\build\x64-Release cd D:\projects\PaddleX\deploy\cpp\out\build\x64-Release
``` ```
编译成功后,预测demo的入口程序为`detector`,`classifer`,`segmenter`,用户可根据自己的模型类型选择,其主要命令参数说明如下: 编译成功后,预测demo的入口程序为`demo\detector`,`demo\classifer`,`demo\segmenter`,用户可根据自己的模型类型选择,其主要命令参数说明如下:
| 参数 | 说明 | | 参数 | 说明 |
| ---- | ---- | | ---- | ---- |
......
# OpenVINO 分类demo编译
## 说明
本文档在 `Ubuntu`使用`GCC 4.8.5` 进行了验证,如果需要使用更多G++版本和平台的OpenVino编译,请参考: [OpenVINO](https://github.com/openvinotoolkit/openvino/blob/2020/build-instruction.md)
## 验证环境
* Ubuntu* 16.04 (64-bit) with GCC* 4.8.5
* CMake 3.12
* Python 2.7 or higher
请确保系统已经安装好上述基本软件,**下面所有示例以工作目录 `/root/projects/`演示**
`git clone https://github.com/PaddlePaddle/PaddleX.git`
**说明**:其中`C++`预测代码在`/root/projects/PaddleX/deploy/openvino` 目录,该目录不依赖任何`PaddleX`下其他目录。
### Step1: 软件依赖
- openvino:
[编译文档](https://github.com/openvinotoolkit/openvino/blob/2020/build-instruction.md#build-steps)
- gflags:
[编译文档](https://gflags.github.io/gflags/#download)
- opencv:
[编译文档](https://docs.opencv.org/master/d7/d9f/tutorial_linux_install.html)
说明:/root/projects/PaddleX/deploy/openvino/scripts/bootstrap.sh提供了预编译版本下载,也可自行编译。
- ngraph:
说明:openvino编译的过程中会生成ngraph的lib文件,位于{openvino根目录}/bin/intel64/Release/lib/下。
### Step2: 编译demo
编译`cmake`的命令在`scripts/build.sh`中,请根据Step1中编译软件的实际情况修改主要参数,其主要内容说明如下:
```
# openvino预编译库的路径
OPENVINO_DIR=/path/to/inference_engine/
# gflags预编译库的路径
GFLAGS_DIR=/path/to/gflags
# ngraph lib的路径,编译openvino时通常会生成
NGRAPH_LIB=/path/to/ngraph/lib/
# opencv预编译库的路径, 如果使用自带预编译版本可不修改
OPENCV_DIR=$(pwd)/deps/opencv3gcc4.8/
# 下载自带预编译版本
sh $(pwd)/scripts/bootstrap.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}
make
```
修改脚本设置好主要参数后,执行`build`脚本:
```shell
sh ./scripts/build.sh
```
### Step3: 模型转换
[]()生成的onnx文件转换为OpencVINO支持的格式,请参考:[Model Optimizer文档](https://docs.openvinotoolkit.org/latest/_docs_MO_DG_Deep_Learning_Model_Optimizer_DevGuide.html)
### Step4: 预测
编译成功后,预测demo的可执行程序分别为`build/classifer`,其主要命令参数说明如下:
| 参数 | 说明 |
| ---- | ---- |
| --model_dir | Model Optimizer生成的.xml文件路径,请保证Model Optimizer生成的三个文件在同一路径下|
| --image | 要预测的图片文件路径 |
| --image_list | 按行存储图片路径的.txt文件 |
| --device | 运行的平台, 默认值为"CPU" |
## 样例
可使用[小度熊识别模型](deploy.md#导出inference模型)中导出的`inference_model`和测试图片进行预测。
`样例一`
测试图片 `/path/to/xiaoduxiong.jpeg`
```shell
./build/classifier --model_dir=/path/to/inference_model --image=/path/to/xiaoduxiong.jpeg
```
`样例二`:
预测多个图片`/path/to/image_list.txt`,image_list.txt内容的格式如下:
```
/path/to/images/xiaoduxiong1.jpeg
/path/to/images/xiaoduxiong2.jpeg
...
/path/to/images/xiaoduxiongn.jpeg
```
```shell
./build/classifier --model_dir=/path/to/models/inference_model --image_list=/root/projects/images_list.txt -
```
# Paddle模型加密方案
飞桨团队推出模型加密方案,使用业内主流的AES加密技术对最终模型进行加密。飞桨用户可以通过PaddleX导出模型后,使用该方案对模型进行加密,预测时使用解密SDK进行模型解密并完成推理,大大提升AI应用安全性和开发效率。
## 1. 方案介绍
### 1.1 工具组成
[PaddleX模型加密SDK下载](https://bj.bcebos.com/paddlex/tools/paddlex-encryption.zip)
下载并解压后,目录包含内容为:
```
paddle_model_encrypt
├── include # 头文件:paddle_model_decrypt.h(解密)和paddle_model_encrypt.h(加密)
|
├── lib # libpmodel-encrypt.so和libpmodel-decrypt.so动态库
|
└── tool # paddle_encrypt_tool
```
### 1.2 二进制工具
#### 1.2.1 生成密钥
产生随机密钥信息(用于AES加解密使用)(32字节key + 16字节iv, 注意这里产生的key是经过base64编码后的,这样可以扩充选取key的范围)
```
paddle_encrypt_tool -g
```
#### 1.2.1 文件加密
```
paddle_encrypt_tool -e -key keydata -infile infile -outfile outfile
```
#### 1.3 SDK
```
// 加密API
int paddle_encrypt_model(const char* keydata, const char* infile, const char* outfile);
// 加载加密模型API:
int paddle_security_load_model(
paddle::AnalysisConfig *config,
const char *key,
const char *model_file,
const char *param_file);
```
## 2. PaddleX C++加密部署
多端部署
==============
使用教程 PaddleX全流程开发教程
========================= =========================
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
dataset_prepare.md
train/index.rst train/index.rst
compress/index.rst compress/index.rst
deploy/index.rst
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
# 更新日志
- 2020.05.17
> - 发布v0.1.8 pip更新
> - 修复部分代码Bug
> - 新增EasyData平台数据标注格式支持
> - 支持imgaug数据增强库的pixel-level算子
...@@ -27,6 +27,7 @@ from . import det ...@@ -27,6 +27,7 @@ from . import det
from . import seg from . import seg
from . import cls from . import cls
from . import slim from . import slim
from . import convertor
from . import tools from . import tools
try: try:
...@@ -48,4 +49,4 @@ load_model = cv.models.load_model ...@@ -48,4 +49,4 @@ load_model = cv.models.load_model
datasets = cv.datasets datasets = cv.datasets
log_level = 2 log_level = 2
__version__ = '0.1.7.github' __version__ = '0.2.0.github'
...@@ -29,6 +29,12 @@ def arg_parser(): ...@@ -29,6 +29,12 @@ def arg_parser():
action="store_true", action="store_true",
default=False, default=False,
help="export inference model for C++/Python deployment") help="export inference model for C++/Python deployment")
parser.add_argument(
"--export_onnx",
"-eo",
action="store_true",
default=False,
help="export onnx model for deployment")
parser.add_argument( parser.add_argument(
"--fixed_input_shape", "--fixed_input_shape",
"-fs", "-fs",
...@@ -54,25 +60,36 @@ def main(): ...@@ -54,25 +60,36 @@ def main():
print("Repo: https://github.com/PaddlePaddle/PaddleX.git") print("Repo: https://github.com/PaddlePaddle/PaddleX.git")
print("Email: paddlex@baidu.com") print("Email: paddlex@baidu.com")
return return
if args.export_inference: if args.export_inference:
assert args.model_dir is not None, "--model_dir should be defined while exporting inference model" assert args.model_dir is not None, "--model_dir should be defined while exporting inference model"
assert args.save_dir is not None, "--save_dir should be defined to save inference model" assert args.save_dir is not None, "--save_dir should be defined to save inference model"
fixed_input_shape = eval(args.fixed_input_shape)
assert len( fixed_input_shape = None
fixed_input_shape) == 2, "len of fixed input shape must == 2" if args.fixed_input_shape is not None:
fixed_input_shape = eval(args.fixed_input_shape)
assert len(
fixed_input_shape
) == 2, "len of fixed input shape must == 2, such as [224,224]"
else:
fixed_input_shape = None
model = pdx.load_model(args.model_dir, fixed_input_shape) model = pdx.load_model(args.model_dir, fixed_input_shape)
model.export_inference_model(args.save_dir) model.export_inference_model(args.save_dir)
if args.export_onnx: if args.export_onnx:
assert args.model_dir is not None, "--model_dir should be defined while exporting onnx model" assert args.model_dir is not None, "--model_dir should be defined while exporting onnx model"
assert args.save_dir is not None, "--save_dir should be defined to save onnx model" assert args.save_dir is not None, "--save_dir should be defined to create onnx model"
fixed_input_shape = eval(args.fixed_input_shape) assert args.fixed_input_shape is not None, "--fixed_input_shape should be defined [w,h] to create onnx model, such as [224,224]"
assert len(
fixed_input_shape) == 2, "len of fixed input shape must == 2"
fixed_input_shape = []
if args.fixed_input_shape is not None:
fixed_input_shape = eval(args.fixed_input_shape)
assert len(
fixed_input_shape
) == 2, "len of fixed input shape must == 2, such as [224,224]"
model = pdx.load_model(args.model_dir, fixed_input_shape) model = pdx.load_model(args.model_dir, fixed_input_shape)
model.export_onnx_model(args.save_dir) pdx.convertor.export_onnx_model(model, args.save_dir)
if __name__ == "__main__": if __name__ == "__main__":
......
#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
#
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#limitations under the License.
from __future__ import absolute_import
import paddle.fluid as fluid
import os
import sys
import paddlex as pdx
import paddlex.utils.logging as logging
__all__ = ['export_onnx']
def export_onnx(model_dir, save_dir, fixed_input_shape):
assert len(fixed_input_shape) == 2, "len of fixed input shape must == 2"
model = pdx.load_model(model_dir, fixed_input_shape)
model_name = os.path.basename(model_dir.strip('/')).split('/')[-1]
export_onnx_model(model, save_dir)
def export_onnx_model(model, save_dir):
support_list = [
'ResNet18', 'ResNet34', 'ResNet50', 'ResNet101', 'ResNet50_vd',
'ResNet101_vd', 'ResNet50_vd_ssld', 'ResNet101_vd_ssld', 'DarkNet53',
'MobileNetV1', 'MobileNetV2', 'DenseNet121', 'DenseNet161',
'DenseNet201'
]
if model.__class__.__name__ not in support_list:
raise Exception("Model: {} unsupport export to ONNX".format(
model.__class__.__name__))
try:
from fluid.utils import op_io_info, init_name_prefix
from onnx import helper, checker
import fluid_onnx.ops as ops
from fluid_onnx.variables import paddle_variable_to_onnx_tensor, paddle_onnx_weight
from debug.model_check import debug_model, Tracker
except Exception as e:
logging.error(
"Import Module Failed! Please install paddle2onnx. Related requirements see https://github.com/PaddlePaddle/paddle2onnx."
)
raise e
place = fluid.CPUPlace()
exe = fluid.Executor(place)
inference_scope = fluid.global_scope()
with fluid.scope_guard(inference_scope):
test_input_names = [
var.name for var in list(model.test_inputs.values())
]
inputs_outputs_list = ["fetch", "feed"]
weights, weights_value_info = [], []
global_block = model.test_prog.global_block()
for var_name in global_block.vars:
var = global_block.var(var_name)
if var_name not in test_input_names\
and var.persistable:
weight, val_info = paddle_onnx_weight(
var=var, scope=inference_scope)
weights.append(weight)
weights_value_info.append(val_info)
# Create inputs
inputs = [
paddle_variable_to_onnx_tensor(v, global_block)
for v in test_input_names
]
logging.INFO("load the model parameter done.")
onnx_nodes = []
op_check_list = []
op_trackers = []
nms_first_index = -1
nms_outputs = []
for block in model.test_prog.blocks:
for op in block.ops:
if op.type in ops.node_maker:
# TODO: deal with the corner case that vars in
# different blocks have the same name
node_proto = ops.node_maker[str(op.type)](
operator=op, block=block)
op_outputs = []
last_node = None
if isinstance(node_proto, tuple):
onnx_nodes.extend(list(node_proto))
last_node = list(node_proto)
else:
onnx_nodes.append(node_proto)
last_node = [node_proto]
tracker = Tracker(str(op.type), last_node)
op_trackers.append(tracker)
op_check_list.append(str(op.type))
if op.type == "multiclass_nms" and nms_first_index < 0:
nms_first_index = 0
if nms_first_index >= 0:
_, _, output_op = op_io_info(op)
for output in output_op:
nms_outputs.extend(output_op[output])
else:
if op.type not in ['feed', 'fetch']:
op_check_list.append(op.type)
logging.info('The operator sets to run test case.')
logging.info(set(op_check_list))
# Create outputs
# Get the new names for outputs if they've been renamed in nodes' making
renamed_outputs = op_io_info.get_all_renamed_outputs()
test_outputs = list(model.test_outputs.values())
test_outputs_names = [var.name for var in model.test_outputs.values()]
test_outputs_names = [
name if name not in renamed_outputs else renamed_outputs[name]
for name in test_outputs_names
]
outputs = [
paddle_variable_to_onnx_tensor(v, global_block)
for v in test_outputs_names
]
# Make graph
onnx_name = 'paddlex.onnx'
onnx_graph = helper.make_graph(
nodes=onnx_nodes,
name=onnx_name,
initializer=weights,
inputs=inputs + weights_value_info,
outputs=outputs)
# Make model
onnx_model = helper.make_model(
onnx_graph, producer_name='PaddlePaddle')
# Model check
checker.check_model(onnx_model)
if onnx_model is not None:
onnx_model_file = os.path.join(save_dir, onnx_name)
if not os.path.exists(save_dir):
os.mkdir(save_dir)
with open(onnx_model_file, 'wb') as f:
f.write(onnx_model.SerializeToString())
logging.info("Saved converted model to path: %s" % onnx_model_file)
...@@ -95,8 +95,8 @@ class VOCDetection(Dataset): ...@@ -95,8 +95,8 @@ class VOCDetection(Dataset):
if not osp.isfile(xml_file): if not osp.isfile(xml_file):
continue continue
if not osp.exists(img_file): if not osp.exists(img_file):
raise IOError( raise IOError('The image file {} is not exist!'.format(
'The image file {} is not exist!'.format(img_file)) img_file))
tree = ET.parse(xml_file) tree = ET.parse(xml_file)
if tree.find('id') is None: if tree.find('id') is None:
im_id = np.array([ct]) im_id = np.array([ct])
...@@ -122,25 +122,20 @@ class VOCDetection(Dataset): ...@@ -122,25 +122,20 @@ class VOCDetection(Dataset):
y2 = float(obj.find('bndbox').find('ymax').text) y2 = float(obj.find('bndbox').find('ymax').text)
x1 = max(0, x1) x1 = max(0, x1)
y1 = max(0, y1) y1 = max(0, y1)
x2 = min(im_w - 1, x2) if im_w > 0.5 and im_h > 0.5:
y2 = min(im_h - 1, y2) x2 = min(im_w - 1, x2)
y2 = min(im_h - 1, y2)
gt_bbox[i] = [x1, y1, x2, y2] gt_bbox[i] = [x1, y1, x2, y2]
is_crowd[i][0] = 0 is_crowd[i][0] = 0
difficult[i][0] = _difficult difficult[i][0] = _difficult
annotations['annotations'].append({ annotations['annotations'].append({
'iscrowd': 'iscrowd': 0,
0, 'image_id': int(im_id[0]),
'image_id':
int(im_id[0]),
'bbox': [x1, y1, x2 - x1 + 1, y2 - y1 + 1], 'bbox': [x1, y1, x2 - x1 + 1, y2 - y1 + 1],
'area': 'area': float((x2 - x1 + 1) * (y2 - y1 + 1)),
float((x2 - x1 + 1) * (y2 - y1 + 1)), 'category_id': cname2cid[cname],
'category_id': 'id': ann_ct,
cname2cid[cname], 'difficult': _difficult
'id':
ann_ct,
'difficult':
_difficult
}) })
ann_ct += 1 ann_ct += 1
...@@ -160,14 +155,10 @@ class VOCDetection(Dataset): ...@@ -160,14 +155,10 @@ class VOCDetection(Dataset):
self.file_list.append([img_file, voc_rec]) self.file_list.append([img_file, voc_rec])
ct += 1 ct += 1
annotations['images'].append({ annotations['images'].append({
'height': 'height': im_h,
im_h, 'width': im_w,
'width': 'id': int(im_id[0]),
im_w, 'file_name': osp.split(img_file)[1]
'id':
int(im_id[0]),
'file_name':
osp.split(img_file)[1]
}) })
if not len(self.file_list) > 0: if not len(self.file_list) > 0:
...@@ -198,8 +189,7 @@ class VOCDetection(Dataset): ...@@ -198,8 +189,7 @@ class VOCDetection(Dataset):
else: else:
mix_pos = 0 mix_pos = 0
im_info['mixup'] = [ im_info['mixup'] = [
files[mix_pos][0], files[mix_pos][0], copy.deepcopy(files[mix_pos][1][0]),
copy.deepcopy(files[mix_pos][1][0]),
copy.deepcopy(files[mix_pos][1][1]) copy.deepcopy(files[mix_pos][1][1])
] ]
self._pos += 1 self._pos += 1
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
from __future__ import absolute_import from __future__ import absolute_import
import paddle.fluid as fluid import paddle.fluid as fluid
import os import os
import sys
import numpy as np import numpy as np
import time import time
import math import math
...@@ -251,6 +252,9 @@ class BaseAPI: ...@@ -251,6 +252,9 @@ class BaseAPI:
del self.init_params['self'] del self.init_params['self']
if '__class__' in self.init_params: if '__class__' in self.init_params:
del self.init_params['__class__'] del self.init_params['__class__']
if 'model_name' in self.init_params:
del self.init_params['model_name']
info['_init_params'] = self.init_params info['_init_params'] = self.init_params
info['_Attributes']['num_classes'] = self.num_classes info['_Attributes']['num_classes'] = self.num_classes
...@@ -371,6 +375,8 @@ class BaseAPI: ...@@ -371,6 +375,8 @@ class BaseAPI:
use_vdl=False, use_vdl=False,
early_stop=False, early_stop=False,
early_stop_patience=5): early_stop_patience=5):
if train_dataset.num_samples < train_batch_size:
raise Exception('The amount of training datset must be larger than batch size.')
if not osp.isdir(save_dir): if not osp.isdir(save_dir):
if osp.exists(save_dir): if osp.exists(save_dir):
os.remove(save_dir) os.remove(save_dir)
...@@ -428,9 +434,7 @@ class BaseAPI: ...@@ -428,9 +434,7 @@ class BaseAPI:
if use_vdl: if use_vdl:
# VisualDL component # VisualDL component
log_writer = LogWriter(vdl_logdir, sync_cycle=20) log_writer = LogWriter(vdl_logdir)
train_step_component = OrderedDict()
eval_component = OrderedDict()
thresh = 0.0001 thresh = 0.0001
if early_stop: if early_stop:
...@@ -468,13 +472,7 @@ class BaseAPI: ...@@ -468,13 +472,7 @@ class BaseAPI:
if use_vdl: if use_vdl:
for k, v in step_metrics.items(): for k, v in step_metrics.items():
if k not in train_step_component.keys(): log_writer.add_scalar('Metrics/Training(Step): {}'.format(k), v, num_steps)
with log_writer.mode('Each_Step_while_Training'
) as step_logger:
train_step_component[
k] = step_logger.scalar(
'Training: {}'.format(k))
train_step_component[k].add_record(num_steps, v)
# 估算剩余时间 # 估算剩余时间
avg_step_time = np.mean(time_stat) avg_step_time = np.mean(time_stat)
...@@ -535,12 +533,7 @@ class BaseAPI: ...@@ -535,12 +533,7 @@ class BaseAPI:
if isinstance(v, np.ndarray): if isinstance(v, np.ndarray):
if v.size > 1: if v.size > 1:
continue continue
if k not in eval_component: log_writer.add_scalar("Metrics/Eval(Epoch): {}".format(k), v, i+1)
with log_writer.mode('Each_Epoch_on_Eval_Data'
) as eval_logger:
eval_component[k] = eval_logger.scalar(
'Evaluation: {}'.format(k))
eval_component[k].add_record(i + 1, v)
self.save_model(save_dir=current_save_dir) self.save_model(save_dir=current_save_dir)
time_eval_one_epoch = time.time() - eval_epoch_start_time time_eval_one_epoch = time.time() - eval_epoch_start_time
eval_epoch_start_time = time.time() eval_epoch_start_time = time.time()
......
...@@ -400,14 +400,19 @@ class DeepLabv3p(BaseAPI): ...@@ -400,14 +400,19 @@ class DeepLabv3p(BaseAPI):
fetch_list=list(self.test_outputs.values())) fetch_list=list(self.test_outputs.values()))
pred = result[0] pred = result[0]
pred = np.squeeze(pred).astype('uint8') pred = np.squeeze(pred).astype('uint8')
logit = result[1]
logit = np.squeeze(logit)
logit = np.transpose(logit, (1, 2, 0))
for info in im_info[::-1]: for info in im_info[::-1]:
if info[0] == 'resize': if info[0] == 'resize':
w, h = info[1][1], info[1][0] w, h = info[1][1], info[1][0]
pred = cv2.resize(pred, (w, h), cv2.INTER_NEAREST) pred = cv2.resize(pred, (w, h), cv2.INTER_NEAREST)
logit = cv2.resize(logit, (w, h), cv2.INTER_LINEAR)
elif info[0] == 'padding': elif info[0] == 'padding':
w, h = info[1][1], info[1][0] w, h = info[1][1], info[1][0]
pred = pred[0:h, 0:w] pred = pred[0:h, 0:w]
logit = logit[0:h, 0:w, :]
else: else:
raise Exception("Unexpected info '{}' in im_info".format( raise Exception("Unexpected info '{}' in im_info".format(
info[0])) info[0]))
return {'label_map': pred, 'score_map': result[1]} return {'label_map': pred, 'score_map': logit}
...@@ -38,12 +38,9 @@ def load_model(model_dir, fixed_input_shape=None): ...@@ -38,12 +38,9 @@ def load_model(model_dir, fixed_input_shape=None):
if not hasattr(paddlex.cv.models, info['Model']): if not hasattr(paddlex.cv.models, info['Model']):
raise Exception("There's no attribute {} in paddlex.cv.models".format( raise Exception("There's no attribute {} in paddlex.cv.models".format(
info['Model'])) info['Model']))
if 'model_name' in info['_init_params']:
if info['_Attributes']['model_type'] == 'classifier': del info['_init_params']['model_name']
model = paddlex.cv.models.BaseClassifier(**info['_init_params']) model = getattr(paddlex.cv.models, info['Model'])(**info['_init_params'])
else:
model = getattr(paddlex.cv.models,
info['Model'])(**info['_init_params'])
model.fixed_input_shape = fixed_input_shape model.fixed_input_shape = fixed_input_shape
if status == "Normal" or \ if status == "Normal" or \
status == "Prune" or status == "fluid.save": status == "Prune" or status == "fluid.save":
......
...@@ -19,6 +19,9 @@ from paddle.fluid.contrib.slim.quantization import PostTrainingQuantization ...@@ -19,6 +19,9 @@ from paddle.fluid.contrib.slim.quantization import PostTrainingQuantization
import paddlex.utils.logging as logging import paddlex.utils.logging as logging
import paddle.fluid as fluid import paddle.fluid as fluid
import os import os
import re
import numpy as np
import time
class PaddleXPostTrainingQuantization(PostTrainingQuantization): class PaddleXPostTrainingQuantization(PostTrainingQuantization):
...@@ -123,28 +126,37 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization): ...@@ -123,28 +126,37 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
the program of quantized model. the program of quantized model.
''' '''
self._preprocess() self._preprocess()
batch_ct = 0
for data in self._data_loader():
batch_ct += 1
if self._batch_nums and batch_ct >= self._batch_nums:
break
batch_id = 0 batch_id = 0
logging.info("Start to run batch!")
for data in self._data_loader(): for data in self._data_loader():
start = time.time()
self._executor.run( self._executor.run(
program=self._program, program=self._program,
feed=data, feed=data,
fetch_list=self._fetch_list, fetch_list=self._fetch_list,
return_numpy=False) return_numpy=False)
self._sample_data(batch_id) self._sample_data(batch_id)
end = time.time()
if batch_id % 5 == 0: logging.debug('[Run batch data] Batch={}/{}, time_each_batch={} s.'.format(
logging.info("run batch: {}".format(batch_id)) str(batch_id + 1),
str(batch_ct),
str(end-start)))
batch_id += 1 batch_id += 1
if self._batch_nums and batch_id >= self._batch_nums: if self._batch_nums and batch_id >= self._batch_nums:
break break
logging.info("all run batch: ".format(batch_id)) logging.info("All run batch: ".format(batch_id))
logging.info("calculate scale factor ...") logging.info("Calculate scale factor ...")
self._calculate_scale_factor() self._calculate_scale_factor()
logging.info("update the program ...") logging.info("Update the program ...")
self._update_program() self._update_program()
logging.info("Save ...")
self._save_output_scale() self._save_output_scale()
logging.info("Finish quant!")
return self._program return self._program
def save_quantized_model(self, save_model_path): def save_quantized_model(self, save_model_path):
...@@ -221,3 +233,69 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization): ...@@ -221,3 +233,69 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
for var in self._program.list_vars(): for var in self._program.list_vars():
if var.name in self._quantized_act_var_name: if var.name in self._quantized_act_var_name:
var.persistable = True var.persistable = True
def _calculate_scale_factor(self):
'''
Calculate the scale factor of quantized variables.
'''
# apply channel_wise_abs_max quantization for weights
ct = 1
for var_name in self._quantized_weight_var_name:
start = time.time()
data = self._sampling_data[var_name]
scale_factor_per_channel = []
for i in range(data.shape[0]):
abs_max_value = np.max(np.abs(data[i]))
scale_factor_per_channel.append(abs_max_value)
self._quantized_var_scale_factor[
var_name] = scale_factor_per_channel
end = time.time()
logging.debug('[Calculate weight] Weight_id={}/{}, time_each_weight={} s.'.format(
str(ct),
str(len(self._quantized_weight_var_name)),
str(end-start)))
ct += 1
ct = 1
# apply kl quantization for activation
if self._is_use_cache_file:
for var_name in self._quantized_act_var_name:
start = time.time()
sampling_data = []
filenames = [f for f in os.listdir(self._cache_dir) \
if re.match(var_name + '_[0-9]+.npy', f)]
for filename in filenames:
file_path = os.path.join(self._cache_dir, filename)
sampling_data.append(np.load(file_path))
os.remove(file_path)
sampling_data = np.concatenate(sampling_data)
if self._algo == "KL":
self._quantized_var_scale_factor[var_name] = \
self._get_kl_scaling_factor(np.abs(sampling_data))
else:
self._quantized_var_scale_factor[var_name] = \
np.max(np.abs(sampling_data))
end = time.time()
logging.debug('[Calculate activation] Activation_id={}/{}, time_each_activation={} s.'.format(
str(ct),
str(len(self._quantized_act_var_name)),
str(end-start)))
ct += 1
else:
for var_name in self._quantized_act_var_name:
start = time.time()
self._sampling_data[var_name] = np.concatenate(
self._sampling_data[var_name])
if self._algo == "KL":
self._quantized_var_scale_factor[var_name] = \
self._get_kl_scaling_factor(np.abs(self._sampling_data[var_name]))
else:
self._quantized_var_scale_factor[var_name] = \
np.max(np.abs(self._sampling_data[var_name]))
end = time.time()
logging.debug('[Calculate activation] Activation_id={}/{}, time_each_activation={} s.'.format(
str(ct),
str(len(self._quantized_act_var_name)),
str(end-start)))
ct += 1
\ No newline at end of file
...@@ -30,7 +30,6 @@ def visualize(model, sensitivities_file, save_dir='./'): ...@@ -30,7 +30,6 @@ def visualize(model, sensitivities_file, save_dir='./'):
import matplotlib import matplotlib
matplotlib.use('Agg') matplotlib.use('Agg')
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
program = model.test_prog program = model.test_prog
place = model.places[0] place = model.places[0]
fig = plt.figure() fig = plt.figure()
...@@ -51,15 +50,21 @@ def visualize(model, sensitivities_file, save_dir='./'): ...@@ -51,15 +50,21 @@ def visualize(model, sensitivities_file, save_dir='./'):
min(np.array(x)) - 0.01, min(np.array(x)) - 0.01,
max(np.array(x)) + 0.01, 0.05) max(np.array(x)) + 0.01, 0.05)
my_y_ticks = np.arange(0.05, 1, 0.05) my_y_ticks = np.arange(0.05, 1, 0.05)
plt.xticks(my_x_ticks, fontsize=3) plt.xticks(my_x_ticks, rotation=30, fontsize=8)
plt.yticks(my_y_ticks, fontsize=3) plt.yticks(my_y_ticks, fontsize=8)
for a, b in zip(x, y): for a, b in zip(x, y):
plt.text( plt.text(
a, a,
b, (float('%0.4f' % a), float('%0.3f' % b)), b, (float('%0.3f' % a), float('%0.3f' % b)),
ha='center', ha='center',
va='bottom', va='bottom',
fontsize=3) fontsize=8)
plt.rcParams['savefig.dpi'] = 120
plt.rcParams['figure.dpi'] = 150
suffix = osp.splitext(sensitivities_file)[-1] suffix = osp.splitext(sensitivities_file)[-1]
plt.savefig('sensitivities.png', dpi=800) plt.savefig(osp.join(save_dir, 'sensitivities.png'))
plt.close() plt.close()
import pickle
coor = dict(zip(x, y))
output = open(osp.join(save_dir, 'sensitivities_xy.pkl'), 'wb')
pickle.dump(coor, output)
...@@ -86,10 +86,10 @@ class Compose(ClsTransform): ...@@ -86,10 +86,10 @@ class Compose(ClsTransform):
else: else:
import imgaug.augmenters as iaa import imgaug.augmenters as iaa
if isinstance(op, iaa.Augmenter): if isinstance(op, iaa.Augmenter):
im, = execute_imgaug(op, im) im = execute_imgaug(op, im)
output = (im, ) outputs = (im, )
if label is not None: if label is not None:
output = (im, label) outputs = (im, label)
return outputs return outputs
......
...@@ -111,8 +111,8 @@ class Compose(DetTransform): ...@@ -111,8 +111,8 @@ class Compose(DetTransform):
try: try:
im = cv2.imread(im_file).astype('float32') im = cv2.imread(im_file).astype('float32')
except: except:
raise TypeError( raise TypeError('Can\'t read The image file {}!'.format(
'Can\'t read The image file {}!'.format(im_file)) im_file))
im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB) im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
# make default im_info with [h, w, 1] # make default im_info with [h, w, 1]
im_info['im_resize_info'] = np.array( im_info['im_resize_info'] = np.array(
...@@ -145,19 +145,10 @@ class Compose(DetTransform): ...@@ -145,19 +145,10 @@ class Compose(DetTransform):
outputs = op(im, im_info, label_info) outputs = op(im, im_info, label_info)
im = outputs[0] im = outputs[0]
else: else:
im = execute_imgaug(op, im)
if label_info is not None: if label_info is not None:
gt_poly = label_info.get('gt_poly', None)
gt_bbox = label_info['gt_bbox']
if gt_poly is None:
im, aug_bbox = execute_imgaug(op, im, bboxes=gt_bbox)
else:
im, aug_bbox, aug_poly = execute_imgaug(
op, im, bboxes=gt_bbox, polygons=gt_poly)
label_info['gt_poly'] = aug_poly
label_info['gt_bbox'] = aug_bbox
outputs = (im, im_info, label_info) outputs = (im, im_info, label_info)
else: else:
im, = execute_imgaug(op, im)
outputs = (im, im_info) outputs = (im, im_info)
return outputs return outputs
...@@ -218,8 +209,8 @@ class ResizeByShort(DetTransform): ...@@ -218,8 +209,8 @@ class ResizeByShort(DetTransform):
im_short_size = min(im.shape[0], im.shape[1]) im_short_size = min(im.shape[0], im.shape[1])
im_long_size = max(im.shape[0], im.shape[1]) im_long_size = max(im.shape[0], im.shape[1])
scale = float(self.short_size) / im_short_size scale = float(self.short_size) / im_short_size
if self.max_size > 0 and np.round( if self.max_size > 0 and np.round(scale *
scale * im_long_size) > self.max_size: im_long_size) > self.max_size:
scale = float(self.max_size) / float(im_long_size) scale = float(self.max_size) / float(im_long_size)
resized_width = int(round(im.shape[1] * scale)) resized_width = int(round(im.shape[1] * scale))
resized_height = int(round(im.shape[0] * scale)) resized_height = int(round(im.shape[0] * scale))
...@@ -302,8 +293,8 @@ class Padding(DetTransform): ...@@ -302,8 +293,8 @@ class Padding(DetTransform):
if isinstance(self.target_size, int): if isinstance(self.target_size, int):
padding_im_h = self.target_size padding_im_h = self.target_size
padding_im_w = self.target_size padding_im_w = self.target_size
elif isinstance(self.target_size, list) or isinstance( elif isinstance(self.target_size, list) or isinstance(self.target_size,
self.target_size, tuple): tuple):
padding_im_w = self.target_size[0] padding_im_w = self.target_size[0]
padding_im_h = self.target_size[1] padding_im_h = self.target_size[1]
elif self.coarsest_stride > 0: elif self.coarsest_stride > 0:
...@@ -321,8 +312,8 @@ class Padding(DetTransform): ...@@ -321,8 +312,8 @@ class Padding(DetTransform):
raise ValueError( raise ValueError(
'the size of image should be less than target_size, but the size of image ({}, {}), is larger than target_size ({}, {})' 'the size of image should be less than target_size, but the size of image ({}, {}), is larger than target_size ({}, {})'
.format(im_w, im_h, padding_im_w, padding_im_h)) .format(im_w, im_h, padding_im_w, padding_im_h))
padding_im = np.zeros((padding_im_h, padding_im_w, im_c), padding_im = np.zeros(
dtype=np.float32) (padding_im_h, padding_im_w, im_c), dtype=np.float32)
padding_im[:im_h, :im_w, :] = im padding_im[:im_h, :im_w, :] = im
if label_info is None: if label_info is None:
return (padding_im, im_info) return (padding_im, im_info)
...@@ -932,8 +923,9 @@ class RandomCrop(DetTransform): ...@@ -932,8 +923,9 @@ class RandomCrop(DetTransform):
crop_y = np.random.randint(0, h - crop_h) crop_y = np.random.randint(0, h - crop_h)
crop_x = np.random.randint(0, w - crop_w) crop_x = np.random.randint(0, w - crop_w)
crop_box = [crop_x, crop_y, crop_x + crop_w, crop_y + crop_h] crop_box = [crop_x, crop_y, crop_x + crop_w, crop_y + crop_h]
iou = iou_matrix(gt_bbox, np.array([crop_box], iou = iou_matrix(
dtype=np.float32)) gt_bbox, np.array(
[crop_box], dtype=np.float32))
if iou.max() < thresh: if iou.max() < thresh:
continue continue
...@@ -941,16 +933,21 @@ class RandomCrop(DetTransform): ...@@ -941,16 +933,21 @@ class RandomCrop(DetTransform):
continue continue
cropped_box, valid_ids = crop_box_with_center_constraint( cropped_box, valid_ids = crop_box_with_center_constraint(
gt_bbox, np.array(crop_box, dtype=np.float32)) gt_bbox, np.array(
crop_box, dtype=np.float32))
if valid_ids.size > 0: if valid_ids.size > 0:
found = True found = True
break break
if found: if found:
if 'gt_poly' in label_info and len(label_info['gt_poly']) > 0: if 'gt_poly' in label_info and len(label_info['gt_poly']) > 0:
crop_polys = crop_segms(label_info['gt_poly'], valid_ids, crop_polys = crop_segms(
np.array(crop_box, dtype=np.int64), label_info['gt_poly'],
h, w) valid_ids,
np.array(
crop_box, dtype=np.int64),
h,
w)
if [] in crop_polys: if [] in crop_polys:
delete_id = list() delete_id = list()
valid_polys = list() valid_polys = list()
......
...@@ -13,36 +13,41 @@ ...@@ -13,36 +13,41 @@
# limitations under the License. # limitations under the License.
import numpy as np import numpy as np
import copy
def execute_imgaug(augmenter, im, bboxes=None, polygons=None, def execute_imgaug(augmenter, im, bboxes=None, polygons=None,
segment_map=None): segment_map=None):
# 预处理,将bboxes, polygons转换成imgaug格式 # 预处理,将bboxes, polygons转换成imgaug格式
import imgaug.augmentables.polys as polys import imgaug.augmentables.kps as kps
import imgaug.augmentables.bbs as bbs import imgaug.augmentables.bbs as bbs
aug_im = im.astype('uint8') aug_im = im.astype('uint8')
aug_im = augmenter.augment(image=aug_im)
return aug_im
# TODO imgaug的标注处理逻辑与paddlex已存的transform存在部分差异
# 目前仅支持对原图进行处理,因此只能使用pixlevel的imgaug增强操作
# 以下代码暂不会执行
aug_bboxes = None aug_bboxes = None
if bboxes is not None: if bboxes is not None:
aug_bboxes = list() aug_bboxes = list()
for i in range(len(bboxes)): for i in range(len(bboxes)):
x1 = bboxes[i, 0] - 1 x1 = bboxes[i, 0]
y1 = bboxes[i, 1] y1 = bboxes[i, 1]
x2 = bboxes[i, 2] x2 = bboxes[i, 2]
y2 = bboxes[i, 3] y2 = bboxes[i, 3]
aug_bboxes.append(bbs.BoundingBox(x1, y1, x2, y2)) aug_bboxes.append(bbs.BoundingBox(x1, y1, x2, y2))
aug_polygons = None aug_points = None
lod_info = list()
if polygons is not None: if polygons is not None:
aug_polygons = list() aug_points = list()
for i in range(len(polygons)): for i in range(len(polygons)):
num = len(polygons[i]) num = len(polygons[i])
lod_info.append(num)
for j in range(num): for j in range(num):
points = np.reshape(polygons[i][j], (-1, 2)) tmp = np.reshape(polygons[i][j], (-1, 2))
aug_polygons.append(polys.Polygon(points)) for k in range(len(tmp)):
aug_points.append(kps.Keypoint(tmp[k, 0], tmp[k, 1]))
aug_segment_map = None aug_segment_map = None
if segment_map is not None: if segment_map is not None:
...@@ -56,72 +61,47 @@ def execute_imgaug(augmenter, im, bboxes=None, polygons=None, ...@@ -56,72 +61,47 @@ def execute_imgaug(augmenter, im, bboxes=None, polygons=None,
raise Exception( raise Exception(
"Only support 2-dimensions for 3-dimensions for segment_map") "Only support 2-dimensions for 3-dimensions for segment_map")
aug_im, aug_bboxes, aug_polygons, aug_seg_map = augmenter.augment( unnormalized_batch = augmenter.augment(
image=aug_im, image=aug_im,
bounding_boxes=aug_bboxes, bounding_boxes=aug_bboxes,
polygons=aug_polygons, keypoints=aug_points,
segmentation_maps=aug_segment_map) segmentation_maps=aug_segment_map,
return_batch=True)
aug_im = unnormalized_batch.images_aug[0]
aug_bboxes = unnormalized_batch.bounding_boxes_aug
aug_points = unnormalized_batch.keypoints_aug
aug_seg_map = unnormalized_batch.segmentation_maps_aug
aug_im = aug_im.astype('float32') aug_im = aug_im.astype('float32')
if aug_polygons is not None:
assert len(aug_bboxes) == len(
lod_info
), "Number of aug_bboxes should be equal to number of aug_polygons"
if aug_bboxes is not None: if aug_bboxes is not None:
# 裁剪掉在图像之外的bbox和polygon
for i in range(len(aug_bboxes)):
aug_bboxes[i] = aug_bboxes[i].clip_out_of_image(aug_im)
if aug_polygons is not None:
for i in range(len(aug_polygons)):
aug_polygons[i] = aug_polygons[i].clip_out_of_image(aug_im)
# 过滤掉无效的bbox和polygon,并转换为训练数据格式
converted_bboxes = list() converted_bboxes = list()
converted_polygons = list()
poly_index = 0
for i in range(len(aug_bboxes)): for i in range(len(aug_bboxes)):
# 过滤width或height不足1像素的框
if aug_bboxes[i].width < 1 or aug_bboxes[i].height < 1:
continue
if aug_polygons is None:
converted_bboxes.append([
aug_bboxes[i].x1, aug_bboxes[i].y1, aug_bboxes[i].x2,
aug_bboxes[i].y2
])
continue
# 如若有polygons,将会继续执行下面代码
polygons_this_box = list()
for ps in aug_polygons[poly_index:poly_index + lod_info[i]]:
if len(ps) == 0:
continue
for p in ps:
# 没有3个point的polygon被过滤
if len(p.exterior) < 3:
continue
polygons_this_box.append(p.exterior.flatten().tolist())
poly_index += lod_info[i]
if len(polygons_this_box) == 0:
continue
converted_bboxes.append([ converted_bboxes.append([
aug_bboxes[i].x1, aug_bboxes[i].y1, aug_bboxes[i].x2, aug_bboxes[i].x1, aug_bboxes[i].y1, aug_bboxes[i].x2,
aug_bboxes[i].y2 aug_bboxes[i].y2
]) ])
converted_polygons.append(polygons_this_box) aug_bboxes = converted_bboxes
if len(converted_bboxes) == 0:
aug_im = im aug_polygons = None
converted_bboxes = bboxes if aug_points is not None:
converted_polygons = polygons aug_polygons = copy.deepcopy(polygons)
idx = 0
for i in range(len(aug_polygons)):
num = len(aug_polygons[i])
for j in range(num):
num_points = len(aug_polygons[i][j]) // 2
for k in range(num_points):
aug_polygons[i][j][k * 2] = aug_points[idx].x
aug_polygons[i][j][k * 2 + 1] = aug_points[idx].y
idx += 1
result = [aug_im] result = [aug_im]
if bboxes is not None: if aug_bboxes is not None:
result.append(np.array(converted_bboxes)) result.append(np.array(aug_bboxes))
if polygons is not None: if aug_polygons is not None:
result.append(converted_polygons) result.append(aug_polygons)
if segment_map is not None: if aug_seg_map is not None:
n, h, w, c = aug_seg_map.shape n, h, w, c = aug_seg_map.shape
if len(segment_map.shape) == 2: if len(segment_map.shape) == 2:
aug_seg_map = np.reshape(aug_seg_map, (h, w)) aug_seg_map = np.reshape(aug_seg_map, (h, w))
......
...@@ -101,11 +101,10 @@ class Compose(SegTransform): ...@@ -101,11 +101,10 @@ class Compose(SegTransform):
if len(outputs) == 3: if len(outputs) == 3:
label = outputs[2] label = outputs[2]
else: else:
im = execute_imgaug(op, im)
if label is not None: if label is not None:
im, label = execute_imgaug(op, im, segment_map=label)
outputs = (im, im_info, label) outputs = (im, im_info, label)
else: else:
im, = execute_imgaug(op, im)
outputs = (im, im_info) outputs = (im, im_info)
return outputs return outputs
...@@ -391,8 +390,8 @@ class ResizeByShort(SegTransform): ...@@ -391,8 +390,8 @@ class ResizeByShort(SegTransform):
im_short_size = min(im.shape[0], im.shape[1]) im_short_size = min(im.shape[0], im.shape[1])
im_long_size = max(im.shape[0], im.shape[1]) im_long_size = max(im.shape[0], im.shape[1])
scale = float(self.short_size) / im_short_size scale = float(self.short_size) / im_short_size
if self.max_size > 0 and np.round( if self.max_size > 0 and np.round(scale *
scale * im_long_size) > self.max_size: im_long_size) > self.max_size:
scale = float(self.max_size) / float(im_long_size) scale = float(self.max_size) / float(im_long_size)
resized_width = int(round(im.shape[1] * scale)) resized_width = int(round(im.shape[1] * scale))
resized_height = int(round(im.shape[0] * scale)) resized_height = int(round(im.shape[0] * scale))
...@@ -423,8 +422,8 @@ class ResizeRangeScaling(SegTransform): ...@@ -423,8 +422,8 @@ class ResizeRangeScaling(SegTransform):
def __init__(self, min_value=400, max_value=600): def __init__(self, min_value=400, max_value=600):
if min_value > max_value: if min_value > max_value:
raise ValueError('min_value must be less than max_value, ' raise ValueError('min_value must be less than max_value, '
'but they are {} and {}.'.format( 'but they are {} and {}.'.format(min_value,
min_value, max_value)) max_value))
self.min_value = min_value self.min_value = min_value
self.max_value = max_value self.max_value = max_value
...@@ -761,8 +760,8 @@ class RandomPaddingCrop(SegTransform): ...@@ -761,8 +760,8 @@ class RandomPaddingCrop(SegTransform):
h_off = np.random.randint(img_height - crop_height + 1) h_off = np.random.randint(img_height - crop_height + 1)
w_off = np.random.randint(img_width - crop_width + 1) w_off = np.random.randint(img_width - crop_width + 1)
im = im[h_off:(crop_height + h_off), w_off:( im = im[h_off:(crop_height + h_off), w_off:(w_off + crop_width
w_off + crop_width), :] ), :]
if label is not None: if label is not None:
label = label[h_off:(crop_height + h_off), w_off:( label = label[h_off:(crop_height + h_off), w_off:(
w_off + crop_width)] w_off + crop_width)]
......
...@@ -19,7 +19,7 @@ long_description = "PaddleX. A end-to-end deeplearning model development toolkit ...@@ -19,7 +19,7 @@ long_description = "PaddleX. A end-to-end deeplearning model development toolkit
setuptools.setup( setuptools.setup(
name="paddlex", name="paddlex",
version='0.1.7', version='0.2.0',
author="paddlex", author="paddlex",
author_email="paddlex@baidu.com", author_email="paddlex@baidu.com",
description=long_description, description=long_description,
...@@ -27,10 +27,10 @@ setuptools.setup( ...@@ -27,10 +27,10 @@ setuptools.setup(
long_description_content_type="text/plain", long_description_content_type="text/plain",
url="https://github.com/PaddlePaddle/PaddleX", url="https://github.com/PaddlePaddle/PaddleX",
packages=setuptools.find_packages(), packages=setuptools.find_packages(),
setup_requires=['cython', 'numpy', 'sklearn'], setup_requires=['cython', 'numpy'],
install_requires=[ install_requires=[
"pycocotools;platform_system!='Windows'", 'pyyaml', 'colorama', 'tqdm', "pycocotools;platform_system!='Windows'", 'pyyaml', 'colorama', 'tqdm',
'visualdl==1.3.0', 'paddleslim==1.0.1' 'paddleslim==1.0.1', 'visualdl==2.0.0a2'
], ],
classifiers=[ classifiers=[
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
...@@ -38,6 +38,4 @@ setuptools.setup( ...@@ -38,6 +38,4 @@ setuptools.setup(
"Operating System :: OS Independent", "Operating System :: OS Independent",
], ],
license='Apache 2.0', license='Apache 2.0',
entry_points={'console_scripts': [ entry_points={'console_scripts': ['paddlex=paddlex.command:main', ]})
'paddlex=paddlex.command:main',
]})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册