未验证 提交 441634a1 编写于 作者: S SunAhong1993 提交者: GitHub

Merge pull request #5 from PaddlePaddle/develop

00
# 数据集转换
## 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)
```
...@@ -29,3 +29,4 @@ PaddleX目前支持主流的CV数据集格式和 `EasyData <https://ai.baidu.com ...@@ -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
# 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**: 训练过程中保存的模型路径 > > * **model_dir**: 训练过程中保存的模型路径, 注意需要使用导出的inference模型
* **use_gpu**: 是否使用GPU进行预测 > > * **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)
> ```
### 示例 > **参数
``` * **image(str|np.ndarray)**: 待预测的图片路径或np.ndarray,若为后者需注意为BGR格式
import paddlex * **topk(int)**: 图像分类时使用的参数,表示预测前topk个可能的分类
# 下
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)
```
...@@ -10,3 +10,4 @@ PaddleX API说明文档 ...@@ -10,3 +10,4 @@ PaddleX API说明文档
slim.md slim.md
load_model.md load_model.md
visualize.md visualize.md
deploy.md
...@@ -5,7 +5,7 @@ PaddleX提供了一系列模型预测和结果分析的可视化函数。 ...@@ -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') ...@@ -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='./') ...@@ -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加载的模型 >* **model** (paddlex.cv.models): 使用PaddleX加载的模型。
>* **sensitivities_file**: 模型各参数在验证集上计算得到的参数敏感度信息文件 >* **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') ...@@ -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)。
# 数据集格式说明
---
## 图像分类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))加载分类数据集。
# 数据集转换
当前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数据集 |
\ No newline at end of file
...@@ -8,6 +8,9 @@ ...@@ -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
......
# 数据集格式说明 # 数据集格式说明
该部分内容已迁移至[附录](./appendix/datasets.md)
---
## 图像分类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))加载语义分割数据集
多端部署 多端部署
============== ==============
.. toctree::
:maxdepth: 2
:caption: 文档目录:
...@@ -29,7 +29,6 @@ from . import cls ...@@ -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 ...@@ -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'
...@@ -28,7 +28,7 @@ class EasyDataCls(ImageNet): ...@@ -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'时,根据
......
...@@ -139,9 +139,10 @@ class BaseAPI: ...@@ -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: ...@@ -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
\ No newline at end of file
...@@ -14,7 +14,7 @@ ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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, Set data loader.
and set activation variables to be persistable.
''' '''
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 def _calculate_kl_threshold(self):
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):
''' '''
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] weight_data = self._sampling_data[var_name]
scale_factor_per_channel = [] weight_threshold = None
for i in range(data.shape[0]): if self._weight_quantize_type == "abs_max":
abs_max_value = np.max(np.abs(data[i])) weight_threshold = np.max(np.abs(weight_data))
scale_factor_per_channel.append(abs_max_value) elif self._weight_quantize_type == "channel_wise_abs_max":
self._quantized_var_scale_factor[ weight_threshold = []
var_name] = scale_factor_per_channel 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): ...@@ -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)
self._quantized_var_kl_threshold[var_name] = \
if self._algo == "KL": self._get_kl_scaling_factor(np.abs(sampling_data))
self._quantized_var_scale_factor[var_name] = \
self._get_kl_scaling_factor(np.abs(sampling_data))
else:
self._quantized_var_scale_factor[var_name] = \
np.max(np.abs(sampling_data))
end = time.time() 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): ...@@ -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_kl_threshold[var_name] = \
self._quantized_var_scale_factor[var_name] = \ self._get_kl_scaling_factor(np.abs(self._sampling_data[var_name]))
self._get_kl_scaling_factor(np.abs(self._sampling_data[var_name]))
else:
self._quantized_var_scale_factor[var_name] = \
np.max(np.abs(self._sampling_data[var_name]))
end = time.time() 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
\ No newline at end of file
\ No newline at end of file
...@@ -13,15 +13,30 @@ ...@@ -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'] def gen_user_home():
root_path = os.path.join(root_path, '.paddlex') if "HOME" in os.environ:
h_pre_models = os.path.join(root_path, "pre_models") home_path = os.environ["HOME"]
h_pre_models_kmeans = os.path.join(h_pre_models, "kmeans_model.pkl") 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): ...@@ -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]
\ No newline at end of file
...@@ -17,9 +17,10 @@ import numpy as np ...@@ -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): ...@@ -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
)))
...@@ -36,6 +36,7 @@ from skimage.color import gray2rgb ...@@ -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): ...@@ -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)
......
...@@ -16,7 +16,7 @@ import os ...@@ -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
......
...@@ -21,7 +21,7 @@ import paddlex as pdx ...@@ -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, ...@@ -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 ...@@ -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,
......
...@@ -24,18 +24,15 @@ test_dataset = pdx.datasets.ImageNet( ...@@ -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', 'mini_imagenet_veg/mushroom/n07734744_1106.JPEG',
model, model,
test_dataset, test_dataset,
algo='lime', algo='lime',
save_dir='./') save_dir='./')
# NormLIME算法
pdx.interpret.visualize( pdx.interpret.visualize(
'mini_imagenet_veg/mushroom/n07734744_1106.JPEG', 'mini_imagenet_veg/mushroom/n07734744_1106.JPEG',
model, model,
test_dataset, test_dataset,
algo='normlime', algo='normlime',
save_dir='./') save_dir='./')
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册