浏览代码

Merge pull request #5 from PaddlePaddle/develop

00
SunAhong1993 5 年之前
父节点
当前提交
441634a167

+ 42 - 0
docs/apis/datasets/dataset_convert.md

@@ -0,0 +1,42 @@
+# 数据集转换
+## labelme2voc
+```python
+pdx.tools.labelme2voc(image_dir, json_dir, dataset_save_dir)
+```
+将LabelMe标注的数据集转换为VOC数据集。
+
+> **参数**
+> > * **image_dir** (str): 图像文件存放的路径。
+> > * **json_dir** (str): 与每张图像对应的json文件的存放路径。
+> > * **dataset_save_dir** (str): 转换后数据集存放路径。
+
+## 其它数据集转换
+### easydata2imagenet
+```python
+pdx.tools.easydata2imagenet(image_dir, json_dir, dataset_save_dir)
+```
+### easydata2voc
+```python
+pdx.tools.easydata2voc(image_dir, json_dir, dataset_save_dir)
+```
+### easydata2coco
+```python
+pdx.tools.easydata2coco(image_dir, json_dir, dataset_save_dir)
+```
+### easydata2seg
+```python
+pdx.tools.easydata2seg(image_dir, json_dir, dataset_save_dir)
+```
+### labelme2coco
+```python
+pdx.tools.labelme2coco(image_dir, json_dir, dataset_save_dir)
+```
+### labelme2seg
+```python
+pdx.tools.labelme2seg(image_dir, json_dir, dataset_save_dir)
+```
+### jingling2seg
+```python
+pdx.tools.jingling2seg(image_dir, json_dir, dataset_save_dir)
+```
+

+ 1 - 0
docs/apis/datasets/index.rst

