提交 72728391 编写于 作者: F FlyingQianMM

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

...@@ -65,6 +65,15 @@ bool Model::load_config(const std::string& model_dir) { ...@@ -65,6 +65,15 @@ bool Model::load_config(const std::string& model_dir) {
YAML::Node config = YAML::LoadFile(yaml_file); YAML::Node config = YAML::LoadFile(yaml_file);
type = config["_Attributes"]["model_type"].as<std::string>(); type = config["_Attributes"]["model_type"].as<std::string>();
name = config["Model"].as<std::string>(); name = config["Model"].as<std::string>();
std::string version = config["version"].as<std::string>();
if (version[0] == '0') {
std::cerr << "[Init] Version of the loaded model is lower than 1.0.0, deployment "
<< "cannot be done, please refer to "
<< "https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/tutorials/deploy/upgrade_version.md "
<< "to transfer version."
<< std::endl;
return false;
}
bool to_rgb = true; bool to_rgb = true;
if (config["TransformsMode"].IsDefined()) { if (config["TransformsMode"].IsDefined()) {
std::string mode = config["TransformsMode"].as<std::string>(); std::string mode = config["TransformsMode"].as<std::string>();
......
# Predictor部署-paddlex.deploy # 预测部署-paddlex.deploy
使用AnalysisPredictor进行预测部署。 使用Paddle Inference进行高性能的Python预测部署。更多关于Paddle Inference信息请参考[Paddle Inference文档](https://paddle-inference.readthedocs.io/en/latest/#)
## Predictor类 ## Predictor类
...@@ -22,6 +22,7 @@ paddlex.deploy.Predictor(model_dir, use_gpu=False, gpu_id=0, use_mkl=False, use_ ...@@ -22,6 +22,7 @@ paddlex.deploy.Predictor(model_dir, use_gpu=False, gpu_id=0, use_mkl=False, use_
> > > >
> > ``` > > ```
> > import paddlex > > import paddlex
> >
> > model = paddlex.deploy.Predictor(model_dir, use_gpu=True) > > model = paddlex.deploy.Predictor(model_dir, use_gpu=True)
> > result = model.predict(image_file) > > result = model.predict(image_file)
> > ``` > > ```
......
...@@ -15,7 +15,7 @@ paddlex.cls.transforms.Compose(transforms) ...@@ -15,7 +15,7 @@ paddlex.cls.transforms.Compose(transforms)
## RandomCrop类 ## RandomCrop类
```python ```python
paddlex.cls.transforms.RandomCrop(crop_size=224, lower_scale=0.88, lower_ratio=3. / 4, upper_ratio=4. / 3) paddlex.cls.transforms.RandomCrop(crop_size=224, lower_scale=0.08, lower_ratio=3. / 4, upper_ratio=4. / 3)
``` ```
对图像进行随机剪裁,模型训练时的数据增强操作。 对图像进行随机剪裁,模型训练时的数据增强操作。
...@@ -26,7 +26,7 @@ paddlex.cls.transforms.RandomCrop(crop_size=224, lower_scale=0.88, lower_ratio=3 ...@@ -26,7 +26,7 @@ paddlex.cls.transforms.RandomCrop(crop_size=224, lower_scale=0.88, lower_ratio=3
### 参数 ### 参数
* **crop_size** (int): 随机裁剪后重新调整的目标边长。默认为224。 * **crop_size** (int): 随机裁剪后重新调整的目标边长。默认为224。
* **lower_scale** (float): 裁剪面积相对原面积比例的最小限制。默认为0.88。 * **lower_scale** (float): 裁剪面积相对原面积比例的最小限制。默认为0.08。
* **lower_ratio** (float): 宽变换比例的最小限制。默认为3. / 4。 * **lower_ratio** (float): 宽变换比例的最小限制。默认为3. / 4。
* **upper_ratio** (float): 宽变换比例的最小限制。默认为4. / 3。 * **upper_ratio** (float): 宽变换比例的最小限制。默认为4. / 3。
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
model_zoo.md model_zoo.md
metrics.md metrics.md
interpret.md
parameters.md parameters.md
how_to_convert_dataset.md how_to_convert_dataset.md
datasets.md datasets.md
......
# PaddleX可解释性
目前深度学习模型普遍存在一个问题,因为使用模型预测还是一个黑盒,几乎无法去感知它的内部工作状态,预测结果的可信度一直遭到质疑。为此,PadlleX提供了2种对图像分类预测结果进行可解释性研究的算法:LIME和NormLIME。
## LIME
LIME全称Local interpretable model-agnostic explanations,表示一种与模型无关的局部可解释性。其实现步骤主要如下:
1. 获取图像的超像素。
2. 以输入样本为中心,在其附近的空间中进行随机采样,每个采样即对对象中的超像素进行随机遮掩(每个采样的权重和该采样与原样本的距离成反比)。
3. 每个采样通过预测模型得到新的输出,这样得到一系列的输入`X`和对应的输出`Y`
4.`X`转换为超像素特征`F`,用一个简单的、可解释的模型`Model`(这里使用岭回归)来拟合`F``Y`的映射关系。
5. `Model`将得到`F`每个输入维度的权重(每个维度代表一个超像素),以此来解释模型。
LIME的使用方式可参见[代码示例](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/interpret/lime.py)[api介绍](../apis/visualize.html#lime)。在使用时,参数中的`num_samples`设置尤为重要,其表示上述步骤2中的随机采样的个数,若设置过小会影响可解释性结果的稳定性,若设置过大则将在上述步骤3耗费较长时间;参数`batch_size`则表示在计算上述步骤3时,预测的batch size,若设置过小将在上述步骤3耗费较长时间,而上限则根据机器配置决定。
最终LIME可解释性算法的可视化结果如下所示:
![](../images/lime.png)
图中绿色区域代表起正向作用的超像素,红色区域代表起反向作用的超像素,"First n superpixels"代表前n个权重比较大的超像素(由上述步骤5计算所得结果)。
## NormLIME
NormLIME是在LIME上的改进,LIME的解释是局部性的,是针对当前样本给的特定解释,而NormLIME是利用一定数量的样本对当前样本的一个全局性的解释,有一定的降噪效果。其实现步骤如下所示:
1. 下载Kmeans模型参数和ResNet50_vc网络前三层参数。(ResNet50_vc的参数是在ImageNet上训练所得网络的参数;使用ImageNet图像作为数据集,每张图像从ResNet50_vc的第三层输出提取对应超象素位置上的平均特征和质心上的特征,训练将得到此处的Kmeans模型)
2. 计算测试集中每张图像的LIME结果。(如无测试集,可用验证集代替)
3. 使用Kmeans模型对所有图像中的所有像素进行聚类。
4. 对在同一个簇的超像素(相同的特征)进行权重的归一化,得到每个超像素的权重,以此来解释模型。
NormLIME的使用方式可参见[代码示例](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/interpret/normlime.py)[api介绍](../apis/visualize.html#normlime)。在使用时,参数中的`num_samples`设置尤为重要,其表示上述步骤2中的随机采样的个数,若设置过小会影响可解释性结果的稳定性,若设置过大则将在上述步骤3耗费较长时间;参数`batch_size`则表示在计算上述步骤3时,预测的batch size,若设置过小将在上述步骤3耗费较长时间,而上限则根据机器配置决定;而`dataset`则是由测试集或验证集构造的数据。
最终NormLIME可解释性算法的可视化结果如下所示:
![](../images/normlime.png)
图中绿色区域代表起正向作用的超像素,红色区域代表起反向作用的超像素,"First n superpixels"代表前n个权重比较大的超像素(由上述步骤5计算所得结果)。图中最后一行代表把LIME和NormLIME对应超像素权重相乘的结果。
\ No newline at end of file
...@@ -32,7 +32,7 @@ PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习 ...@@ -32,7 +32,7 @@ PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习
* PaddleX版本: v1.0.0 * PaddleX版本: v1.0.0
* 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex * 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex
* 项目GitHub: https://github.com/PaddlePaddle/PaddleX/tree/develop * 项目GitHub: https://github.com/PaddlePaddle/PaddleX
* 官方QQ用户群: 1045148026 * 官方QQ用户群: 1045148026
* GitHub Issue反馈: http://www.github.com/PaddlePaddle/PaddleX/issues * GitHub Issue反馈: http://www.github.com/PaddlePaddle/PaddleX/issues
...@@ -61,7 +61,7 @@ eval_dataset = pdx.datasets.ImageNet( ...@@ -61,7 +61,7 @@ eval_dataset = pdx.datasets.ImageNet(
本文档中使用百度基于蒸馏方法得到的MobileNetV3预训练模型,模型结构与MobileNetV3一致,但精度更高。PaddleX内置了20多种分类模型,查阅[PaddleX模型库](appendix/model_zoo.md)了解更多分类模型。 本文档中使用百度基于蒸馏方法得到的MobileNetV3预训练模型,模型结构与MobileNetV3一致,但精度更高。PaddleX内置了20多种分类模型,查阅[PaddleX模型库](appendix/model_zoo.md)了解更多分类模型。
``` ```
num_classes = len(train_dataset.labels) num_classes = len(train_dataset.labels)
model.pdx.cls.MobileNetV3_small_ssld(num_classes=num_classes) model = pdx.cls.MobileNetV3_small_ssld(num_classes=num_classes)
``` ```
### 3.4 定义训练参数 ### 3.4 定义训练参数
...@@ -86,7 +86,7 @@ python train.py ...@@ -86,7 +86,7 @@ python train.py
## 5. 训练过程中查看训练指标 ## 5. 训练过程中查看训练指标
模型在训练过程中,所有的迭代信息将以标注输出流的形式,输出到命令执行的终端上,用户也可通过visualdl以可视化的方式查看训练指标的变化,通过如下方式启动visualdl后,在浏览器打开https://0.0.0.0:8001 (或 https://localhost:8001)即可。 模型在训练过程中,所有的迭代信息将以标注输出流的形式,输出到命令执行的终端上,用户也可通过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 8001
``` ```
![](./images/vdl1.jpg) ![](./images/vdl1.jpg)
......
# 数据准备 # 数据准备
## 数据标注 该部分内容已迁移至[附录](../appendix/datasets.md)
## 主流标注软件支持
## EasyData数据标注支持
...@@ -9,6 +9,7 @@ pip install paddlelite ...@@ -9,6 +9,7 @@ pip install paddlelite
step 2: 将PaddleX模型导出为inference模型 step 2: 将PaddleX模型导出为inference模型
参考[导出inference模型](deploy_server/deploy_python.html#inference)将模型导出为inference格式模型。 参考[导出inference模型](deploy_server/deploy_python.html#inference)将模型导出为inference格式模型。
**注意:由于PaddleX代码的持续更新,版本低于1.0.0的模型暂时无法直接用于预测部署,参考[模型版本升级](../upgrade_version.md)对模型版本进行升级。**
step 3: 将inference模型转换成PaddleLite模型 step 3: 将inference模型转换成PaddleLite模型
......
...@@ -104,7 +104,8 @@ make ...@@ -104,7 +104,8 @@ make
### Step5: 预测及可视化 ### Step5: 预测及可视化
参考[导出inference模型](../deploy_python.html#inference)将模型导出为inference格式模型。 参考[导出inference模型](../../deploy_python.html#inference)将模型导出为inference格式模型。
**注意:由于PaddleX代码的持续更新,版本低于1.0.0的模型暂时无法直接用于预测部署,参考[模型版本升级](../../upgrade_version.md)对模型版本进行升级。**
编译成功后,预测demo的可执行程序分别为`build/demo/detector``build/demo/classifer``build/demo/segmenter`,用户可根据自己的模型类型选择,其主要命令参数说明如下: 编译成功后,预测demo的可执行程序分别为`build/demo/detector``build/demo/classifer``build/demo/segmenter`,用户可根据自己的模型类型选择,其主要命令参数说明如下:
......
...@@ -100,6 +100,7 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens ...@@ -100,6 +100,7 @@ PaddlePaddle C++ 预测库针对不同的`CPU`,`CUDA`,以及是否支持Tens
### Step5: 预测及可视化 ### Step5: 预测及可视化
参考[导出inference模型](../deploy_python.html#inference)将模型导出为inference格式模型。 参考[导出inference模型](../deploy_python.html#inference)将模型导出为inference格式模型。
**注意:由于PaddleX代码的持续更新,版本低于1.0.0的模型暂时无法直接用于预测部署,参考[模型版本升级](../../upgrade_version.md)对模型版本进行升级。**
上述`Visual Studio 2019`编译产出的可执行文件在`out\build\x64-Release`目录下,打开`cmd`,并切换到该目录: 上述`Visual Studio 2019`编译产出的可执行文件在`out\build\x64-Release`目录下,打开`cmd`,并切换到该目录:
......
...@@ -20,6 +20,8 @@ paddlex --export_inference --model_dir=./xiaoduxiong_epoch_12 --save_dir=./infer ...@@ -20,6 +20,8 @@ paddlex --export_inference --model_dir=./xiaoduxiong_epoch_12 --save_dir=./infer
``` ```
## 预测部署 ## 预测部署
**注意:由于PaddleX代码的持续更新,版本低于1.0.0的模型暂时无法直接用于预测部署,参考[模型版本升级](../upgrade_version.md)对模型版本进行升级。**
> 点击下载测试图片 [xiaoduxiong_test_image.tar.gz](https://bj.bcebos.com/paddlex/datasets/xiaoduxiong_test_image.tar.gz) > 点击下载测试图片 [xiaoduxiong_test_image.tar.gz](https://bj.bcebos.com/paddlex/datasets/xiaoduxiong_test_image.tar.gz)
``` ```
......
...@@ -61,7 +61,7 @@ paddlex-encryption ...@@ -61,7 +61,7 @@ paddlex-encryption
./paddlex-encryption/tool/paddlex_encrypt_tool -model_dir /path/to/paddlex_inference_model -save_dir /path/to/paddlex_encrypted_model ./paddlex-encryption/tool/paddlex_encrypt_tool -model_dir /path/to/paddlex_inference_model -save_dir /path/to/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`**注意**:由于PaddleX代码的持续更新,版本低于1.0.0的模型暂时无法直接用于预测部署,参考[模型版本升级](../upgrade_version.md)对模型版本进行升级。)。加密完成后,加密过的模型会保存至指定的`-save_dir`下,包含`__model__.encrypted``__params__.encrypted``model.yml`三个文件,同时生成密钥信息,命令输出如下图所示,密钥为`kLAl1qOs5uRbFt0/RrIDTZW2+tOf5bzvUIaHGF8lJ1c=`
![](../images/encrypt.png) ![](../images/encrypt.png)
......
# 模型版本升级
由于PaddleX代码的持续更新,版本低于1.0.0的模型暂时无法直接用于预测部署,用户需要按照以下步骤对模型版本进行转换,转换后的模型可以在多端上完成部署。
## 检查模型版本
存放模型的文件夹存有一个`model.yml`文件,该文件的最后一行`version`值表示模型的版本号,若版本号小于1.0.0,则需要进行版本转换,若版本号大于及等于1.0.0,则不需要进行版本转换。
## 版本转换
```
paddlex --export_inference --model_dir=/path/to/low_version_model --save_dir=SSpath/to/high_version_model
```
`--model_dir`为版本号小于1.0.0的模型路径,可以是PaddleX训练过程保存的模型,也可以是导出为inference格式的模型。`--save_dir`为转换为高版本的模型,后续可用于多端部署。
\ No newline at end of file
...@@ -42,7 +42,7 @@ def sensitivity(program, ...@@ -42,7 +42,7 @@ def sensitivity(program,
if pruned_ratios is None: if pruned_ratios is None:
pruned_ratios = np.arange(0.1, 1, step=0.1) pruned_ratios = np.arange(0.1, 1, step=0.1)
total_evaluate_iters = 1 total_evaluate_iters = 0
for name in param_names: for name in param_names:
if name not in sensitivities: if name not in sensitivities:
sensitivities[name] = {} sensitivities[name] = {}
...@@ -52,12 +52,6 @@ def sensitivity(program, ...@@ -52,12 +52,6 @@ def sensitivity(program,
len(list(pruned_ratios)) - len(sensitivities[name])) len(list(pruned_ratios)) - len(sensitivities[name]))
eta = '-' eta = '-'
start_time = time.time() start_time = time.time()
progress = 1.0 / total_evaluate_iters
progress = "%.2f%%" % (progress * 100)
logging.info(
"Total evaluate iters={}, current={}, progress={}, eta={}".format(
total_evaluate_iters, 1, progress, eta),
use_color=True)
baseline = eval_func(graph.program) baseline = eval_func(graph.program)
cost = time.time() - start_time cost = time.time() - start_time
eta = cost * (total_evaluate_iters - 1) eta = cost * (total_evaluate_iters - 1)
...@@ -73,7 +67,7 @@ def sensitivity(program, ...@@ -73,7 +67,7 @@ def sensitivity(program,
logging.info( logging.info(
"Total evaluate iters={}, current={}, progress={}, eta={}". "Total evaluate iters={}, current={}, progress={}, eta={}".
format( format(
total_evaluate_iters, current_iter+1, progress, total_evaluate_iters, current_iter, progress,
seconds_to_hms( seconds_to_hms(
int(cost * (total_evaluate_iters - current_iter)))), int(cost * (total_evaluate_iters - current_iter)))),
use_color=True) use_color=True)
......
...@@ -50,7 +50,7 @@ def visualize(model, sensitivities_file, save_dir='./'): ...@@ -50,7 +50,7 @@ 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, rotation=30, fontsize=8) plt.xticks(my_x_ticks, rotation=15, fontsize=8)
plt.yticks(my_y_ticks, fontsize=8) 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(
......
...@@ -103,14 +103,14 @@ class RandomCrop(ClsTransform): ...@@ -103,14 +103,14 @@ class RandomCrop(ClsTransform):
Args: Args:
crop_size (int): 随机裁剪后重新调整的目标边长。默认为224。 crop_size (int): 随机裁剪后重新调整的目标边长。默认为224。
lower_scale (float): 裁剪面积相对原面积比例的最小限制。默认为0.88。 lower_scale (float): 裁剪面积相对原面积比例的最小限制。默认为0.08。
lower_ratio (float): 宽变换比例的最小限制。默认为3. / 4。 lower_ratio (float): 宽变换比例的最小限制。默认为3. / 4。
upper_ratio (float): 宽变换比例的最大限制。默认为4. / 3。 upper_ratio (float): 宽变换比例的最大限制。默认为4. / 3。
""" """
def __init__(self, def __init__(self,
crop_size=224, crop_size=224,
lower_scale=0.88, lower_scale=0.08,
lower_ratio=3. / 4, lower_ratio=3. / 4,
upper_ratio=4. / 3): upper_ratio=4. / 3):
self.crop_size = crop_size self.crop_size = crop_size
......
...@@ -23,7 +23,7 @@ def execute_imgaug(augmenter, im, bboxes=None, polygons=None, ...@@ -23,7 +23,7 @@ def execute_imgaug(augmenter, im, bboxes=None, polygons=None,
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) aug_im = augmenter.augment(image=aug_im).astype('float32')
return aug_im return aug_im
# TODO imgaug的标注处理逻辑与paddlex已存的transform存在部分差异 # TODO imgaug的标注处理逻辑与paddlex已存的transform存在部分差异
......
...@@ -269,11 +269,9 @@ def load_pretrain_weights(exe, ...@@ -269,11 +269,9 @@ def load_pretrain_weights(exe,
vars_to_load.append(var) vars_to_load.append(var)
logging.debug("Weight {} will be load".format(var.name)) logging.debug("Weight {} will be load".format(var.name))
fluid.io.load_vars( params_dict = fluid.io.load_program_state(
executor=exe, weights_dir, var_list=vars_to_load)
dirname=weights_dir, fluid.io.set_program_state(main_prog, params_dict)
main_program=main_prog,
vars=vars_to_load)
if len(vars_to_load) == 0: if len(vars_to_load) == 0:
logging.warning( logging.warning(
"There is no pretrain weights loaded, maybe you should check you pretrain model!" "There is no pretrain weights loaded, maybe you should check you pretrain model!"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册