提交 8f88d64f 编写于 作者: J jack

merge

...@@ -141,10 +141,12 @@ class ResizeByLong : public Transform { ...@@ -141,10 +141,12 @@ class ResizeByLong : public Transform {
class Resize : public Transform { class Resize : public Transform {
public: public:
virtual void Init(const YAML::Node& item) { virtual void Init(const YAML::Node& item) {
if (item["interp"].IsDefined()) {
interp_ = item["interp"].as<std::string>();
}
if (item["target_size"].IsScalar()) { if (item["target_size"].IsScalar()) {
height_ = item["target_size"].as<int>(); height_ = item["target_size"].as<int>();
width_ = item["target_size"].as<int>(); width_ = item["target_size"].as<int>();
interp_ = item["interp"].as<std::string>();
} else if (item["target_size"].IsSequence()) { } else if (item["target_size"].IsSequence()) {
std::vector<int> target_size = item["target_size"].as<std::vector<int>>(); std::vector<int> target_size = item["target_size"].as<std::vector<int>>();
width_ = target_size[0]; width_ = target_size[0];
......
...@@ -167,3 +167,20 @@ NormLIME是利用一定数量的样本来出一个全局的解释。由于NormLI ...@@ -167,3 +167,20 @@ NormLIME是利用一定数量的样本来出一个全局的解释。由于NormLI
### 使用示例 ### 使用示例
> 对预测可解释性结果可视化的过程可参见[代码](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/interpret/normlime.py)。 > 对预测可解释性结果可视化的过程可参见[代码](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/interpret/normlime.py)。
## 数据预处理/增强过程可视化
```
paddlex.transforms.visualize(dataset,
img_count=3,
save_dir='vdl_output')
```
对数据预处理/增强中间结果进行可视化。
可使用VisualDL查看中间结果:
1. VisualDL启动方式: visualdl --logdir vdl_output --port 8001
2. 浏览器打开 https://0.0.0.0:8001即可,
其中0.0.0.0为本机访问,如为远程服务, 改成相应机器IP
### 参数
>* **dataset** (paddlex.datasets): 数据集读取器。
>* **img_count** (int): 需要进行数据预处理/增强的图像数目。默认为3。
>* **save_dir** (str): 日志保存的路径。默认为'vdl_output'。
\ No newline at end of file
...@@ -10,11 +10,10 @@ Windows 平台下,我们使用`Visual Studio 2019 Community` 进行了测试 ...@@ -10,11 +10,10 @@ Windows 平台下,我们使用`Visual Studio 2019 Community` 进行了测试
请确保系统已经安装好上述基本软件,我们使用的是`VS2019`的社区版。 请确保系统已经安装好上述基本软件,我们使用的是`VS2019`的社区版。
**下面所有示例以工作目录为 `D:\projects`演示** **下面所有示例以工作目录为 `D:\projects`演示。**
### Step1: 下载代码 ### Step1: 下载PaddleX预测代码
下载源代码
```shell ```shell
d: d:
mkdir projects mkdir projects
...@@ -22,12 +21,12 @@ cd projects ...@@ -22,12 +21,12 @@ cd projects
git clone https://github.com/PaddlePaddle/PaddleX.git git clone https://github.com/PaddlePaddle/PaddleX.git
``` ```
**说明**:其中`C++`预测代码在`PaddleX/deploy/cpp` 目录,该目录不依赖任何`PaddleX`下其他目录。 **说明**:其中`C++`预测代码在`PaddleX\deploy\cpp` 目录,该目录不依赖任何`PaddleX`下其他目录。
### Step2: 下载PaddlePaddle C++ 预测库 fluid_inference ### Step2: 下载PaddlePaddle C++ 预测库 fluid_inference
PaddlePaddle C++ 预测库针对不同的`CPU``CUDA`,以及是否支持TensorRT,提供了不同的预编译版本,目前PaddleX依赖于Paddle1.8版本,以下提供了多个不同版本的Paddle预测库: PaddlePaddle C++ 预测库针对是否使用GPU、是否支持TensorRT、以及不同的CUDA版本提供了已经编译好的预测库,目前PaddleX依赖于Paddle 1.8,基于Paddle 1.8的Paddle预测库下载链接如下所示:
| 版本说明 | 预测库(1.8.2版本) | 编译器 | 构建工具| cuDNN | CUDA | | 版本说明 | 预测库(1.8.2版本) | 编译器 | 构建工具| cuDNN | CUDA |
| ---- | ---- | ---- | ---- | ---- | ---- | | ---- | ---- | ---- | ---- | ---- | ---- |
...@@ -37,10 +36,9 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens ...@@ -37,10 +36,9 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens
| cuda9.0_cudnn7_avx_openblas | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.8.2/win-infer/open/post97/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 | 7.4.1 | 9.0 | | cuda9.0_cudnn7_avx_openblas | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.8.2/win-infer/open/post97/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 | 7.4.1 | 9.0 |
| cuda10.0_cudnn7_avx_mkl | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.8.2/win-infer/mkl/post107/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 | 7.5.0 | 9.0 | | cuda10.0_cudnn7_avx_mkl | [fluid_inference.zip](https://paddle-wheel.bj.bcebos.com/1.8.2/win-infer/mkl/post107/fluid_inference_install_dir.zip) | MSVC 2015 update 3 | CMake v3.16.0 | 7.5.0 | 9.0 |
请根据实际情况选择下载,如若以上版本不满足您的需求,请至[C++预测库下载列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_guide/inference_deployment/inference/windows_cpp_inference.html)选择符合的版本。
更多和更新的版本,请根据实际情况下载: [C++预测库下载列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_guide/inference_deployment/inference/windows_cpp_inference.html) 将预测库解压后,其所在目录(例如`D:\projects\fluid_inference\`)下主要包含的内容有:
解压后`D:\projects\fluid_inference\`目录下主要包含的内容为:
``` ```
├── \paddle\ # paddle核心库和头文件 ├── \paddle\ # paddle核心库和头文件
| |
...@@ -52,7 +50,7 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens ...@@ -52,7 +50,7 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens
### Step3: 安装配置OpenCV ### Step3: 安装配置OpenCV
1. 在OpenCV官网下载适用于Windows平台的3.4.6版本, [下载地址](https://sourceforge.net/projects/opencvlibrary/files/3.4.6/opencv-3.4.6-vc14_vc15.exe/download) 1. 在OpenCV官网下载适用于Windows平台的3.4.6版本, [下载地址](https://sourceforge.net/projects/opencvlibrary/files/3.4.6/opencv-3.4.6-vc14_vc15.exe/download)
2. 运行下载的可执行文件,将OpenCV解压至指定目录,如`D:\projects\opencv` 2. 运行下载的可执行文件,将OpenCV解压至指定目录,如`D:\projects\opencv`
3. 配置环境变量,如下流程所示 3. 配置环境变量,如下流程所示
- 我的电脑->属性->高级系统设置->环境变量 - 我的电脑->属性->高级系统设置->环境变量
- 在系统变量中找到Path(如没有,自行创建),并双击编辑 - 在系统变量中找到Path(如没有,自行创建),并双击编辑
...@@ -67,7 +65,7 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens ...@@ -67,7 +65,7 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens
![step2.1](../../images/vs2019_step2.png) ![step2.1](../../images/vs2019_step2.png)
选择项目代码所在路径,并打开`CMakeList.txt`: 选择C++预测代码所在路径(例如`D:\projects\PaddleX\deploy\cpp`),并打开`CMakeList.txt`:
![step2.2](../../images/vs2019_step3.png) ![step2.2](../../images/vs2019_step3.png)
3. 点击:`项目`->`CMake设置` 3. 点击:`项目`->`CMake设置`
...@@ -77,7 +75,7 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens ...@@ -77,7 +75,7 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens
![step3](../../images/vs2019_step5.png) ![step3](../../images/vs2019_step5.png)
依赖库路径的含义说明如下(带*表示仅在使用**GPU版本**预测库时指定, 其中CUDA库版本尽量对齐,**使用9.0、10.0版本,不使用9.2、10.1等版本CUDA库**): 依赖库路径的含义说明如下(带*表示仅在使用**GPU版本**预测库时指定, 其中CUDA库版本尽量与Paddle预测库的对齐,例如Paddle预测库是**使用9.0、10.0版本**编译的,则编译PaddleX预测代码时**不使用9.2、10.1等版本**CUDA库):
| 参数名 | 含义 | | 参数名 | 含义 |
| ---- | ---- | | ---- | ---- |
...@@ -86,11 +84,11 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens ...@@ -86,11 +84,11 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens
| PADDLE_DIR | Paddle c++预测库的路径 | | PADDLE_DIR | Paddle c++预测库的路径 |
**注意:** **注意:**
1. 使用`CPU`版预测库,请把`WITH_GPU`的``去掉勾 1. 如果使用`CPU`版预测库,请把`WITH_GPU`的``去掉勾
2. 如果使用的是`openblas`版本,请把`WITH_MKL`的``去掉勾 2. 如果使用的是`openblas`版本,请把`WITH_MKL`的``去掉勾
3. Windows环境下编译会自动下载YAML,如果编译环境无法访问外网,可手动下载: [yaml-cpp.zip](https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip) 3. Windows环境下编译会自动下载YAML,如果编译环境无法访问外网,可手动下载: [yaml-cpp.zip](https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip)
yaml-cpp.zip文件下载后无需解压,在cmake/yaml.cmake中将`URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip` 中的网址,改为下载文件的路径。 yaml-cpp.zip文件下载后无需解压,在cmake/yaml.cmake中将`URL https://bj.bcebos.com/paddlex/deploy/deps/yaml-cpp.zip` 中的网址,改为下载文件的路径。
4. 如果需要使用模型加密功能,需要手动下载[Windows预测模型加密工具](https://bj.bcebos.com/paddlex/tools/win/paddlex-encryption.zip),解压到D:/projects。解压后目录为D:/projects/paddlex-encryption。编译时需勾选WITH_EBNCRYPTION并且在ENCRTYPTION_DIR填入D:/projects/paddlex-encryption。 4. 如果需要使用模型加密功能,需要手动下载[Windows预测模型加密工具](https://bj.bcebos.com/paddlex/tools/win/paddlex-encryption.zip)。例如解压到D:/projects,解压后目录为D:/projects/paddlex-encryption。编译时需勾选WITH_EBNCRYPTION并且在ENCRTYPTION_DIR填入D:/projects/paddlex-encryption。
![step_encryption](../../images/vs2019_step_encryption.png) ![step_encryption](../../images/vs2019_step_encryption.png)
...@@ -128,29 +126,39 @@ cd D:\projects\PaddleX\deploy\cpp\out\build\x64-Release ...@@ -128,29 +126,39 @@ cd D:\projects\PaddleX\deploy\cpp\out\build\x64-Release
## 样例 ## 样例
可使用[小度熊识别模型](../deploy_python.md)中导出的`inference_model`和测试图片进行预测, 导出到D:/projects,模型路径为D:/projects/inference_model。 可使用[小度熊识别模型](../deploy_python.md)中导出的`inference_model`和测试图片进行预测, 例如导出到D:\projects,模型路径为D:\projects\inference_model。
`样例一`: ### 样例一:(使用未加密的模型对单张图像做预测)
不使用`GPU`测试图片 `D:\\images\\xiaoduxiong.jpeg` 不使用`GPU`测试图片 `D:\images\xiaoduxiong.jpeg`
```shell ```
.\\paddlex_inference\\detector.exe --model_dir=D:\\projects\\inference_model --image=D:\\images\\xiaoduxiong.jpeg --save_dir=output .\paddlex_inference\detector.exe --model_dir=D:\projects\inference_model --image=D:\images\xiaoduxiong.jpeg --save_dir=output
``` ```
图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
`样例二`: ### 样例二:(使用未加密的模型对图像列表做预测)
使用`GPU`预测多个图片`D:\\images\\image_list.txt`,image_list.txt内容的格式如下: 使用`GPU`预测多个图片`D:\images\image_list.txt`,image_list.txt内容的格式如下:
``` ```
D:\\images\\xiaoduxiong1.jpeg D:\images\xiaoduxiong1.jpeg
D:\\images\\xiaoduxiong2.jpeg D:\images\xiaoduxiong2.jpeg
... ...
D:\\images\\xiaoduxiongn.jpeg D:\images\xiaoduxiongn.jpeg
``` ```
```shell ```
.\\paddlex_inference\\detector.exe --model_dir=D:\\projects\\inference_model --image_list=D:\\images\\image_list.txt --use_gpu=1 --save_dir=output --batch_size=2 --thread_num=2 .\paddlex_inference\detector.exe --model_dir=D:\projects\inference_model --image_list=D:\images\image_list.txt --use_gpu=1 --save_dir=output --batch_size=2 --thread_num=2
``` ```
图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
### 样例三:(使用加密后的模型对单张图片进行预测)
如果未对模型进行加密,请参考[加密PaddleX模型](../encryption.html#paddlex)对模型进行加密。例如加密后的模型所在目录为`D:\projects\encrypted_inference_model`。
```
.\paddlex_inference\detector.exe --model_dir=D:\projects\encrypted_inference_model --image=D:\images\xiaoduxiong.jpeg --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=
```
`--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件可视化预测结果会保存在`save_dir`参数设置的目录下。
...@@ -42,7 +42,7 @@ PaddleX提供一个轻量级的模型加密部署方案,通过PaddleX内置的 ...@@ -42,7 +42,7 @@ PaddleX提供一个轻量级的模型加密部署方案,通过PaddleX内置的
[Linux版本 PaddleX模型加密工具](https://bj.bcebos.com/paddlex/tools/paddlex-encryption.zip),编译脚本会自动下载该版本加密工具,您也可以选择手动下载。 [Linux版本 PaddleX模型加密工具](https://bj.bcebos.com/paddlex/tools/paddlex-encryption.zip),编译脚本会自动下载该版本加密工具,您也可以选择手动下载。
[Windows版本 PaddleX模型加密工具](https://bj.bcebos.com/paddlex/tools/win/paddlex-encryption.zip),该版本加密工具需手动下载。 [Windows版本 PaddleX模型加密工具](https://bj.bcebos.com/paddlex/tools/win/paddlex-encryption.zip),该版本加密工具需手动下载,如果您在使用Visual Studio 2019编译C++预测代码的过程中已经下载过该工具,此处可不必重复下载
Linux加密工具包含内容为: Linux加密工具包含内容为:
``` ```
...@@ -68,16 +68,16 @@ paddlex-encryption ...@@ -68,16 +68,16 @@ paddlex-encryption
对模型完成加密后,加密工具会产生随机密钥信息(用于AES加解密使用),需要在后续加密部署时传入该密钥来用于解密。 对模型完成加密后,加密工具会产生随机密钥信息(用于AES加解密使用),需要在后续加密部署时传入该密钥来用于解密。
> 密钥由32字节key + 16字节iv组成, 注意这里产生的key是经过base64编码后的,这样可以扩充key的选取范围 > 密钥由32字节key + 16字节iv组成, 注意这里产生的key是经过base64编码后的,这样可以扩充key的选取范围
Linux: Linux平台:
``` ```
# 假设模型在/root/projects下 # 假设模型在/root/projects下
./paddlex-encryption/tool/paddlex_encrypt_tool -model_dir /root/projects/paddlex_inference_model -save_dir /root/projects/paddlex_encrypted_model ./paddlex-encryption/tool/paddlex_encrypt_tool -model_dir /root/projects/paddlex_inference_model -save_dir /root/projects/paddlex_encrypted_model
``` ```
Windows: Windows平台:
``` ```
# 假设模型在D:/projects下 # 假设模型在D:/projects下
.\paddlex-encryption\tool\paddlex_encrypt_tool.exe -model_dir D:\\projects\\paddlex_inference_model -save_dir D:\\projects\\paddlex_encrypted_model .\paddlex-encryption\tool\paddlex_encrypt_tool.exe -model_dir D:\projects\paddlex_inference_model -save_dir D:\projects\paddlex_encrypted_model
``` ```
`-model_dir`用于指定inference模型路径(参考[导出inference模型](deploy_python.html#inference)将模型导出为inference格式模型),可使用[导出小度熊识别模型](deploy_python.html#inference)中导出的`inference_model`。加密完成后,加密过的模型会保存至指定的`-save_dir`下,包含`__model__.encrypted``__params__.encrypted``model.yml`三个文件,同时生成密钥信息,命令输出如下图所示,密钥为`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=` `-model_dir`用于指定inference模型路径(参考[导出inference模型](deploy_python.html#inference)将模型导出为inference格式模型),可使用[导出小度熊识别模型](deploy_python.html#inference)中导出的`inference_model`。加密完成后,加密过的模型会保存至指定的`-save_dir`下,包含`__model__.encrypted``__params__.encrypted``model.yml`三个文件,同时生成密钥信息,命令输出如下图所示,密钥为`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`
...@@ -103,21 +103,21 @@ Windows: ...@@ -103,21 +103,21 @@ Windows:
| thread_num | 预测的线程数,默认为cpu处理器个数 | | thread_num | 预测的线程数,默认为cpu处理器个数 |
## 样例 ### 样例
可使用[导出小度熊识别模型](deploy_python.md#inference)中的测试图片进行预测。 可使用[导出小度熊识别模型](deploy_python.md#inference)中的测试图片进行预测。
`样例一` #### 样例一
不使用`GPU`测试图片 `/root/projects/images/xiaoduxiong.jpeg` 不使用`GPU`测试图片 `/root/projects/images/xiaoduxiong.jpeg`
```shell ```shell
./build/demo/detector --model_dir=/root/projects/inference_model --image=/root/projects/xiaoduxiong.jpeg --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c= ./build/demo/detector --model_dir=/root/projects/paddlex_encrypted_model --image=/root/projects/xiaoduxiong.jpeg --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=
``` ```
`--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。 `--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
`样例二`: #### 样例二:
使用`GPU`预测多个图片`/root/projects/image_list.txt`,image_list.txt内容的格式如下: 使用`GPU`预测多个图片`/root/projects/image_list.txt`,image_list.txt内容的格式如下:
``` ```
...@@ -127,37 +127,40 @@ Windows: ...@@ -127,37 +127,40 @@ Windows:
/root/projects/xiaoduxiongn.jpeg /root/projects/xiaoduxiongn.jpeg
``` ```
```shell ```shell
./build/demo/detector --model_dir=/root/projects/models/inference_model --image_list=/root/projects/images_list.txt --use_gpu=1 --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c= ./build/demo/detector --model_dir=/root/projects/models/paddlex_encrypted_model --image_list=/root/projects/images_list.txt --use_gpu=1 --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=
``` ```
`--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。 `--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
### 2.2 Windows平台使用 ### 2.2 Windows平台使用
参考[Windows平台编译指南](deploy_cpp/deploy_cpp_win_vs2019.md)。需自行下载Windows版PaddleX加密工具压缩包,解压,在编译指南的编译流程基础上,在CMake设置中勾选WITH_ENCRYPTION,ENCRYPTION_DIR填写为加密工具包解压后的目录,再进行编译。参数与Linux版本预测部署一致。预测demo的入口程序为paddlex_inference\detector.exe,paddlex_inference\classifier.exe,paddlex_inference\segmenter.exe。 参考[Windows平台编译指南](deploy_cpp/deploy_cpp_win_vs2019.md)。需自行下载Windows版PaddleX加密工具压缩包,解压,在编译指南的编译流程基础上,在CMake设置中勾选WITH_ENCRYPTION,ENCRYPTION_DIR填写为加密工具包解压后的目录,再进行编译。参数与Linux版本预测部署一致。预测demo的入口程序为paddlex_inference\detector.exe,paddlex_inference\classifier.exe,paddlex_inference\segmenter.exe。
## 样例 ### 样例
可使用[导出小度熊识别模型](deploy_python.md#inference)中的测试图片进行预测。 可使用[导出小度熊识别模型](deploy_python.md#inference)中的测试图片进行预测。
`样例一` #### 样例一
不使用`GPU`测试图片 `D:\\images\\xiaoduxiong.jpeg` 不使用`GPU`测试单张图片,例如图片为`D:\images\xiaoduxiong.jpeg`,加密后的模型目录为`D:\projects\paddlex_encrypted_model`
```shell ```shell
.\\paddlex_inference\\detector.exe --model_dir=D:\\projects\\inference_model --image=D:\\images\\xiaoduxiong.jpeg --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c= .\paddlex_inference\detector.exe --model_dir=D:\projects\paddlex_encrypted_model --image=D:\images\xiaoduxiong.jpeg --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=
``` ```
`--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。 `--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
`样例二`: #### 样例二:
使用`GPU`预测多个图片`D:\\projects\\image_list.txt`,image_list.txt内容的格式如下: 使用`GPU`预测图片列表,例如图片列表为`D:\projects\image_list.txt``image_list.txt`的内容如下:
``` ```
D:\\projects\\images\\xiaoduxiong1.jpeg D:\projects\images\xiaoduxiong1.jpeg
D:\\projects\\images\\xiaoduxiong2.jpeg D:\projects\images\xiaoduxiong2.jpeg
... ...
D:\\projects\\images\\xiaoduxiongn.jpeg D:\projects\images\xiaoduxiongn.jpeg
``` ```
```shell
.\\paddlex_inference\\detector.exe --model_dir=D:\\projects\\inference_encrypted_model --image_list=D:\\projects\\images_list.txt --use_gpu=1 --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c= 加密后的模型目录例如为`D:\projects\paddlex_encrypted_model`
```
.\paddlex_inference\detector.exe --model_dir=D:\projects\paddlex_encrypted_model --image_list=D:\projects\images_list.txt --use_gpu=1 --save_dir=output --key=kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=
``` ```
`--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。 `--key`传入加密工具输出的密钥,例如`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`, 图片文件`可视化预测结果`会保存在`save_dir`参数设置的目录下。
...@@ -48,6 +48,7 @@ if hub.version.hub_version < '1.6.2': ...@@ -48,6 +48,7 @@ if hub.version.hub_version < '1.6.2':
env_info = get_environ_info() env_info = get_environ_info()
load_model = cv.models.load_model load_model = cv.models.load_model
datasets = cv.datasets datasets = cv.datasets
transforms = cv.transforms
log_level = 2 log_level = 2
......
...@@ -15,3 +15,5 @@ ...@@ -15,3 +15,5 @@
from . import cls_transforms from . import cls_transforms
from . import det_transforms from . import det_transforms
from . import seg_transforms from . import seg_transforms
from . import visualize
visualize = visualize.visualize
...@@ -32,10 +32,8 @@ class ClsTransform: ...@@ -32,10 +32,8 @@ class ClsTransform:
class Compose(ClsTransform): class Compose(ClsTransform):
"""根据数据预处理/增强算子对输入数据进行操作。 """根据数据预处理/增强算子对输入数据进行操作。
所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。 所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。
Args: Args:
transforms (list): 数据预处理/增强算子。 transforms (list): 数据预处理/增强算子。
Raises: Raises:
TypeError: 形参数据类型不满足需求。 TypeError: 形参数据类型不满足需求。
ValueError: 数据长度不匹配。 ValueError: 数据长度不匹配。
...@@ -434,6 +432,7 @@ class RandomDistort(ClsTransform): ...@@ -434,6 +432,7 @@ class RandomDistort(ClsTransform):
params['im'] = im params['im'] = im
if np.random.uniform(0, 1) < prob: if np.random.uniform(0, 1) < prob:
im = ops[id](**params) im = ops[id](**params)
im = im.astype('float32')
if label is None: if label is None:
return (im, ) return (im, )
else: else:
......
...@@ -41,10 +41,8 @@ class DetTransform: ...@@ -41,10 +41,8 @@ class DetTransform:
class Compose(DetTransform): class Compose(DetTransform):
"""根据数据预处理/增强列表对输入数据进行操作。 """根据数据预处理/增强列表对输入数据进行操作。
所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。 所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。
Args: Args:
transforms (list): 数据预处理/增强列表。 transforms (list): 数据预处理/增强列表。
Raises: Raises:
TypeError: 形参数据类型不满足需求。 TypeError: 形参数据类型不满足需求。
ValueError: 数据长度不匹配。 ValueError: 数据长度不匹配。
...@@ -619,6 +617,7 @@ class RandomDistort(DetTransform): ...@@ -619,6 +617,7 @@ class RandomDistort(DetTransform):
if np.random.uniform(0, 1) < prob: if np.random.uniform(0, 1) < prob:
im = ops[id](**params) im = ops[id](**params)
im = im.astype('float32')
if label_info is None: if label_info is None:
return (im, im_info) return (im, im_info)
else: else:
...@@ -823,7 +822,7 @@ class RandomExpand(DetTransform): ...@@ -823,7 +822,7 @@ class RandomExpand(DetTransform):
'gt_class' not in label_info: 'gt_class' not in label_info:
raise TypeError('Cannot do RandomExpand! ' + \ raise TypeError('Cannot do RandomExpand! ' + \
'Becasuse gt_bbox/gt_class is not in label_info!') 'Becasuse gt_bbox/gt_class is not in label_info!')
if np.random.uniform(0., 1.) < self.prob: if np.random.uniform(0., 1.) > self.prob:
return (im, im_info, label_info) return (im, im_info, label_info)
if 'gt_class' in label_info and 0 in label_info['gt_class']: if 'gt_class' in label_info and 0 in label_info['gt_class']:
......
...@@ -35,14 +35,11 @@ class SegTransform: ...@@ -35,14 +35,11 @@ class SegTransform:
class Compose(SegTransform): class Compose(SegTransform):
"""根据数据预处理/增强算子对输入数据进行操作。 """根据数据预处理/增强算子对输入数据进行操作。
所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。 所有操作的输入图像流形状均是[H, W, C],其中H为图像高,W为图像宽,C为图像通道数。
Args: Args:
transforms (list): 数据预处理/增强算子。 transforms (list): 数据预处理/增强算子。
Raises: Raises:
TypeError: transforms不是list对象 TypeError: transforms不是list对象
ValueError: transforms元素个数小于1。 ValueError: transforms元素个数小于1。
""" """
def __init__(self, transforms): def __init__(self, transforms):
...@@ -71,7 +68,6 @@ class Compose(SegTransform): ...@@ -71,7 +68,6 @@ class Compose(SegTransform):
图像在过resize前shape为(200, 300), 过padding前shape为 图像在过resize前shape为(200, 300), 过padding前shape为
(400, 600) (400, 600)
label (str/np.ndarray): 标注图像路径/标注图像np.ndarray数据。 label (str/np.ndarray): 标注图像路径/标注图像np.ndarray数据。
Returns: Returns:
tuple: 根据网络所需字段所组成的tuple;字段由transforms中的最后一个数据预处理操作决定。 tuple: 根据网络所需字段所组成的tuple;字段由transforms中的最后一个数据预处理操作决定。
""" """
...@@ -1054,6 +1050,7 @@ class RandomDistort(SegTransform): ...@@ -1054,6 +1050,7 @@ class RandomDistort(SegTransform):
params['im'] = im params['im'] = im
if np.random.uniform(0, 1) < prob: if np.random.uniform(0, 1) < prob:
im = ops[id](**params) im = ops[id](**params)
im = im.astype('float32')
if label is None: if label is None:
return (im, im_info) return (im, im_info)
else: else:
......
# copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import os.path as osp
import cv2
from PIL import Image
import numpy as np
import math
from .imgaug_support import execute_imgaug
from .cls_transforms import ClsTransform
from .det_transforms import DetTransform
from .seg_transforms import SegTransform
import paddlex as pdx
from paddlex.cv.models.utils.visualize import get_color_map_list
def _draw_rectangle_and_cname(img, xmin, ymin, xmax, ymax, cname, color):
""" 根据提供的标注信息,给图片描绘框体和类别显示
Args:
img: 图片路径
xmin: 检测框最小的x坐标
ymin: 检测框最小的y坐标
xmax: 检测框最大的x坐标
ymax: 检测框最大的y坐标
cname: 类别信息
color: 类别与颜色的对应信息
"""
# 描绘检测框
line_width = math.ceil(2 * max(img.shape[0:2]) / 600)
cv2.rectangle(
img,
pt1=(xmin, ymin),
pt2=(xmax, ymax),
color=color,
thickness=line_width)
return img
def cls_compose(im, label=None, transforms=None, vdl_writer=None, step=0):
"""
Args:
im (str/np.ndarray): 图像路径/图像np.ndarray数据。
label (int): 每张图像所对应的类别序号。
vdl_writer (visualdl.LogWriter): VisualDL存储器,日志信息将保存在其中。
当为None时,不对日志进行保存。默认为None。
step (int): 数据预处理的轮数,当vdl_writer不为None时有效。默认为0。
Returns:
tuple: 根据网络所需字段所组成的tuple;
字段由transforms中的最后一个数据预处理操作决定。
"""
if isinstance(im, np.ndarray):
if len(im.shape) != 3:
raise Exception(
"im should be 3-dimension, but now is {}-dimensions".
format(len(im.shape)))
else:
try:
im = cv2.imread(im).astype('float32')
except:
raise TypeError('Can\'t read The image file {}!'.format(im))
im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
if vdl_writer is not None:
vdl_writer.add_image(tag='0. OriginalImange/' + str(step),
img=im,
step=0)
op_id = 1
for op in transforms:
if isinstance(op, ClsTransform):
if vdl_writer is not None and hasattr(op, 'prob'):
op.prob = 1.0
outputs = op(im, label)
im = outputs[0]
if len(outputs) == 2:
label = outputs[1]
if isinstance(op, pdx.cv.transforms.cls_transforms.Normalize):
continue
else:
import imgaug.augmenters as iaa
if isinstance(op, iaa.Augmenter):
im = execute_imgaug(op, im)
outputs = (im, )
if label is not None:
outputs = (im, label)
if vdl_writer is not None:
tag = str(op_id) + '. ' + op.__class__.__name__ + '/' + str(step)
vdl_writer.add_image(tag=tag,
img=im,
step=0)
op_id += 1
def det_compose(im, im_info=None, label_info=None, transforms=None, vdl_writer=None, step=0,
labels=[], catid2color=None):
def decode_image(im_file, im_info, label_info):
if im_info is None:
im_info = dict()
if isinstance(im_file, np.ndarray):
if len(im_file.shape) != 3:
raise Exception(
"im should be 3-dimensions, but now is {}-dimensions".
format(len(im_file.shape)))
im = im_file
else:
try:
im = cv2.imread(im_file).astype('float32')
except:
raise TypeError('Can\'t read The image file {}!'.format(
im_file))
im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
# make default im_info with [h, w, 1]
im_info['im_resize_info'] = np.array(
[im.shape[0], im.shape[1], 1.], dtype=np.float32)
im_info['image_shape'] = np.array([im.shape[0],
im.shape[1]]).astype('int32')
use_mixup = False
for t in transforms:
if type(t).__name__ == 'MixupImage':
use_mixup = True
if not use_mixup:
if 'mixup' in im_info:
del im_info['mixup']
# decode mixup image
if 'mixup' in im_info:
im_info['mixup'] = \
decode_image(im_info['mixup'][0],
im_info['mixup'][1],
im_info['mixup'][2])
if label_info is None:
return (im, im_info)
else:
return (im, im_info, label_info)
outputs = decode_image(im, im_info, label_info)
im = outputs[0]
im_info = outputs[1]
if len(outputs) == 3:
label_info = outputs[2]
if vdl_writer is not None:
vdl_writer.add_image(tag='0. OriginalImange/' + str(step),
img=im,
step=0)
op_id = 1
bboxes = label_info['gt_bbox']
transforms = [None] + transforms
for op in transforms:
if im is None:
return None
if isinstance(op, DetTransform) or op is None:
if vdl_writer is not None and hasattr(op, 'prob'):
op.prob = 1.0
if op is not None:
outputs = op(im, im_info, label_info)
else:
outputs = (im, im_info, label_info)
im = outputs[0]
vdl_im = im
if vdl_writer is not None:
if isinstance(op, pdx.cv.transforms.det_transforms.ResizeByShort):
scale = outputs[1]['im_resize_info'][2]
bboxes = bboxes * scale
elif isinstance(op, pdx.cv.transforms.det_transforms.Resize):
h = outputs[1]['image_shape'][0]
w = outputs[1]['image_shape'][1]
target_size = op.target_size
if isinstance(target_size, int):
h_scale = float(target_size) / h
w_scale = float(target_size) / w
else:
h_scale = float(target_size[0]) / h
w_scale = float(target_size[1]) / w
bboxes[:,0] = bboxes[:,0] * w_scale
bboxes[:,1] = bboxes[:,1] * h_scale
bboxes[:,2] = bboxes[:,2] * w_scale
bboxes[:,3] = bboxes[:,3] * h_scale
else:
bboxes = outputs[2]['gt_bbox']
if not isinstance(op, pdx.cv.transforms.det_transforms.RandomHorizontalFlip):
for i in range(bboxes.shape[0]):
bbox = bboxes[i]
cname = labels[outputs[2]['gt_class'][i][0]-1]
vdl_im = _draw_rectangle_and_cname(vdl_im,
int(bbox[0]),
int(bbox[1]),
int(bbox[2]),
int(bbox[3]),
cname,
catid2color[outputs[2]['gt_class'][i][0]-1])
if isinstance(op, pdx.cv.transforms.det_transforms.Normalize):
continue
else:
im = execute_imgaug(op, im)
if label_info is not None:
outputs = (im, im_info, label_info)
else:
outputs = (im, im_info)
vdl_im = im
if vdl_writer is not None:
tag = str(op_id) + '. ' + op.__class__.__name__ + '/' + str(step)
if op is None:
tag = str(op_id) + '. OriginalImangeWithGTBox/' + str(step)
vdl_writer.add_image(tag=tag,
img=vdl_im,
step=0)
op_id += 1
def seg_compose(im, im_info=None, label=None, transforms=None, vdl_writer=None, step=0):
if im_info is None:
im_info = list()
if isinstance(im, np.ndarray):
if len(im.shape) != 3:
raise Exception(
"im should be 3-dimensions, but now is {}-dimensions".
format(len(im.shape)))
else:
try:
im = cv2.imread(im).astype('float32')
except:
raise ValueError('Can\'t read The image file {}!'.format(im))
im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
if label is not None:
if not isinstance(label, np.ndarray):
label = np.asarray(Image.open(label))
if vdl_writer is not None:
vdl_writer.add_image(tag='0. OriginalImange' + '/' + str(step),
img=im,
step=0)
op_id = 1
for op in transforms:
if isinstance(op, SegTransform):
outputs = op(im, im_info, label)
im = outputs[0]
if len(outputs) >= 2:
im_info = outputs[1]
if len(outputs) == 3:
label = outputs[2]
if isinstance(op, pdx.cv.transforms.seg_transforms.Normalize):
continue
else:
im = execute_imgaug(op, im)
if label is not None:
outputs = (im, im_info, label)
else:
outputs = (im, im_info)
if vdl_writer is not None:
tag = str(op_id) + '. ' + op.__class__.__name__ + '/' + str(step)
vdl_writer.add_image(tag=tag,
img=im,
step=0)
op_id += 1
def visualize(dataset, img_count=3, save_dir='vdl_output'):
'''对数据预处理/增强中间结果进行可视化。
可使用VisualDL查看中间结果:
1. VisualDL启动方式: visualdl --logdir vdl_output --port 8001
2. 浏览器打开 https://0.0.0.0:8001即可,
其中0.0.0.0为本机访问,如为远程服务, 改成相应机器IP
Args:
dataset (paddlex.datasets): 数据集读取器。
img_count (int): 需要进行数据预处理/增强的图像数目。默认为3。
save_dir (str): 日志保存的路径。默认为'vdl_output'。
'''
if dataset.num_samples < img_count:
img_count = dataset.num_samples
transforms = dataset.transforms
if not osp.isdir(save_dir):
if osp.exists(save_dir):
os.remove(save_dir)
os.makedirs(save_dir)
from visualdl import LogWriter
vdl_save_dir = osp.join(save_dir, 'image_transforms')
vdl_writer = LogWriter(vdl_save_dir)
for i, data in enumerate(dataset.iterator()):
if i == img_count:
break
data.append(transforms.transforms)
data.append(vdl_writer)
data.append(i)
if isinstance(transforms, ClsTransform):
cls_compose(*data)
elif isinstance(transforms, DetTransform):
labels = dataset.labels
color_map = get_color_map_list(len(labels) + 1)
catid2color = {}
for catid in range(len(labels)):
catid2color[catid] = color_map[catid + 1]
data.append(labels)
data.append(catid2color)
det_compose(*data)
elif isinstance(transforms, SegTransform):
seg_compose(*data)
else:
raise Exception('The transform must the subclass of \
ClsTransform or DetTransform or SegTransform!')
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册