@@ -29,3 +29,4 @@ PaddleX目前支持主流的CV数据集格式和 `EasyData <https://ai.baidu.com
    classification.md
    classification.md
    detection.md
    detection.md
    semantic_segmentation.md
    semantic_segmentation.md
+   dataset_convert.md

+ 25 - 38
docs/apis/deploy.md

@@ -1,50 +1,37 @@
-# paddlex.deploy
+# Predictor部署-paddlex.deploy
 
 
 使用AnalysisPredictor进行预测部署。
 使用AnalysisPredictor进行预测部署。
 
 
-## create_predictor
+## Predictor类
 
 
 ```
 ```
-paddlex.deploy.create_predictor(model_dir, use_gpu=False)
+paddlex.deploy.Predictor(model_dir, use_gpu=False, gpu_id=0, use_mkl=False, use_trt=False, use_glog=False, memory_optimize=True)
 ```
 ```
 
 
-#### Args
+> **参数**
 
 
-* **model_dir**: 训练过程中保存的模型路径
-* **use_gpu**: 是否使用GPU进行预测
+> > * **model_dir**: 训练过程中保存的模型路径, 注意需要使用导出的inference模型
+> > * **use_gpu**: 是否使用GPU进行预测
+> > * **gpu_id**: 使用的GPU序列号
+> > * **use_mkl**: 是否使用mkldnn加速库
+> > * **use_trt**: 是否使用TensorRT预测引擎
+> > * **use_glog**: 是否打印中间日志
+> > * **memory_optimize**: 是否优化内存使用
 
 
-#### Returns
+> > ### 示例
+> >
+> > ```
+> > import paddlex
+> > model = paddlex.deploy.Predictor(model_dir, use_gpu=True)
+> > result = model.predict(image_file)
+> > ```
 
 
-* **Predictor**: paddlex.deploy.predictor.Predictor
+### predict 接口
+> ```
+> predict(image, topk=1)
+> ```
 
 
-### 示例
+> **参数
 
 
-```
-import paddlex
-# 下
-Predictor = paddlex.deploy.create_predictor(model_dir, use_gpu=True)
-```
-
-## ClassifyPredictor
-继承至paddlex.deploy.predictor.Predictor,当model_dir/model.yml里面
-
-```
-paddlex.deploy.create_predictor(model_dir, use_gpu=False)
-```
-
-#### Args
-
-* **model_dir**: 训练过程中保存的模型路径
-* **use_gpu**: 是否使用GPU进行预测
-
-#### Returns
-
-* **Predictor**: paddlex.deploy.predictor.Predictor
-
-### 示例
-
-```
-import paddlex
-# 下
-Predictor = paddlex.deploy.create_predictor(model_dir, use_gpu=True)
-```
+* **image(str|np.ndarray)**: 待预测的图片路径或np.ndarray,若为后者需注意为BGR格式
+* **topk(int)**: 图像分类时使用的参数,表示预测前topk个可能的分类

+ 1 - 0
docs/apis/index.rst

@@ -10,3 +10,4 @@ PaddleX API说明文档
    slim.md
    slim.md
    load_model.md
    load_model.md
    visualize.md
    visualize.md
+   deploy.md

+ 30 - 5
docs/apis/visualize.md

@@ -5,7 +5,7 @@ PaddleX提供了一系列模型预测和结果分析的可视化函数。
 ```
 ```
 paddlex.det.visualize(image, result, threshold=0.5, save_dir='./')
 paddlex.det.visualize(image, result, threshold=0.5, save_dir='./')
 ```
 ```
-将目标检测/实例分割模型预测得到的Box框和Mask在原图上进行可视化
+将目标检测/实例分割模型预测得到的Box框和Mask在原图上进行可视化
 
 
 ### 参数
 ### 参数
 > * **image** (str): 原图文件路径。  
 > * **image** (str): 原图文件路径。  
@@ -77,7 +77,7 @@ pdx.det.draw_pr_curve(gt=gt, pred_bbox=bbox, save_dir='./insect')
 ```
 ```
 paddlex.seg.visualize(image, result, weight=0.6, save_dir='./')
 paddlex.seg.visualize(image, result, weight=0.6, save_dir='./')
 ```
 ```
-将语义分割模型预测得到的Mask在原图上进行可视化
+将语义分割模型预测得到的Mask在原图上进行可视化
 
 
 ### 参数
 ### 参数
 > * **image** (str): 原图文件路径。  
 > * **image** (str): 原图文件路径。  
@@ -99,11 +99,11 @@ pdx.det.visualize('city.png', result, save_dir='./')
 ```
 ```
 paddlex.slim.visualize(model, sensitivities_file)
 paddlex.slim.visualize(model, sensitivities_file)
 ```
 ```
-利用此接口,可以分析在不同的`eval_metric_loss`参数下,模型被裁剪的比例情况。可视化结果纵轴为eval_metric_loss参数值,横轴为对应的模型被裁剪的比例
+利用此接口,可以分析在不同的`eval_metric_loss`参数下,模型被裁剪的比例情况。可视化结果纵轴为eval_metric_loss参数值,横轴为对应的模型被裁剪的比例
 
 
 ### 参数
 ### 参数
->* **model**: 使用PaddleX加载的模型
->* **sensitivities_file**: 模型各参数在验证集上计算得到的参数敏感度信息文件
+>* **model** (paddlex.cv.models): 使用PaddleX加载的模型
+>* **sensitivities_file** (str): 模型各参数在验证集上计算得到的参数敏感度信息文件
 
 
 ### 使用示例
 ### 使用示例
 > 点击下载示例中的[模型](https://bj.bcebos.com/paddlex/models/vegetables_mobilenet.tar.gz)和[sensitivities_file](https://bj.bcebos.com/paddlex/slim_prune/mobilenetv2.sensitivities)
 > 点击下载示例中的[模型](https://bj.bcebos.com/paddlex/models/vegetables_mobilenet.tar.gz)和[sensitivities_file](https://bj.bcebos.com/paddlex/slim_prune/mobilenetv2.sensitivities)
@@ -113,3 +113,28 @@ model = pdx.load_model('vegetables_mobilenet')
 pdx.slim.visualize(model, 'mobilenetv2.sensitivities', save_dir='./')
 pdx.slim.visualize(model, 'mobilenetv2.sensitivities', save_dir='./')
 # 可视化结果保存在./sensitivities.png
 # 可视化结果保存在./sensitivities.png
 ```
 ```
+
+## 可解释性结果可视化
+```
+paddlex.interpret.visualize(img_file, 
+                            model, 
+                            dataset=None, 
+                            algo='lime',
+                            num_samples=3000, 
+                            batch_size=50,
+                            save_dir='./')
+```
+将模型预测结果的可解释性可视化,目前只支持分类模型。
+
+### 参数
+>* **img_file** (str): 预测图像路径。
+>* **model** (paddlex.cv.models): paddlex中的模型。
+>* **dataset** (paddlex.datasets): 数据集读取器,默认为None。
+>* **algo** (str): 可解释性方式,当前可选'lime'和'normlime'。
+>* **num_samples** (int): LIME用于学习线性模型的采样数,默认为3000。
+>* **batch_size** (int): 预测数据batch大小,默认为50。
+>* **save_dir** (str): 可解释性可视化结果(保存为png格式文件)和中间文件存储路径。 
+
+
+### 使用示例
+> 对预测可解释性结果可视化的过程可参见[代码](https://github.com/PaddlePaddle/PaddleX/blob/develop/tutorials/interpret/interpret.py)。

+ 367 - 0
docs/appendix/datasets.md

@@ -0,0 +1,367 @@
+# 数据集格式说明
+
+---
+## 图像分类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/classification.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/detection.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/detection.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/semantic_segmentation.html#segdataset))加载语义分割数据集。
+
+
+## 图像分类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/classification.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/detection.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/semantic_segmentation.html#easydataseg))加载分类数据集。
+

+ 28 - 0
docs/appendix/how_to_convert_dataset.md

@@ -0,0 +1,28 @@
+# 数据集转换
+
+当前PaddleX GUI支持ImageNet格式的图像分类数据集、VOC格式的目标检测数据集、COCO格式的实例分割数据集、Seg格式的语义分割的数据集,当使用LabelMe、EasyData、标注精灵这3个工具标注数据时,PaddleX提供了相应接口可将数据转换成与PaddleX GUI想适配的数据集,使用方式如下所示:
+
+```python
+import paddlex as pdx
+
+# 该接口实现LabelMe数据集到VOC数据集的转换。
+# image_dir为图像文件存放的路径。
+# json_dir为与每张图像对应的json文件的存放路径。
+# dataset_save_dir为转换后数据集存放路径。
+pdx.tools.labelme2voc(image_dir='labelme_imgs',
+                      json_dir='labelme_jsons',
+                      dataset_save_dir='voc_dataset')
+```
+
+可替换labelme2voc实现不同数据集间的转换,目前提供的转换接口如下:  
+
+| 接口      | 转换关系 |
+| :-------- | :------- |
+| labelme2voc  | LabelMe数据集转换为VOC数据集   |
+| labelme2coco  | LabelMe数据集转换为COCO数据集   |
+| labelme2seg  | LabelMe数据集转换为Seg数据集  |
+| easydata2imagenet | EasyData数据集转换为ImageNet数据集  |
+| easydata2voc | EasyData数据集转换为VOC数据集  |
+| easydata2coco | EasyData数据集转换为COCO数据集  |
+| easydata2seg | EasyData数据集转换为Seg数据集  |
+| jingling2seg | 标注精灵数据集转换为Seg数据集  |

+ 3 - 0
docs/appendix/index.rst

@@ -8,6 +8,9 @@
 
 
    model_zoo.md
    model_zoo.md
    metrics.md
    metrics.md
+   how_to_convert_dataset.md
+   datasets.md
+
 
 
 * PaddleX版本: v0.1.7
 * PaddleX版本: v0.1.7
 * 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex  
 * 项目官网: http://www.paddlepaddle.org.cn/paddle/paddlex  

+ 1 - 203
docs/datasets.md

@@ -1,204 +1,2 @@
 # 数据集格式说明
 # 数据集格式说明
-
----
-## 图像分类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开始),如下所示:
-```
-labelA
-labelB
-...
-```
-
-标注图像为单通道图像,像素值即为对应的类别,像素标注类别需要从0开始递增,
-例如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))加载语义分割数据集
-
+该部分内容已迁移至[附录](./appendix/datasets.md)

+ 6 - 0
docs/tutorials/deploy/index.rst

@@ -1,2 +1,8 @@
 多端部署
 多端部署
 ==============
 ==============
+
+.. toctree::
+   :maxdepth: 2
+   :caption: 文档目录:
+
+   

+ 3 - 1
paddlex/__init__.py

@@ -29,7 +29,6 @@ from . import cls
 from . import slim
 from . import slim
 from . import convertor
 from . import convertor
 from . import tools
 from . import tools
-from . import interpret
 from . import deploy
 from . import deploy
 
 
 try:
 try:
@@ -51,4 +50,7 @@ load_model = cv.models.load_model
 datasets = cv.datasets
 datasets = cv.datasets
 
 
 log_level = 2
 log_level = 2
+
+from . import interpret
+
 __version__ = '0.2.0.github'
 __version__ = '0.2.0.github'

+ 1 - 1
paddlex/cv/datasets/easydata_cls.py

@@ -28,7 +28,7 @@ class EasyDataCls(ImageNet):
 
 
     Args:
     Args:
         data_dir (str): 数据集所在的目录路径。
         data_dir (str): 数据集所在的目录路径。
-        file_list (str): 描述数据集图片文件和类别id的文件路径(文本内每行路径为相对data_dir的相对路)。
+        file_list (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对data_dir的相对路)。
         label_list (str): 描述数据集包含的类别信息文件路径。
         label_list (str): 描述数据集包含的类别信息文件路径。
         transforms (paddlex.cls.transforms): 数据集中每个样本的预处理/增强算子。
         transforms (paddlex.cls.transforms): 数据集中每个样本的预处理/增强算子。
         num_workers (int|str): 数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据
         num_workers (int|str): 数据集中样本在预处理过程中的线程或进程数。默认为'auto'。当设为'auto'时,根据

+ 3 - 2
paddlex/cv/models/base.py

@@ -139,9 +139,10 @@ class BaseAPI:
         dataset.num_samples = batch_size * batch_num
         dataset.num_samples = batch_size * batch_num
         try:
         try:
             from .slim.post_quantization import PaddleXPostTrainingQuantization
             from .slim.post_quantization import PaddleXPostTrainingQuantization
+            PaddleXPostTrainingQuantization._collect_target_varnames
         except:
         except:
             raise Exception(
             raise Exception(
-                "Model Quantization is not available, try to upgrade your paddlepaddle>=1.7.0"
+                "Model Quantization is not available, try to upgrade your paddlepaddle>=1.8.0"
             )
             )
         is_use_cache_file = True
         is_use_cache_file = True
         if cache_dir is None:
         if cache_dir is None:
@@ -544,4 +545,4 @@ class BaseAPI:
                                 best_accuracy))
                                 best_accuracy))
                 if eval_dataset is not None and early_stop:
                 if eval_dataset is not None and early_stop:
                     if earlystop(current_accuracy):
                     if earlystop(current_accuracy):
-                        break
+                        break

+ 68 - 90
paddlex/cv/models/slim/post_quantization.py

@@ -14,7 +14,7 @@
 
 
 from paddle.fluid.contrib.slim.quantization.quantization_pass import QuantizationTransformPass
 from paddle.fluid.contrib.slim.quantization.quantization_pass import QuantizationTransformPass
 from paddle.fluid.contrib.slim.quantization.quantization_pass import AddQuantDequantPass
 from paddle.fluid.contrib.slim.quantization.quantization_pass import AddQuantDequantPass
-from paddle.fluid.contrib.slim.quantization.quantization_pass import _op_real_in_out_name
+from paddle.fluid.contrib.slim.quantization.quantization_pass import _out_scale_op_list
 from paddle.fluid.contrib.slim.quantization import PostTrainingQuantization
 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
@@ -44,7 +44,6 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
         fp32 model. It uses calibrate data to calculate the scale factor of
         fp32 model. It uses calibrate data to calculate the scale factor of
         quantized variables, and inserts fake quant/dequant op to obtain the
         quantized variables, and inserts fake quant/dequant op to obtain the
         quantized model.
         quantized model.
-
         Args:
         Args:
             executor(fluid.Executor): The executor to load, run and save the
             executor(fluid.Executor): The executor to load, run and save the
                 quantized model.
                 quantized model.
@@ -78,6 +77,21 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
         Returns:
         Returns:
             None
             None
         '''
         '''
+        self._support_activation_quantize_type = [
+            'range_abs_max', 'moving_average_abs_max', 'abs_max'
+        ]
+        self._support_weight_quantize_type = ['abs_max', 'channel_wise_abs_max']
+        self._support_algo_type = ['KL', 'abs_max', 'min_max']
+        self._support_quantize_op_type = \
+            list(set(QuantizationTransformPass._supported_quantizable_op_type +
+                AddQuantDequantPass._supported_quantizable_op_type))
+        
+        # Check inputs
+        assert executor is not None, "The executor cannot be None."
+        assert batch_size > 0, "The batch_size should be greater than 0."
+        assert algo in self._support_algo_type, \
+            "The algo should be KL, abs_max or min_max."
+        
         self._executor = executor
         self._executor = executor
         self._dataset = dataset
         self._dataset = dataset
         self._batch_size = batch_size
         self._batch_size = batch_size
@@ -86,18 +100,19 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
         self._algo = algo
         self._algo = algo
         self._is_use_cache_file = is_use_cache_file
         self._is_use_cache_file = is_use_cache_file
         self._cache_dir = cache_dir
         self._cache_dir = cache_dir
+        self._activation_bits = 8
+        self._weight_bits = 8
+        self._activation_quantize_type = 'range_abs_max'
+        self._weight_quantize_type = 'channel_wise_abs_max'
         if self._is_use_cache_file and not os.path.exists(self._cache_dir):
         if self._is_use_cache_file and not os.path.exists(self._cache_dir):
             os.mkdir(self._cache_dir)
             os.mkdir(self._cache_dir)
 
 
-        supported_quantizable_op_type = \
-            QuantizationTransformPass._supported_quantizable_op_type + \
-            AddQuantDequantPass._supported_quantizable_op_type
         if is_full_quantize:
         if is_full_quantize:
-            self._quantizable_op_type = supported_quantizable_op_type
+            self._quantizable_op_type = self._support_quantize_op_type
         else:
         else:
             self._quantizable_op_type = quantizable_op_type
             self._quantizable_op_type = quantizable_op_type
             for op_type in self._quantizable_op_type:
             for op_type in self._quantizable_op_type:
-                assert op_type in supported_quantizable_op_type + \
+                assert op_type in self._support_quantize_op_type + \
                     AddQuantDequantPass._activation_type, \
                     AddQuantDequantPass._activation_type, \
                     op_type + " is not supported for quantization."
                     op_type + " is not supported for quantization."
 
 
@@ -107,25 +122,29 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
         self._fetch_list = list(outputs.values())
         self._fetch_list = list(outputs.values())
         self._data_loader = None
         self._data_loader = None
 
 
-        self._op_real_in_out_name = _op_real_in_out_name
+        self._out_scale_op_list = _out_scale_op_list
         self._bit_length = 8
         self._bit_length = 8
         self._quantized_weight_var_name = set()
         self._quantized_weight_var_name = set()
         self._quantized_act_var_name = set()
         self._quantized_act_var_name = set()
         self._sampling_data = {}
         self._sampling_data = {}
-        self._quantized_var_scale_factor = {}
+        self._quantized_var_kl_threshold = {}
+        self._quantized_var_min = {}
+        self._quantized_var_max = {}
+        self._quantized_var_abs_max = {}
 
 
     def quantize(self):
     def quantize(self):
         '''
         '''
         Quantize the fp32 model. Use calibrate data to calculate the scale factor of
         Quantize the fp32 model. Use calibrate data to calculate the scale factor of
         quantized variables, and inserts fake quant/dequant op to obtain the
         quantized variables, and inserts fake quant/dequant op to obtain the
         quantized model.
         quantized model.
-
         Args:
         Args:
             None
             None
         Returns:
         Returns:
             the program of quantized model.
             the program of quantized model.
         '''
         '''
-        self._preprocess()
+        self._load_model_data()
+        self._collect_target_varnames()
+        self._set_activation_persistable()
         batch_ct = 0
         batch_ct = 0
         for data in self._data_loader():
         for data in self._data_loader():
             batch_ct += 1
             batch_ct += 1
@@ -140,7 +159,10 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
                 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)
+            if self._algo == "KL":
+                self._sample_data(batch_id)
+            else:
+                self._sample_threshold()
             end = time.time()
             end = time.time()
             logging.debug('[Run batch data] Batch={}/{}, time_each_batch={} s.'.format(
             logging.debug('[Run batch data] Batch={}/{}, time_each_batch={} s.'.format(
                 str(batch_id + 1),
                 str(batch_id + 1),
@@ -150,19 +172,23 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
             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))
+        self._reset_activation_persistable()
         logging.info("Calculate scale factor ...")
         logging.info("Calculate scale factor ...")
-        self._calculate_scale_factor()
+        if self._algo == "KL":
+            self._calculate_kl_threshold()
         logging.info("Update the program ...")
         logging.info("Update the program ...")
-        self._update_program()
+        if self._algo in ["KL", "abs_max"]:
+            self._update_program()
+        else:
+            self._save_input_threhold()
         logging.info("Save ...")
         logging.info("Save ...")
-        self._save_output_scale()
+        self._save_output_threshold()
         logging.info("Finish quant!")
         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):
         '''
         '''
         Save the quantized model to the disk.
         Save the quantized model to the disk.
-
         Args:
         Args:
             save_model_path(str): The path to save the quantized model
             save_model_path(str): The path to save the quantized model
         Returns:
         Returns:
@@ -176,88 +202,47 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
             executor=self._executor,
             executor=self._executor,
             params_filename='__params__',
             params_filename='__params__',
             main_program=self._program)
             main_program=self._program)
-
-    def _preprocess(self):
+        
+    def _load_model_data(self):
         '''
         '''
-        Load model and set data loader, collect the variable names for sampling,
-        and set activation variables to be persistable.
+        Set data loader.
         '''
         '''
         feed_vars = [fluid.framework._get_var(var.name, self._program) \
         feed_vars = [fluid.framework._get_var(var.name, self._program) \
             for var in self._feed_list]
             for var in self._feed_list]
-
         self._data_loader = fluid.io.DataLoader.from_generator(
         self._data_loader = fluid.io.DataLoader.from_generator(
             feed_list=feed_vars, capacity=3 * self._batch_size, iterable=True)
             feed_list=feed_vars, capacity=3 * self._batch_size, iterable=True)
         self._data_loader.set_sample_list_generator(
         self._data_loader.set_sample_list_generator(
             self._dataset.generator(self._batch_size, drop_last=True),
             self._dataset.generator(self._batch_size, drop_last=True),
             places=self._place)
             places=self._place)
 
 
-        # collect the variable names for sampling
-        persistable_var_names = []
-        for var in self._program.list_vars():
-            if var.persistable:
-                persistable_var_names.append(var.name)
-
-        for op in self._program.global_block().ops:
-            op_type = op.type
-            if op_type in self._quantizable_op_type:
-                if op_type in ("conv2d", "depthwise_conv2d"):
-                    self._quantized_act_var_name.add(op.input("Input")[0])
-                    self._quantized_weight_var_name.add(op.input("Filter")[0])
-                    self._quantized_act_var_name.add(op.output("Output")[0])
-                elif op_type == "mul":
-                    if self._is_input_all_not_persistable(
-                            op, persistable_var_names):
-                        op._set_attr("skip_quant", True)
-                        logging.warning(
-                            "Skip quant a mul op for two input variables are not persistable"
-                        )
-                    else:
-                        self._quantized_act_var_name.add(op.input("X")[0])
-                        self._quantized_weight_var_name.add(op.input("Y")[0])
-                        self._quantized_act_var_name.add(op.output("Out")[0])
-                else:
-                    # process other quantizable op type, the input must all not persistable
-                    if self._is_input_all_not_persistable(
-                            op, persistable_var_names):
-                        input_output_name_list = self._op_real_in_out_name[
-                            op_type]
-                        for input_name in input_output_name_list[0]:
-                            for var_name in op.input(input_name):
-                                self._quantized_act_var_name.add(var_name)
-                        for output_name in input_output_name_list[1]:
-                            for var_name in op.output(output_name):
-                                self._quantized_act_var_name.add(var_name)
-
-        # set activation variables to be persistable, so can obtain
-        # the tensor data in sample_data
-        for var in self._program.list_vars():
-            if var.name in self._quantized_act_var_name:
-                var.persistable = True
-                
-    def _calculate_scale_factor(self):
+    def _calculate_kl_threshold(self):
         '''
         '''
-        Calculate the scale factor of quantized variables.
+        Calculate the KL threshold of quantized variables.
         '''
         '''
-        # apply channel_wise_abs_max quantization for weights
+        assert self._algo == "KL", "The algo should be KL to calculate kl threshold."
         ct = 1
         ct = 1
+        # Abs_max threshold for weights
         for var_name in self._quantized_weight_var_name:
         for var_name in self._quantized_weight_var_name:
             start = time.time()
             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
+            weight_data = self._sampling_data[var_name]
+            weight_threshold = None
+            if self._weight_quantize_type == "abs_max":
+                weight_threshold = np.max(np.abs(weight_data))
+            elif self._weight_quantize_type == "channel_wise_abs_max":
+                weight_threshold = []
+                for i in range(weight_data.shape[0]):
+                    abs_max_value = np.max(np.abs(weight_data[i]))
+                    weight_threshold.append(abs_max_value)
+            self._quantized_var_kl_threshold[var_name] = weight_threshold
             end = time.time()
             end = time.time()
             logging.debug('[Calculate weight] Weight_id={}/{}, time_each_weight={} s.'.format(
             logging.debug('[Calculate weight] Weight_id={}/{}, time_each_weight={} s.'.format(
                 str(ct),
                 str(ct),
                 str(len(self._quantized_weight_var_name)),
                 str(len(self._quantized_weight_var_name)),
                 str(end-start)))
                 str(end-start)))
             ct += 1
             ct += 1
-            
+
         ct = 1
         ct = 1
-        # apply kl quantization for activation
+        # KL threshold for activations
         if self._is_use_cache_file:
         if self._is_use_cache_file:
             for var_name in self._quantized_act_var_name:
             for var_name in self._quantized_act_var_name:
                 start = time.time()
                 start = time.time()
@@ -269,13 +254,8 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
                     sampling_data.append(np.load(file_path))
                     sampling_data.append(np.load(file_path))
                     os.remove(file_path)
                     os.remove(file_path)
                 sampling_data = np.concatenate(sampling_data)
                 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))
+                self._quantized_var_kl_threshold[var_name] = \
+                    self._get_kl_scaling_factor(np.abs(sampling_data))
                 end = time.time()
                 end = time.time()
                 logging.debug('[Calculate activation] Activation_id={}/{}, time_each_activation={} s.'.format(
                 logging.debug('[Calculate activation] Activation_id={}/{}, time_each_activation={} s.'.format(
                     str(ct),
                     str(ct),
@@ -287,15 +267,13 @@ class PaddleXPostTrainingQuantization(PostTrainingQuantization):
                 start = time.time()
                 start = time.time()
                 self._sampling_data[var_name] = np.concatenate(
                 self._sampling_data[var_name] = np.concatenate(
                     self._sampling_data[var_name])
                     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]))
+                self._quantized_var_kl_threshold[var_name] = \
+                    self._get_kl_scaling_factor(np.abs(self._sampling_data[var_name]))
                 end = time.time()
                 end = time.time()
                 logging.debug('[Calculate activation] Activation_id={}/{}, time_each_activation={} s.'.format(
                 logging.debug('[Calculate activation] Activation_id={}/{}, time_each_activation={} s.'.format(
                     str(ct),
                     str(ct),
                     str(len(self._quantized_act_var_name)),
                     str(len(self._quantized_act_var_name)),
                     str(end-start)))
                     str(end-start)))
-                ct += 1
+                ct += 1
+
+                

+ 21 - 6
paddlex/interpret/core/_session_preparation.py

@@ -13,15 +13,30 @@
 #limitations under the License.
 #limitations under the License.
 
 
 import os
 import os
+import os.path as osp
 import paddle.fluid as fluid
 import paddle.fluid as fluid
+import paddlex as pdx
 import numpy as np
 import numpy as np
 from paddle.fluid.param_attr import ParamAttr
 from paddle.fluid.param_attr import ParamAttr
-from ..as_data_reader.readers import preprocess_image
+from paddlex.interpret.as_data_reader.readers import preprocess_image
 
 
-root_path = os.environ['HOME']
-root_path = os.path.join(root_path, '.paddlex')
-h_pre_models = os.path.join(root_path, "pre_models")
-h_pre_models_kmeans = os.path.join(h_pre_models, "kmeans_model.pkl")
+def gen_user_home():
+    if "HOME" in os.environ:
+        home_path = os.environ["HOME"]
+        if os.path.exists(home_path) and os.path.isdir(home_path):
+            return home_path
+    return os.path.expanduser('~')
+
+
+root_path = gen_user_home()
+root_path = osp.join(root_path, '.paddlex')
+h_pre_models = osp.join(root_path, "pre_models")
+if not osp.exists(h_pre_models):
+    if not osp.exists(root_path):
+        os.makedirs(root_path)
+    url = "https://bj.bcebos.com/paddlex/interpret/pre_models.tar.gz"
+    pdx.utils.download_and_decompress(url, path=root_path)
+h_pre_models_kmeans = osp.join(h_pre_models, "kmeans_model.pkl")
 
 
 
 
 def paddle_get_fc_weights(var_name="fc_0.w_0"):
 def paddle_get_fc_weights(var_name="fc_0.w_0"):
@@ -110,4 +125,4 @@ def compute_features_for_kmeans(data_content):
     images = preprocess_image(data_content)  # transpose to [N, 3, H, W], scaled to [0.0, 1.0]
     images = preprocess_image(data_content)  # transpose to [N, 3, H, W], scaled to [0.0, 1.0]
     result = exe.run(prog, fetch_list=[resized_features], feed={'image': images})
     result = exe.run(prog, fetch_list=[resized_features], feed={'image': images})
 
 
-    return result[0][0]
+    return result[0][0]

+ 5 - 1
paddlex/interpret/core/interpretation_algorithms.py

@@ -17,9 +17,10 @@ import numpy as np
 import time
 import time
 
 
 from . import lime_base
 from . import lime_base
-from ..as_data_reader.readers import read_image
 from ._session_preparation import paddle_get_fc_weights, compute_features_for_kmeans, h_pre_models_kmeans
 from ._session_preparation import paddle_get_fc_weights, compute_features_for_kmeans, h_pre_models_kmeans
 from .normlime_base import combine_normlime_and_lime, get_feature_for_kmeans, load_kmeans_model
 from .normlime_base import combine_normlime_and_lime, get_feature_for_kmeans, load_kmeans_model
+from paddlex.interpret.as_data_reader.readers import read_image
+
 
 
 import cv2
 import cv2
 
 
@@ -442,3 +443,6 @@ def save_fig(data_, save_outdir, algorithm_name, num_samples=3000):
                 save_outdir, f_out
                 save_outdir, f_out
             )
             )
         )
         )
+    print('The image of intrepretation result save in {}'.format(os.path.join(
+                save_outdir, f_out
+            )))

+ 2 - 1
paddlex/interpret/core/lime_base.py

@@ -36,6 +36,7 @@ from skimage.color import gray2rgb
 from sklearn.linear_model import Ridge, lars_path
 from sklearn.linear_model import Ridge, lars_path
 from sklearn.utils import check_random_state
 from sklearn.utils import check_random_state
 
 
+import tqdm
 import copy
 import copy
 from functools import partial
 from functools import partial
 from skimage.segmentation import quickshift
 from skimage.segmentation import quickshift
@@ -509,7 +510,7 @@ class LimeImageInterpreter(object):
         labels = []
         labels = []
         data[0, :] = 1
         data[0, :] = 1
         imgs = []
         imgs = []
-        for row in data:
+        for row in tqdm.tqdm(data):
             temp = copy.deepcopy(image)
             temp = copy.deepcopy(image)
             zeros = np.where(row == 0)[0]
             zeros = np.where(row == 0)[0]
             mask = np.zeros(segments.shape).astype(bool)
             mask = np.zeros(segments.shape).astype(bool)

+ 1 - 1
paddlex/interpret/core/normlime_base.py

@@ -16,7 +16,7 @@ import os
 import numpy as np
 import numpy as np
 import glob
 import glob
 
 
-from ..as_data_reader.readers import read_image
+from paddlex.interpret.as_data_reader.readers import read_image
 from . import lime_base
 from . import lime_base
 from ._session_preparation import compute_features_for_kmeans, h_pre_models_kmeans
 from ._session_preparation import compute_features_for_kmeans, h_pre_models_kmeans
 
 

+ 7 - 4
paddlex/interpret/visualize.py

@@ -21,7 +21,7 @@ import paddlex as pdx
 from .interpretation_predict import interpretation_predict
 from .interpretation_predict import interpretation_predict
 from .core.interpretation import Interpretation
 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
 
 
 def visualize(img_file, 
 def visualize(img_file, 
               model, 
               model, 
@@ -44,6 +44,8 @@ def visualize(img_file,
         'Now the interpretation visualize only be supported in classifier!'
         'Now the interpretation visualize only be supported in classifier!'
     if model.status != 'Normal':
     if model.status != 'Normal':
         raise Exception('The interpretation only can deal with the Normal model')
         raise Exception('The interpretation only can deal with the Normal model')
+    if not osp.exists(save_dir):
+        os.makedirs(save_dir)
     model.arrange_transforms(
     model.arrange_transforms(
                 transforms=model.test_transforms, mode='test')
                 transforms=model.test_transforms, mode='test')
     tmp_transforms = copy.deepcopy(model.test_transforms)
     tmp_transforms = copy.deepcopy(model.test_transforms)
@@ -107,13 +109,14 @@ def get_normlime_interpreter(img, model, dataset, num_samples=3000, batch_size=5
     labels_name = None
     labels_name = None
     if dataset is not None:
     if dataset is not None:
         labels_name = dataset.labels
         labels_name = dataset.labels
-    root_path = os.environ['HOME']
+    root_path = gen_user_home()
     root_path = osp.join(root_path, '.paddlex')
     root_path = osp.join(root_path, '.paddlex')
     pre_models_path = osp.join(root_path, "pre_models")
     pre_models_path = osp.join(root_path, "pre_models")
     if not osp.exists(pre_models_path):
     if not osp.exists(pre_models_path):
-        os.makedirs(pre_models_path)
+        if not osp.exists(root_path):
+            os.makedirs(root_path)
         url = "https://bj.bcebos.com/paddlex/interpret/pre_models.tar.gz"
         url = "https://bj.bcebos.com/paddlex/interpret/pre_models.tar.gz"
-        pdx.utils.download_and_decompress(url, path=pre_models_path)
+        pdx.utils.download_and_decompress(url, path=root_path)
     npy_dir = precompute_for_normlime(precompute_predict_func, 
     npy_dir = precompute_for_normlime(precompute_predict_func, 
                                       dataset, 
                                       dataset, 
                                       num_samples=num_samples, 
                                       num_samples=num_samples, 

+ 2 - 3
requirements.txt

@@ -1,9 +1,8 @@
-pyyaml
 tqdm
 tqdm
 colorama
 colorama
 sklearn
 sklearn
 cython
 cython
 pycocotools
 pycocotools
-visualdl=1.3.0
-paddleslim=1.0.1
+visualdl >= 2.0.0b
+paddleslim == 1.0.1
 shapely
 shapely

+ 10 - 13
tutorials/interpret/interpret.py

@@ -24,18 +24,15 @@ test_dataset = pdx.datasets.ImageNet(
     transforms=model.test_transforms)
     transforms=model.test_transforms)
 
 
 # 可解释性可视化
 # 可解释性可视化
-# LIME算法
 pdx.interpret.visualize(
 pdx.interpret.visualize(
-    'mini_imagenet_veg/mushroom/n07734744_1106.JPEG',
-    model,
-    test_dataset,
-    algo='lime',
-    save_dir='./')
-
-# NormLIME算法
+         'mini_imagenet_veg/mushroom/n07734744_1106.JPEG', 
+          model,
+          test_dataset, 
+          algo='lime',
+          save_dir='./')
 pdx.interpret.visualize(
 pdx.interpret.visualize(
-    'mini_imagenet_veg/mushroom/n07734744_1106.JPEG',
-    model,
-    test_dataset,
-    algo='normlime',
-    save_dir='./')
+         'mini_imagenet_veg/mushroom/n07734744_1106.JPEG', 
+          model, 
+          test_dataset, 
+          algo='normlime',
+          save_dir='./')