提交 573b2217 编写于 作者: F FlyingQianMM

Merge branch 'develop' of https://github.com/PaddlePaddle/PaddleX into develop_qh

...@@ -83,7 +83,7 @@ Paddle-GUI的使用教程可参考[PaddleX-GUI模式使用教程](https://paddle ...@@ -83,7 +83,7 @@ Paddle-GUI的使用教程可参考[PaddleX-GUI模式使用教程](https://paddle
* 2020.05.20 * 2020.05.20
**`v1.0.0`** **`v1.0.0`**
* 初始版本发布。 * 正式版本发布。
## 贡献代码 ## 贡献代码
......
...@@ -114,27 +114,54 @@ pdx.slim.visualize(model, 'mobilenetv2.sensitivities', save_dir='./') ...@@ -114,27 +114,54 @@ pdx.slim.visualize(model, 'mobilenetv2.sensitivities', save_dir='./')
# 可视化结果保存在./sensitivities.png # 可视化结果保存在./sensitivities.png
``` ```
## 可解释性结果可视化 ## LIME可解释性结果可视化
``` ```
paddlex.interpret.visualize(img_file, paddlex.interpret.lime(img_file,
model,
num_samples=3000,
batch_size=50,
save_dir='./')
```
使用LIME算法将模型预测结果的可解释性可视化。
LIME表示与模型无关的局部可解释性,可以解释任何模型。LIME的思想是以输入样本为中心,在其附近的空间中进行随机采样,每个采样通过原模型得到新的输出,这样得到一系列的输入和对应的输出,LIME用一个简单的、可解释的模型(比如线性回归模型)来拟合这个映射关系,得到每个输入维度的权重,以此来解释模型。
**注意:** 可解释性结果可视化目前只支持分类模型。
### 参数
>* **img_file** (str): 预测图像路径。
>* **model** (paddlex.cv.models): paddlex中的模型。
>* **num_samples** (int): LIME用于学习线性模型的采样数,默认为3000。
>* **batch_size** (int): 预测数据batch大小,默认为50。
>* **save_dir** (str): 可解释性可视化结果(保存为png格式文件)和中间文件存储路径。
### 使用示例
> 对预测可解释性结果可视化的过程可参见[代码](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/interpret/lime.py)。
## NormLIME可解释性结果可视化
```
paddlex.interpret.normlime(img_file,
model, model,
dataset=None, dataset=None,
algo='lime',
num_samples=3000, num_samples=3000,
batch_size=50, batch_size=50,
save_dir='./') save_dir='./')
``` ```
将模型预测结果的可解释性可视化,目前只支持分类模型。 使用NormLIME算法将模型预测结果的可解释性可视化。
NormLIME是利用一定数量的样本来出一个全局的解释。NormLIME会提前计算一定数量的测试样本的LIME结果,然后对相同的特征进行权重的归一化,这样来得到一个全局的输入和输出的关系。
**注意:** 可解释性结果可视化目前只支持分类模型。
### 参数 ### 参数
>* **img_file** (str): 预测图像路径。 >* **img_file** (str): 预测图像路径。
>* **model** (paddlex.cv.models): paddlex中的模型。 >* **model** (paddlex.cv.models): paddlex中的模型。
>* **dataset** (paddlex.datasets): 数据集读取器,默认为None。 >* **dataset** (paddlex.datasets): 数据集读取器,默认为None。
>* **algo** (str): 可解释性方式,当前可选'lime'和'normlime'。
>* **num_samples** (int): LIME用于学习线性模型的采样数,默认为3000。 >* **num_samples** (int): LIME用于学习线性模型的采样数,默认为3000。
>* **batch_size** (int): 预测数据batch大小,默认为50。 >* **batch_size** (int): 预测数据batch大小,默认为50。
>* **save_dir** (str): 可解释性可视化结果(保存为png格式文件)和中间文件存储路径。 >* **save_dir** (str): 可解释性可视化结果(保存为png格式文件)和中间文件存储路径。
**注意:** dataset`读取的是一个数据集,该数据集不宜过大,否则计算时间会较长,但应包含所有类别的数据。
### 使用示例 ### 使用示例
> 对预测可解释性结果可视化的过程可参见[代码](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/interpret/interpret.py)。 > 对预测可解释性结果可视化的过程可参见[代码](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/interpret/normlime.py)。
...@@ -11,10 +11,10 @@ PaddleX目前提供了4种视觉任务解决方案,分别为图像分类、目 ...@@ -11,10 +11,10 @@ PaddleX目前提供了4种视觉任务解决方案,分别为图像分类、目
| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | 准确率 | 备注 | | 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | 准确率 | 备注 |
| :--------- | :------ | :---------- | :-----------| :------------- | :----- | :--- | | :--------- | :------ | :---------- | :-----------| :------------- | :----- | :--- |
| MobileNetV3_small_ssld | 12M | ? | ? | ? | 71.3% |适用于移动端场景 | | MobileNetV3_small_ssld | 12M | - | - | - | 71.3% |适用于移动端场景 |
| MobileNetV3_large_ssld | 21M | ? | ? | ? | 79.0% | 适用于移动端/服务端场景 | | MobileNetV3_large_ssld | 21M | - | - | - | 79.0% | 适用于移动端/服务端场景 |
| ResNet50_vd_ssld | 102.8MB | ? | ? | ? | 82.4% | 适用于服务端场景 | | ResNet50_vd_ssld | 102.8MB | - | - | - | 82.4% | 适用于服务端场景 |
| ResNet101_vd_ssld | 179.2MB | ? | ? | ? |83.7% | 适用于服务端场景 | | ResNet101_vd_ssld | 179.2MB | - | - | - |83.7% | 适用于服务端场景 |
除上述模型外,PaddleX还支持近20种图像分类模型,模型列表可参考[PaddleX模型库](../appendix/model_zoo.md) 除上述模型外,PaddleX还支持近20种图像分类模型,模型列表可参考[PaddleX模型库](../appendix/model_zoo.md)
...@@ -28,10 +28,10 @@ PaddleX目前提供了4种视觉任务解决方案,分别为图像分类、目 ...@@ -28,10 +28,10 @@ PaddleX目前提供了4种视觉任务解决方案,分别为图像分类、目
| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 |ARM芯片预测速度 | BoxMAP | 备注 | | 模型 | 模型大小 | GPU预测速度 | CPU预测速度 |ARM芯片预测速度 | BoxMAP | 备注 |
| :------- | :------- | :--------- | :---------- | :------------- | :----- | :--- | | :------- | :------- | :--------- | :---------- | :------------- | :----- | :--- |
| YOLOv3-MobileNetV1 | 101.2M | ? | ? | ? | 29.3 | | | YOLOv3-MobileNetV1 | 101.2M | - | - | - | 29.3 | |
| YOLOv3-MobileNetV3 | 94.6M | ? | ? | ? | 31.6 | | | YOLOv3-MobileNetV3 | 94.6M | - | - | - | 31.6 | |
| YOLOv3-ResNet34 | 169.7M | ? | ? | ? | 36.2 | | | YOLOv3-ResNet34 | 169.7M | - | - | - | 36.2 | |
| YOLOv3-DarkNet53 | 252.4 | ? | ? | ? | 38.9 | | | YOLOv3-DarkNet53 | 252.4 | - | - | - | 38.9 | |
除YOLOv3模型外,PaddleX同时也支持FasterRCNN模型,支持FPN结构和5种backbone网络,详情可参考[PaddleX模型库](../appendix/model_zoo.md) 除YOLOv3模型外,PaddleX同时也支持FasterRCNN模型,支持FPN结构和5种backbone网络,详情可参考[PaddleX模型库](../appendix/model_zoo.md)
...@@ -44,8 +44,8 @@ PaddleX目前提供了实例分割MaskRCNN模型,支持5种不同的backbone ...@@ -44,8 +44,8 @@ PaddleX目前提供了实例分割MaskRCNN模型,支持5种不同的backbone
| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | BoxMAP | SegMAP | 备注 | | 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | BoxMAP | SegMAP | 备注 |
| :---- | :------- | :---------- | :---------- | :------------- | :----- | :----- | :--- | | :---- | :------- | :---------- | :---------- | :------------- | :----- | :----- | :--- |
| MaskRCNN-ResNet50_vd-FPN | 185.5M | ? | ? | ? | 39.8 | 35.4 | | | MaskRCNN-ResNet50_vd-FPN | 185.5M | - | - | - | 39.8 | 35.4 | |
| MaskRCNN-ResNet101_vd-FPN | 268.6M | ? | ? | ? | 41.4 | 36.8 | | | MaskRCNN-ResNet101_vd-FPN | 268.6M | - | - | - | 41.4 | 36.8 | |
## 语义分割 ## 语义分割
...@@ -57,7 +57,7 @@ PaddleX目前提供了实例分割MaskRCNN模型,支持5种不同的backbone ...@@ -57,7 +57,7 @@ PaddleX目前提供了实例分割MaskRCNN模型,支持5种不同的backbone
| 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | mIOU | 备注 | | 模型 | 模型大小 | GPU预测速度 | CPU预测速度 | ARM芯片预测速度 | mIOU | 备注 |
| :---- | :------- | :---------- | :---------- | :------------- | :----- | :----- | | :---- | :------- | :---------- | :---------- | :------------- | :----- | :----- |
| DeepLabv3p-MobileNetV2_x0.25 | | ? | ? | ? | ? | ? | | DeepLabv3p-MobileNetV2_x0.25 | | - | - | - | - | - |
| DeepLabv3p-MobileNetV2_x1.0 | | ? | ? | ? | ? | ? | | DeepLabv3p-MobileNetV2_x1.0 | | - | - | - | - | - |
| DeepLabv3p-Xception65 | | ? | ? | ? | ? | ? | | DeepLabv3p-Xception65 | | - | - | - | - | - |
| UNet | | ? | ? | ? | ? | ? | | UNet | | - | - | - | - | - |
# 模型加密 # 模型加密部署
飞桨团队推出模型加密方案,使用业内主流的AES加密技术对最终模型进行加密。飞桨用户可以通过PaddleX导出模型后,使用该方案对模型进行加密,预测时使用解密SDK进行模型解密并完成推理,大大提升AI应用安全性和开发效率 PaddleX提供一个轻量级的模型加密部署方案,通过PaddleX内置的模型加密工具对推理模型进行加密,预测部署SDK支持直接加载密文模型并完成推理,提升AI模型部署的安全性
**注意:目前加密方案仅支持Linux系统** **注意:目前加密方案仅支持Linux系统**
...@@ -62,6 +62,7 @@ paddlex-encryption ...@@ -62,6 +62,7 @@ paddlex-encryption
``` ```
`-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=`
![](../images/encrypt.png) ![](../images/encrypt.png)
## 2. PaddleX C++加密部署 ## 2. PaddleX C++加密部署
......
多端部署 多端安全部署
============== ==============
本文档指引用户如何采用更高性能地方式来部署使用PaddleX训练的模型。使用本文档模型部署方式,会在模型运算过程中,对模型计算图进行优化,同时减少内存操作,相对比普通的paddlepaddle模型加载和预测方式,预测速度平均可提升1倍,具体各模型性能对比见服务端Python部署的预测性能对比章节。 本文档指引用户如何采用更高性能地方式来部署使用PaddleX训练的模型。本文档模型部署采用Paddle Inference高性能部署方式,在模型运算过程中,对模型计算图进行优化,同时减少内存操作,具体各模型性能对比见服务端Python部署的预测性能对比章节。
同时结合产业实践开发者对模型知识产权的保护需求,提供了轻量级模型加密部署的方案,提升深度学习模型部署的安全性。
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
......
...@@ -15,4 +15,5 @@ ...@@ -15,4 +15,5 @@
from __future__ import absolute_import from __future__ import absolute_import
from . import visualize from . import visualize
visualize = visualize.visualize lime = visualize.lime
\ No newline at end of file normlime = visualize.normlime
\ No newline at end of file
...@@ -116,9 +116,8 @@ def precompute_lime_weights(list_data_, predict_fn, num_samples, batch_size, sav ...@@ -116,9 +116,8 @@ def precompute_lime_weights(list_data_, predict_fn, num_samples, batch_size, sav
if os.path.exists(save_path): if os.path.exists(save_path):
logging.info(save_path + ' exists, not computing this one.', use_color=True) logging.info(save_path + ' exists, not computing this one.', use_color=True)
continue continue
img_file_name = each_data_ if isinstance(each_data_, str) else data_index
logging.info('processing'+each_data_ if isinstance(each_data_, str) else data_index + \ logging.info('processing '+ img_file_name + ' [{}/{}]'.format(data_index, len(list_data_)), use_color=True)
f'+{data_index}/{len(list_data_)}', use_color=True)
image_show = read_image(each_data_) image_show = read_image(each_data_)
result = predict_fn(image_show) result = predict_fn(image_show)
......
...@@ -23,19 +23,64 @@ from .core.interpretation import Interpretation ...@@ -23,19 +23,64 @@ from .core.interpretation import Interpretation
from .core.normlime_base import precompute_normlime_weights from .core.normlime_base import precompute_normlime_weights
from .core._session_preparation import gen_user_home from .core._session_preparation import gen_user_home
def visualize(img_file, def lime(img_file,
model,
num_samples=3000,
batch_size=50,
save_dir='./'):
"""使用LIME算法将模型预测结果的可解释性可视化。
LIME表示与模型无关的局部可解释性,可以解释任何模型。LIME的思想是以输入样本为中心,
在其附近的空间中进行随机采样,每个采样通过原模型得到新的输出,这样得到一系列的输入
和对应的输出,LIME用一个简单的、可解释的模型(比如线性回归模型)来拟合这个映射关系,
得到每个输入维度的权重,以此来解释模型。
注意:LIME可解释性结果可视化目前只支持分类模型。
Args:
img_file (str): 预测图像路径。
model (paddlex.cv.models): paddlex中的模型。
num_samples (int): LIME用于学习线性模型的采样数,默认为3000。
batch_size (int): 预测数据batch大小,默认为50。
save_dir (str): 可解释性可视化结果(保存为png格式文件)和中间文件存储路径。
"""
assert model.model_type == 'classifier', \
'Now the interpretation visualize only be supported in classifier!'
if model.status != 'Normal':
raise Exception('The interpretation only can deal with the Normal model')
if not osp.exists(save_dir):
os.makedirs(save_dir)
model.arrange_transforms(
transforms=model.test_transforms, mode='test')
tmp_transforms = copy.deepcopy(model.test_transforms)
tmp_transforms.transforms = tmp_transforms.transforms[:-2]
img = tmp_transforms(img_file)[0]
img = np.around(img).astype('uint8')
img = np.expand_dims(img, axis=0)
interpreter = None
interpreter = get_lime_interpreter(img, model, num_samples=num_samples, batch_size=batch_size)
img_name = osp.splitext(osp.split(img_file)[-1])[0]
interpreter.interpret(img, save_dir=save_dir)
def normlime(img_file,
model, model,
dataset=None, dataset=None,
algo='lime',
num_samples=3000, num_samples=3000,
batch_size=50, batch_size=50,
save_dir='./'): save_dir='./'):
"""可解释性可视化。 """使用NormLIME算法将模型预测结果的可解释性可视化。
NormLIME是利用一定数量的样本来出一个全局的解释。NormLIME会提前计算一定数量的测
试样本的LIME结果,然后对相同的特征进行权重的归一化,这样来得到一个全局的输入和输出的关系。
注意1:dataset读取的是一个数据集,该数据集不宜过大,否则计算时间会较长,但应包含所有类别的数据。
注意2:NormLIME可解释性结果可视化目前只支持分类模型。
Args: Args:
img_file (str): 预测图像路径。 img_file (str): 预测图像路径。
model (paddlex.cv.models): paddlex中的模型。 model (paddlex.cv.models): paddlex中的模型。
dataset (paddlex.datasets): 数据集读取器,默认为None。 dataset (paddlex.datasets): 数据集读取器,默认为None。
algo (str): 可解释性方式,当前可选'lime'和'normlime'。
num_samples (int): LIME用于学习线性模型的采样数,默认为3000。 num_samples (int): LIME用于学习线性模型的采样数,默认为3000。
batch_size (int): 预测数据batch大小,默认为50。 batch_size (int): 预测数据batch大小,默认为50。
save_dir (str): 可解释性可视化结果(保存为png格式文件)和中间文件存储路径。 save_dir (str): 可解释性可视化结果(保存为png格式文件)和中间文件存储路径。
...@@ -54,21 +99,16 @@ def visualize(img_file, ...@@ -54,21 +99,16 @@ def visualize(img_file,
img = np.around(img).astype('uint8') img = np.around(img).astype('uint8')
img = np.expand_dims(img, axis=0) img = np.expand_dims(img, axis=0)
interpreter = None interpreter = None
if algo == 'lime':
interpreter = get_lime_interpreter(img, model, dataset, num_samples=num_samples, batch_size=batch_size)
elif algo == 'normlime':
if dataset is None: if dataset is None:
raise Exception('The dataset is None. Cannot implement this kind of interpretation') raise Exception('The dataset is None. Cannot implement this kind of interpretation')
interpreter = get_normlime_interpreter(img, model, dataset, interpreter = get_normlime_interpreter(img, model, dataset,
num_samples=num_samples, batch_size=batch_size, num_samples=num_samples, batch_size=batch_size,
save_dir=save_dir) save_dir=save_dir)
else:
raise Exception('The {} interpretation method is not supported yet!'.format(algo))
img_name = osp.splitext(osp.split(img_file)[-1])[0] img_name = osp.splitext(osp.split(img_file)[-1])[0]
interpreter.interpret(img, save_dir=save_dir) interpreter.interpret(img, save_dir=save_dir)
def get_lime_interpreter(img, model, dataset, num_samples=3000, batch_size=50): def get_lime_interpreter(img, model, num_samples=3000, batch_size=50):
def predict_func(image): def predict_func(image):
image = image.astype('float32') image = image.astype('float32')
for i in range(image.shape[0]): for i in range(image.shape[0]):
...@@ -79,8 +119,8 @@ def get_lime_interpreter(img, model, dataset, num_samples=3000, batch_size=50): ...@@ -79,8 +119,8 @@ def get_lime_interpreter(img, model, dataset, num_samples=3000, batch_size=50):
model.test_transforms.transforms = tmp_transforms model.test_transforms.transforms = tmp_transforms
return out[0] return out[0]
labels_name = None labels_name = None
if dataset is not None: if hasattr(model, 'labels'):
labels_name = dataset.labels labels_name = model.labels
interpreter = Interpretation('lime', interpreter = Interpretation('lime',
predict_func, predict_func,
labels_name, labels_name,
......
import os
# 选择使用0号卡
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
import os.path as osp
import paddlex as pdx
# 下载和解压Imagenet果蔬分类数据集
veg_dataset = 'https://bj.bcebos.com/paddlex/interpret/mini_imagenet_veg.tar.gz'
pdx.utils.download_and_decompress(veg_dataset, path='./')
# 下载和解压已训练好的MobileNetV2模型
model_file = 'https://bj.bcebos.com/paddlex/interpret/mini_imagenet_veg_mobilenetv2.tar.gz'
pdx.utils.download_and_decompress(model_file, path='./')
# 加载模型
model = pdx.load_model('mini_imagenet_veg_mobilenetv2')
# 可解释性可视化
pdx.interpret.lime(
'mini_imagenet_veg/mushroom/n07734744_1106.JPEG',
model,
save_dir='./')
...@@ -24,15 +24,8 @@ test_dataset = pdx.datasets.ImageNet( ...@@ -24,15 +24,8 @@ test_dataset = pdx.datasets.ImageNet(
transforms=model.test_transforms) transforms=model.test_transforms)
# 可解释性可视化 # 可解释性可视化
pdx.interpret.visualize( pdx.interpret.normlime(
'mini_imagenet_veg/mushroom/n07734744_1106.JPEG', 'mini_imagenet_veg/mushroom/n07734744_1106.JPEG',
model, model,
test_dataset, test_dataset,
algo='lime',
save_dir='./')
pdx.interpret.visualize(
'mini_imagenet_veg/mushroom/n07734744_1106.JPEG',
model,
test_dataset,
algo='normlime',
save_dir='./') save_dir='./')
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册