diff --git a/README.md b/README.md
index 5289fb2e4d53ef57ee39b86a1a4c61025a1d101f..063ae08aac281782e319709d4457049f6e3fb48c 100755
--- a/README.md
+++ b/README.md
@@ -4,40 +4,51 @@
-
-
-
+
+
+
+
+
+
+
+
-PaddleSlim是一个专注于深度学习模型压缩的工具库,提供**低比特量化、知识蒸馏、稀疏化和模型结构搜索**等模型压缩策略,帮助用户快速实现模型的小型化。
+PaddleSlim是一个专注于深度学习模型压缩的工具库,提供**低比特量化、知识蒸馏、稀疏化和模型结构搜索**等模型压缩策略,帮助开发者快速实现模型的小型化。
## 产品动态
+- 🔥 **2022.08.16:自动化压缩功能升级**
+ - 支持直接加载ONNX模型和Paddle模型导出至ONNX
+ - 发布量化分析工具试用版,发布[YOLO系列离线量化工具](example/post_training_quantization/pytorch_yolo_series/)
+ - 更新[YOLO-Series自动化压缩模型库](example/auto_compression/pytorch_yolo_series)
+
+ | 模型 | Base mAPval
0.5:0.95 | ACT量化mAPval
0.5:0.95 | 模型体积压缩比 | 预测时延FP32
| 预测时延INT8
| 预测加速比 |
+ | :-------- |:-------- |:--------: | :--------: | :---------------------: | :----------------: | :----------------: |
+ | PPYOLOE-s | 43.1 | 42.6 | 3.9倍 | 6.51ms | 2.12ms | 3.1倍 |
+ | YOLOv5s | 37.4 | 36.9 | 3.8倍 | 5.95ms | 1.87ms | 3.2倍 |
+ | YOLOv6s | 42.4 | 41.3 | 3.9倍 | 9.06ms | 1.83ms | 5.0倍 |
+ | YOLOv7 | 51.1 | 50.9 | 3.9倍 | 26.84ms | 4.55ms | 5.9倍 |
+ | YOLOv7-Tiny | 37.3 | 37.0 | 3.9倍 | 5.06ms | 1.68ms | 3.0倍 |
+
+
- 🔥 **2022.07.01: 发布[v2.3.0版本](https://github.com/PaddlePaddle/PaddleSlim/releases/tag/v2.3.0)**
- 发布[自动化压缩功能](example/auto_compression)
-
- - 支持代码无感知压缩:用户只需提供推理模型文件和数据,既可进行离线量化(PTQ)、量化训练(QAT)、稀疏训练等压缩任务。
+ - 支持代码无感知压缩:开发者只需提供推理模型文件和数据,既可进行离线量化(PTQ)、量化训练(QAT)、稀疏训练等压缩任务。
- 支持自动策略选择,根据任务特点和部署环境特性:自动搜索合适的离线量化方法,自动搜索最佳的压缩策略组合方式。
- 发布[自然语言处理](example/auto_compression/nlp)、[图像语义分割](example/auto_compression/semantic_segmentation)、[图像目标检测](example/auto_compression/detection)三个方向的自动化压缩示例。
- - 发布`X2Paddle`模型自动化压缩方案:[YOLOv5](example/auto_compression/pytorch_yolov5)、[YOLOv6](example/auto_compression/pytorch_yolov6)、[YOLOv7](example/auto_compression/pytorch_yolov7)、[HuggingFace](example/auto_compression/pytorch_huggingface)、[MobileNet](example/auto_compression/tensorflow_mobilenet)。
-
+ - 发布`X2Paddle`模型自动化压缩方案:[YOLOv5](example/auto_compression/pytorch_yolo_series)、[YOLOv6](example/auto_compression/pytorch_yolo_series)、[YOLOv7](example/auto_compression/pytorch_yolo_series)、[HuggingFace](example/auto_compression/pytorch_huggingface)、[MobileNet](example/auto_compression/tensorflow_mobilenet)。
- 升级量化功能
-
- - 统一量化模型格式
- - 离线量化支持while op
- - 新增7种[离线量化方法](docs/zh_cn/tutorials/quant/post_training_quantization.md), 包括HIST, AVG, EMD, Bias Correction, AdaRound等
- - 修复BERT大模型量化训练过慢的问题
-
+ - 统一量化模型格式;离线量化支持while op;修复BERT大模型量化训练过慢的问题。
+ - 新增7种[离线量化方法](docs/zh_cn/tutorials/quant/post_training_quantization.md), 包括HIST, AVG, EMD, Bias Correction, AdaRound等。
- 支持半结构化稀疏训练
-
- 新增延时预估工具
+ - 支持对稀疏化模型、低比特量化模型的性能预估;支持预估指定模型在特定部署环境下 (ARM CPU + Paddle Lite) 的推理性能;提供 SD625、SD710、RK3288 芯片 + Paddle Lite 的预估接口。
+ - 提供部署环境自动扩展工具,可以自动增加在更多 ARM CPU 设备上的预估工具。
- - 支持预估指定模型在特定部署环境下 (ARM CPU + Paddle Lite) 的推理性能
- - 提供部署环境自动扩展工具,可以自动增加在更多 ARM CPU 设备上的预估工具
- - 支持对稀疏化模型、低比特量化模型的性能预估
- - 提供 SD625、SD710、RK3288 芯片 + Paddle Lite 的预估接口
-
+
+历史更新
- **2021.11.15: 发布v2.2.0版本**
@@ -52,6 +63,7 @@ PaddleSlim是一个专注于深度学习模型压缩的工具库,提供**低
更多信息请参考:[release note](https://github.com/PaddlePaddle/PaddleSlim/releases)
+
## 基础压缩功能概览
diff --git a/demo/quant/pact_quant_aware/train.py b/demo/quant/pact_quant_aware/train.py
index fb70c0fc22fae462249b54a02145749b2ef40a1b..67945a455d261681046f42caa19e8f1c18a37380 100644
--- a/demo/quant/pact_quant_aware/train.py
+++ b/demo/quant/pact_quant_aware/train.py
@@ -65,6 +65,8 @@ add_arg('use_pact', bool, True,
"Whether to use PACT or not.")
add_arg('analysis', bool, False,
"Whether analysis variables distribution.")
+add_arg('onnx_format', bool, False,
+ "Whether use onnx format or not.")
add_arg('ce_test', bool, False, "Whether to CE test.")
# yapf: enable
@@ -257,6 +259,8 @@ def compress(args):
'window_size': 10000,
# The decay coefficient of moving average, default is 0.9
'moving_rate': 0.9,
+ # Whether use onnx format or not
+ 'onnx_format': args.onnx_format,
}
# 2. quantization transform programs (training aware)
@@ -298,9 +302,9 @@ def compress(args):
places,
quant_config,
scope=None,
- act_preprocess_func=act_preprocess_func,
- optimizer_func=optimizer_func,
- executor=executor,
+ act_preprocess_func=None,
+ optimizer_func=None,
+ executor=None,
for_test=True)
compiled_train_prog = quant_aware(
train_prog,
@@ -425,29 +429,23 @@ def compress(args):
# 3. Freeze the graph after training by adjusting the quantize
# operators' order for the inference.
# The dtype of float_program's weights is float32, but in int8 range.
- float_program, int8_program = convert(val_program, places, quant_config, \
- scope=None, \
- save_int8=True)
+ model_path = os.path.join(quantization_model_save_dir, args.model)
+ if not os.path.isdir(model_path):
+ os.makedirs(model_path)
+ float_program = convert(val_program, places, quant_config)
_logger.info("eval best_model after convert")
final_acc1 = test(best_epoch, float_program)
_logger.info("final acc:{}".format(final_acc1))
# 4. Save inference model
- model_path = os.path.join(quantization_model_save_dir, args.model,
- 'act_' + quant_config['activation_quantize_type']
- + '_w_' + quant_config['weight_quantize_type'])
- float_path = os.path.join(model_path, 'float')
- if not os.path.isdir(model_path):
- os.makedirs(model_path)
-
paddle.fluid.io.save_inference_model(
- dirname=float_path,
+ dirname=model_path,
feeded_var_names=[image.name],
target_vars=[out],
executor=exe,
main_program=float_program,
- model_filename=float_path + '/model',
- params_filename=float_path + '/params')
+ model_filename=model_path + '/model.pdmodel',
+ params_filename=model_path + '/model.pdiparams')
def main():
diff --git a/demo/quant/quant_aware/train.py b/demo/quant/quant_aware/train.py
index abf6073ec7bce5f870a5b3c1d0ca545351791833..7fc133a465f6e1f90cee34848a024897faeaf85d 100644
--- a/demo/quant/quant_aware/train.py
+++ b/demo/quant/quant_aware/train.py
@@ -126,6 +126,8 @@ def compress(args):
'window_size': 10000,
# The decay coefficient of moving average, default is 0.9
'moving_rate': 0.9,
+ # Whether use onnx format or not
+ 'onnx_format': args.onnx_format,
}
pretrain = True
@@ -294,10 +296,7 @@ def compress(args):
# operators' order for the inference.
# The dtype of float_program's weights is float32, but in int8 range.
############################################################################################################
- float_program, int8_program = convert(val_program, places, quant_config, \
- scope=None, \
- save_int8=True,
- onnx_format=args.onnx_format)
+ float_program = convert(val_program, places, quant_config)
print("eval best_model after convert")
final_acc1 = test(best_epoch, float_program)
############################################################################################################
diff --git a/demo/quant/quant_post/eval.py b/demo/quant/quant_post/eval.py
index 310eacd08d833bdcae2fc9ede5323f602be0f2c3..e8184e848c3e0785c398ef3dcdf53a1903e3cf86 100755
--- a/demo/quant/quant_post/eval.py
+++ b/demo/quant/quant_post/eval.py
@@ -21,8 +21,7 @@ import functools
import paddle
sys.path[0] = os.path.join(
os.path.dirname("__file__"), os.path.pardir, os.path.pardir)
-sys.path[1] = os.path.join(
- os.path.dirname("__file__"), os.path.pardir)
+sys.path[1] = os.path.join(os.path.dirname("__file__"), os.path.pardir)
import imagenet_reader as reader
from utility import add_arguments, print_arguments
@@ -31,8 +30,8 @@ parser = argparse.ArgumentParser(description=__doc__)
add_arg = functools.partial(add_arguments, argparser=parser)
add_arg('use_gpu', bool, True, "Whether to use GPU or not.")
add_arg('model_path', str, "./pruning/checkpoints/resnet50/2/eval_model/", "Whether to use pretrained model.")
-add_arg('model_name', str, '__model__', "model filename for inference model")
-add_arg('params_name', str, '__params__', "params filename for inference model")
+add_arg('model_name', str, 'model.pdmodel', "model filename for inference model")
+add_arg('params_name', str, 'model.pdiparams', "params filename for inference model")
add_arg('batch_size', int, 64, "Minibatch size.")
# yapf: enable
diff --git a/docs/zh_cn/api_cn/static/auto-compression/auto_compression_api.rst b/docs/zh_cn/api_cn/static/auto-compression/auto_compression_api.rst
index f5731df45e0309dfca0d69a8c2a1c9ba5d5db5c7..c308413db6c32088b766bf50d5ed3c7dc0570677 100644
--- a/docs/zh_cn/api_cn/static/auto-compression/auto_compression_api.rst
+++ b/docs/zh_cn/api_cn/static/auto-compression/auto_compression_api.rst
@@ -3,19 +3,19 @@ AutoCompression自动压缩功能
AutoCompression
---------------
-.. py:class:: paddleslim.auto_compression.AutoCompression(model_dir, model_filename, params_filename, save_dir, strategy_config, train_config, train_dataloader, eval_callback, devices='gpu')
+.. py:class:: paddleslim.auto_compression.AutoCompression(model_dir, train_dataloader, model_filename, params_filename, save_dir, strategy_config, train_config, eval_callback, devices='gpu')
-`源代码 `_
+`源代码 `_
根据指定的配置对使用 ``paddle.jit.save`` 接口或者 ``paddle.static.save_inference_model`` 接口保存的推理模型进行压缩。
**参数: **
- **model_dir(str)** - 需要压缩的推理模型所在的目录。
+- **train_dataloader(paddle.io.DataLoader)** - 训练数据迭代器。注意:如果选择离线量化超参搜索策略的话, ``train_dataloader`` 和 ``eval_callback`` 设置相同的数据读取即可。
- **model_filename(str)** - 需要压缩的推理模型文件名称。
- **params_filename(str)** - 需要压缩的推理模型参数文件名称。
- **save_dir(str)** - 压缩后模型的所保存的目录。
-- **train_dataloader(paddle.io.DataLoader)** - 训练数据迭代器。注意:如果选择离线量化超参搜索策略的话, ``train_dataloader`` 和 ``eval_callback`` 设置相同的数据读取即可。
- **train_config(dict)** - 训练配置。可以配置的参数请参考: ``_ 。注意:如果选择离线量化超参搜索策略的话, ``train_config`` 直接设置为 ``None`` 即可。
- **strategy_config(dict, list(dict), 可选)** - 使用的压缩策略,可以通过设置多个单种策略来并行使用这些压缩方式。字典的关键字必须在:
``Quantization`` (量化配置, 可配置的参数参考 ``_ ),
@@ -82,13 +82,13 @@ AutoCompression
eval_dataloader = Cifar10(mode='eval')
- ac = AutoCompression(model_path, model_filename, params_filename, save_dir, \
+ ac = AutoCompression(model_path, train_dataloader, model_filename, params_filename, save_dir, \
strategy_config="Quantization": Quantization(**default_ptq_config),
"Distillation": HyperParameterOptimization(**default_distill_config)}, \
- train_config=None, train_dataloader=train_dataloader, eval_callback=eval_dataloader,devices='gpu')
+ train_config=None, eval_callback=eval_dataloader,devices='gpu')
```
diff --git a/docs/zh_cn/api_cn/static/quant/quantization_api.rst b/docs/zh_cn/api_cn/static/quant/quantization_api.rst
index a12e4e9b574ec672b2611c23f6d8aeb1785248fd..f2d7b77d54e87a7ae897f02fa391b77c2fae5e2f 100644
--- a/docs/zh_cn/api_cn/static/quant/quantization_api.rst
+++ b/docs/zh_cn/api_cn/static/quant/quantization_api.rst
@@ -118,7 +118,7 @@ quant_post_dynamic
quant_post_static
---------------
-.. py:function:: paddleslim.quant.quant_post_static(executor,model_dir, quantize_model_path, batch_generator=None, sample_generator=None, model_filename=None, params_filename=None, save_model_filename='__model__', save_params_filename='__params__', batch_size=16, batch_nums=None, scope=None, algo='KL', round_type='round', quantizable_op_type=["conv2d","depthwise_conv2d","mul"], is_full_quantize=False, weight_bits=8, activation_bits=8, activation_quantize_type='range_abs_max', weight_quantize_type='channel_wise_abs_max', onnx_format=False, skip_tensor_list=None, optimize_model=False)
+.. py:function:: paddleslim.quant.quant_post_static(executor,model_dir, quantize_model_path, batch_generator=None, sample_generator=None, model_filename=None, params_filename=None, save_model_filename='model.pdmodel', save_params_filename='model.pdiparams', batch_size=16, batch_nums=None, scope=None, algo='KL', round_type='round', quantizable_op_type=["conv2d","depthwise_conv2d","mul"], is_full_quantize=False, weight_bits=8, activation_bits=8, activation_quantize_type='range_abs_max', weight_quantize_type='channel_wise_abs_max', onnx_format=False, skip_tensor_list=None, optimize_model=False)
`源代码 `_
@@ -217,15 +217,15 @@ quant_post_static
target_vars=[out],
main_program=val_prog,
executor=exe,
- model_filename='__model__',
- params_filename='__params__')
+ model_filename='model.pdmodel',
+ params_filename='model.pdiparams')
quant_post_static(
executor=exe,
model_dir='./model_path',
quantize_model_path='./save_path',
sample_generator=val_reader,
- model_filename='__model__',
- params_filename='__params__',
+ model_filename='model.pdmodel',
+ params_filename='model.pdiparams',
batch_size=16,
batch_nums=10)
diff --git a/example/auto_compression/README.md b/example/auto_compression/README.md
index e907908bcf4e8fb05f0787cc6256407dc1ae18d4..cb3b9277da0d281ef32e0a4d21f19a51d7b2b8d3 100644
--- a/example/auto_compression/README.md
+++ b/example/auto_compression/README.md
@@ -82,15 +82,15 @@ ACT相比传统的模型压缩方法,
| [语义分割](./semantic_segmentation) | UNet | 65.00 | 64.93 | 15.29 | 10.23 | **1.49** | NVIDIA Tesla T4 |
| NLP | PP-MiniLM | 72.81 | 72.44 | 128.01 | 17.97 | **7.12** | NVIDIA Tesla T4 |
| NLP | ERNIE 3.0-Medium | 73.09 | 72.40 | 29.25(fp16) | 19.61 | **1.49** | NVIDIA Tesla T4 |
-| [目标检测](./pytorch_yolov5) | YOLOv5s
(PyTorch) | 37.40 | 36.9 | 5.95 | 1.87 | **3.18** | NVIDIA Tesla T4 |
-| [目标检测](./pytorch_yolov6) | YOLOv6s
(PyTorch) | 42.4 | 41.3 | 9.06 | 1.83 | **4.95** | NVIDIA Tesla T4 |
-| [目标检测](./pytorch_yolov7) | YOLOv7
(PyTorch) | 51.1 | 50.8 | 26.84 | 4.55 | **5.89** | NVIDIA Tesla T4 |
-| [目标检测](./detection) | PP-YOLOE-l | 50.9 | 50.6 | 11.2 | 6.7 | **1.67** | NVIDIA Tesla V100 |
+| [目标检测](./pytorch_yolo_series) | YOLOv5s
(PyTorch) | 37.40 | 36.9 | 5.95 | 1.87 | **3.18** | NVIDIA Tesla T4 |
+| [目标检测](./pytorch_yolo_series) | YOLOv6s
(PyTorch) | 42.4 | 41.3 | 9.06 | 1.83 | **4.95** | NVIDIA Tesla T4 |
+| [目标检测](./pytorch_yolo_series) | YOLOv7
(PyTorch) | 51.1 | 50.8 | 26.84 | 4.55 | **5.89** | NVIDIA Tesla T4 |
+| [目标检测](./detection) | PP-YOLOE-s | 43.1 | 42.6 | 6.51 | 2.12 | **3.07** | NVIDIA Tesla T4 |
| [图像分类](./image_classification) | MobileNetV1
(TensorFlow) | 71.0 | 70.22 | 30.45 | 15.86 | **1.92** | SDMM865(骁龙865) |
- 备注:目标检测精度指标为mAP(0.5:0.95)精度测量结果。图像分割精度指标为IoU精度测量结果。
- 更多飞桨模型应用示例及Benchmark可以参考:[图像分类](./image_classification),[目标检测](./detection),[语义分割](./semantic_segmentation),[自然语言处理](./nlp)
-- 更多其它框架应用示例及Benchmark可以参考:[YOLOv5(PyTorch)](./pytorch_yolov5),[YOLOv6(PyTorch)](./pytorch_yolov6),[YOLOv7(PyTorch)](./pytorch_yolov7),[HuggingFace(PyTorch)](./pytorch_huggingface),[MobileNet(TensorFlow)](./tensorflow_mobilenet)。
+- 更多其它框架应用示例及Benchmark可以参考:[YOLOv5(PyTorch)](./pytorch_yolo_series),[YOLOv6(PyTorch)](./pytorch_yolo_series),[YOLOv7(PyTorch)](./pytorch_yolo_series),[HuggingFace(PyTorch)](./pytorch_huggingface),[MobileNet(TensorFlow)](./tensorflow_mobilenet)。
## **环境准备**
diff --git a/example/auto_compression/detection/configs/ppyoloe_l_qat_dis.yaml b/example/auto_compression/detection/configs/ppyoloe_l_qat_dis.yaml
index 0b28ef893b0a2d69bd57c91079bb31f0f9c0f530..1727e5337865455d6a8bec28da8b69e12b8fcb52 100644
--- a/example/auto_compression/detection/configs/ppyoloe_l_qat_dis.yaml
+++ b/example/auto_compression/detection/configs/ppyoloe_l_qat_dis.yaml
@@ -12,6 +12,7 @@ Distillation:
loss: soft_label
Quantization:
+ onnx_format: true
use_pact: true
activation_quantize_type: 'moving_average_abs_max'
quantize_op_types:
diff --git a/example/auto_compression/detection/configs/ppyoloe_s_qat_dis.yaml b/example/auto_compression/detection/configs/ppyoloe_s_qat_dis.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..466c9c2b53c121bec28052010248b48636b3bf40
--- /dev/null
+++ b/example/auto_compression/detection/configs/ppyoloe_s_qat_dis.yaml
@@ -0,0 +1,34 @@
+
+Global:
+ reader_config: configs/yolo_reader.yml
+ input_list: ['image']
+ arch: PPYOLOE # When export exclude_nms=True, need set arch: PPYOLOE
+ Evaluation: True
+ model_dir: ./ppyoloe_crn_s_300e_coco
+ model_filename: model.pdmodel
+ params_filename: model.pdiparams
+
+Distillation:
+ alpha: 1.0
+ loss: soft_label
+
+Quantization:
+ onnx_format: true
+ use_pact: true
+ activation_quantize_type: 'moving_average_abs_max'
+ quantize_op_types:
+ - conv2d
+ - depthwise_conv2d
+
+TrainConfig:
+ train_iter: 5000
+ eval_iter: 1000
+ learning_rate:
+ type: CosineAnnealingDecay
+ learning_rate: 0.00003
+ T_max: 6000
+ optimizer_builder:
+ optimizer:
+ type: SGD
+ weight_decay: 4.0e-05
+
diff --git a/example/auto_compression/detection/eval.py b/example/auto_compression/detection/eval.py
index 3a723653d3472fd1c4f5b267206f6d9255cfdf20..a4ea554c869e5023fbd914d1d379fe6602a3a9de 100644
--- a/example/auto_compression/detection/eval.py
+++ b/example/auto_compression/detection/eval.py
@@ -20,7 +20,7 @@ import paddle
from ppdet.core.workspace import load_config, merge_config
from ppdet.core.workspace import create
from ppdet.metrics import COCOMetric, VOCMetric, KeyPointTopDownCOCOEval
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config as load_slim_config
from keypoint_utils import keypoint_post_process
diff --git a/example/auto_compression/detection/run.py b/example/auto_compression/detection/run.py
index b7cc75051981c891c1701f08f1f6d239a91727e4..523f2439e5958c3d5ed7bc3a697edaa103fabd28 100644
--- a/example/auto_compression/detection/run.py
+++ b/example/auto_compression/detection/run.py
@@ -20,7 +20,7 @@ import paddle
from ppdet.core.workspace import load_config, merge_config
from ppdet.core.workspace import create
from ppdet.metrics import COCOMetric, VOCMetric, KeyPointTopDownCOCOEval
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config as load_slim_config
from paddleslim.auto_compression import AutoCompression
from keypoint_utils import keypoint_post_process
@@ -121,7 +121,8 @@ def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
def main():
global global_config
all_config = load_slim_config(FLAGS.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
+ assert "Global" in all_config, "Key 'Global' not found in config file. \n{}".format(
+ all_config)
global_config = all_config["Global"]
reader_cfg = load_config(global_config['reader_config'])
diff --git a/example/auto_compression/hyperparameter_tutorial.md b/example/auto_compression/hyperparameter_tutorial.md
index 6d423a9f9982485797fb98cd266cd6c94f5b6452..29ce9fefce5c1f922e8e57227e9a9f4fa1db7ba5 100644
--- a/example/auto_compression/hyperparameter_tutorial.md
+++ b/example/auto_compression/hyperparameter_tutorial.md
@@ -1,9 +1,9 @@
-# ACT超参详细教程
+# 1. ACT超参详细教程
-## 各压缩方法超参解析
+## 1.1 各压缩方法超参解析
-#### 配置定制量化方案
+### 1.1.1 量化(quantization)
量化参数主要设置量化比特数和量化op类型,其中量化op包含卷积层(conv2d, depthwise_conv2d)和全连接层(mul, matmul_v2)。以下为只量化卷积层的示例:
```yaml
@@ -20,69 +20,148 @@ Quantization:
moving_rate: 0.9 # 'moving_average_abs_max' 量化方式的衰减系数,默认 0.9。
for_tensorrt: false # 量化后的模型是否使用 TensorRT 进行预测。如果是的话,量化op类型为: TENSORRT_OP_TYPES 。默认值为False.
is_full_quantize: false # 是否全量化
+ onnx_format: false # 是否采用ONNX量化标准格式
```
-#### 配置定制蒸馏策略
+以上配置项说明如下:
+
+
+- use_pact: 是否开启PACT。一般情况下,开启PACT后,量化产出的模型精度会更高。算法原理请参考:[PACT: Parameterized Clipping Activation for Quantized Neural Networks](https://arxiv.org/abs/1805.06085)
+- activation_bits: 激活量化bit数,可选1~8。默认为8。
+- weight_bits: 参数量化bit数,可选1~8。默认为8。
+- activation_quantize_type: 激活量化方式,可选 'abs_max' , 'range_abs_max' , 'moving_average_abs_max' 。如果使用 TensorRT 加载量化后的模型来预测,请使用 'range_abs_max' 或 'moving_average_abs_max' 。默认为 'moving_average_abs_max'。
+- weight_quantize_type: 参数量化方式。可选 'abs_max' , 'channel_wise_abs_max' , 'range_abs_max' , 'moving_average_abs_max' 。如果使用 TensorRT 加载量化后的模型来预测,请使用 'channel_wise_abs_max' 。 默认 'channel_wise_abs_max' 。
+- not_quant_pattern: 所有 `name_scope` 包含 'not_quant_pattern' 字符串的 op ,都不量化。 `name_scope` 设置方式请参考 [paddle.static.name_scope](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/static/name_scope_cn.html#name-scope)。
+- quantize_op_types:需要进行量化的OP类型。通过以下代码输出所有支持量化的OP类型:
+```
+from paddleslim.quant.quanter import TRANSFORM_PASS_OP_TYPES,QUANT_DEQUANT_PASS_OP_TYPES
+print(TRANSFORM_PASS_OP_TYPES + QUANT_DEQUANT_PASS_OP_TYPES)
+```
+- dtype: 量化后的参数类型,默认 int8 , 目前仅支持 int8
+- window_size: 'range_abs_max' 量化方式的 window size ,默认10000。
+- moving_rate: 'moving_average_abs_max' 量化方式的衰减系数,默认 0.9。
+- for_tensorrt: 量化后的模型是否使用 TensorRT 进行预测。默认值为False. 通过以下代码,输出for_tensorrt=True时会量化到的OP:
+```
+from paddleslim.quant.quanter import TENSORRT_OP_TYPES
+print(TENSORRT_OP_TYPES)
+```
+
+- is_full_quantize: 是否量化所有可支持op类型。默认值为False.
+
+
+### 1.1.2 知识蒸馏(knowledge distillation)
蒸馏参数主要设置蒸馏节点(`node`)和教师预测模型路径,如下所示:
```yaml
Distillation:
- # alpha: 蒸馏loss所占权重;可输入多个数值,支持不同节点之间使用不同的ahpha值
alpha: 1.0
- # loss: 蒸馏loss算法;可输入多个loss,支持不同节点之间使用不同的loss算法
loss: l2
- # node: 蒸馏节点,即某层输出的变量名称,可以选择:
- # 1. 使用自蒸馏的话,蒸馏结点仅包含学生网络节点即可, 支持多节点蒸馏;
- # 2. 使用其他蒸馏的话,蒸馏节点需要包含教师网络节点和对应的学生网络节点,
- # 每两个节点组成一对,分别属于教师模型和学生模型,支持多节点蒸馏。
node:
- relu_30.tmp_0
- # teacher_model_dir: 保存预测模型文件和预测模型参数文件的文件夹名称
+
teacher_model_dir: ./inference_model
# teacher_model_filename: 预测模型文件,格式为 *.pdmodel 或 __model__
teacher_model_filename: model.pdmodel
# teacher_params_filename: 预测模型参数文件,格式为 *.pdiparams 或 __params__
teacher_params_filename: model.pdiparams
```
+以上配置项说明如下:
+
+- alpha: 蒸馏loss所占权重;可输入多个数值,支持不同节点之间使用不同的alpha值。
+- loss: 蒸馏loss算法;可输入多个loss,支持不同节点之间使用不同的loss算法。 可选"soft_label"、“l2”或“fsp”。也可自定义loss。具体定义和使用可参考[知识蒸馏API文档](https://paddleslim.readthedocs.io/zh_CN/latest/api_cn/static/dist/single_distiller_api.html)。
+- node: 蒸馏节点,即某层输出的变量名称。该选项设置方式分两种情况:
-- 蒸馏loss目前支持的有:fsp,l2,soft_label,也可自定义loss。具体定义和使用可参考[知识蒸馏API文档](https://paddleslim.readthedocs.io/zh_CN/latest/api_cn/static/dist/single_distiller_api.html)。
+ - 自蒸馏:教师模型为压缩前的推理模型,学生模型为压缩后的推理模型。‘node’ 可设置为变量名称的列表,ACT会自动在该列表中的变量上依次添加知识蒸馏loss。示例如下:
+ ```
+ node:
+ - relu_30.tmp_0
+ - relu_31.tmp_0
+ ```
+ 上述示例,会添加两个知识蒸馏loss。第一个loss的输入为教师模型和学生模型的 'relu_30.tmp_0',第二个loss的输入为教师模型和学生模型的'relu_31.tmp_0'。
+ - 普通蒸馏:教师模型为任意模型,学生模型为压缩后的推理模型。‘node’ 可设置为变量名称的列表,列表中元素数量必须为偶数。示例如下:
+ ```
+ node:
+ - teacher_relu_0.tmp_0
+ - student_relu_0.tmp_0
+ - teacher_relu_1.tmp_0
+ - student_relu_1.tmp_0
+ ```
-#### 配置定制结构化稀疏策略
+ 上述示例,会添加两个知识蒸馏loss。第一个loss的输入为教师模型的变量“teacher_relu_0.tmp_0”和学生模型的变量“student_relu_0.tmp_0”,第二个loss的输入为教师模型的变量“teacher_relu_1.tmp_0”和学生模型的“student_relu_1.tmp_0”。
+
+ 如果不设置`node`,则分别取教师模型和学生模型的最后一个带参数的层的输出,组成知识蒸馏loss.
+
+- teacher_model_dir: 用于监督压缩后模型训练的教师模型所在的路径。如果不设置该选项,则使用压缩前的模型做为教师模型。
+- teacher_model_filename: 教师模型的模型文件名称,格式为 *.pdmodel 或 __model__。仅当设置`teacher_model_dir`后生效。
+- teacher_params_filename: 教师模型的参数文件名称,格式为 *.pdiparams 或 __params__。仅当设置`teacher_model_dir`后生效。
+
+
+### 1.1.3 结构化稀疏(sparsity)
结构化稀疏参数设置如下所示:
```yaml
ChannelPrune:
- # pruned_ratio: 裁剪比例
pruned_ratio: 0.25
- # prune_params_name: 需要裁剪的参数名字
prune_params_name:
- conv1_weights
- # criterion: 评估一个卷积层内通道重要性所参考的指标
criterion: l1_norm
```
-- criterion目前支持的有:l1_norm , bn_scale , geometry_median。具体定义和使用可参考[结构化稀疏API文档](https://paddleslim.readthedocs.io/zh_CN/latest/api_cn/static/prune/prune_api.html)。
-#### 配置定制ASP半结构化稀疏策略
+- pruned_ratio: 每个卷积层的通道数被剪裁的比例。
+- prune_params_name: 待剪裁的卷积层的权重名称。通过以下脚本获得推理模型中所有卷积层的权重名称:
+
+```
+import paddle
+paddle.enable_static()
+model_dir="./inference_model"
+exe = paddle.static.Executor(paddle.CPUPlace())
+[inference_program, feed_target_names, fetch_targets] = (
+ paddle.static.load_inference_model(model_dir, exe))
+for var_ in inference_program.list_vars():
+ if var_.persistable and "conv2d" in var_.name:
+ print(f"{var_.name}")
+```
+
+或者,使用[Netron工具](https://netron.app/) 可视化`*.pdmodel`模型文件,选择合适的卷积层进行剪裁。
+
+- criterion: 评估卷积通道重要性的指标。可选 “l1_norm” , “bn_scale” , “geometry_median”。具体定义和使用可参考[结构化稀疏API文档](https://paddleslim.readthedocs.io/zh_CN/latest/api_cn/static/prune/prune_api.html)。
+
+### 1.1.4 ASP半结构化稀疏
半结构化稀疏参数设置如下所示:
```yaml
ASPPrune:
- # prune_params_name: 需要裁剪的参数名字
prune_params_name:
- conv1_weights
```
-#### 配置定制针对Transformer结构的结构化剪枝策略
+- prune_params_name: 待剪裁的卷积层的权重名称。通过以下脚本获得推理模型中所有卷积层的权重名称:
+
+```
+import paddle
+paddle.enable_static()
+model_dir="./inference_model"
+exe = paddle.static.Executor(paddle.CPUPlace())
+[inference_program, feed_target_names, fetch_targets] = (
+ paddle.static.load_inference_model(model_dir, exe))
+for var_ in inference_program.list_vars():
+ if var_.persistable and "conv2d" in var_.name:
+ print(f"{var_.name}")
+```
+
+或者,使用[Netron工具](https://netron.app/) 可视化`*.pdmodel`模型文件,选择合适的卷积层进行剪裁。
+
+### 1.1.5 Transformer结构化剪枝
针对Transformer结构的结构化剪枝参数设置如下所示:
```yaml
TransformerPrune:
- # pruned_ratio: 每个全链接层的裁剪比例
pruned_ratio: 0.25
```
+- pruned_ratio: 每个全链接层的被剪裁的比例。
-#### 配置定制非结构化稀疏策略
+### 1.1.6 非结构化稀疏策略
非结构化稀疏参数设置如下所示:
```yaml
@@ -122,7 +201,7 @@ UnstructurePrune:
- local_sparsity 表示剪裁比例(ratio)应用的范围,仅在 'ratio' 模式生效。local_sparsity 开启时意味着每个参与剪裁的参数矩阵稀疏度均为 'ratio', 关闭时表示只保证模型整体稀疏度达到'ratio',但是每个参数矩阵的稀疏度可能存在差异。各个矩阵稀疏度保持一致时,稀疏加速更显著。
- 更多非结构化稀疏的参数含义详见[非结构化稀疏API文档](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/docs/zh_cn/api_cn/dygraph/pruners/unstructured_pruner.rst)
-#### 配置训练超参
+### 1.1.7 训练超参
训练参数主要设置学习率、训练次数(epochs)和优化器等。
```yaml
@@ -143,12 +222,69 @@ TrainConfig:
boundaries: [4500] # 设置策略参数
values: [0.005, 0.0005] # 设置策略参数
```
-## 其他参数配置
+## 1.2 FAQ
-#### 1.自动蒸馏效果不理想,怎么自主选择蒸馏节点?
+### 1.自动蒸馏效果不理想,怎么自主选择蒸馏节点?
首先使用[Netron工具](https://netron.app/) 可视化`model.pdmodel`模型文件,选择模型中某些层输出Tensor名称,对蒸馏节点进行配置。(一般选择Backbone或网络的输出等层进行蒸馏)
+
+### 2.如何获得推理模型中的OP类型
+
+执行以下代码获取推理模型中的OP类型,其中`model_dir`为推理模型存储路径。
+
+```
+import paddle
+paddle.enable_static()
+model_dir="./inference_model"
+exe = paddle.static.Executor(paddle.CPUPlace())
+inference_program, _, _ = (
+ paddle.static.load_inference_model(model_dir, exe))
+op_types = {}
+for block in inference_program.blocks:
+ for op in block.ops:
+ op_types[op.type] = 1
+print(f"Operators in inference model:\n{op_types.keys()}")
+```
+
+所用飞桨框架接口:
+
+- [load_inference_model](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/static/load_inference_model_cn.html#load-inference-model)
+- [Program](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/static/Program_cn.html#program)
+- [Executor](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/static/Executor_cn.html#executor)
+
+### 3. 量化支持对哪些OP进行量化
+
+执行以下代码,查看当前PaddlePaddle版本的量化功能所支持的OP类型:
+```
+from paddle.fluid.contrib.slim.quantization.utils import _weight_supported_quantizable_op_type, _act_supported_quantizable_op_type
+print(f"_supported_quantizable_op_type:\n{_weight_supported_quantizable_op_type}")
+print(f"_supported_quantizable_op_type:\n{_act_supported_quantizable_op_type}")
+```
+
+### 4. 如何设置推理模型中OP的‘name_scope’属性
+
+以下代码,将输出变量为`conv2d_52.tmp_0`的OP的`name_scope`设置为'skip_quant':
+```
+import paddle
+paddle.enable_static()
+model_dir="./original_model"
+exe = paddle.static.Executor(paddle.CPUPlace())
+[inference_program, feed_target_names, fetch_targets] = (
+ paddle.static.load_inference_model(model_dir, exe))
+skips = ['conv2d_52.tmp_0']
+for block in inference_program.blocks:
+ for op in block.ops:
+ if op.output_arg_names[0] in skips:
+ op._set_attr("name_scope", "skip_quant")
+
+feed_vars = []
+for var_ in inference_program.list_vars():
+ if var_.name in feed_target_names:
+ feed_vars.append(var_)
+paddle.static.save_inference_model("./infer_model", feed_vars, fetch_targets, exe, program=inference_program)
+
+```
diff --git a/example/auto_compression/image_classification/README.md b/example/auto_compression/image_classification/README.md
index c11e51c2dbe7fffc09b50180b944d017cebd9335..14c70fbd45bb49d517bcac0f0c5ed59f19b8c4ec 100644
--- a/example/auto_compression/image_classification/README.md
+++ b/example/auto_compression/image_classification/README.md
@@ -21,28 +21,30 @@
### PaddleClas模型
-| 模型 | 策略 | Top-1 Acc | GPU 耗时(ms) | ARM CPU 耗时(ms) |
-|:------:|:------:|:------:|:------:|:------:|
-| MobileNetV1 | Baseline | 70.90 | - | 33.15 |
-| MobileNetV1 | 量化+蒸馏 | 70.57 | - | 13.64 |
-| ResNet50_vd | Baseline | 79.12 | 3.19 | - |
-| ResNet50_vd | 量化+蒸馏 | 78.74 | 0.92 | - |
-| ShuffleNetV2_x1_0 | Baseline | 68.65 | - | 10.43 |
-| ShuffleNetV2_x1_0 | 量化+蒸馏 | 68.32 | - | 5.51 |
-| SqueezeNet1_0_infer | Baseline | 59.60 | - | 35.98 |
-| SqueezeNet1_0_infer | 量化+蒸馏 | 59.45 | - | 16.96 |
-| PPLCNetV2_base | Baseline | 76.86 | - | 36.50 |
-| PPLCNetV2_base | 量化+蒸馏 | 76.43 | - | 15.79 |
-| PPHGNet_tiny | Baseline | 79.59 | 2.82 | - |
-| PPHGNet_tiny | 量化+蒸馏 | 79.20 | 0.98 | - |
-| InceptionV3 | Baseline | 79.14 | 4.79 | - |
-| InceptionV3 | 量化+蒸馏 | 78.32 | 1.47 | - |
-| EfficientNetB0 | Baseline | 77.02 | 1.95 | - |
-| EfficientNetB0 | 量化+蒸馏 | 75.39 | 1.44 | - |
-| GhostNet_x1_0 | Baseline | 74.02 | 2.93 | - |
-| GhostNet_x1_0 | 量化+蒸馏 | 72.62 | 1.03 | - |
-| MobileNetV3_large_x1_0 | Baseline | 75.32 | - | 16.62 |
-| MobileNetV3_large_x1_0 | 量化+蒸馏 | 70.93 | - | 9.85 |
+| 模型 | 策略 | Top-1 Acc | GPU 耗时(ms) | ARM CPU 耗时(ms) | 配置文件 | Inference模型 |
+|:------:|:------:|:------:|:------:|:------:|:------:|:------:|
+| MobileNetV1 | Baseline | 70.90 | - | 33.15 | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/MobileNetV1_infer.tar) |
+| MobileNetV1 | 量化+蒸馏 | 70.57 | - | 13.64 | [Config](./configs/MobileNetV1/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/MobileNetV1_QAT.tar) |
+| ResNet50_vd | Baseline | 79.12 | 3.19 | - | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/ResNet50_vd_infer.tar) |
+| ResNet50_vd | 量化+蒸馏 | 78.74 | 0.92 | - | [Config](./configs/ResNet50_vd/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/ResNet50_vd_QAT.tar) |
+| ShuffleNetV2_x1_0 | Baseline | 68.65 | - | 10.43 | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/ShuffleNetV2_x1_0_infer.tar) |
+| ShuffleNetV2_x1_0 | 量化+蒸馏 | 68.32 | - | 5.51 | [Config](./configs/ShuffleNetV2_x1_0/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/ShuffleNetV2_x1_0_QAT.tar) |
+| SqueezeNet1_0 | Baseline | 59.60 | - | 35.98 | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/SqueezeNet1_0_infer.tar) |
+| SqueezeNet1_0 | 量化+蒸馏 | 59.45 | - | 16.96 | [Config](./configs/SqueezeNet1_0/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/SqueezeNet1_0_QAT.tar) |
+| PPLCNetV2_base | Baseline | 76.86 | - | 36.50 | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/PPLCNetV2_base_infer.tar) |
+| PPLCNetV2_base | 量化+蒸馏 | 76.43 | - | 15.79 | [Config](./configs/PPLCNetV2_base/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/PPLCNetV2_base_QAT.tar) |
+| PPHGNet_tiny | Baseline | 79.59 | 2.82 | - | - |[Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/PPHGNet_tiny_infer.tar) |
+| PPHGNet_tiny | 量化+蒸馏 | 79.20 | 0.98 | - | [Config](./configs/PPHGNet_tiny/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/PPHGNet_tiny_QAT.tar) |
+| InceptionV3 | Baseline | 79.14 | 4.79 | - | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/InceptionV3_infer.tar) |
+| InceptionV3 | 量化+蒸馏 | 78.32 | 1.47 | - | [Config](./configs/InceptionV3/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/InceptionV3_QAT.tar) |
+| EfficientNetB0 | Baseline | 77.02 | 1.95 | - | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/EfficientNetB0_infer.tar) |
+| EfficientNetB0 | 量化+蒸馏 | 75.39 | 1.44 | - | [Config](./configs/EfficientNetB0/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/EfficientNetB0_QAT.tar) |
+| GhostNet_x1_0 | Baseline | 74.02 | 2.93 | - | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/GhostNet_x1_0_infer.tar) |
+| GhostNet_x1_0 | 量化+蒸馏 | 72.62 | 1.03 | - | [Config](./configs/GhostNet_x1_0/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/GhostNet_x1_0_QAT.tar) |
+| MobileNetV3_large_x1_0 | Baseline | 75.32 | - | 16.62 | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/MobileNetV3_large_x1_0_infer.tar) |
+| MobileNetV3_large_x1_0 | 量化+蒸馏 | 74.41 | - | 9.85 | [Config](./configs/MobileNetV3_large_x1_0/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/MobileNetV3_large_x1_0_QAT.tar) |
+| MobileNetV3_large_x1_0_ssld | Baseline | 78.96 | - | 16.62 | - | [Model](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/MobileNetV3_large_x1_0_ssld_infer.tar) |
+| MobileNetV3_large_x1_0_ssld | 量化+蒸馏 | 77.17 | - | 9.85 | [Config](./configs/MobileNetV3_large_x1_0/qat_dis.yaml) | [Model](https://paddle-slim-models.bj.bcebos.com/act/MobileNetV3_large_x1_0_ssld_QAT.tar) |
- ARM CPU 测试环境:`SDM865(4xA77+4xA55)`
- Nvidia GPU 测试环境:
diff --git a/example/auto_compression/image_classification/eval.py b/example/auto_compression/image_classification/eval.py
index d0e0c3d17ed845e4da649e3867f2f8ac1de6e8e3..9cd9b4a3b4a2bff7e97c00be88dc50fe802779e6 100644
--- a/example/auto_compression/image_classification/eval.py
+++ b/example/auto_compression/image_classification/eval.py
@@ -23,7 +23,7 @@ import paddle
import paddle.nn as nn
from paddle.io import DataLoader
from imagenet_reader import ImageNetDataset
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config as load_slim_config
def argsparser():
diff --git a/example/auto_compression/image_classification/infer.py b/example/auto_compression/image_classification/infer.py
index 5060115c60e9f16dfeb4d417c4a2f49a6f517602..46eb7115a948e10fa756e89c3ea83dce8d6ba7cc 100644
--- a/example/auto_compression/image_classification/infer.py
+++ b/example/auto_compression/image_classification/infer.py
@@ -22,7 +22,7 @@ import yaml
from utils import preprocess, postprocess
import paddle
from paddle.inference import create_predictor
-from paddleslim.auto_compression.config_helpers import load_config
+from paddleslim.common import load_config
def argsparser():
diff --git a/example/auto_compression/image_classification/run.py b/example/auto_compression/image_classification/run.py
index d8da1a9f419b7f19c03b7fb004ea0725724f2803..dee25a175d133fbdddaa72c7c7745045e9e2f71a 100644
--- a/example/auto_compression/image_classification/run.py
+++ b/example/auto_compression/image_classification/run.py
@@ -24,7 +24,7 @@ import paddle
import paddle.nn as nn
from paddle.io import DataLoader
from imagenet_reader import ImageNetDataset
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config as load_slim_config
from paddleslim.auto_compression import AutoCompression
@@ -46,6 +46,11 @@ def argsparser():
type=int,
default=1281167,
help="the number of total training images.")
+ parser.add_argument(
+ '--devices',
+ type=str,
+ default='gpu',
+ help="which device used to compress.")
return parser
@@ -122,7 +127,12 @@ def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
def main():
rank_id = paddle.distributed.get_rank()
- place = paddle.CUDAPlace(rank_id)
+ if args.devices == 'gpu':
+ place = paddle.CUDAPlace(rank_id)
+ paddle.set_device('gpu')
+ else:
+ place = paddle.CPUPlace()
+ paddle.set_device('cpu')
global global_config
all_config = load_slim_config(args.config_path)
diff --git a/example/auto_compression/nlp/run.py b/example/auto_compression/nlp/run.py
index 013b582625209fd349f2ee3e86e9fe4251215ff5..e1bf4f254d59af38b03dbf09636f105ea5307fc6 100644
--- a/example/auto_compression/nlp/run.py
+++ b/example/auto_compression/nlp/run.py
@@ -15,7 +15,7 @@ from paddlenlp.datasets import load_dataset
from paddlenlp.data import Stack, Tuple, Pad
from paddlenlp.data.sampler import SamplerHelper
from paddlenlp.metrics import Mcc, PearsonAndSpearman
-from paddleslim.auto_compression.config_helpers import load_config
+from paddleslim.common import load_config
from paddleslim.auto_compression.compressor import AutoCompression
diff --git a/example/auto_compression/pytorch_huggingface/run.py b/example/auto_compression/pytorch_huggingface/run.py
index 4da4e703fb8b3177f17d567564159f0b6a41f483..0c730dffa6823f5e4b6a0879be2a5b120ada320b 100644
--- a/example/auto_compression/pytorch_huggingface/run.py
+++ b/example/auto_compression/pytorch_huggingface/run.py
@@ -27,7 +27,7 @@ from paddlenlp.transformers import AutoModelForTokenClassification, AutoTokenize
from paddlenlp.datasets import load_dataset
from paddlenlp.data import Stack, Tuple, Pad
from paddlenlp.metrics import AccuracyAndF1, Mcc, PearsonAndSpearman
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config as load_slim_config
from paddleslim.auto_compression.compressor import AutoCompression
diff --git a/example/auto_compression/pytorch_yolo_series/README.md b/example/auto_compression/pytorch_yolo_series/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3f80ad6f17df4c9d8e0df760be8550c2c289f9b0
--- /dev/null
+++ b/example/auto_compression/pytorch_yolo_series/README.md
@@ -0,0 +1,170 @@
+# YOLO系列模型自动压缩示例
+
+目录:
+- [1.简介](#1简介)
+- [2.Benchmark](#2Benchmark)
+- [3.开始自动压缩](#自动压缩流程)
+ - [3.1 环境准备](#31-准备环境)
+ - [3.2 准备数据集](#32-准备数据集)
+ - [3.3 准备预测模型](#33-准备预测模型)
+ - [3.4 测试模型精度](#34-测试模型精度)
+ - [3.5 自动压缩并产出模型](#35-自动压缩并产出模型)
+- [4.预测部署](#4预测部署)
+- [5.FAQ](5FAQ)
+
+## 1. 简介
+
+本示例将以以[ultralytics/yolov5](https://github.com/ultralytics/yolov5),[meituan/YOLOv6](https://github.com/meituan/YOLOv6) 和 [WongKinYiu/yolov7](https://github.com/WongKinYiu/yolov7) 目标检测模型为例,借助[X2Paddle](https://github.com/PaddlePaddle/X2Paddle)的能力,将PyTorch框架模型转换为Paddle框架模型,再使用ACT自动压缩功能进行模型压缩,压缩后的模型可使用Paddle Inference或者导出至ONNX,利用TensorRT部署。
+
+## 2.Benchmark
+
+| 模型 | 策略 | 输入尺寸 | mAPval
0.5:0.95 | 模型体积 | 预测时延FP32
|预测时延FP16
| 预测时延INT8
| 配置文件 | Inference模型 |
+| :-------- |:-------- |:--------: | :--------: | :---------------------: | :----------------: | :----------------: | :---------------: | :-----------------------------: | :-----------------------------: |
+| YOLOv5s | Base模型 | 640*640 | 37.4 | 28.1MB | 5.95ms | 2.44ms | - | - | [Model](https://paddle-slim-models.bj.bcebos.com/act/yolov5s.onnx) |
+| YOLOv5s | 离线量化 | 640*640 | 36.0 | 7.4MB | - | - | 1.87ms | [config](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/example/post_training_quantization/pytorch_yolo_series) | - |
+| YOLOv5s | ACT量化训练 | 640*640 | **36.9** | 7.4MB | - | - | **1.87ms** | [config](./configs/yolov5s_qat_dis.yaml) | [Infer Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov5s_quant.tar) | [ONNX Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov5s_quant.onnx) |
+| | | | | | | | | |
+| YOLOv6s | Base模型 | 640*640 | 42.4 | 65.9MB | 9.06ms | 2.90ms | - | - | [Model](https://paddle-slim-models.bj.bcebos.com/act/yolov6s.onnx) |
+| YOLOv6s | KL离线量化 | 640*640 | 30.3 | 16.8MB | - | - | 1.83ms | [config](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/example/post_training_quantization/pytorch_yolo_series) | - |
+| YOLOv6s | 量化蒸馏训练 | 640*640 | **41.3** | 16.8MB | - | - | **1.83ms** | [config](./configs/yolov6s_qat_dis.yaml) | [Infer Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov6s_quant.tar) | [ONNX Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov6s_quant.onnx) |
+| | | | | | | | | |
+| YOLOv7 | Base模型 | 640*640 | 51.1 | 141MB | 26.84ms | 7.44ms | - | - | [Model](https://paddle-slim-models.bj.bcebos.com/act/yolov7.onnx) |
+| YOLOv7 | 离线量化 | 640*640 | 50.2 | 36MB | - | - | 4.55ms | [config](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/example/post_training_quantization/pytorch_yolo_series) | - |
+| YOLOv7 | ACT量化训练 | 640*640 | **50.9** | 36MB | - | - | **4.55ms** | [config](./configs/yolov7_qat_dis.yaml) | [Infer Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov7_quant.tar) | [ONNX Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov7_quant.onnx) |
+| | | | | | | | | |
+| YOLOv7-Tiny | Base模型 | 640*640 | 37.3 | 24MB | 5.06ms | 2.32ms | - | - | [Model](https://paddle-slim-models.bj.bcebos.com/act/yolov7-tiny.onnx) |
+| YOLOv7-Tiny | 离线量化 | 640*640 | 35.8 | 6.1MB | - | - | 1.68ms | - | - |
+| YOLOv7-Tiny | ACT量化训练 | 640*640 | **37.0** | 6.1MB | - | - | **1.68ms** | [config](./configs/yolov7_tiny_qat_dis.yaml) | [Infer Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov7_tiny_quant.tar) | [ONNX Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov7_tiny_quant.onnx) |
+
+说明:
+- mAP的指标均在COCO val2017数据集中评测得到。
+- YOLOv7模型在Tesla T4的GPU环境下开启TensorRT 8.4.1,batch_size=1, 测试脚本是[cpp_infer](./cpp_infer)。
+
+## 3. 自动压缩流程
+
+#### 3.1 准备环境
+- PaddlePaddle >= 2.3.2版本 (可从[Paddle官网](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)根据相应环境的安装指令进行安装)
+- PaddleSlim develop 版本
+
+(1)安装paddlepaddle
+```
+# CPU
+pip install paddlepaddle==2.3.2
+# GPU
+pip install paddlepaddle-gpu==2.3.2
+```
+
+(2)安装paddleslim:
+```shell
+git clone https://github.com/PaddlePaddle/PaddleSlim.git & cd PaddleSlim
+python setup.py install
+```
+
+
+#### 3.2 准备数据集
+
+本示例默认以COCO数据进行自动压缩实验,可以从[MS COCO官网](https://cocodataset.org)下载[Train](http://images.cocodataset.org/zips/train2017.zip)、[Val](http://images.cocodataset.org/zips/val2017.zip)、[annotation](http://images.cocodataset.org/annotations/annotations_trainval2017.zip)。
+
+目录格式如下:
+```
+dataset/coco/
+├── annotations
+│ ├── instances_train2017.json
+│ ├── instances_val2017.json
+│ | ...
+├── train2017
+│ ├── 000000000009.jpg
+│ ├── 000000580008.jpg
+│ | ...
+├── val2017
+│ ├── 000000000139.jpg
+│ ├── 000000000285.jpg
+```
+
+如果是自定义数据集,请按照如上COCO数据格式准备数据。
+
+
+#### 3.3 准备预测模型
+
+(1)准备ONNX模型:
+
+- YOLOv5:
+
+ 本示例模型使用[ultralytics/yolov5](https://github.com/ultralytics/yolov5)的master分支导出,要求v6.1之后的ONNX模型,可以根据官方的[导出教程](https://github.com/ultralytics/yolov5/issues/251)来准备ONNX模型。也可以下载准备好的[yolov5s.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov5s.onnx)。
+ ```shell
+ python export.py --weights yolov5s.pt --include onnx
+ ```
+
+- YOLOv6:
+
+ 可通过[meituan/YOLOv6](https://github.com/meituan/YOLOv6)官方的[导出教程](https://github.com/meituan/YOLOv6/blob/main/deploy/ONNX/README.md)来准备ONNX模型。也可以下载已经准备好的[yolov6s.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov6s.onnx)。
+
+- YOLOv7: 可通过[WongKinYiu/yolov7](https://github.com/WongKinYiu/yolov7)的导出脚本来准备ONNX模型,具体步骤如下:
+ ```shell
+ git clone https://github.com/WongKinYiu/yolov7.git
+ python export.py --weights yolov7-tiny.pt --grid
+ ```
+
+ **注意**:目前ACT支持**不带NMS**模型,使用如上命令导出即可。也可以直接下载我们已经准备好的[yolov7.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov7-tiny.onnx)。
+
+#### 3.4 自动压缩并产出模型
+
+蒸馏量化自动压缩示例通过run.py脚本启动,会使用接口```paddleslim.auto_compression.AutoCompression```对模型进行自动压缩。配置config文件中模型路径、蒸馏、量化、和训练等部分的参数,配置完成后便可对模型进行量化和蒸馏。
+
+本示例启动自动压缩以YOLOv7-Tiny为例,如果想要更换模型,可修改`--config_path`路径即可,具体运行命令为:
+
+- 单卡训练:
+```
+export CUDA_VISIBLE_DEVICES=0
+python run.py --config_path=./configs/yolov7_tiny_qat_dis.yaml --save_dir='./output/'
+```
+
+- 多卡训练:
+```
+CUDA_VISIBLE_DEVICES=0,1,2,3 python -m paddle.distributed.launch --log_dir=log --gpus 0,1,2,3 run.py \
+ --config_path=./configs/yolov7_tiny_qat_dis.yaml --save_dir='./output/'
+```
+
+#### 3.5 测试模型精度
+
+修改[yolov7_qat_dis.yaml](./configs/yolov7_qat_dis.yaml)中`model_dir`字段为模型存储路径,然后使用eval.py脚本得到模型的mAP:
+```
+export CUDA_VISIBLE_DEVICES=0
+python eval.py --config_path=./configs/yolov7_tiny_qat_dis.yaml
+```
+
+
+## 4.预测部署
+
+#### 导出至ONNX使用TensorRT部署
+
+执行完自动压缩后会默认在`save_dir`中生成`quant_model.onnx`的ONNX模型文件,可以直接使用TensorRT测试脚本进行验证。
+
+- 进行测试:
+```shell
+python yolov7_onnx_trt.py --model_path=output/quant_model.onnx --image_file=images/000000570688.jpg --precision=int8
+```
+
+#### Paddle-TensorRT部署
+- C++部署
+
+进入[cpp_infer](./cpp_infer)文件夹内,请按照[C++ TensorRT Benchmark测试教程](./cpp_infer/README.md)进行准备环境及编译,然后开始测试:
+```shell
+# 编译
+bash complie.sh
+# 执行
+./build/trt_run --model_file yolov7_quant/model.pdmodel --params_file yolov7_quant/model.pdiparams --run_mode=trt_int8
+```
+
+- Python部署:
+
+首先安装带有TensorRT的[Paddle安装包](https://www.paddlepaddle.org.cn/inference/v2.3/user_guides/download_lib.html#python)。
+
+然后使用[paddle_trt_infer.py](./paddle_trt_infer.py)进行部署:
+```shell
+python paddle_trt_infer.py --model_path=output --image_file=images/000000570688.jpg --benchmark=True --run_mode=trt_int8
+```
+
+## 5.FAQ
+
+- 如果想对模型进行离线量化,可进入[YOLO系列模型离线量化示例](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/example/post_training_quantization/pytorch_yolo_series)中进行实验。
diff --git a/example/auto_compression/pytorch_yolov5/configs/yolov5s_qat_dis.yaml b/example/auto_compression/pytorch_yolo_series/configs/yolov5s_qat_dis.yaml
similarity index 60%
rename from example/auto_compression/pytorch_yolov5/configs/yolov5s_qat_dis.yaml
rename to example/auto_compression/pytorch_yolo_series/configs/yolov5s_qat_dis.yaml
index ef9bf8b7cbfcfbca983af4f7ecc7a23ce6109af4..d5c853bedeffa09771d60806d4d45845251c1a30 100644
--- a/example/auto_compression/pytorch_yolov5/configs/yolov5s_qat_dis.yaml
+++ b/example/auto_compression/pytorch_yolo_series/configs/yolov5s_qat_dis.yaml
@@ -1,18 +1,19 @@
-
Global:
- reader_config: configs/yolov5_reader.yml
- input_list: {'image': 'x2paddle_images'}
+ model_dir: ./yolov5s.onnx
+ dataset_dir: dataset/coco/
+ train_image_dir: train2017
+ val_image_dir: val2017
+ train_anno_path: annotations/instances_train2017.json
+ val_anno_path: annotations/instances_val2017.json
Evaluation: True
- arch: 'YOLOv5'
- model_dir: ./yolov5s_infer
- model_filename: model.pdmodel
- params_filename: model.pdiparams
+ arch: YOLOv5
Distillation:
alpha: 1.0
loss: soft_label
Quantization:
+ onnx_format: true
use_pact: true
activation_quantize_type: 'moving_average_abs_max'
quantize_op_types:
diff --git a/example/auto_compression/pytorch_yolov6/configs/yolov6s_qat_dis.yaml b/example/auto_compression/pytorch_yolo_series/configs/yolov6s_qat_dis.yaml
similarity index 62%
rename from example/auto_compression/pytorch_yolov6/configs/yolov6s_qat_dis.yaml
rename to example/auto_compression/pytorch_yolo_series/configs/yolov6s_qat_dis.yaml
index 4fcf4777f396b1207ee1da4f3e196af1d18970d5..e14a6b6512fb76b846393d2bb84265fb58cd6390 100644
--- a/example/auto_compression/pytorch_yolov6/configs/yolov6s_qat_dis.yaml
+++ b/example/auto_compression/pytorch_yolo_series/configs/yolov6s_qat_dis.yaml
@@ -1,18 +1,19 @@
-
Global:
- reader_config: configs/yolov6_reader.yml
- input_list: {'image': 'x2paddle_image_arrays'}
+ model_dir: ./yolov6s.onnx
+ dataset_dir: dataset/coco/
+ train_image_dir: train2017
+ val_image_dir: val2017
+ train_anno_path: annotations/instances_train2017.json
+ val_anno_path: annotations/instances_val2017.json
Evaluation: True
- arch: 'YOLOv6'
- model_dir: ./yolov6s_infer
- model_filename: model.pdmodel
- params_filename: model.pdiparams
+ arch: YOLOv6
Distillation:
alpha: 1.0
loss: soft_label
Quantization:
+ onnx_format: true
activation_quantize_type: 'moving_average_abs_max'
quantize_op_types:
- conv2d
diff --git a/example/auto_compression/pytorch_yolov7/configs/yolov7_qat_dis.yaml b/example/auto_compression/pytorch_yolo_series/configs/yolov7_qat_dis.yaml
similarity index 56%
rename from example/auto_compression/pytorch_yolov7/configs/yolov7_qat_dis.yaml
rename to example/auto_compression/pytorch_yolo_series/configs/yolov7_qat_dis.yaml
index 6607e3615d30509645b34217681899c89d5eecef..437ceea90fd0ce835e528910cadf607d3c5e78bf 100644
--- a/example/auto_compression/pytorch_yolov7/configs/yolov7_qat_dis.yaml
+++ b/example/auto_compression/pytorch_yolo_series/configs/yolov7_qat_dis.yaml
@@ -1,26 +1,28 @@
-
Global:
- reader_config: configs/yolov7_reader.yaml
- input_list: {'image': 'x2paddle_images'}
+ model_dir: ./yolov7.onnx
+ dataset_dir: dataset/coco/
+ train_image_dir: train2017
+ val_image_dir: val2017
+ train_anno_path: annotations/instances_train2017.json
+ val_anno_path: annotations/instances_val2017.json
Evaluation: True
- model_dir: ./yolov7_infer
- model_filename: model.pdmodel
- params_filename: model.pdiparams
+ arch: YOLOv7
Distillation:
alpha: 1.0
loss: soft_label
Quantization:
+ onnx_format: true
activation_quantize_type: 'moving_average_abs_max'
quantize_op_types:
- conv2d
- depthwise_conv2d
TrainConfig:
- train_iter: 8000
+ train_iter: 5000
eval_iter: 1000
- learning_rate:
+ learning_rate:
type: CosineAnnealingDecay
learning_rate: 0.00003
T_max: 8000
diff --git a/example/auto_compression/pytorch_yolo_series/configs/yolov7_tiny_qat_dis.yaml b/example/auto_compression/pytorch_yolo_series/configs/yolov7_tiny_qat_dis.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..958182f6c9ef48d9f10d191a7cce6e8c5ef65f2e
--- /dev/null
+++ b/example/auto_compression/pytorch_yolo_series/configs/yolov7_tiny_qat_dis.yaml
@@ -0,0 +1,32 @@
+Global:
+ model_dir: ./yolov7-tiny.onnx
+ dataset_dir: dataset/coco/
+ train_image_dir: train2017
+ val_image_dir: val2017
+ train_anno_path: annotations/instances_train2017.json
+ val_anno_path: annotations/instances_val2017.json
+ Evaluation: True
+ arch: YOLOv7
+
+Distillation:
+ alpha: 1.0
+ loss: soft_label
+
+Quantization:
+ onnx_format: true
+ activation_quantize_type: 'moving_average_abs_max'
+ quantize_op_types:
+ - conv2d
+ - depthwise_conv2d
+
+TrainConfig:
+ train_iter: 5000
+ eval_iter: 1000
+ learning_rate:
+ type: CosineAnnealingDecay
+ learning_rate: 0.00003
+ T_max: 8000
+ optimizer_builder:
+ optimizer:
+ type: SGD
+ weight_decay: 0.00004
diff --git a/example/auto_compression/pytorch_yolov5/cpp_infer/CMakeLists.txt b/example/auto_compression/pytorch_yolo_series/cpp_infer/CMakeLists.txt
similarity index 100%
rename from example/auto_compression/pytorch_yolov5/cpp_infer/CMakeLists.txt
rename to example/auto_compression/pytorch_yolo_series/cpp_infer/CMakeLists.txt
diff --git a/example/auto_compression/pytorch_yolov5/cpp_infer/README.md b/example/auto_compression/pytorch_yolo_series/cpp_infer/README.md
similarity index 64%
rename from example/auto_compression/pytorch_yolov5/cpp_infer/README.md
rename to example/auto_compression/pytorch_yolo_series/cpp_infer/README.md
index 9566728a94e1a238b66bcc0a8c61ff5e9c51db6f..0286c26df27dc85cab015be6657413062c63a715 100644
--- a/example/auto_compression/pytorch_yolov5/cpp_infer/README.md
+++ b/example/auto_compression/pytorch_yolo_series/cpp_infer/README.md
@@ -1,4 +1,4 @@
-# YOLOv5 TensorRT Benchmark测试(Linux)
+# YOLOv7 TensorRT Benchmark测试(Linux)
## 环境准备
@@ -22,21 +22,37 @@ CUDA_LIB=/usr/local/cuda/lib64
TENSORRT_ROOT=/root/auto_compress/trt/trt8.4/
```
-## Paddle TensorRT测试
+## Paddle tensorRT测试
-- FP32
+- YOLOv5
```
+# FP32
./build/trt_run --model_file yolov5s_infer/model.pdmodel --params_file yolov5s_infer/model.pdiparams --run_mode=trt_fp32
+# FP16
+./build/trt_run --model_file yolov5s_infer/model.pdmodel --params_file yolov5s_infer/model.pdiparams --run_mode=trt_fp16
+# INT8
+./build/trt_run --model_file yolov5s_quant/model.pdmodel --params_file yolov5s_quant/model.pdiparams --run_mode=trt_int8
```
-- FP16
+- YOLOv6
```
-./build/trt_run --model_file yolov5s_infer/model.pdmodel --params_file yolov5s_infer/model.pdiparams --run_mode=trt_fp16
+# FP32
+./build/trt_run --arch=YOLOv6 --model_file yolov6s_infer/model.pdmodel --params_file yolov6s_infer/model.pdiparams --run_mode=trt_fp32
+# FP16
+./build/trt_run --arch=YOLOv6 --model_file yolov6s_infer/model.pdmodel --params_file yolov6s_infer/model.pdiparams --run_mode=trt_fp16
+# INT8
+./build/trt_run --arch=YOLOv6 --model_file yolov6s_quant/model.pdmodel --params_file yolov6s_quant/model.pdiparams --run_mode=trt_int8
```
-- INT8
+
+- YOLOv7
```
-./build/trt_run --model_file yolov5s_quant/model.pdmodel --params_file yolov5s_quant/model.pdiparams --run_mode=trt_int8
+# FP32
+./build/trt_run --model_file yolov7_infer/model.pdmodel --params_file yolov7_infer/model.pdiparams --run_mode=trt_fp32
+# FP16
+./build/trt_run --model_file yolov7_infer/model.pdmodel --params_file yolov7_infer/model.pdiparams --run_mode=trt_fp16
+# INT8
+./build/trt_run --model_file yolov7_quant/model.pdmodel --params_file yolov7_quant/model.pdiparams --run_mode=trt_int8
```
## 原生TensorRT测试
@@ -49,6 +65,7 @@ trtexec --onnx=yolov5s.onnx --workspace=1024 --avgRuns=1000 --inputIOFormats=fp1
# INT8
trtexec --onnx=yolov5s.onnx --workspace=1024 --avgRuns=1000 --inputIOFormats=fp16:chw --outputIOFormats=fp16:chw --int8
```
+- 注:可把--onnx=yolov5s.onnx替换成yolov6s.onnx和yolov7.onnx模型
## 性能对比
@@ -56,6 +73,12 @@ trtexec --onnx=yolov5s.onnx --workspace=1024 --avgRuns=1000 --inputIOFormats=fp1
| :--------: | :--------: |:-------- |:--------: | :---------------------: |
| Paddle TensorRT | yolov5s | 5.95ms | 2.44ms | 1.87ms |
| TensorRT | yolov5s | 6.16ms | 2.58ms | 2.07ms |
+| | | | | |
+| Paddle TensorRT | YOLOv6s | 9.06ms | 2.90ms | 1.83ms |
+| TensorRT | YOLOv6s | 8.59ms | 2.83ms | 1.87ms |
+| | | | | |
+| Paddle TensorRT | YOLOv7 | 26.84ms | 7.44ms | 4.55ms |
+| TensorRT | YOLOv7 | 28.25ms | 7.23ms | 4.67ms |
环境:
- Tesla T4,TensorRT 8.4.1,CUDA 11.2
diff --git a/example/auto_compression/pytorch_yolov5/cpp_infer/compile.sh b/example/auto_compression/pytorch_yolo_series/cpp_infer/compile.sh
similarity index 100%
rename from example/auto_compression/pytorch_yolov5/cpp_infer/compile.sh
rename to example/auto_compression/pytorch_yolo_series/cpp_infer/compile.sh
diff --git a/example/auto_compression/pytorch_yolov7/cpp_infer/trt_run.cc b/example/auto_compression/pytorch_yolo_series/cpp_infer/trt_run.cc
similarity index 93%
rename from example/auto_compression/pytorch_yolov7/cpp_infer/trt_run.cc
rename to example/auto_compression/pytorch_yolo_series/cpp_infer/trt_run.cc
index 0ae055acb6e42f226d023fadfd5923bd79c19bfd..22095b39e1ed872759cdc2d90a0c63bb3da41890 100644
--- a/example/auto_compression/pytorch_yolov7/cpp_infer/trt_run.cc
+++ b/example/auto_compression/pytorch_yolo_series/cpp_infer/trt_run.cc
@@ -19,6 +19,7 @@ using phi::dtype::float16;
DEFINE_string(model_dir, "", "Directory of the inference model.");
DEFINE_string(model_file, "", "Path of the inference model file.");
DEFINE_string(params_file, "", "Path of the inference params file.");
+DEFINE_string(arch, "YOLOv5", "Architectures name, can be: YOLOv5, YOLOv6, YOLOv7.");
DEFINE_string(run_mode, "trt_fp32", "run_mode which can be: trt_fp32, trt_fp16 and trt_int8");
DEFINE_int32(batch_size, 1, "Batch size.");
DEFINE_int32(gpu_id, 0, "GPU card ID num.");
@@ -106,11 +107,15 @@ int main(int argc, char *argv[]) {
using dtype = float16;
std::vector input_data(FLAGS_batch_size * 3 * 640 * 640, dtype(1.0));
+ int out_box_shape = 25200;
+ if (FLAGS_arch == "YOLOv6"){
+ out_box_shape = 8400;
+ }
dtype *out_data;
- int out_data_size = FLAGS_batch_size * 25200 * 85;
+ int out_data_size = FLAGS_batch_size * out_box_shape * 85;
cudaHostAlloc((void**)&out_data, sizeof(float) * out_data_size, cudaHostAllocMapped);
- std::vector out_shape{ FLAGS_batch_size, 1, 25200, 85};
+ std::vector out_shape{ FLAGS_batch_size, 1, out_box_shape, 85};
run(predictor.get(), input_data, input_shape, out_data, out_shape);
return 0;
}
diff --git a/example/auto_compression/pytorch_yolo_series/dataset.py b/example/auto_compression/pytorch_yolo_series/dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..0250b936ffeef4497c03354333b515c6fc3551bf
--- /dev/null
+++ b/example/auto_compression/pytorch_yolo_series/dataset.py
@@ -0,0 +1,115 @@
+from pycocotools.coco import COCO
+import cv2
+import os
+import numpy as np
+import paddle
+
+
+class COCOValDataset(paddle.io.Dataset):
+ def __init__(self,
+ dataset_dir=None,
+ image_dir=None,
+ anno_path=None,
+ img_size=[640, 640],
+ input_name='x2paddle_images'):
+ self.dataset_dir = dataset_dir
+ self.image_dir = image_dir
+ self.img_size = img_size
+ self.input_name = input_name
+ self.ann_file = os.path.join(dataset_dir, anno_path)
+ self.coco = COCO(self.ann_file)
+ ori_ids = list(sorted(self.coco.imgs.keys()))
+ # check gt bbox
+ clean_ids = []
+ for idx in ori_ids:
+ ins_anno_ids = self.coco.getAnnIds(imgIds=[idx], iscrowd=False)
+ instances = self.coco.loadAnns(ins_anno_ids)
+ num_bbox = 0
+ for inst in instances:
+ if inst.get('ignore', False):
+ continue
+ if 'bbox' not in inst.keys():
+ continue
+ elif not any(np.array(inst['bbox'])):
+ continue
+ else:
+ num_bbox += 1
+ if num_bbox > 0:
+ clean_ids.append(idx)
+ self.ids = clean_ids
+
+ def __getitem__(self, idx):
+ img_id = self.ids[idx]
+ img = self._get_img_data_from_img_id(img_id)
+ img, scale_factor = self.image_preprocess(img, self.img_size)
+ return {
+ 'image': img,
+ 'im_id': np.array([img_id]),
+ 'scale_factor': scale_factor
+ }
+
+ def __len__(self):
+ return len(self.ids)
+
+ def _get_img_data_from_img_id(self, img_id):
+ img_info = self.coco.loadImgs(img_id)[0]
+ img_path = os.path.join(self.dataset_dir, self.image_dir,
+ img_info['file_name'])
+ img = cv2.imread(img_path)
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
+ return img
+
+ def _generate_scale(self, im, target_shape, keep_ratio=True):
+ """
+ Args:
+ im (np.ndarray): image (np.ndarray)
+ Returns:
+ im_scale_x: the resize ratio of X
+ im_scale_y: the resize ratio of Y
+ """
+ origin_shape = im.shape[:2]
+ if keep_ratio:
+ im_size_min = np.min(origin_shape)
+ im_size_max = np.max(origin_shape)
+ target_size_min = np.min(target_shape)
+ target_size_max = np.max(target_shape)
+ im_scale = float(target_size_min) / float(im_size_min)
+ if np.round(im_scale * im_size_max) > target_size_max:
+ im_scale = float(target_size_max) / float(im_size_max)
+ im_scale_x = im_scale
+ im_scale_y = im_scale
+ else:
+ resize_h, resize_w = target_shape
+ im_scale_y = resize_h / float(origin_shape[0])
+ im_scale_x = resize_w / float(origin_shape[1])
+ return im_scale_y, im_scale_x
+
+ def image_preprocess(self, img, target_shape):
+ # Resize image
+ im_scale_y, im_scale_x = self._generate_scale(img, target_shape)
+ img = cv2.resize(
+ img,
+ None,
+ None,
+ fx=im_scale_x,
+ fy=im_scale_y,
+ interpolation=cv2.INTER_LINEAR)
+ # Pad
+ im_h, im_w = img.shape[:2]
+ h, w = target_shape[:]
+ if h != im_h or w != im_w:
+ canvas = np.ones((h, w, 3), dtype=np.float32)
+ canvas *= np.array([114.0, 114.0, 114.0], dtype=np.float32)
+ canvas[0:im_h, 0:im_w, :] = img.astype(np.float32)
+ img = canvas
+ img = np.transpose(img / 255, [2, 0, 1])
+ scale_factor = np.array([im_scale_y, im_scale_x])
+ return img.astype(np.float32), scale_factor
+
+
+class COCOTrainDataset(COCOValDataset):
+ def __getitem__(self, idx):
+ img_id = self.ids[idx]
+ img = self._get_img_data_from_img_id(img_id)
+ img, scale_factor = self.image_preprocess(img, self.img_size)
+ return {self.input_name: img}
diff --git a/example/auto_compression/pytorch_yolo_series/eval.py b/example/auto_compression/pytorch_yolo_series/eval.py
new file mode 100644
index 0000000000000000000000000000000000000000..de11989e4da7455d92cba55bcca30cbea67c9628
--- /dev/null
+++ b/example/auto_compression/pytorch_yolo_series/eval.py
@@ -0,0 +1,102 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import numpy as np
+import argparse
+from tqdm import tqdm
+import paddle
+from paddleslim.common import load_config
+from paddleslim.common import load_inference_model
+from post_process import YOLOPostProcess, coco_metric
+from dataset import COCOValDataset
+
+
+def argsparser():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '--config_path',
+ type=str,
+ default=None,
+ help="path of compression strategy config.",
+ required=True)
+ parser.add_argument(
+ '--batch_size', type=int, default=1, help="Batch size of model input.")
+ parser.add_argument(
+ '--devices',
+ type=str,
+ default='gpu',
+ help="which device used to compress.")
+
+ return parser
+
+
+def eval():
+
+ place = paddle.CUDAPlace(0) if FLAGS.devices == 'gpu' else paddle.CPUPlace()
+ exe = paddle.static.Executor(place)
+
+ val_program, feed_target_names, fetch_targets = load_inference_model(
+ global_config["model_dir"], exe)
+
+ bboxes_list, bbox_nums_list, image_id_list = [], [], []
+ with tqdm(
+ total=len(val_loader),
+ bar_format='Evaluation stage, Run batch:|{bar}| {n_fmt}/{total_fmt}',
+ ncols=80) as t:
+ for data in val_loader:
+ data_all = {k: np.array(v) for k, v in data.items()}
+ outs = exe.run(val_program,
+ feed={feed_target_names[0]: data_all['image']},
+ fetch_list=fetch_targets,
+ return_numpy=False)
+ postprocess = YOLOPostProcess(
+ score_threshold=0.001, nms_threshold=0.65, multi_label=True)
+ res = postprocess(np.array(outs[0]), data_all['scale_factor'])
+ bboxes_list.append(res['bbox'])
+ bbox_nums_list.append(res['bbox_num'])
+ image_id_list.append(np.array(data_all['im_id']))
+ t.update()
+
+ coco_metric(anno_file, bboxes_list, bbox_nums_list, image_id_list)
+
+
+def main():
+ global global_config
+ all_config = load_config(FLAGS.config_path)
+ global_config = all_config["Global"]
+
+ global val_loader
+ dataset = COCOValDataset(
+ dataset_dir=global_config['dataset_dir'],
+ image_dir=global_config['val_image_dir'],
+ anno_path=global_config['val_anno_path'])
+ global anno_file
+ anno_file = dataset.ann_file
+ val_loader = paddle.io.DataLoader(
+ dataset, batch_size=FLAGS.batch_size, drop_last=True)
+
+ eval()
+
+
+if __name__ == '__main__':
+ paddle.enable_static()
+ parser = argsparser()
+ FLAGS = parser.parse_args()
+
+ assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
+ paddle.set_device(FLAGS.devices)
+
+ main()
diff --git a/example/auto_compression/pytorch_yolov5/images/000000570688.jpg b/example/auto_compression/pytorch_yolo_series/images/000000570688.jpg
similarity index 100%
rename from example/auto_compression/pytorch_yolov5/images/000000570688.jpg
rename to example/auto_compression/pytorch_yolo_series/images/000000570688.jpg
diff --git a/example/auto_compression/pytorch_yolo_series/onnx_trt_infer.py b/example/auto_compression/pytorch_yolo_series/onnx_trt_infer.py
new file mode 100644
index 0000000000000000000000000000000000000000..3540c33d6ed8a86398b620d3cc722dc1a11ca85a
--- /dev/null
+++ b/example/auto_compression/pytorch_yolo_series/onnx_trt_infer.py
@@ -0,0 +1,378 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import numpy as np
+import cv2
+import tensorrt as trt
+import pycuda.driver as cuda
+import pycuda.autoinit
+import os
+import time
+import random
+import argparse
+
+EXPLICIT_BATCH = 1 << (int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
+EXPLICIT_PRECISION = 1 << (
+ int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_PRECISION)
+
+# load coco labels
+CLASS_LABEL = [
+ "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
+ "truck", "boat", "traffic light", "fire hydrant", "stop sign",
+ "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
+ "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag",
+ "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
+ "baseball bat", "baseball glove", "skateboard", "surfboard",
+ "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon",
+ "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot",
+ "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant",
+ "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote",
+ "keyboard", "cell phone", "microwave", "oven", "toaster", "sink",
+ "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
+ "hair drier", "toothbrush"
+]
+
+
+def preprocess(image, input_size, mean=None, std=None, swap=(2, 0, 1)):
+ if len(image.shape) == 3:
+ padded_img = np.ones((input_size[0], input_size[1], 3)) * 114.0
+ else:
+ padded_img = np.ones(input_size) * 114.0
+ img = np.array(image)
+ r = min(input_size[0] / img.shape[0], input_size[1] / img.shape[1])
+ resized_img = cv2.resize(
+ img,
+ (int(img.shape[1] * r), int(img.shape[0] * r)),
+ interpolation=cv2.INTER_LINEAR, ).astype(np.float32)
+ padded_img[:int(img.shape[0] * r), :int(img.shape[1] * r)] = resized_img
+
+ padded_img = padded_img[:, :, ::-1]
+ padded_img /= 255.0
+ if mean is not None:
+ padded_img -= mean
+ if std is not None:
+ padded_img /= std
+ padded_img = padded_img.transpose(swap)
+ padded_img = np.ascontiguousarray(padded_img, dtype=np.float32)
+ return padded_img, r
+
+
+def postprocess(predictions, ratio):
+ boxes = predictions[:, :4]
+ scores = predictions[:, 4:5] * predictions[:, 5:]
+ boxes_xyxy = np.ones_like(boxes)
+ boxes_xyxy[:, 0] = boxes[:, 0] - boxes[:, 2] / 2.
+ boxes_xyxy[:, 1] = boxes[:, 1] - boxes[:, 3] / 2.
+ boxes_xyxy[:, 2] = boxes[:, 0] + boxes[:, 2] / 2.
+ boxes_xyxy[:, 3] = boxes[:, 1] + boxes[:, 3] / 2.
+ boxes_xyxy /= ratio
+ dets = multiclass_nms(boxes_xyxy, scores, nms_thr=0.45, score_thr=0.1)
+ return dets
+
+
+def nms(boxes, scores, nms_thr):
+ """Single class NMS implemented in Numpy."""
+ x1 = boxes[:, 0]
+ y1 = boxes[:, 1]
+ x2 = boxes[:, 2]
+ y2 = boxes[:, 3]
+
+ areas = (x2 - x1 + 1) * (y2 - y1 + 1)
+ order = scores.argsort()[::-1]
+
+ keep = []
+ while order.size > 0:
+ i = order[0]
+ keep.append(i)
+ xx1 = np.maximum(x1[i], x1[order[1:]])
+ yy1 = np.maximum(y1[i], y1[order[1:]])
+ xx2 = np.minimum(x2[i], x2[order[1:]])
+ yy2 = np.minimum(y2[i], y2[order[1:]])
+
+ w = np.maximum(0.0, xx2 - xx1 + 1)
+ h = np.maximum(0.0, yy2 - yy1 + 1)
+ inter = w * h
+ ovr = inter / (areas[i] + areas[order[1:]] - inter)
+
+ inds = np.where(ovr <= nms_thr)[0]
+ order = order[inds + 1]
+
+ return keep
+
+
+def multiclass_nms(boxes, scores, nms_thr, score_thr):
+ """Multiclass NMS implemented in Numpy"""
+ final_dets = []
+ num_classes = scores.shape[1]
+ for cls_ind in range(num_classes):
+ cls_scores = scores[:, cls_ind]
+ valid_score_mask = cls_scores > score_thr
+ if valid_score_mask.sum() == 0:
+ continue
+ else:
+ valid_scores = cls_scores[valid_score_mask]
+ valid_boxes = boxes[valid_score_mask]
+ keep = nms(valid_boxes, valid_scores, nms_thr)
+ if len(keep) > 0:
+ cls_inds = np.ones((len(keep), 1)) * cls_ind
+ dets = np.concatenate(
+ [valid_boxes[keep], valid_scores[keep, None], cls_inds], 1)
+ final_dets.append(dets)
+ if len(final_dets) == 0:
+ return None
+ return np.concatenate(final_dets, 0)
+
+
+def get_color_map_list(num_classes):
+ color_map = num_classes * [0, 0, 0]
+ for i in range(0, num_classes):
+ j = 0
+ lab = i
+ while lab:
+ color_map[i * 3] |= (((lab >> 0) & 1) << (7 - j))
+ color_map[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j))
+ color_map[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j))
+ j += 1
+ lab >>= 3
+ color_map = [color_map[i:i + 3] for i in range(0, len(color_map), 3)]
+ return color_map
+
+
+def draw_box(img, boxes, scores, cls_ids, conf=0.5, class_names=None):
+ color_list = get_color_map_list(len(class_names))
+ for i in range(len(boxes)):
+ box = boxes[i]
+ cls_id = int(cls_ids[i])
+ color = tuple(color_list[cls_id])
+ score = scores[i]
+ if score < conf:
+ continue
+ x0 = int(box[0])
+ y0 = int(box[1])
+ x1 = int(box[2])
+ y1 = int(box[3])
+
+ text = '{}:{:.1f}%'.format(class_names[cls_id], score * 100)
+ font = cv2.FONT_HERSHEY_SIMPLEX
+
+ txt_size = cv2.getTextSize(text, font, 0.4, 1)[0]
+ cv2.rectangle(img, (x0, y0), (x1, y1), color, 2)
+ cv2.rectangle(img, (x0, y0 + 1),
+ (x0 + txt_size[0] + 1, y0 + int(1.5 * txt_size[1])),
+ color, -1)
+ cv2.putText(
+ img,
+ text, (x0, y0 + txt_size[1]),
+ font,
+ 0.8, (0, 255, 0),
+ thickness=2)
+
+ return img
+
+
+def get_engine(precision, model_file_path):
+ # TRT_LOGGER = trt.Logger(trt.Logger.VERBOSE)
+ TRT_LOGGER = trt.Logger()
+ builder = trt.Builder(TRT_LOGGER)
+ config = builder.create_builder_config()
+ if precision == 'int8':
+ network = builder.create_network(EXPLICIT_BATCH | EXPLICIT_PRECISION)
+ else:
+ network = builder.create_network(EXPLICIT_BATCH)
+ parser = trt.OnnxParser(network, TRT_LOGGER)
+
+ runtime = trt.Runtime(TRT_LOGGER)
+ if model_file_path.endswith('.trt'):
+ # If a serialized engine exists, use it instead of building an engine.
+ print("Reading engine from file {}".format(model_file_path))
+ with open(model_file_path,
+ "rb") as f, trt.Runtime(TRT_LOGGER) as runtime:
+ engine = runtime.deserialize_cuda_engine(f.read())
+ for i in range(network.num_layers):
+ layer = network.get_layer(i)
+ print(i, layer.name)
+ return engine
+ else:
+ config.max_workspace_size = 1 << 30
+
+ if precision == "fp16":
+ if not builder.platform_has_fast_fp16:
+ print("FP16 is not supported natively on this platform/device")
+ else:
+ config.set_flag(trt.BuilderFlag.FP16)
+ elif precision == "int8":
+ if not builder.platform_has_fast_int8:
+ print("INT8 is not supported natively on this platform/device")
+ else:
+ if builder.platform_has_fast_fp16:
+ # Also enable fp16, as some layers may be even more efficient in fp16 than int8
+ config.set_flag(trt.BuilderFlag.FP16)
+ config.set_flag(trt.BuilderFlag.INT8)
+
+ builder.max_batch_size = 1
+ print('Loading ONNX file from path {}...'.format(model_file_path))
+ with open(model_file_path, 'rb') as model:
+ print('Beginning ONNX file parsing')
+ if not parser.parse(model.read()):
+ print('ERROR: Failed to parse the ONNX file.')
+ for error in range(parser.num_errors):
+ print(parser.get_error(error))
+ return None
+
+ print('Completed parsing of ONNX file')
+ print('Building an engine from file {}; this may take a while...'.
+ format(model_file_path))
+ plan = builder.build_serialized_network(network, config)
+ engine = runtime.deserialize_cuda_engine(plan)
+ print("Completed creating Engine")
+ with open(model_file_path, "wb") as f:
+ f.write(engine.serialize())
+ for i in range(network.num_layers):
+ layer = network.get_layer(i)
+ print(i, layer.name)
+ return engine
+
+
+# Simple helper data class that's a little nicer to use than a 2-tuple.
+class HostDeviceMem(object):
+ def __init__(self, host_mem, device_mem):
+ self.host = host_mem
+ self.device = device_mem
+
+ def __str__(self):
+ return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device)
+
+ def __repr__(self):
+ return self.__str__()
+
+
+def allocate_buffers(engine):
+ inputs = []
+ outputs = []
+ bindings = []
+ stream = cuda.Stream()
+ for binding in engine:
+ size = trt.volume(engine.get_binding_shape(
+ binding)) * engine.max_batch_size
+ dtype = trt.nptype(engine.get_binding_dtype(binding))
+ # Allocate host and device buffers
+ host_mem = cuda.pagelocked_empty(size, dtype)
+ device_mem = cuda.mem_alloc(host_mem.nbytes)
+ # Append the device buffer to device bindings.
+ bindings.append(int(device_mem))
+ # Append to the appropriate list.
+ if engine.binding_is_input(binding):
+ inputs.append(HostDeviceMem(host_mem, device_mem))
+ else:
+ outputs.append(HostDeviceMem(host_mem, device_mem))
+ return inputs, outputs, bindings, stream
+
+
+def run_inference(context, bindings, inputs, outputs, stream):
+ # Transfer input data to the GPU.
+ [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
+ # Run inference.
+ context.execute_async_v2(bindings=bindings, stream_handle=stream.handle)
+ # Transfer predictions back from the GPU.
+ [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
+ # Synchronize the stream
+ stream.synchronize()
+ # Return only the host outputs.
+ return [out.host for out in outputs]
+
+
+def main(args):
+ onnx_model = args.model_path
+ img_path = args.image_file
+ num_class = len(CLASS_LABEL)
+ repeat = 1000
+ engine = get_engine(args.precision, onnx_model)
+
+ model_all_names = []
+ for idx in range(engine.num_bindings):
+ is_input = engine.binding_is_input(idx)
+ name = engine.get_binding_name(idx)
+ op_type = engine.get_binding_dtype(idx)
+ model_all_names.append(name)
+ shape = engine.get_binding_shape(idx)
+ print('input id:', idx, ' is input: ', is_input, ' binding name:',
+ name, ' shape:', shape, 'type: ', op_type)
+
+ context = engine.create_execution_context()
+ print('Allocate buffers ...')
+ inputs, outputs, bindings, stream = allocate_buffers(engine)
+ print("TRT set input ...")
+
+ origin_img = cv2.imread(img_path)
+ input_shape = [args.img_shape, args.img_shape]
+ input_image, ratio = preprocess(origin_img, input_shape)
+
+ inputs[0].host = np.expand_dims(input_image, axis=0)
+
+ for _ in range(0, 50):
+ trt_outputs = run_inference(
+ context,
+ bindings=bindings,
+ inputs=inputs,
+ outputs=outputs,
+ stream=stream)
+
+ time1 = time.time()
+ for _ in range(0, repeat):
+ trt_outputs = run_inference(
+ context,
+ bindings=bindings,
+ inputs=inputs,
+ outputs=outputs,
+ stream=stream)
+ time2 = time.time()
+ # total time cost(ms)
+ total_inference_cost = (time2 - time1) * 1000
+ print("model path: ", onnx_model, " precision: ", args.precision)
+ print("In TensorRT, ",
+ "average latency is : {} ms".format(total_inference_cost / repeat))
+ # Do postprocess
+ output = trt_outputs[0]
+ predictions = np.reshape(output, (1, -1, int(5 + num_class)))[0]
+ dets = postprocess(predictions, ratio)
+ # Draw rectangles and labels on the original image
+ if dets is not None:
+ final_boxes, final_scores, final_cls_inds = dets[:, :
+ 4], dets[:, 4], dets[:,
+ 5]
+ origin_img = draw_box(
+ origin_img,
+ final_boxes,
+ final_scores,
+ final_cls_inds,
+ conf=0.5,
+ class_names=CLASS_LABEL)
+ cv2.imwrite('output.jpg', origin_img)
+ print('The prediction results are saved in output.jpg.')
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--model_path',
+ type=str,
+ default="quant_model.onnx",
+ help="inference model filepath")
+ parser.add_argument(
+ '--image_file', type=str, default="bus.jpg", help="image path")
+ parser.add_argument(
+ '--precision', type=str, default='fp32', help="support fp32/fp16/int8.")
+ parser.add_argument('--img_shape', type=int, default=640, help="input_size")
+ args = parser.parse_args()
+ main(args)
diff --git a/example/auto_compression/pytorch_yolov7/paddle_trt_infer.py b/example/auto_compression/pytorch_yolo_series/paddle_trt_infer.py
similarity index 98%
rename from example/auto_compression/pytorch_yolov7/paddle_trt_infer.py
rename to example/auto_compression/pytorch_yolo_series/paddle_trt_infer.py
index fedc9cc17fed3bd409d6d3a91630f05f9a907af1..eacb67fbbaf1bfbd32df403aed4a93ea110d6e94 100644
--- a/example/auto_compression/pytorch_yolov7/paddle_trt_infer.py
+++ b/example/auto_compression/pytorch_yolo_series/paddle_trt_infer.py
@@ -244,8 +244,9 @@ def predict_image(predictor,
threshold=0.5,
arch='YOLOv5'):
img, scale_factor = image_preprocess(image_file, image_shape)
- inputs = {}
- if arch == 'YOLOv5':
+ if arch == 'YOLOv6':
+ inputs['x2paddle_image_arrays'] = img
+ else:
inputs['x2paddle_images'] = img
input_names = predictor.get_input_names()
for i in range(len(input_names)):
@@ -306,6 +307,8 @@ if __name__ == '__main__':
default='GPU',
help="Choose the device you want to run, it can be: CPU/GPU/XPU, default is GPU"
)
+ parser.add_argument(
+ '--arch', type=str, default='YOLOv5', help="architectures name.")
parser.add_argument('--img_shape', type=int, default=640, help="input_size")
args = parser.parse_args()
@@ -319,4 +322,5 @@ if __name__ == '__main__':
args.image_file,
image_shape=[args.img_shape, args.img_shape],
warmup=warmup,
- repeats=repeats)
+ repeats=repeats,
+ arch=args.arch)
diff --git a/example/auto_compression/pytorch_yolov6/post_process.py b/example/auto_compression/pytorch_yolo_series/post_process.py
similarity index 75%
rename from example/auto_compression/pytorch_yolov6/post_process.py
rename to example/auto_compression/pytorch_yolo_series/post_process.py
index 37bd2c959fb2609f573a599a56c0188dd92d1f09..644c24b8157f7c861fac2a49965e617615db4231 100644
--- a/example/auto_compression/pytorch_yolov6/post_process.py
+++ b/example/auto_compression/pytorch_yolo_series/post_process.py
@@ -14,6 +14,8 @@
import numpy as np
import cv2
+import json
+import sys
def box_area(boxes):
@@ -68,9 +70,9 @@ def nms(boxes, scores, iou_threshold):
return keep
-class YOLOv6PostProcess(object):
+class YOLOPostProcess(object):
"""
- Post process of YOLOv6 network.
+ Post process of YOLO-series network.
args:
score_threshold(float): Threshold to filter out bounding boxes with low
confidence score. If not provided, consider all boxes.
@@ -157,8 +159,8 @@ class YOLOv6PostProcess(object):
if len(pred.shape) == 1:
pred = pred[np.newaxis, :]
pred_bboxes = pred[:, :4]
- scale_factor = np.tile(scale_factor[i][::-1], (1, 2))
- pred_bboxes /= scale_factor
+ scale = np.tile(scale_factor[i][::-1], (2))
+ pred_bboxes /= scale
bbox = np.concatenate(
[
pred[:, -1][:, np.newaxis], pred[:, -2][:, np.newaxis],
@@ -171,3 +173,59 @@ class YOLOv6PostProcess(object):
bboxs = np.concatenate(bboxs, axis=0)
box_nums = np.array(box_nums)
return {'bbox': bboxs, 'bbox_num': box_nums}
+
+
+def coco_metric(anno_file, bboxes_list, bbox_nums_list, image_id_list):
+ try:
+ from pycocotools.coco import COCO
+ from pycocotools.cocoeval import COCOeval
+ except:
+ print(
+ "[ERROR] Not found pycocotools, please install by `pip install pycocotools`"
+ )
+ sys.exit(1)
+
+ coco_gt = COCO(anno_file)
+ cats = coco_gt.loadCats(coco_gt.getCatIds())
+ clsid2catid = {i: cat['id'] for i, cat in enumerate(cats)}
+ results = []
+ for bboxes, bbox_nums, image_id in zip(bboxes_list, bbox_nums_list,
+ image_id_list):
+ results += _get_det_res(bboxes, bbox_nums, image_id, clsid2catid)
+
+ output = "bbox.json"
+ with open(output, 'w') as f:
+ json.dump(results, f)
+
+ coco_dt = coco_gt.loadRes(output)
+ coco_eval = COCOeval(coco_gt, coco_dt, 'bbox')
+ coco_eval.evaluate()
+ coco_eval.accumulate()
+ coco_eval.summarize()
+ return coco_eval.stats
+
+
+def _get_det_res(bboxes, bbox_nums, image_id, label_to_cat_id_map):
+ det_res = []
+ k = 0
+ for i in range(len(bbox_nums)):
+ cur_image_id = int(image_id[i][0])
+ det_nums = bbox_nums[i]
+ for j in range(det_nums):
+ dt = bboxes[k]
+ k = k + 1
+ num_id, score, xmin, ymin, xmax, ymax = dt.tolist()
+ if int(num_id) < 0:
+ continue
+ category_id = label_to_cat_id_map[int(num_id)]
+ w = xmax - xmin
+ h = ymax - ymin
+ bbox = [xmin, ymin, w, h]
+ dt_res = {
+ 'image_id': cur_image_id,
+ 'category_id': category_id,
+ 'bbox': bbox,
+ 'score': score
+ }
+ det_res.append(dt_res)
+ return det_res
diff --git a/example/auto_compression/pytorch_yolo_series/run.py b/example/auto_compression/pytorch_yolo_series/run.py
new file mode 100644
index 0000000000000000000000000000000000000000..1a22d822044fd2cbc8f445359ba398ed7738a96e
--- /dev/null
+++ b/example/auto_compression/pytorch_yolo_series/run.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import numpy as np
+import argparse
+from tqdm import tqdm
+import paddle
+from paddleslim.common import load_config
+from paddleslim.auto_compression import AutoCompression
+from dataset import COCOValDataset, COCOTrainDataset
+from post_process import YOLOPostProcess, coco_metric
+
+
+def argsparser():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '--config_path',
+ type=str,
+ default=None,
+ help="path of compression strategy config.",
+ required=True)
+ parser.add_argument(
+ '--save_dir',
+ type=str,
+ default='output',
+ help="directory to save compressed model.")
+ parser.add_argument(
+ '--devices',
+ type=str,
+ default='gpu',
+ help="which device used to compress.")
+ parser.add_argument(
+ '--eval', type=bool, default=False, help="whether to run evaluation.")
+
+ return parser
+
+
+def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
+ bboxes_list, bbox_nums_list, image_id_list = [], [], []
+ with tqdm(
+ total=len(val_loader),
+ bar_format='Evaluation stage, Run batch:|{bar}| {n_fmt}/{total_fmt}',
+ ncols=80) as t:
+ for data in val_loader:
+ data_all = {k: np.array(v) for k, v in data.items()}
+ outs = exe.run(compiled_test_program,
+ feed={test_feed_names[0]: data_all['image']},
+ fetch_list=test_fetch_list,
+ return_numpy=False)
+ res = {}
+ postprocess = YOLOPostProcess(
+ score_threshold=0.001, nms_threshold=0.65, multi_label=True)
+ res = postprocess(np.array(outs[0]), data_all['scale_factor'])
+ bboxes_list.append(res['bbox'])
+ bbox_nums_list.append(res['bbox_num'])
+ image_id_list.append(np.array(data_all['im_id']))
+ t.update()
+ map_res = coco_metric(anno_file, bboxes_list, bbox_nums_list, image_id_list)
+ return map_res[0]
+
+
+def main():
+ global global_config
+ all_config = load_config(FLAGS.config_path)
+ assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
+ global_config = all_config["Global"]
+ input_name = 'x2paddle_image_arrays' if global_config[
+ 'arch'] == 'YOLOv6' else 'x2paddle_images'
+ dataset = COCOTrainDataset(
+ dataset_dir=global_config['dataset_dir'],
+ image_dir=global_config['train_image_dir'],
+ anno_path=global_config['train_anno_path'],
+ input_name=input_name)
+ train_loader = paddle.io.DataLoader(
+ dataset, batch_size=1, shuffle=True, drop_last=True, num_workers=0)
+
+ if 'Evaluation' in global_config.keys() and global_config[
+ 'Evaluation'] and paddle.distributed.get_rank() == 0:
+ eval_func = eval_function
+ global val_loader
+ dataset = COCOValDataset(
+ dataset_dir=global_config['dataset_dir'],
+ image_dir=global_config['val_image_dir'],
+ anno_path=global_config['val_anno_path'])
+ global anno_file
+ anno_file = dataset.ann_file
+ val_loader = paddle.io.DataLoader(
+ dataset,
+ batch_size=1,
+ shuffle=False,
+ drop_last=False,
+ num_workers=0)
+ else:
+ eval_func = None
+
+ ac = AutoCompression(
+ model_dir=global_config["model_dir"],
+ train_dataloader=train_loader,
+ save_dir=FLAGS.save_dir,
+ config=all_config,
+ eval_callback=eval_func)
+ ac.compress()
+ ac.export_onnx()
+
+
+if __name__ == '__main__':
+ paddle.enable_static()
+ parser = argsparser()
+ FLAGS = parser.parse_args()
+
+ assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
+ paddle.set_device(FLAGS.devices)
+
+ main()
diff --git a/example/auto_compression/pytorch_yolov5/README.md b/example/auto_compression/pytorch_yolov5/README.md
deleted file mode 100644
index 1670940842ff8acb65f46b82ea90152502ec0ab5..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov5/README.md
+++ /dev/null
@@ -1,147 +0,0 @@
-# YOLOv5目标检测模型自动压缩示例
-
-目录:
-- [1.简介](#1简介)
-- [2.Benchmark](#2Benchmark)
-- [3.开始自动压缩](#自动压缩流程)
- - [3.1 环境准备](#31-准备环境)
- - [3.2 准备数据集](#32-准备数据集)
- - [3.3 准备预测模型](#33-准备预测模型)
- - [3.4 测试模型精度](#34-测试模型精度)
- - [3.5 自动压缩并产出模型](#35-自动压缩并产出模型)
-- [4.预测部署](#4预测部署)
-- [5.FAQ](5FAQ)
-
-## 1. 简介
-
-飞桨模型转换工具[X2Paddle](https://github.com/PaddlePaddle/X2Paddle)支持将```Caffe/TensorFlow/ONNX/PyTorch```的模型一键转为飞桨(PaddlePaddle)的预测模型。借助X2Paddle的能力,各种框架的推理模型可以很方便的使用PaddleSlim的自动化压缩功能。
-
-本示例将以[ultralytics/yolov5](https://github.com/ultralytics/yolov5)目标检测模型为例,将PyTorch框架模型转换为Paddle框架模型,再使用ACT自动压缩功能进行自动压缩。本示例使用的自动压缩策略为量化训练。
-
-## 2.Benchmark
-
-| 模型 | 策略 | 输入尺寸 | mAPval
0.5:0.95 | 预测时延FP32
(ms) |预测时延FP16
(ms) | 预测时延INT8
(ms) | 配置文件 | Inference模型 |
-| :-------- |:-------- |:--------: | :---------------------: | :----------------: | :----------------: | :---------------: | :-----------------------------: | :-----------------------------: |
-| YOLOv5s | Base模型 | 640*640 | 37.4 | 5.95ms | 2.44ms | - | - | [Model](https://bj.bcebos.com/v1/paddle-slim-models/detection/yolov5s_infer.tar) |
-| YOLOv5s | KL离线量化 | 640*640 | 36.0 | - | - | 1.87ms | - | - |
-| YOLOv5s | 量化蒸馏训练 | 640*640 | **36.9** | - | - | **1.87ms** | [config](./configs/yolov5s_qat_dis.yaml) | [Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov5s_quant.tar) |
-
-
-说明:
-- mAP的指标均在COCO val2017数据集中评测得到。
-- YOLOv5s模型在Tesla T4的GPU环境下开启TensorRT 8.4.1,batch_size=1, 测试脚本是[cpp_infer](./cpp_infer)。
-
-## 3. 自动压缩流程
-
-#### 3.1 准备环境
-- PaddlePaddle >= 2.3 (可从[Paddle官网](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)下载安装)
-- PaddleSlim >= 2.3
-- PaddleDet >= 2.4
-- [X2Paddle](https://github.com/PaddlePaddle/X2Paddle) >= 1.3.6
-- opencv-python
-
-(1)安装paddlepaddle:
-```shell
-# CPU
-pip install paddlepaddle
-# GPU
-pip install paddlepaddle-gpu
-```
-
-(2)安装paddleslim:
-```shell
-pip install paddleslim
-```
-
-(3)安装paddledet:
-```shell
-pip install paddledet
-```
-
-注:安装PaddleDet的目的是为了直接使用PaddleDetection中的Dataloader组件。
-
-(4)安装X2Paddle的1.3.6以上版本:
-```shell
-pip install x2paddle sympy onnx
-```
-
-#### 3.2 准备数据集
-
-本案例默认以COCO数据进行自动压缩实验,并且依赖PaddleDetection中数据读取模块,如果自定义COCO数据,或者其他格式数据,请参考[PaddleDetection数据准备文档](https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.4/docs/tutorials/PrepareDataSet.md) 来准备数据。
-
-如果已经准备好数据集,请直接修改[./configs/yolov6_reader.yml]中`EvalDataset`的`dataset_dir`字段为自己数据集路径即可。
-
-#### 3.3 准备预测模型
-
-(1)准备ONNX模型:
-
-可通过[ultralytics/yolov5](https://github.com/ultralytics/yolov5) 官方的[导出教程](https://github.com/ultralytics/yolov5/issues/251)来准备ONNX模型。也可以下载准备好的[yolov5s.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov5s.onnx)。
-```shell
-python export.py --weights yolov5s.pt --include onnx
-```
-
-(2) 转换模型:
-```shell
-x2paddle --framework=onnx --model=yolov5s.onnx --save_dir=pd_model
-cp -r pd_model/inference_model/ yolov5s_infer
-```
-即可得到YOLOv5s模型的预测模型(`model.pdmodel` 和 `model.pdiparams`)。如想快速体验,可直接下载上方表格中YOLOv5s的[Paddle预测模型](https://bj.bcebos.com/v1/paddle-slim-models/detection/yolov5s_infer.tar)。
-
-
-预测模型的格式为:`model.pdmodel` 和 `model.pdiparams`两个,带`pdmodel`的是模型文件,带`pdiparams`后缀的是权重文件。
-
-
-#### 3.4 自动压缩并产出模型
-
-蒸馏量化自动压缩示例通过run.py脚本启动,会使用接口```paddleslim.auto_compression.AutoCompression```对模型进行自动压缩。配置config文件中模型路径、蒸馏、量化、和训练等部分的参数,配置完成后便可对模型进行量化和蒸馏。具体运行命令为:
-
-- 单卡训练:
-```
-export CUDA_VISIBLE_DEVICES=0
-python run.py --config_path=./configs/yolov5s_qat_dis.yaml --save_dir='./output/'
-```
-
-- 多卡训练:
-```
-CUDA_VISIBLE_DEVICES=0,1,2,3 python -m paddle.distributed.launch --log_dir=log --gpus 0,1,2,3 run.py \
- --config_path=./configs/yolov5s_qat_dis.yaml --save_dir='./output/'
-```
-
-#### 3.5 测试模型精度
-
-使用eval.py脚本得到模型的mAP:
-```
-export CUDA_VISIBLE_DEVICES=0
-python eval.py --config_path=./configs/yolov5s_qat_dis.yaml
-```
-
-**注意**:如果要测试量化后的模型,模型路径需要在配置文件中`model_dir`字段下进行修改指定。
-
-
-## 4.预测部署
-
-#### Paddle-TensorRT C++部署
-
-进入[cpp_infer](./cpp_infer)文件夹内,请按照[C++ TensorRT Benchmark测试教程](./cpp_infer/README.md)进行准备环境及编译,然后开始测试:
-```shell
-# 编译
-bash complie.sh
-# 执行
-./build/trt_run --model_file yolov5s_quant/model.pdmodel --params_file yolov5s_quant/model.pdiparams --run_mode=trt_int8
-```
-
-#### Paddle-TensorRT Python部署:
-
-首先安装带有TensorRT的[Paddle安装包](https://www.paddlepaddle.org.cn/inference/v2.3/user_guides/download_lib.html#python)。
-
-然后使用[paddle_trt_infer.py](./paddle_trt_infer.py)进行部署:
-```shell
-python paddle_trt_infer.py --model_path=output --image_file=images/000000570688.jpg --benchmark=True --run_mode=trt_int8
-```
-
-## 5.FAQ
-
-- 如果想测试离线量化模型精度,可执行:
-```shell
-python post_quant.py --config_path=./configs/yolov5s_qat_dis.yaml
-```
diff --git a/example/auto_compression/pytorch_yolov5/configs/yolov5_reader.yml b/example/auto_compression/pytorch_yolov5/configs/yolov5_reader.yml
deleted file mode 100644
index cb87c3f8fde8bd0149189cd6a9f3437e7f4548e2..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov5/configs/yolov5_reader.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-metric: COCO
-num_classes: 80
-
-# Datset configuration
-TrainDataset:
- !COCODataSet
- image_dir: train2017
- anno_path: annotations/instances_train2017.json
- dataset_dir: dataset/coco/
-
-EvalDataset:
- !COCODataSet
- image_dir: val2017
- anno_path: annotations/instances_val2017.json
- dataset_dir: dataset/coco/
-
-worker_num: 0
-
-# preprocess reader in test
-EvalReader:
- sample_transforms:
- - Decode: {}
- - Resize: {target_size: [640, 640], keep_ratio: True}
- - Pad: {size: [640, 640], fill_value: [114., 114., 114.]}
- - NormalizeImage: {mean: [0, 0, 0], std: [1, 1, 1], is_scale: True}
- - Permute: {}
- batch_size: 1
diff --git a/example/auto_compression/pytorch_yolov5/cpp_infer/trt_run.cc b/example/auto_compression/pytorch_yolov5/cpp_infer/trt_run.cc
deleted file mode 100644
index 0ae055acb6e42f226d023fadfd5923bd79c19bfd..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov5/cpp_infer/trt_run.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include "paddle/include/paddle_inference_api.h"
-#include "paddle/include/experimental/phi/common/float16.h"
-
-using paddle_infer::Config;
-using paddle_infer::Predictor;
-using paddle_infer::CreatePredictor;
-using paddle_infer::PrecisionType;
-using phi::dtype::float16;
-
-DEFINE_string(model_dir, "", "Directory of the inference model.");
-DEFINE_string(model_file, "", "Path of the inference model file.");
-DEFINE_string(params_file, "", "Path of the inference params file.");
-DEFINE_string(run_mode, "trt_fp32", "run_mode which can be: trt_fp32, trt_fp16 and trt_int8");
-DEFINE_int32(batch_size, 1, "Batch size.");
-DEFINE_int32(gpu_id, 0, "GPU card ID num.");
-DEFINE_int32(trt_min_subgraph_size, 3, "tensorrt min_subgraph_size");
-DEFINE_int32(warmup, 50, "warmup");
-DEFINE_int32(repeats, 1000, "repeats");
-
-using Time = decltype(std::chrono::high_resolution_clock::now());
-Time time() { return std::chrono::high_resolution_clock::now(); };
-double time_diff(Time t1, Time t2) {
- typedef std::chrono::microseconds ms;
- auto diff = t2 - t1;
- ms counter = std::chrono::duration_cast(diff);
- return counter.count() / 1000.0;
-}
-
-std::shared_ptr InitPredictor() {
- Config config;
- std::string model_path;
- if (FLAGS_model_dir != "") {
- config.SetModel(FLAGS_model_dir);
- model_path = FLAGS_model_dir.substr(0, FLAGS_model_dir.find_last_of("/"));
- } else {
- config.SetModel(FLAGS_model_file, FLAGS_params_file);
- model_path = FLAGS_model_file.substr(0, FLAGS_model_file.find_last_of("/"));
- }
- // enable tune
- std::cout << "model_path: " << model_path << std::endl;
- config.EnableUseGpu(256, FLAGS_gpu_id);
- if (FLAGS_run_mode == "trt_fp32") {
- config.EnableTensorRtEngine(1 << 30, FLAGS_batch_size, FLAGS_trt_min_subgraph_size,
- PrecisionType::kFloat32, false, false);
- } else if (FLAGS_run_mode == "trt_fp16") {
- config.EnableTensorRtEngine(1 << 30, FLAGS_batch_size, FLAGS_trt_min_subgraph_size,
- PrecisionType::kHalf, false, false);
- } else if (FLAGS_run_mode == "trt_int8") {
- config.EnableTensorRtEngine(1 << 30, FLAGS_batch_size, FLAGS_trt_min_subgraph_size,
- PrecisionType::kInt8, false, false);
- }
- config.EnableMemoryOptim();
- config.SwitchIrOptim(true);
- return CreatePredictor(config);
-}
-
-template
-void run(Predictor *predictor, const std::vector &input,
- const std::vector &input_shape, type* out_data, std::vector out_shape) {
-
- // prepare input
- int input_num = std::accumulate(input_shape.begin(), input_shape.end(), 1,
- std::multiplies());
-
- auto input_names = predictor->GetInputNames();
- auto input_t = predictor->GetInputHandle(input_names[0]);
- input_t->Reshape(input_shape);
- input_t->CopyFromCpu(input.data());
-
- for (int i = 0; i < FLAGS_warmup; ++i)
- CHECK(predictor->Run());
-
- auto st = time();
- for (int i = 0; i < FLAGS_repeats; ++i) {
- auto input_names = predictor->GetInputNames();
- auto input_t = predictor->GetInputHandle(input_names[0]);
- input_t->Reshape(input_shape);
- input_t->CopyFromCpu(input.data());
-
- CHECK(predictor->Run());
-
- auto output_names = predictor->GetOutputNames();
- auto output_t = predictor->GetOutputHandle(output_names[0]);
- std::vector output_shape = output_t->shape();
- output_t -> ShareExternalData(out_data, out_shape, paddle_infer::PlaceType::kGPU);
- }
-
- LOG(INFO) << "[" << FLAGS_run_mode << " bs-" << FLAGS_batch_size << " ] run avg time is " << time_diff(st, time()) / FLAGS_repeats
- << " ms";
-}
-
-int main(int argc, char *argv[]) {
- google::ParseCommandLineFlags(&argc, &argv, true);
- auto predictor = InitPredictor();
- std::vector input_shape = {FLAGS_batch_size, 3, 640, 640};
- // float16
- using dtype = float16;
- std::vector input_data(FLAGS_batch_size * 3 * 640 * 640, dtype(1.0));
-
- dtype *out_data;
- int out_data_size = FLAGS_batch_size * 25200 * 85;
- cudaHostAlloc((void**)&out_data, sizeof(float) * out_data_size, cudaHostAllocMapped);
-
- std::vector out_shape{ FLAGS_batch_size, 1, 25200, 85};
- run(predictor.get(), input_data, input_shape, out_data, out_shape);
- return 0;
-}
diff --git a/example/auto_compression/pytorch_yolov5/paddle_trt_infer.py b/example/auto_compression/pytorch_yolov5/paddle_trt_infer.py
deleted file mode 100644
index 62c2c89b28c07de1207ab451d69d537c07b876ca..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov5/paddle_trt_infer.py
+++ /dev/null
@@ -1,322 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import cv2
-import numpy as np
-import argparse
-import time
-
-from paddle.inference import Config
-from paddle.inference import create_predictor
-
-from post_process import YOLOv5PostProcess
-
-CLASS_LABEL = [
- 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train',
- 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign',
- 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
- 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag',
- 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite',
- 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
- 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon',
- 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot',
- 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant',
- 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote',
- 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink',
- 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
- 'hair drier', 'toothbrush'
-]
-
-
-def generate_scale(im, target_shape, keep_ratio=True):
- """
- Args:
- im (np.ndarray): image (np.ndarray)
- Returns:
- im_scale_x: the resize ratio of X
- im_scale_y: the resize ratio of Y
- """
- origin_shape = im.shape[:2]
- if keep_ratio:
- im_size_min = np.min(origin_shape)
- im_size_max = np.max(origin_shape)
- target_size_min = np.min(target_shape)
- target_size_max = np.max(target_shape)
- im_scale = float(target_size_min) / float(im_size_min)
- if np.round(im_scale * im_size_max) > target_size_max:
- im_scale = float(target_size_max) / float(im_size_max)
- im_scale_x = im_scale
- im_scale_y = im_scale
- else:
- resize_h, resize_w = target_shape
- im_scale_y = resize_h / float(origin_shape[0])
- im_scale_x = resize_w / float(origin_shape[1])
- return im_scale_y, im_scale_x
-
-
-def image_preprocess(img_path, target_shape):
- img = cv2.imread(img_path)
- # Resize
- im_scale_y, im_scale_x = generate_scale(img, target_shape)
- img = cv2.resize(
- img,
- None,
- None,
- fx=im_scale_x,
- fy=im_scale_y,
- interpolation=cv2.INTER_LINEAR)
- # Pad
- im_h, im_w = img.shape[:2]
- h, w = target_shape[:]
- if h != im_h or w != im_w:
- canvas = np.ones((h, w, 3), dtype=np.float32)
- canvas *= np.array([114.0, 114.0, 114.0], dtype=np.float32)
- canvas[0:im_h, 0:im_w, :] = img.astype(np.float32)
- img = canvas
- img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
- img = np.transpose(img, [2, 0, 1]) / 255
- img = np.expand_dims(img, 0)
- scale_factor = np.array([[im_scale_y, im_scale_x]])
- return img.astype(np.float32), scale_factor
-
-
-def get_color_map_list(num_classes):
- color_map = num_classes * [0, 0, 0]
- for i in range(0, num_classes):
- j = 0
- lab = i
- while lab:
- color_map[i * 3] |= (((lab >> 0) & 1) << (7 - j))
- color_map[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j))
- color_map[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j))
- j += 1
- lab >>= 3
- color_map = [color_map[i:i + 3] for i in range(0, len(color_map), 3)]
- return color_map
-
-
-def draw_box(image_file, results, class_label, threshold=0.5):
- srcimg = cv2.imread(image_file, 1)
- for i in range(len(results)):
- color_list = get_color_map_list(len(class_label))
- clsid2color = {}
- classid, conf = int(results[i, 0]), results[i, 1]
- if conf < threshold:
- continue
- xmin, ymin, xmax, ymax = int(results[i, 2]), int(results[i, 3]), int(
- results[i, 4]), int(results[i, 5])
-
- if classid not in clsid2color:
- clsid2color[classid] = color_list[classid]
- color = tuple(clsid2color[classid])
-
- cv2.rectangle(srcimg, (xmin, ymin), (xmax, ymax), color, thickness=2)
- print(class_label[classid] + ': ' + str(round(conf, 3)))
- cv2.putText(
- srcimg,
- class_label[classid] + ':' + str(round(conf, 3)), (xmin, ymin - 10),
- cv2.FONT_HERSHEY_SIMPLEX,
- 0.8, (0, 255, 0),
- thickness=2)
- return srcimg
-
-
-def load_predictor(model_dir,
- run_mode='paddle',
- batch_size=1,
- device='CPU',
- min_subgraph_size=3,
- use_dynamic_shape=False,
- trt_min_shape=1,
- trt_max_shape=1280,
- trt_opt_shape=640,
- trt_calib_mode=False,
- cpu_threads=1,
- enable_mkldnn=False,
- enable_mkldnn_bfloat16=False,
- delete_shuffle_pass=False):
- """set AnalysisConfig, generate AnalysisPredictor
- Args:
- model_dir (str): root path of __model__ and __params__
- device (str): Choose the device you want to run, it can be: CPU/GPU/XPU, default is CPU
- run_mode (str): mode of running(paddle/trt_fp32/trt_fp16/trt_int8)
- use_dynamic_shape (bool): use dynamic shape or not
- trt_min_shape (int): min shape for dynamic shape in trt
- trt_max_shape (int): max shape for dynamic shape in trt
- trt_opt_shape (int): opt shape for dynamic shape in trt
- trt_calib_mode (bool): If the model is produced by TRT offline quantitative
- calibration, trt_calib_mode need to set True
- delete_shuffle_pass (bool): whether to remove shuffle_channel_detect_pass in TensorRT.
- Used by action model.
- Returns:
- predictor (PaddlePredictor): AnalysisPredictor
- Raises:
- ValueError: predict by TensorRT need device == 'GPU'.
- """
- if device != 'GPU' and run_mode != 'paddle':
- raise ValueError(
- "Predict by TensorRT mode: {}, expect device=='GPU', but device == {}"
- .format(run_mode, device))
- config = Config(
- os.path.join(model_dir, 'model.pdmodel'),
- os.path.join(model_dir, 'model.pdiparams'))
- if device == 'GPU':
- # initial GPU memory(M), device ID
- config.enable_use_gpu(200, 0)
- # optimize graph and fuse op
- config.switch_ir_optim(True)
- elif device == 'XPU':
- config.enable_lite_engine()
- config.enable_xpu(10 * 1024 * 1024)
- else:
- config.disable_gpu()
- config.set_cpu_math_library_num_threads(cpu_threads)
- if enable_mkldnn:
- try:
- # cache 10 different shapes for mkldnn to avoid memory leak
- config.set_mkldnn_cache_capacity(10)
- config.enable_mkldnn()
- if enable_mkldnn_bfloat16:
- config.enable_mkldnn_bfloat16()
- except Exception as e:
- print(
- "The current environment does not support `mkldnn`, so disable mkldnn."
- )
- pass
-
- precision_map = {
- 'trt_int8': Config.Precision.Int8,
- 'trt_fp32': Config.Precision.Float32,
- 'trt_fp16': Config.Precision.Half
- }
- if run_mode in precision_map.keys():
- config.enable_tensorrt_engine(
- workspace_size=(1 << 25) * batch_size,
- max_batch_size=batch_size,
- min_subgraph_size=min_subgraph_size,
- precision_mode=precision_map[run_mode],
- use_static=False,
- use_calib_mode=trt_calib_mode)
-
- if use_dynamic_shape:
- min_input_shape = {
- 'image': [batch_size, 3, trt_min_shape, trt_min_shape]
- }
- max_input_shape = {
- 'image': [batch_size, 3, trt_max_shape, trt_max_shape]
- }
- opt_input_shape = {
- 'image': [batch_size, 3, trt_opt_shape, trt_opt_shape]
- }
- config.set_trt_dynamic_shape_info(min_input_shape, max_input_shape,
- opt_input_shape)
- print('trt set dynamic shape done!')
-
- # disable print log when predict
- config.disable_glog_info()
- # enable shared memory
- config.enable_memory_optim()
- # disable feed, fetch OP, needed by zero_copy_run
- config.switch_use_feed_fetch_ops(False)
- if delete_shuffle_pass:
- config.delete_pass("shuffle_channel_detect_pass")
- predictor = create_predictor(config)
- return predictor
-
-
-def predict_image(predictor,
- image_file,
- image_shape=[640, 640],
- warmup=1,
- repeats=1,
- threshold=0.5,
- arch='YOLOv5'):
- img, scale_factor = image_preprocess(image_file, image_shape)
- inputs = {}
- if arch == 'YOLOv5':
- inputs['x2paddle_images'] = img
- input_names = predictor.get_input_names()
- for i in range(len(input_names)):
- input_tensor = predictor.get_input_handle(input_names[i])
- input_tensor.copy_from_cpu(inputs[input_names[i]])
-
- for i in range(warmup):
- predictor.run()
-
- np_boxes = None
- predict_time = 0.
- time_min = float("inf")
- time_max = float('-inf')
- for i in range(repeats):
- start_time = time.time()
- predictor.run()
- output_names = predictor.get_output_names()
- boxes_tensor = predictor.get_output_handle(output_names[0])
- np_boxes = boxes_tensor.copy_to_cpu()
- end_time = time.time()
- timed = end_time - start_time
- time_min = min(time_min, timed)
- time_max = max(time_max, timed)
- predict_time += timed
-
- time_avg = predict_time / repeats
- print('Inference time(ms): min={}, max={}, avg={}'.format(
- round(time_min * 1000, 2),
- round(time_max * 1000, 1), round(time_avg * 1000, 1)))
- postprocess = YOLOv5PostProcess(
- score_threshold=0.001, nms_threshold=0.6, multi_label=True)
- res = postprocess(np_boxes, scale_factor)
- res_img = draw_box(
- image_file, res['bbox'], CLASS_LABEL, threshold=threshold)
- cv2.imwrite('result.jpg', res_img)
-
-
-if __name__ == '__main__':
-
- parser = argparse.ArgumentParser()
- parser.add_argument(
- '--image_file', type=str, default=None, help="image path")
- parser.add_argument(
- '--model_path', type=str, help="inference model filepath")
- parser.add_argument(
- '--benchmark',
- type=bool,
- default=False,
- help="Whether run benchmark or not.")
- parser.add_argument(
- '--run_mode',
- type=str,
- default='paddle',
- help="mode of running(paddle/trt_fp32/trt_fp16/trt_int8)")
- parser.add_argument(
- '--device',
- type=str,
- default='GPU',
- help="Choose the device you want to run, it can be: CPU/GPU/XPU, default is GPU"
- )
- parser.add_argument('--img_shape', type=int, default=640, help="input_size")
- args = parser.parse_args()
-
- predictor = load_predictor(
- args.model_path, run_mode=args.run_mode, device=args.device)
- warmup, repeats = 1, 1
- if args.benchmark:
- warmup, repeats = 50, 100
- predict_image(
- predictor,
- args.image_file,
- image_shape=[args.img_shape, args.img_shape],
- warmup=warmup,
- repeats=repeats)
diff --git a/example/auto_compression/pytorch_yolov5/run.py b/example/auto_compression/pytorch_yolov5/run.py
deleted file mode 100644
index 965a546f1d7c519130dfef4b0b3de3f2ac8d68cd..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov5/run.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import sys
-import numpy as np
-import argparse
-import paddle
-from ppdet.core.workspace import load_config, merge_config
-from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
-from paddleslim.auto_compression import AutoCompression
-
-from post_process import YOLOv5PostProcess
-
-
-def argsparser():
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument(
- '--config_path',
- type=str,
- default=None,
- help="path of compression strategy config.",
- required=True)
- parser.add_argument(
- '--save_dir',
- type=str,
- default='output',
- help="directory to save compressed model.")
- parser.add_argument(
- '--devices',
- type=str,
- default='gpu',
- help="which device used to compress.")
-
- return parser
-
-
-def reader_wrapper(reader, input_list):
- def gen():
- for data in reader:
- in_dict = {}
- if isinstance(input_list, list):
- for input_name in input_list:
- in_dict[input_name] = data[input_name]
- elif isinstance(input_list, dict):
- for input_name in input_list.keys():
- in_dict[input_list[input_name]] = data[input_name]
- yield in_dict
-
- return gen
-
-
-def convert_numpy_data(data, metric):
- data_all = {}
- data_all = {k: np.array(v) for k, v in data.items()}
- if isinstance(metric, VOCMetric):
- for k, v in data_all.items():
- if not isinstance(v[0], np.ndarray):
- tmp_list = []
- for t in v:
- tmp_list.append(np.array(t))
- data_all[k] = np.array(tmp_list)
- else:
- data_all = {k: np.array(v) for k, v in data.items()}
- return data_all
-
-
-def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
- metric = global_config['metric']
- for batch_id, data in enumerate(val_loader):
- data_all = convert_numpy_data(data, metric)
- data_input = {}
- for k, v in data.items():
- if isinstance(global_config['input_list'], list):
- if k in test_feed_names:
- data_input[k] = np.array(v)
- elif isinstance(global_config['input_list'], dict):
- if k in global_config['input_list'].keys():
- data_input[global_config['input_list'][k]] = np.array(v)
- outs = exe.run(compiled_test_program,
- feed=data_input,
- fetch_list=test_fetch_list,
- return_numpy=False)
- res = {}
- if 'arch' in global_config and global_config['arch'] == 'YOLOv5':
- postprocess = YOLOv5PostProcess(
- score_threshold=0.001, nms_threshold=0.6, multi_label=True)
- res = postprocess(np.array(outs[0]), data_all['scale_factor'])
- else:
- for out in outs:
- v = np.array(out)
- if len(v.shape) > 1:
- res['bbox'] = v
- else:
- res['bbox_num'] = v
-
- metric.update(data_all, res)
- if batch_id % 100 == 0:
- print('Eval iter:', batch_id)
- metric.accumulate()
- metric.log()
- map_res = metric.get_results()
- metric.reset()
- return map_res['bbox'][0]
-
-
-def main():
- global global_config
- all_config = load_slim_config(FLAGS.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
- global_config = all_config["Global"]
- reader_cfg = load_config(global_config['reader_config'])
-
- train_loader = create('EvalReader')(reader_cfg['TrainDataset'],
- reader_cfg['worker_num'],
- return_list=True)
- train_loader = reader_wrapper(train_loader, global_config['input_list'])
-
- if 'Evaluation' in global_config.keys() and global_config[
- 'Evaluation'] and paddle.distributed.get_rank() == 0:
- eval_func = eval_function
- dataset = reader_cfg['EvalDataset']
- global val_loader
- _eval_batch_sampler = paddle.io.BatchSampler(
- dataset, batch_size=reader_cfg['EvalReader']['batch_size'])
- val_loader = create('EvalReader')(dataset,
- reader_cfg['worker_num'],
- batch_sampler=_eval_batch_sampler,
- return_list=True)
- metric = None
- if reader_cfg['metric'] == 'COCO':
- clsid2catid = {v: k for k, v in dataset.catid2clsid.items()}
- anno_file = dataset.get_anno()
- metric = COCOMetric(
- anno_file=anno_file, clsid2catid=clsid2catid, IouType='bbox')
- elif reader_cfg['metric'] == 'VOC':
- metric = VOCMetric(
- label_list=dataset.get_label_list(),
- class_num=reader_cfg['num_classes'],
- map_type=reader_cfg['map_type'])
- else:
- raise ValueError("metric currently only supports COCO and VOC.")
- global_config['metric'] = metric
- else:
- eval_func = None
-
- ac = AutoCompression(
- model_dir=global_config["model_dir"],
- model_filename=global_config["model_filename"],
- params_filename=global_config["params_filename"],
- save_dir=FLAGS.save_dir,
- config=all_config,
- train_dataloader=train_loader,
- eval_callback=eval_func)
- ac.compress()
-
-
-if __name__ == '__main__':
- paddle.enable_static()
- parser = argsparser()
- FLAGS = parser.parse_args()
-
- assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
- paddle.set_device(FLAGS.devices)
-
- main()
diff --git a/example/auto_compression/pytorch_yolov6/README.md b/example/auto_compression/pytorch_yolov6/README.md
deleted file mode 100644
index 7cdb546476ff8bc3898644d6cfbcde2a1d77a80f..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/README.md
+++ /dev/null
@@ -1,143 +0,0 @@
-# YOLOv6自动压缩示例
-
-目录:
-- [1.简介](#1简介)
-- [2.Benchmark](#2Benchmark)
-- [3.开始自动压缩](#自动压缩流程)
- - [3.1 环境准备](#31-准备环境)
- - [3.2 准备数据集](#32-准备数据集)
- - [3.3 准备预测模型](#33-准备预测模型)
- - [3.4 测试模型精度](#34-测试模型精度)
- - [3.5 自动压缩并产出模型](#35-自动压缩并产出模型)
-- [4.预测部署](#4预测部署)
-- [5.FAQ](5FAQ)
-
-## 1. 简介
-
-飞桨模型转换工具[X2Paddle](https://github.com/PaddlePaddle/X2Paddle)支持将```Caffe/TensorFlow/ONNX/PyTorch```的模型一键转为飞桨(PaddlePaddle)的预测模型。借助X2Paddle的能力,各种框架的推理模型可以很方便的使用PaddleSlim的自动化压缩功能。
-
-本示例将以[meituan/YOLOv6](https://github.com/meituan/YOLOv6)目标检测模型为例,将PyTorch框架模型转换为Paddle框架模型,再使用ACT自动压缩功能进行自动压缩。本示例使用的自动压缩策略为量化训练。
-
-## 2.Benchmark
-
-| 模型 | 策略 | 输入尺寸 | mAPval
0.5:0.95 | 预测时延FP32
(ms) |预测时延FP16
(ms) | 预测时延INT8
(ms) | 配置文件 | Inference模型 |
-| :-------- |:-------- |:--------: | :---------------------: | :----------------: | :----------------: | :---------------: | :-----------------------------: | :-----------------------------: |
-| YOLOv6s | Base模型 | 640*640 | 42.4 | 9.06ms | 2.90ms | - | - | [Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov6s_infer.tar) |
-| YOLOv6s | KL离线量化 | 640*640 | 30.3 | - | - | 1.83ms | - | - |
-| YOLOv6s | 量化蒸馏训练 | 640*640 | **41.3** | - | - | **1.83ms** | [config](./configs/yolov6s_qat_dis.yaml) | [Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov6s_quant.tar) |
-
-说明:
-- mAP的指标均在COCO val2017数据集中评测得到。
-- YOLOv6s模型在Tesla T4的GPU环境下开启TensorRT 8.4.1,batch_size=1, 测试脚本是[cpp_infer](./cpp_infer)。
-
-## 3. 自动压缩流程
-
-#### 3.1 准备环境
-- PaddlePaddle >= 2.3 (可从[Paddle官网](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)下载安装)
-- PaddleSlim > 2.3版本
-- PaddleDet >= 2.4
-- [X2Paddle](https://github.com/PaddlePaddle/X2Paddle) >= 1.3.6
-- opencv-python
-
-(1)安装paddlepaddle:
-```shell
-# CPU
-pip install paddlepaddle
-# GPU
-pip install paddlepaddle-gpu
-```
-
-(2)安装paddleslim:
-```shell
-pip install paddleslim
-```
-
-(3)安装paddledet:
-```shell
-pip install paddledet
-```
-
-注:安装PaddleDet的目的只是为了直接使用PaddleDetection中的Dataloader组件。
-
-(4)安装X2Paddle的1.3.6以上版本:
-```shell
-pip install x2paddle sympy onnx
-```
-
-#### 3.2 准备数据集
-
-本案例默认以COCO数据进行自动压缩实验,并且依赖PaddleDetection中数据读取模块,如果自定义COCO数据,或者其他格式数据,请参考[PaddleDetection数据准备文档](https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.4/docs/tutorials/PrepareDataSet.md) 来准备数据。
-
-如果已经准备好数据集,请直接修改[./configs/yolov6_reader.yml]中`EvalDataset`的`dataset_dir`字段为自己数据集路径即可。
-
-
-#### 3.3 准备预测模型
-
-(1)准备ONNX模型:
-
-可通过[meituan/YOLOv6](https://github.com/meituan/YOLOv6)官方的[导出教程](https://github.com/meituan/YOLOv6/blob/main/deploy/ONNX/README.md)来准备ONNX模型。也可以下载已经准备好的[yolov6s.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov6s.onnx)。
-
-
-(2) 转换模型:
-```
-x2paddle --framework=onnx --model=yolov6s.onnx --save_dir=pd_model
-cp -r pd_model/inference_model/ yolov6s_infer
-```
-即可得到YOLOv6s模型的预测模型(`model.pdmodel` 和 `model.pdiparams`)。如想快速体验,可直接下载上方表格中YOLOv6s的[Paddle预测模型](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov6s_infer.tar)。
-
-
-预测模型的格式为:`model.pdmodel` 和 `model.pdiparams`两个,带`pdmodel`的是模型文件,带`pdiparams`后缀的是权重文件。
-
-
-#### 3.4 自动压缩并产出模型
-
-蒸馏量化自动压缩示例通过run.py脚本启动,会使用接口```paddleslim.auto_compression.AutoCompression```对模型进行自动压缩。配置config文件中模型路径、蒸馏、量化、和训练等部分的参数,配置完成后便可对模型进行量化和蒸馏。具体运行命令为:
-
-- 单卡训练:
-```
-export CUDA_VISIBLE_DEVICES=0
-python run.py --config_path=./configs/yolov6s_qat_dis.yaml --save_dir='./output/'
-```
-
-- 多卡训练:
-```
-CUDA_VISIBLE_DEVICES=0,1,2,3 python -m paddle.distributed.launch --log_dir=log --gpus 0,1,2,3 run.py \
- --config_path=./configs/yolov6s_qat_dis.yaml --save_dir='./output/'
-```
-
-#### 3.5 测试模型精度
-
-修改[yolov6s_qat_dis.yaml](./configs/yolov6s_qat_dis.yaml)中`model_dir`字段为模型存储路径,然后使用eval.py脚本得到模型的mAP:
-```
-export CUDA_VISIBLE_DEVICES=0
-python eval.py --config_path=./configs/yolov6s_qat_dis.yaml
-```
-
-
-## 4.预测部署
-
-#### Paddle-TensorRT C++部署
-
-进入[cpp_infer](./cpp_infer)文件夹内,请按照[C++ TensorRT Benchmark测试教程](./cpp_infer/README.md)进行准备环境及编译,然后开始测试:
-```shell
-# 编译
-bash complie.sh
-# 执行
-./build/trt_run --model_file yolov6s_quant/model.pdmodel --params_file yolov6s_quant/model.pdiparams --run_mode=trt_int8
-```
-
-#### Paddle-TensorRT Python部署:
-
-首先安装带有TensorRT的[Paddle安装包](https://www.paddlepaddle.org.cn/inference/v2.3/user_guides/download_lib.html#python)。
-
-然后使用[paddle_trt_infer.py](./paddle_trt_infer.py)进行部署:
-```shell
-python paddle_trt_infer.py --model_path=output --image_file=images/000000570688.jpg --benchmark=True --run_mode=trt_int8
-```
-
-## 5.FAQ
-
-- 如果想测试离线量化模型精度,可执行:
-```shell
-python post_quant.py --config_path=./configs/yolov6s_qat_dis.yaml
-```
diff --git a/example/auto_compression/pytorch_yolov6/configs/yolov6_reader.yml b/example/auto_compression/pytorch_yolov6/configs/yolov6_reader.yml
deleted file mode 100644
index cb87c3f8fde8bd0149189cd6a9f3437e7f4548e2..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/configs/yolov6_reader.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-metric: COCO
-num_classes: 80
-
-# Datset configuration
-TrainDataset:
- !COCODataSet
- image_dir: train2017
- anno_path: annotations/instances_train2017.json
- dataset_dir: dataset/coco/
-
-EvalDataset:
- !COCODataSet
- image_dir: val2017
- anno_path: annotations/instances_val2017.json
- dataset_dir: dataset/coco/
-
-worker_num: 0
-
-# preprocess reader in test
-EvalReader:
- sample_transforms:
- - Decode: {}
- - Resize: {target_size: [640, 640], keep_ratio: True}
- - Pad: {size: [640, 640], fill_value: [114., 114., 114.]}
- - NormalizeImage: {mean: [0, 0, 0], std: [1, 1, 1], is_scale: True}
- - Permute: {}
- batch_size: 1
diff --git a/example/auto_compression/pytorch_yolov6/cpp_infer/CMakeLists.txt b/example/auto_compression/pytorch_yolov6/cpp_infer/CMakeLists.txt
deleted file mode 100644
index d5307c657212bc3815353a55904672b6fa5679b4..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/cpp_infer/CMakeLists.txt
+++ /dev/null
@@ -1,263 +0,0 @@
-cmake_minimum_required(VERSION 3.0)
-project(cpp_inference_demo CXX C)
-option(WITH_MKL "Compile demo with MKL/OpenBlas support, default use MKL." ON)
-option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." OFF)
-option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." ON)
-option(USE_TENSORRT "Compile demo with TensorRT." OFF)
-option(WITH_ROCM "Compile demo with rocm." OFF)
-option(WITH_ONNXRUNTIME "Compile demo with ONNXRuntime" OFF)
-option(WITH_ARM "Compile demo with ARM" OFF)
-option(WITH_MIPS "Compile demo with MIPS" OFF)
-option(WITH_SW "Compile demo with SW" OFF)
-option(WITH_XPU "Compile demow ith xpu" OFF)
-option(WITH_NPU "Compile demow ith npu" OFF)
-
-if(NOT WITH_STATIC_LIB)
- add_definitions("-DPADDLE_WITH_SHARED_LIB")
-else()
- # PD_INFER_DECL is mainly used to set the dllimport/dllexport attribute in dynamic library mode.
- # Set it to empty in static library mode to avoid compilation issues.
- add_definitions("/DPD_INFER_DECL=")
-endif()
-
-macro(safe_set_static_flag)
- foreach(flag_var
- CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
- CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
- if(${flag_var} MATCHES "/MD")
- string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
- endif(${flag_var} MATCHES "/MD")
- endforeach(flag_var)
-endmacro()
-
-if(NOT DEFINED PADDLE_LIB)
- message(FATAL_ERROR "please set PADDLE_LIB with -DPADDLE_LIB=/path/paddle/lib")
-endif()
-if(NOT DEFINED DEMO_NAME)
- message(FATAL_ERROR "please set DEMO_NAME with -DDEMO_NAME=demo_name")
-endif()
-
-include_directories("${PADDLE_LIB}/")
-set(PADDLE_LIB_THIRD_PARTY_PATH "${PADDLE_LIB}/third_party/install/")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}cryptopp/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/include")
-
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}cryptopp/lib")
-link_directories("${PADDLE_LIB}/paddle/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/lib")
-
-if (WIN32)
- add_definitions("/DGOOGLE_GLOG_DLL_DECL=")
- option(MSVC_STATIC_CRT "use static C Runtime library by default" ON)
- if (MSVC_STATIC_CRT)
- if (WITH_MKL)
- set(FLAG_OPENMP "/openmp")
- endif()
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /bigobj /MTd ${FLAG_OPENMP}")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /bigobj /MT ${FLAG_OPENMP}")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj /MTd ${FLAG_OPENMP}")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /bigobj /MT ${FLAG_OPENMP}")
- safe_set_static_flag()
- if (WITH_STATIC_LIB)
- add_definitions(-DSTATIC_LIB)
- endif()
- endif()
-else()
- if(WITH_MKL)
- set(FLAG_OPENMP "-fopenmp")
- endif()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${FLAG_OPENMP}")
-endif()
-
-if(WITH_GPU)
- if(NOT WIN32)
- include_directories("/usr/local/cuda/include")
- if(CUDA_LIB STREQUAL "")
- set(CUDA_LIB "/usr/local/cuda/lib64/" CACHE STRING "CUDA Library")
- endif()
- else()
- include_directories("C:\\Program\ Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v8.0\\include")
- if(CUDA_LIB STREQUAL "")
- set(CUDA_LIB "C:\\Program\ Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v8.0\\lib\\x64")
- endif()
- endif(NOT WIN32)
-endif()
-
-if (USE_TENSORRT AND WITH_GPU)
- set(TENSORRT_ROOT "" CACHE STRING "The root directory of TensorRT library")
- if("${TENSORRT_ROOT}" STREQUAL "")
- message(FATAL_ERROR "The TENSORRT_ROOT is empty, you must assign it a value with CMake command. Such as: -DTENSORRT_ROOT=TENSORRT_ROOT_PATH ")
- endif()
- set(TENSORRT_INCLUDE_DIR ${TENSORRT_ROOT}/include)
- set(TENSORRT_LIB_DIR ${TENSORRT_ROOT}/lib)
- file(READ ${TENSORRT_INCLUDE_DIR}/NvInfer.h TENSORRT_VERSION_FILE_CONTENTS)
- string(REGEX MATCH "define NV_TENSORRT_MAJOR +([0-9]+)" TENSORRT_MAJOR_VERSION
- "${TENSORRT_VERSION_FILE_CONTENTS}")
- if("${TENSORRT_MAJOR_VERSION}" STREQUAL "")
- file(READ ${TENSORRT_INCLUDE_DIR}/NvInferVersion.h TENSORRT_VERSION_FILE_CONTENTS)
- string(REGEX MATCH "define NV_TENSORRT_MAJOR +([0-9]+)" TENSORRT_MAJOR_VERSION
- "${TENSORRT_VERSION_FILE_CONTENTS}")
- endif()
- if("${TENSORRT_MAJOR_VERSION}" STREQUAL "")
- message(SEND_ERROR "Failed to detect TensorRT version.")
- endif()
- string(REGEX REPLACE "define NV_TENSORRT_MAJOR +([0-9]+)" "\\1"
- TENSORRT_MAJOR_VERSION "${TENSORRT_MAJOR_VERSION}")
- message(STATUS "Current TensorRT header is ${TENSORRT_INCLUDE_DIR}/NvInfer.h. "
- "Current TensorRT version is v${TENSORRT_MAJOR_VERSION}. ")
- include_directories("${TENSORRT_INCLUDE_DIR}")
- link_directories("${TENSORRT_LIB_DIR}")
-endif()
-
-if(WITH_MKL)
- set(MATH_LIB_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}mklml")
- include_directories("${MATH_LIB_PATH}/include")
- if(WIN32)
- set(MATH_LIB ${MATH_LIB_PATH}/lib/mklml${CMAKE_STATIC_LIBRARY_SUFFIX}
- ${MATH_LIB_PATH}/lib/libiomp5md${CMAKE_STATIC_LIBRARY_SUFFIX})
- else()
- set(MATH_LIB ${MATH_LIB_PATH}/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${MATH_LIB_PATH}/lib/libiomp5${CMAKE_SHARED_LIBRARY_SUFFIX})
- endif()
- set(MKLDNN_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}mkldnn")
- if(EXISTS ${MKLDNN_PATH})
- include_directories("${MKLDNN_PATH}/include")
- if(WIN32)
- set(MKLDNN_LIB ${MKLDNN_PATH}/lib/mkldnn.lib)
- else(WIN32)
- set(MKLDNN_LIB ${MKLDNN_PATH}/lib/libmkldnn.so.0)
- endif(WIN32)
- endif()
-elseif((NOT WITH_MIPS) AND (NOT WITH_SW))
- set(OPENBLAS_LIB_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}openblas")
- include_directories("${OPENBLAS_LIB_PATH}/include/openblas")
- if(WIN32)
- set(MATH_LIB ${OPENBLAS_LIB_PATH}/lib/openblas${CMAKE_STATIC_LIBRARY_SUFFIX})
- else()
- set(MATH_LIB ${OPENBLAS_LIB_PATH}/lib/libopenblas${CMAKE_STATIC_LIBRARY_SUFFIX})
- endif()
-endif()
-
-if(WITH_STATIC_LIB)
- set(DEPS ${PADDLE_LIB}/paddle/lib/libpaddle_inference${CMAKE_STATIC_LIBRARY_SUFFIX})
-else()
- if(WIN32)
- set(DEPS ${PADDLE_LIB}/paddle/lib/paddle_inference${CMAKE_STATIC_LIBRARY_SUFFIX})
- else()
- set(DEPS ${PADDLE_LIB}/paddle/lib/libpaddle_inference${CMAKE_SHARED_LIBRARY_SUFFIX})
- endif()
-endif()
-
-if (WITH_ONNXRUNTIME)
- if(WIN32)
- set(DEPS ${DEPS} ${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/onnxruntime.lib paddle2onnx)
- elseif(APPLE)
- set(DEPS ${DEPS} ${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/libonnxruntime.1.10.0.dylib paddle2onnx)
- else()
- set(DEPS ${DEPS} ${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/libonnxruntime.so.1.10.0 paddle2onnx)
- endif()
-endif()
-
-if (NOT WIN32)
- set(EXTERNAL_LIB "-lrt -ldl -lpthread")
- set(DEPS ${DEPS}
- ${MATH_LIB} ${MKLDNN_LIB}
- glog gflags protobuf xxhash cryptopp
- ${EXTERNAL_LIB})
-else()
- set(DEPS ${DEPS}
- ${MATH_LIB} ${MKLDNN_LIB}
- glog gflags_static libprotobuf xxhash cryptopp-static ${EXTERNAL_LIB})
- set(DEPS ${DEPS} shlwapi.lib)
-endif(NOT WIN32)
-
-if(WITH_GPU)
- if(NOT WIN32)
- if (USE_TENSORRT)
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/libnvinfer${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/libnvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX})
- endif()
- set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX})
- else()
- if(USE_TENSORRT)
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/nvinfer${CMAKE_STATIC_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/nvinfer_plugin${CMAKE_STATIC_LIBRARY_SUFFIX})
- if(${TENSORRT_MAJOR_VERSION} GREATER_EQUAL 7)
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/myelin64_1${CMAKE_STATIC_LIBRARY_SUFFIX})
- endif()
- endif()
- set(DEPS ${DEPS} ${CUDA_LIB}/cudart${CMAKE_STATIC_LIBRARY_SUFFIX} )
- set(DEPS ${DEPS} ${CUDA_LIB}/cublas${CMAKE_STATIC_LIBRARY_SUFFIX} )
- set(DEPS ${DEPS} ${CUDA_LIB}/cudnn${CMAKE_STATIC_LIBRARY_SUFFIX} )
- endif()
-endif()
-
-if(WITH_ROCM AND NOT WIN32)
- set(DEPS ${DEPS} ${ROCM_LIB}/libamdhip64${CMAKE_SHARED_LIBRARY_SUFFIX})
-endif()
-
-if(WITH_XPU AND NOT WIN32)
- set(XPU_INSTALL_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}xpu")
- set(DEPS ${DEPS} ${XPU_INSTALL_PATH}/lib/libxpuapi${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${XPU_INSTALL_PATH}/lib/libxpurt${CMAKE_SHARED_LIBRARY_SUFFIX})
-endif()
-
-if(WITH_NPU AND NOT WIN32)
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libgraph${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libge_runner${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libascendcl${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libascendcl${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libacl_op_compiler${CMAKE_SHARED_LIBRARY_SUFFIX})
-endif()
-
-add_executable(${DEMO_NAME} ${DEMO_NAME}.cc)
-target_link_libraries(${DEMO_NAME} ${DEPS})
-if(WIN32)
- if(USE_TENSORRT)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${TENSORRT_LIB_DIR}/nvinfer${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- COMMAND ${CMAKE_COMMAND} -E copy ${TENSORRT_LIB_DIR}/nvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- )
- if(${TENSORRT_MAJOR_VERSION} GREATER_EQUAL 7)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${TENSORRT_LIB_DIR}/myelin64_1${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE})
- endif()
- endif()
- if(WITH_MKL)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${MATH_LIB_PATH}/lib/mklml.dll ${CMAKE_BINARY_DIR}/Release
- COMMAND ${CMAKE_COMMAND} -E copy ${MATH_LIB_PATH}/lib/libiomp5md.dll ${CMAKE_BINARY_DIR}/Release
- COMMAND ${CMAKE_COMMAND} -E copy ${MKLDNN_PATH}/lib/mkldnn.dll ${CMAKE_BINARY_DIR}/Release
- )
- else()
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${OPENBLAS_LIB_PATH}/lib/openblas.dll ${CMAKE_BINARY_DIR}/Release
- )
- endif()
- if(WITH_ONNXRUNTIME)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/onnxruntime.dll
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- COMMAND ${CMAKE_COMMAND} -E copy ${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/lib/paddle2onnx.dll
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- )
- endif()
- if(NOT WITH_STATIC_LIB)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy "${PADDLE_LIB}/paddle/lib/paddle_inference.dll" ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- )
- endif()
-endif()
diff --git a/example/auto_compression/pytorch_yolov6/cpp_infer/README.md b/example/auto_compression/pytorch_yolov6/cpp_infer/README.md
deleted file mode 100644
index 2f2204862df012b266f27975172ec11511e8f0ba..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/cpp_infer/README.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# YOLOv6 TensorRT Benchmark测试(Linux)
-
-## 环境准备
-
-- CUDA、CUDNN:确认环境中已经安装CUDA和CUDNN,并且提前获取其安装路径。
-
-- TensorRT:可通过NVIDIA官网下载[TensorRT 8.4.1.5](https://developer.nvidia.com/compute/machine-learning/tensorrt/secure/8.4.1/tars/tensorrt-8.4.1.5.linux.x86_64-gnu.cuda-11.6.cudnn8.4.tar.gz)或其他版本安装包。
-
-- Paddle Inference C++预测库:编译develop版本请参考[编译文档](https://www.paddlepaddle.org.cn/inference/user_guides/source_compile.html)。编译完成后,会在build目录下生成`paddle_inference_install_dir`文件夹,这个就是我们需要的C++预测库文件。
-
-## 编译可执行程序
-
-- (1)修改`compile.sh`中依赖库路径,主要是以下内容:
-```shell
-# Paddle Inference预测库路径
-LIB_DIR=/root/auto_compress/Paddle/build/paddle_inference_install_dir/
-# CUDNN路径
-CUDNN_LIB=/usr/lib/x86_64-linux-gnu/
-# CUDA路径
-CUDA_LIB=/usr/local/cuda/lib64
-# TensorRT安装包路径,为TRT资源包解压完成后的绝对路径,其中包含`lib`和`include`文件夹
-TENSORRT_ROOT=/root/auto_compress/trt/trt8.4/
-```
-
-## 测试
-
-- FP32
-```
-./build/trt_run --model_file yolov6s_infer/model.pdmodel --params_file yolov6s_infer/model.pdiparams --run_mode=trt_fp32
-```
-
-- FP16
-```
-./build/trt_run --model_file yolov6s_infer/model.pdmodel --params_file yolov6s_infer/model.pdiparams --run_mode=trt_fp16
-```
-
-- INT8
-```
-./build/trt_run --model_file yolov6s_quant/model.pdmodel --params_file yolov6s_quant/model.pdiparams --run_mode=trt_int8
-```
-
-## 性能对比
-
-| 模型 | 预测时延FP32
(ms) |预测时延FP16
(ms) | 预测时延INT8
(ms) |
-| :-------- |:-------- |:--------: | :---------------------: |
-| YOLOv6s | 9.06ms | 2.90ms | 1.83ms |
-
-环境:
-- Tesla T4,TensorRT 8.4.1,CUDA 11.2
-- batch_size=1
diff --git a/example/auto_compression/pytorch_yolov6/cpp_infer/compile.sh b/example/auto_compression/pytorch_yolov6/cpp_infer/compile.sh
deleted file mode 100644
index afff924b4f63c37e2ae8906d505e046066e0a906..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/cpp_infer/compile.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/bash
-set +x
-set -e
-
-work_path=$(dirname $(readlink -f $0))
-
-mkdir -p build
-cd build
-rm -rf *
-
-DEMO_NAME=trt_run
-
-WITH_MKL=ON
-WITH_GPU=ON
-USE_TENSORRT=ON
-
-LIB_DIR=/root/auto_compress/Paddle/build/paddle_inference_install_dir/
-CUDNN_LIB=/usr/lib/x86_64-linux-gnu/
-CUDA_LIB=/usr/local/cuda/lib64
-TENSORRT_ROOT=/root/auto_compress/trt/trt8.4/
-
-WITH_ROCM=OFF
-ROCM_LIB=/opt/rocm/lib
-
-cmake .. -DPADDLE_LIB=${LIB_DIR} \
- -DWITH_MKL=${WITH_MKL} \
- -DDEMO_NAME=${DEMO_NAME} \
- -DWITH_GPU=${WITH_GPU} \
- -DWITH_STATIC_LIB=OFF \
- -DUSE_TENSORRT=${USE_TENSORRT} \
- -DWITH_ROCM=${WITH_ROCM} \
- -DROCM_LIB=${ROCM_LIB} \
- -DCUDNN_LIB=${CUDNN_LIB} \
- -DCUDA_LIB=${CUDA_LIB} \
- -DTENSORRT_ROOT=${TENSORRT_ROOT}
-
-make -j
diff --git a/example/auto_compression/pytorch_yolov6/cpp_infer/trt_run.cc b/example/auto_compression/pytorch_yolov6/cpp_infer/trt_run.cc
deleted file mode 100644
index 9c14baf7dbaf969eab19df2dc9a6416f8b45ada5..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/cpp_infer/trt_run.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include "paddle/include/paddle_inference_api.h"
-#include "paddle/include/experimental/phi/common/float16.h"
-
-using paddle_infer::Config;
-using paddle_infer::Predictor;
-using paddle_infer::CreatePredictor;
-using paddle_infer::PrecisionType;
-using phi::dtype::float16;
-
-DEFINE_string(model_dir, "", "Directory of the inference model.");
-DEFINE_string(model_file, "", "Path of the inference model file.");
-DEFINE_string(params_file, "", "Path of the inference params file.");
-DEFINE_string(run_mode, "trt_fp32", "run_mode which can be: trt_fp32, trt_fp16 and trt_int8");
-DEFINE_int32(batch_size, 1, "Batch size.");
-DEFINE_int32(gpu_id, 0, "GPU card ID num.");
-DEFINE_int32(trt_min_subgraph_size, 3, "tensorrt min_subgraph_size");
-DEFINE_int32(warmup, 50, "warmup");
-DEFINE_int32(repeats, 1000, "repeats");
-
-using Time = decltype(std::chrono::high_resolution_clock::now());
-Time time() { return std::chrono::high_resolution_clock::now(); };
-double time_diff(Time t1, Time t2) {
- typedef std::chrono::microseconds ms;
- auto diff = t2 - t1;
- ms counter = std::chrono::duration_cast(diff);
- return counter.count() / 1000.0;
-}
-
-std::shared_ptr InitPredictor() {
- Config config;
- std::string model_path;
- if (FLAGS_model_dir != "") {
- config.SetModel(FLAGS_model_dir);
- model_path = FLAGS_model_dir.substr(0, FLAGS_model_dir.find_last_of("/"));
- } else {
- config.SetModel(FLAGS_model_file, FLAGS_params_file);
- model_path = FLAGS_model_file.substr(0, FLAGS_model_file.find_last_of("/"));
- }
- // enable tune
- std::cout << "model_path: " << model_path << std::endl;
- config.EnableUseGpu(256, FLAGS_gpu_id);
- if (FLAGS_run_mode == "trt_fp32") {
- config.EnableTensorRtEngine(1 << 30, FLAGS_batch_size, FLAGS_trt_min_subgraph_size,
- PrecisionType::kFloat32, false, false);
- } else if (FLAGS_run_mode == "trt_fp16") {
- config.EnableTensorRtEngine(1 << 30, FLAGS_batch_size, FLAGS_trt_min_subgraph_size,
- PrecisionType::kHalf, false, false);
- } else if (FLAGS_run_mode == "trt_int8") {
- config.EnableTensorRtEngine(1 << 30, FLAGS_batch_size, FLAGS_trt_min_subgraph_size,
- PrecisionType::kInt8, false, false);
- }
- config.EnableMemoryOptim();
- config.SwitchIrOptim(true);
- return CreatePredictor(config);
-}
-
-template
-void run(Predictor *predictor, const std::vector &input,
- const std::vector &input_shape, type* out_data, std::vector out_shape) {
-
- // prepare input
- int input_num = std::accumulate(input_shape.begin(), input_shape.end(), 1,
- std::multiplies());
-
- auto input_names = predictor->GetInputNames();
- auto input_t = predictor->GetInputHandle(input_names[0]);
- input_t->Reshape(input_shape);
- input_t->CopyFromCpu(input.data());
-
- for (int i = 0; i < FLAGS_warmup; ++i)
- CHECK(predictor->Run());
-
- auto st = time();
- for (int i = 0; i < FLAGS_repeats; ++i) {
- auto input_names = predictor->GetInputNames();
- auto input_t = predictor->GetInputHandle(input_names[0]);
- input_t->Reshape(input_shape);
- input_t->CopyFromCpu(input.data());
-
- CHECK(predictor->Run());
-
- auto output_names = predictor->GetOutputNames();
- auto output_t = predictor->GetOutputHandle(output_names[0]);
- std::vector output_shape = output_t->shape();
- output_t -> ShareExternalData(out_data, out_shape, paddle_infer::PlaceType::kGPU);
- }
-
- LOG(INFO) << "[" << FLAGS_run_mode << " bs-" << FLAGS_batch_size << " ] run avg time is " << time_diff(st, time()) / FLAGS_repeats
- << " ms";
-}
-
-int main(int argc, char *argv[]) {
- google::ParseCommandLineFlags(&argc, &argv, true);
- auto predictor = InitPredictor();
- std::vector input_shape = {FLAGS_batch_size, 3, 640, 640};
- // float16
- using dtype = float16;
- std::vector input_data(FLAGS_batch_size * 3 * 640 * 640, dtype(1.0));
-
- dtype *out_data;
- int out_data_size = FLAGS_batch_size * 8400 * 85;
- cudaHostAlloc((void**)&out_data, sizeof(float) * out_data_size, cudaHostAllocMapped);
-
- std::vector out_shape{ FLAGS_batch_size, 1, 8400, 85};
- run(predictor.get(), input_data, input_shape, out_data, out_shape);
- return 0;
-}
diff --git a/example/auto_compression/pytorch_yolov6/eval.py b/example/auto_compression/pytorch_yolov6/eval.py
deleted file mode 100644
index 62127b512baef72e4105cec2ad6e2d4e1e6a6cbc..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/eval.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import sys
-import numpy as np
-import argparse
-import paddle
-from ppdet.core.workspace import load_config, merge_config
-from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
-
-from post_process import YOLOv6PostProcess
-
-
-def argsparser():
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument(
- '--config_path',
- type=str,
- default=None,
- help="path of compression strategy config.",
- required=True)
- parser.add_argument(
- '--devices',
- type=str,
- default='gpu',
- help="which device used to compress.")
-
- return parser
-
-
-def reader_wrapper(reader, input_list):
- def gen():
- for data in reader:
- in_dict = {}
- if isinstance(input_list, list):
- for input_name in input_list:
- in_dict[input_name] = data[input_name]
- elif isinstance(input_list, dict):
- for input_name in input_list.keys():
- in_dict[input_list[input_name]] = data[input_name]
- yield in_dict
-
- return gen
-
-
-def convert_numpy_data(data, metric):
- data_all = {}
- data_all = {k: np.array(v) for k, v in data.items()}
- if isinstance(metric, VOCMetric):
- for k, v in data_all.items():
- if not isinstance(v[0], np.ndarray):
- tmp_list = []
- for t in v:
- tmp_list.append(np.array(t))
- data_all[k] = np.array(tmp_list)
- else:
- data_all = {k: np.array(v) for k, v in data.items()}
- return data_all
-
-
-def eval():
-
- place = paddle.CUDAPlace(0) if FLAGS.devices == 'gpu' else paddle.CPUPlace()
- exe = paddle.static.Executor(place)
-
- val_program, feed_target_names, fetch_targets = paddle.static.load_inference_model(
- global_config["model_dir"],
- exe,
- model_filename=global_config["model_filename"],
- params_filename=global_config["params_filename"])
- print('Loaded model from: {}'.format(global_config["model_dir"]))
-
- metric = global_config['metric']
- for batch_id, data in enumerate(val_loader):
- data_all = convert_numpy_data(data, metric)
- data_input = {}
- for k, v in data.items():
- if isinstance(global_config['input_list'], list):
- if k in global_config['input_list']:
- data_input[k] = np.array(v)
- elif isinstance(global_config['input_list'], dict):
- if k in global_config['input_list'].keys():
- data_input[global_config['input_list'][k]] = np.array(v)
- outs = exe.run(val_program,
- feed=data_input,
- fetch_list=fetch_targets,
- return_numpy=False)
- res = {}
- if 'arch' in global_config and global_config['arch'] == 'YOLOv6':
- postprocess = YOLOv6PostProcess(
- score_threshold=0.001, nms_threshold=0.65, multi_label=True)
- res = postprocess(np.array(outs[0]), data_all['scale_factor'])
- else:
- for out in outs:
- v = np.array(out)
- if len(v.shape) > 1:
- res['bbox'] = v
- else:
- res['bbox_num'] = v
- metric.update(data_all, res)
- if batch_id % 100 == 0:
- print('Eval iter:', batch_id)
- metric.accumulate()
- metric.log()
- metric.reset()
-
-
-def main():
- global global_config
- all_config = load_slim_config(FLAGS.config_path)
- global_config = all_config["Global"]
- reader_cfg = load_config(global_config['reader_config'])
-
- dataset = reader_cfg['EvalDataset']
- global val_loader
- val_loader = create('EvalReader')(reader_cfg['EvalDataset'],
- reader_cfg['worker_num'],
- return_list=True)
- metric = None
- if reader_cfg['metric'] == 'COCO':
- clsid2catid = {v: k for k, v in dataset.catid2clsid.items()}
- anno_file = dataset.get_anno()
- metric = COCOMetric(
- anno_file=anno_file, clsid2catid=clsid2catid, IouType='bbox')
- elif reader_cfg['metric'] == 'VOC':
- metric = VOCMetric(
- label_list=dataset.get_label_list(),
- class_num=reader_cfg['num_classes'],
- map_type=reader_cfg['map_type'])
- else:
- raise ValueError("metric currently only supports COCO and VOC.")
- global_config['metric'] = metric
-
- eval()
-
-
-if __name__ == '__main__':
- paddle.enable_static()
- parser = argsparser()
- FLAGS = parser.parse_args()
-
- assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
- paddle.set_device(FLAGS.devices)
-
- main()
diff --git a/example/auto_compression/pytorch_yolov6/images/000000570688.jpg b/example/auto_compression/pytorch_yolov6/images/000000570688.jpg
deleted file mode 100644
index cb304bd56c4010c08611a30dcca58ea9140cea54..0000000000000000000000000000000000000000
Binary files a/example/auto_compression/pytorch_yolov6/images/000000570688.jpg and /dev/null differ
diff --git a/example/auto_compression/pytorch_yolov6/paddle_trt_infer.py b/example/auto_compression/pytorch_yolov6/paddle_trt_infer.py
deleted file mode 100644
index 5d88643f4be4f5ecff272f66a660e830d716757a..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/paddle_trt_infer.py
+++ /dev/null
@@ -1,322 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import cv2
-import numpy as np
-import argparse
-import time
-
-from paddle.inference import Config
-from paddle.inference import create_predictor
-
-from post_process import YOLOv6PostProcess
-
-CLASS_LABEL = [
- 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train',
- 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign',
- 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
- 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag',
- 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite',
- 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
- 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon',
- 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot',
- 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant',
- 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote',
- 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink',
- 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
- 'hair drier', 'toothbrush'
-]
-
-
-def generate_scale(im, target_shape, keep_ratio=True):
- """
- Args:
- im (np.ndarray): image (np.ndarray)
- Returns:
- im_scale_x: the resize ratio of X
- im_scale_y: the resize ratio of Y
- """
- origin_shape = im.shape[:2]
- if keep_ratio:
- im_size_min = np.min(origin_shape)
- im_size_max = np.max(origin_shape)
- target_size_min = np.min(target_shape)
- target_size_max = np.max(target_shape)
- im_scale = float(target_size_min) / float(im_size_min)
- if np.round(im_scale * im_size_max) > target_size_max:
- im_scale = float(target_size_max) / float(im_size_max)
- im_scale_x = im_scale
- im_scale_y = im_scale
- else:
- resize_h, resize_w = target_shape
- im_scale_y = resize_h / float(origin_shape[0])
- im_scale_x = resize_w / float(origin_shape[1])
- return im_scale_y, im_scale_x
-
-
-def image_preprocess(img_path, target_shape):
- img = cv2.imread(img_path)
- # Resize
- im_scale_y, im_scale_x = generate_scale(img, target_shape)
- img = cv2.resize(
- img,
- None,
- None,
- fx=im_scale_x,
- fy=im_scale_y,
- interpolation=cv2.INTER_LINEAR)
- # Pad
- im_h, im_w = img.shape[:2]
- h, w = target_shape[:]
- if h != im_h or w != im_w:
- canvas = np.ones((h, w, 3), dtype=np.float32)
- canvas *= np.array([114.0, 114.0, 114.0], dtype=np.float32)
- canvas[0:im_h, 0:im_w, :] = img.astype(np.float32)
- img = canvas
- img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
- img = np.transpose(img, [2, 0, 1]) / 255
- img = np.expand_dims(img, 0)
- scale_factor = np.array([[im_scale_y, im_scale_x]])
- return img.astype(np.float32), scale_factor
-
-
-def get_color_map_list(num_classes):
- color_map = num_classes * [0, 0, 0]
- for i in range(0, num_classes):
- j = 0
- lab = i
- while lab:
- color_map[i * 3] |= (((lab >> 0) & 1) << (7 - j))
- color_map[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j))
- color_map[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j))
- j += 1
- lab >>= 3
- color_map = [color_map[i:i + 3] for i in range(0, len(color_map), 3)]
- return color_map
-
-
-def draw_box(image_file, results, class_label, threshold=0.5):
- srcimg = cv2.imread(image_file, 1)
- for i in range(len(results)):
- color_list = get_color_map_list(len(class_label))
- clsid2color = {}
- classid, conf = int(results[i, 0]), results[i, 1]
- if conf < threshold:
- continue
- xmin, ymin, xmax, ymax = int(results[i, 2]), int(results[i, 3]), int(
- results[i, 4]), int(results[i, 5])
-
- if classid not in clsid2color:
- clsid2color[classid] = color_list[classid]
- color = tuple(clsid2color[classid])
-
- cv2.rectangle(srcimg, (xmin, ymin), (xmax, ymax), color, thickness=2)
- print(class_label[classid] + ': ' + str(round(conf, 3)))
- cv2.putText(
- srcimg,
- class_label[classid] + ':' + str(round(conf, 3)), (xmin, ymin - 10),
- cv2.FONT_HERSHEY_SIMPLEX,
- 0.8, (0, 255, 0),
- thickness=2)
- return srcimg
-
-
-def load_predictor(model_dir,
- run_mode='paddle',
- batch_size=1,
- device='CPU',
- min_subgraph_size=3,
- use_dynamic_shape=False,
- trt_min_shape=1,
- trt_max_shape=1280,
- trt_opt_shape=640,
- trt_calib_mode=False,
- cpu_threads=1,
- enable_mkldnn=False,
- enable_mkldnn_bfloat16=False,
- delete_shuffle_pass=False):
- """set AnalysisConfig, generate AnalysisPredictor
- Args:
- model_dir (str): root path of __model__ and __params__
- device (str): Choose the device you want to run, it can be: CPU/GPU/XPU, default is CPU
- run_mode (str): mode of running(paddle/trt_fp32/trt_fp16/trt_int8)
- use_dynamic_shape (bool): use dynamic shape or not
- trt_min_shape (int): min shape for dynamic shape in trt
- trt_max_shape (int): max shape for dynamic shape in trt
- trt_opt_shape (int): opt shape for dynamic shape in trt
- trt_calib_mode (bool): If the model is produced by TRT offline quantitative
- calibration, trt_calib_mode need to set True
- delete_shuffle_pass (bool): whether to remove shuffle_channel_detect_pass in TensorRT.
- Used by action model.
- Returns:
- predictor (PaddlePredictor): AnalysisPredictor
- Raises:
- ValueError: predict by TensorRT need device == 'GPU'.
- """
- if device != 'GPU' and run_mode != 'paddle':
- raise ValueError(
- "Predict by TensorRT mode: {}, expect device=='GPU', but device == {}"
- .format(run_mode, device))
- config = Config(
- os.path.join(model_dir, 'model.pdmodel'),
- os.path.join(model_dir, 'model.pdiparams'))
- if device == 'GPU':
- # initial GPU memory(M), device ID
- config.enable_use_gpu(200, 0)
- # optimize graph and fuse op
- config.switch_ir_optim(True)
- elif device == 'XPU':
- config.enable_lite_engine()
- config.enable_xpu(10 * 1024 * 1024)
- else:
- config.disable_gpu()
- config.set_cpu_math_library_num_threads(cpu_threads)
- if enable_mkldnn:
- try:
- # cache 10 different shapes for mkldnn to avoid memory leak
- config.set_mkldnn_cache_capacity(10)
- config.enable_mkldnn()
- if enable_mkldnn_bfloat16:
- config.enable_mkldnn_bfloat16()
- except Exception as e:
- print(
- "The current environment does not support `mkldnn`, so disable mkldnn."
- )
- pass
-
- precision_map = {
- 'trt_int8': Config.Precision.Int8,
- 'trt_fp32': Config.Precision.Float32,
- 'trt_fp16': Config.Precision.Half
- }
- if run_mode in precision_map.keys():
- config.enable_tensorrt_engine(
- workspace_size=(1 << 25) * batch_size,
- max_batch_size=batch_size,
- min_subgraph_size=min_subgraph_size,
- precision_mode=precision_map[run_mode],
- use_static=False,
- use_calib_mode=trt_calib_mode)
-
- if use_dynamic_shape:
- min_input_shape = {
- 'image': [batch_size, 3, trt_min_shape, trt_min_shape]
- }
- max_input_shape = {
- 'image': [batch_size, 3, trt_max_shape, trt_max_shape]
- }
- opt_input_shape = {
- 'image': [batch_size, 3, trt_opt_shape, trt_opt_shape]
- }
- config.set_trt_dynamic_shape_info(min_input_shape, max_input_shape,
- opt_input_shape)
- print('trt set dynamic shape done!')
-
- # disable print log when predict
- config.disable_glog_info()
- # enable shared memory
- config.enable_memory_optim()
- # disable feed, fetch OP, needed by zero_copy_run
- config.switch_use_feed_fetch_ops(False)
- if delete_shuffle_pass:
- config.delete_pass("shuffle_channel_detect_pass")
- predictor = create_predictor(config)
- return predictor
-
-
-def predict_image(predictor,
- image_file,
- image_shape=[640, 640],
- warmup=1,
- repeats=1,
- threshold=0.5,
- arch='YOLOv5'):
- img, scale_factor = image_preprocess(image_file, image_shape)
- inputs = {}
- if arch == 'YOLOv5':
- inputs['x2paddle_images'] = img
- input_names = predictor.get_input_names()
- for i in range(len(input_names)):
- input_tensor = predictor.get_input_handle(input_names[i])
- input_tensor.copy_from_cpu(inputs[input_names[i]])
-
- for i in range(warmup):
- predictor.run()
-
- np_boxes = None
- predict_time = 0.
- time_min = float("inf")
- time_max = float('-inf')
- for i in range(repeats):
- start_time = time.time()
- predictor.run()
- output_names = predictor.get_output_names()
- boxes_tensor = predictor.get_output_handle(output_names[0])
- np_boxes = boxes_tensor.copy_to_cpu()
- end_time = time.time()
- timed = end_time - start_time
- time_min = min(time_min, timed)
- time_max = max(time_max, timed)
- predict_time += timed
-
- time_avg = predict_time / repeats
- print('Inference time(ms): min={}, max={}, avg={}'.format(
- round(time_min * 1000, 2),
- round(time_max * 1000, 1), round(time_avg * 1000, 1)))
- postprocess = YOLOv6PostProcess(
- score_threshold=0.001, nms_threshold=0.65, multi_label=True)
- res = postprocess(np_boxes, scale_factor)
- res_img = draw_box(
- image_file, res['bbox'], CLASS_LABEL, threshold=threshold)
- cv2.imwrite('result.jpg', res_img)
-
-
-if __name__ == '__main__':
-
- parser = argparse.ArgumentParser()
- parser.add_argument(
- '--image_file', type=str, default=None, help="image path")
- parser.add_argument(
- '--model_path', type=str, help="inference model filepath")
- parser.add_argument(
- '--benchmark',
- type=bool,
- default=False,
- help="Whether run benchmark or not.")
- parser.add_argument(
- '--run_mode',
- type=str,
- default='paddle',
- help="mode of running(paddle/trt_fp32/trt_fp16/trt_int8)")
- parser.add_argument(
- '--device',
- type=str,
- default='GPU',
- help="Choose the device you want to run, it can be: CPU/GPU/XPU, default is GPU"
- )
- parser.add_argument('--img_shape', type=int, default=640, help="input_size")
- args = parser.parse_args()
-
- predictor = load_predictor(
- args.model_path, run_mode=args.run_mode, device=args.device)
- warmup, repeats = 1, 1
- if args.benchmark:
- warmup, repeats = 50, 100
- predict_image(
- predictor,
- args.image_file,
- image_shape=[args.img_shape, args.img_shape],
- warmup=warmup,
- repeats=repeats)
diff --git a/example/auto_compression/pytorch_yolov6/post_quant.py b/example/auto_compression/pytorch_yolov6/post_quant.py
deleted file mode 100644
index aa4f5d8f67ef6e264a2b1c81bffc5b0e1bbeb0bb..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/post_quant.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import sys
-import numpy as np
-import argparse
-import paddle
-from ppdet.core.workspace import load_config, merge_config
-from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
-from paddleslim.quant import quant_post_static
-
-from post_process import YOLOv6PostProcess
-
-
-def argsparser():
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument(
- '--config_path',
- type=str,
- default=None,
- help="path of compression strategy config.",
- required=True)
- parser.add_argument(
- '--save_dir',
- type=str,
- default='ptq_out',
- help="directory to save compressed model.")
- parser.add_argument(
- '--devices',
- type=str,
- default='gpu',
- help="which device used to compress.")
- parser.add_argument(
- '--algo', type=str, default='KL', help="post quant algo.")
-
- return parser
-
-
-def reader_wrapper(reader, input_list):
- def gen():
- for data in reader:
- in_dict = {}
- if isinstance(input_list, list):
- for input_name in input_list:
- in_dict[input_name] = data[input_name]
- elif isinstance(input_list, dict):
- for input_name in input_list.keys():
- in_dict[input_list[input_name]] = data[input_name]
- yield in_dict
-
- return gen
-
-
-def main():
- global global_config
- all_config = load_slim_config(FLAGS.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
- global_config = all_config["Global"]
- reader_cfg = load_config(global_config['reader_config'])
-
- train_loader = create('EvalReader')(reader_cfg['TrainDataset'],
- reader_cfg['worker_num'],
- return_list=True)
- train_loader = reader_wrapper(train_loader, global_config['input_list'])
-
- place = paddle.CUDAPlace(0) if FLAGS.devices == 'gpu' else paddle.CPUPlace()
- exe = paddle.static.Executor(place)
- quant_post_static(
- executor=exe,
- model_dir=global_config["model_dir"],
- quantize_model_path=FLAGS.save_dir,
- data_loader=train_loader,
- model_filename=global_config["model_filename"],
- params_filename=global_config["params_filename"],
- batch_size=32,
- batch_nums=10,
- algo=FLAGS.algo,
- hist_percent=0.999,
- is_full_quantize=False,
- bias_correction=False,
- onnx_format=False)
-
-
-if __name__ == '__main__':
- paddle.enable_static()
- parser = argsparser()
- FLAGS = parser.parse_args()
-
- assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
- paddle.set_device(FLAGS.devices)
-
- main()
diff --git a/example/auto_compression/pytorch_yolov6/run.py b/example/auto_compression/pytorch_yolov6/run.py
deleted file mode 100644
index 05fe7fddad3568c98bd2e3b8bbf7dcb3552a300a..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov6/run.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import sys
-import numpy as np
-import argparse
-import paddle
-from ppdet.core.workspace import load_config, merge_config
-from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
-from paddleslim.auto_compression import AutoCompression
-
-from post_process import YOLOv6PostProcess
-
-
-def argsparser():
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument(
- '--config_path',
- type=str,
- default=None,
- help="path of compression strategy config.",
- required=True)
- parser.add_argument(
- '--save_dir',
- type=str,
- default='output',
- help="directory to save compressed model.")
- parser.add_argument(
- '--devices',
- type=str,
- default='gpu',
- help="which device used to compress.")
- parser.add_argument(
- '--eval', type=bool, default=False, help="whether to run evaluation.")
-
- return parser
-
-
-def reader_wrapper(reader, input_list):
- def gen():
- for data in reader:
- in_dict = {}
- if isinstance(input_list, list):
- for input_name in input_list:
- in_dict[input_name] = data[input_name]
- elif isinstance(input_list, dict):
- for input_name in input_list.keys():
- in_dict[input_list[input_name]] = data[input_name]
- yield in_dict
-
- return gen
-
-
-def convert_numpy_data(data, metric):
- data_all = {}
- data_all = {k: np.array(v) for k, v in data.items()}
- if isinstance(metric, VOCMetric):
- for k, v in data_all.items():
- if not isinstance(v[0], np.ndarray):
- tmp_list = []
- for t in v:
- tmp_list.append(np.array(t))
- data_all[k] = np.array(tmp_list)
- else:
- data_all = {k: np.array(v) for k, v in data.items()}
- return data_all
-
-
-def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
- metric = global_config['metric']
- for batch_id, data in enumerate(val_loader):
- data_all = convert_numpy_data(data, metric)
- data_input = {}
- for k, v in data.items():
- if isinstance(global_config['input_list'], list):
- if k in test_feed_names:
- data_input[k] = np.array(v)
- elif isinstance(global_config['input_list'], dict):
- if k in global_config['input_list'].keys():
- data_input[global_config['input_list'][k]] = np.array(v)
- outs = exe.run(compiled_test_program,
- feed=data_input,
- fetch_list=test_fetch_list,
- return_numpy=False)
- res = {}
- if 'arch' in global_config and global_config['arch'] == 'YOLOv6':
- postprocess = YOLOv6PostProcess(
- score_threshold=0.001, nms_threshold=0.65, multi_label=True)
- res = postprocess(np.array(outs[0]), data_all['scale_factor'])
- else:
- for out in outs:
- v = np.array(out)
- if len(v.shape) > 1:
- res['bbox'] = v
- else:
- res['bbox_num'] = v
-
- metric.update(data_all, res)
- if batch_id % 100 == 0:
- print('Eval iter:', batch_id)
- metric.accumulate()
- metric.log()
- map_res = metric.get_results()
- metric.reset()
- return map_res['bbox'][0]
-
-
-def main():
- global global_config
- all_config = load_slim_config(FLAGS.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
- global_config = all_config["Global"]
- reader_cfg = load_config(global_config['reader_config'])
-
- train_loader = create('EvalReader')(reader_cfg['TrainDataset'],
- reader_cfg['worker_num'],
- return_list=True)
- train_loader = reader_wrapper(train_loader, global_config['input_list'])
-
- if 'Evaluation' in global_config.keys() and global_config[
- 'Evaluation'] and paddle.distributed.get_rank() == 0:
- eval_func = eval_function
- dataset = reader_cfg['EvalDataset']
- global val_loader
- _eval_batch_sampler = paddle.io.BatchSampler(
- dataset, batch_size=reader_cfg['EvalReader']['batch_size'])
- val_loader = create('EvalReader')(dataset,
- reader_cfg['worker_num'],
- batch_sampler=_eval_batch_sampler,
- return_list=True)
- metric = None
- if reader_cfg['metric'] == 'COCO':
- clsid2catid = {v: k for k, v in dataset.catid2clsid.items()}
- anno_file = dataset.get_anno()
- metric = COCOMetric(
- anno_file=anno_file, clsid2catid=clsid2catid, IouType='bbox')
- elif reader_cfg['metric'] == 'VOC':
- metric = VOCMetric(
- label_list=dataset.get_label_list(),
- class_num=reader_cfg['num_classes'],
- map_type=reader_cfg['map_type'])
- else:
- raise ValueError("metric currently only supports COCO and VOC.")
- global_config['metric'] = metric
- else:
- eval_func = None
-
- ac = AutoCompression(
- model_dir=global_config["model_dir"],
- model_filename=global_config["model_filename"],
- params_filename=global_config["params_filename"],
- save_dir=FLAGS.save_dir,
- config=all_config,
- train_dataloader=train_loader,
- eval_callback=eval_func)
- ac.compress()
-
-
-if __name__ == '__main__':
- paddle.enable_static()
- parser = argsparser()
- FLAGS = parser.parse_args()
-
- assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
- paddle.set_device(FLAGS.devices)
-
- main()
diff --git a/example/auto_compression/pytorch_yolov7/README.md b/example/auto_compression/pytorch_yolov7/README.md
deleted file mode 100644
index 7dddf99bf5ce2ecaac0e4e62c1a9a9c4509a6ce9..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov7/README.md
+++ /dev/null
@@ -1,152 +0,0 @@
-# YOLOv7自动压缩示例
-
-目录:
-- [1.简介](#1简介)
-- [2.Benchmark](#2Benchmark)
-- [3.开始自动压缩](#自动压缩流程)
- - [3.1 环境准备](#31-准备环境)
- - [3.2 准备数据集](#32-准备数据集)
- - [3.3 准备预测模型](#33-准备预测模型)
- - [3.4 测试模型精度](#34-测试模型精度)
- - [3.5 自动压缩并产出模型](#35-自动压缩并产出模型)
-- [4.预测部署](#4预测部署)
-- [5.FAQ](5FAQ)
-
-## 1. 简介
-
-飞桨模型转换工具[X2Paddle](https://github.com/PaddlePaddle/X2Paddle)支持将```Caffe/TensorFlow/ONNX/PyTorch```的模型一键转为飞桨(PaddlePaddle)的预测模型。借助X2Paddle的能力,各种框架的推理模型可以很方便的使用PaddleSlim的自动化压缩功能。
-
-本示例将以[WongKinYiu/yolov7](https://github.com/WongKinYiu/yolov7)目标检测模型为例,将PyTorch框架模型转换为Paddle框架模型,再使用ACT自动压缩功能进行自动压缩。本示例使用的自动压缩策略为量化训练。
-
-## 2.Benchmark
-
-| 模型 | 策略 | 输入尺寸 | mAPval
0.5:0.95 | 预测时延FP32
(ms) |预测时延FP16
(ms) | 预测时延INT8
(ms) | 配置文件 | Inference模型 |
-| :-------- |:-------- |:--------: | :---------------------: | :----------------: | :----------------: | :---------------: | :-----------------------------: | :-----------------------------: |
-| YOLOv7 | Base模型 | 640*640 | 51.1 | 26.84ms | 7.44ms | - | - | [Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov7_infer.tar) |
-| YOLOv7 | KL离线量化 | 640*640 | 50.2 | - | - | 4.55ms | - | - |
-| YOLOv7 | 量化蒸馏训练 | 640*640 | **50.8** | - | - | **4.55ms** | [config](./configs/yolov7_qat_dis.yaml) | [Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov7_quant.tar) |
-
-说明:
-- mAP的指标均在COCO val2017数据集中评测得到。
-- YOLOv7模型在Tesla T4的GPU环境下开启TensorRT 8.4.1,batch_size=1, 测试脚本是[cpp_infer](./cpp_infer)。
-
-## 3. 自动压缩流程
-
-#### 3.1 准备环境
-- PaddlePaddle >= 2.3 (可从[Paddle官网](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)下载安装)
-- PaddleSlim > 2.3版本
-- PaddleDet >= 2.4
-- [X2Paddle](https://github.com/PaddlePaddle/X2Paddle) >= 1.3.6
-- opencv-python
-
-(1)安装paddlepaddle:
-```shell
-# CPU
-pip install paddlepaddle
-# GPU
-pip install paddlepaddle-gpu
-```
-
-(2)安装paddleslim:
-```shell
-pip install paddleslim
-```
-
-(3)安装paddledet:
-```shell
-pip install paddledet
-```
-
-注:安装PaddleDet的目的只是为了直接使用PaddleDetection中的Dataloader组件。
-
-(4)安装X2Paddle的1.3.6以上版本:
-```shell
-pip install x2paddle sympy onnx
-```
-
-#### 3.2 准备数据集
-
-本案例默认以COCO数据进行自动压缩实验,并且依赖PaddleDetection中数据读取模块,如果自定义COCO数据,或者其他格式数据,请参考[PaddleDetection数据准备文档](https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.4/docs/tutorials/PrepareDataSet.md) 来准备数据。
-
-如果已经准备好数据集,请直接修改[./configs/yolov7_reader.yml]中`EvalDataset`的`dataset_dir`字段为自己数据集路径即可。
-
-
-#### 3.3 准备预测模型
-
-(1)准备ONNX模型:
-
-可通过[WongKinYiu/yolov7](https://github.com/WongKinYiu/yolov7)的导出脚本来准备ONNX模型,具体步骤如下:
-```shell
-git clone https://github.com/WongKinYiu/yolov7.git
-# 切换分支到u5分支,保持导出的ONNX模型后处理和YOLOv5一致
-git checkout u5
-# 下载好yolov7.pt权重后执行:
-python export.py --weights yolov7.pt --include onnx
-```
-
-也可以直接下载我们已经准备好的[yolov7.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov7.onnx)。
-
-
-(2) 转换模型:
-```
-x2paddle --framework=onnx --model=yolov7.onnx --save_dir=pd_model
-cp -r pd_model/inference_model/ yolov7_infer
-```
-即可得到YOLOv7模型的预测模型(`model.pdmodel` 和 `model.pdiparams`)。如想快速体验,可直接下载上方表格中YOLOv7的[Paddle预测模型](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov7_infer.tar)。
-
-
-预测模型的格式为:`model.pdmodel` 和 `model.pdiparams`两个,带`pdmodel`的是模型文件,带`pdiparams`后缀的是权重文件。
-
-
-#### 3.4 自动压缩并产出模型
-
-蒸馏量化自动压缩示例通过run.py脚本启动,会使用接口```paddleslim.auto_compression.AutoCompression```对模型进行自动压缩。配置config文件中模型路径、蒸馏、量化、和训练等部分的参数,配置完成后便可对模型进行量化和蒸馏。具体运行命令为:
-
-- 单卡训练:
-```
-export CUDA_VISIBLE_DEVICES=0
-python run.py --config_path=./configs/yolov7_qat_dis.yaml --save_dir='./output/'
-```
-
-- 多卡训练:
-```
-CUDA_VISIBLE_DEVICES=0,1,2,3 python -m paddle.distributed.launch --log_dir=log --gpus 0,1,2,3 run.py \
- --config_path=./configs/yolov7_qat_dis.yaml --save_dir='./output/'
-```
-
-#### 3.5 测试模型精度
-
-修改[yolov7_qat_dis.yaml](./configs/yolov7_qat_dis.yaml)中`model_dir`字段为模型存储路径,然后使用eval.py脚本得到模型的mAP:
-```
-export CUDA_VISIBLE_DEVICES=0
-python eval.py --config_path=./configs/yolov7_qat_dis.yaml
-```
-
-
-## 4.预测部署
-
-#### Paddle-TensorRT C++部署
-
-进入[cpp_infer](./cpp_infer)文件夹内,请按照[C++ TensorRT Benchmark测试教程](./cpp_infer/README.md)进行准备环境及编译,然后开始测试:
-```shell
-# 编译
-bash complie.sh
-# 执行
-./build/trt_run --model_file yolov7_quant/model.pdmodel --params_file yolov7_quant/model.pdiparams --run_mode=trt_int8
-```
-
-#### Paddle-TensorRT Python部署:
-
-首先安装带有TensorRT的[Paddle安装包](https://www.paddlepaddle.org.cn/inference/v2.3/user_guides/download_lib.html#python)。
-
-然后使用[paddle_trt_infer.py](./paddle_trt_infer.py)进行部署:
-```shell
-python paddle_trt_infer.py --model_path=output --image_file=images/000000570688.jpg --benchmark=True --run_mode=trt_int8
-```
-
-## 5.FAQ
-
-- 如果想测试离线量化模型精度,可执行:
-```shell
-python post_quant.py --config_path=./configs/yolov7_qat_dis.yaml
-```
diff --git a/example/auto_compression/pytorch_yolov7/configs/yolov7_reader.yaml b/example/auto_compression/pytorch_yolov7/configs/yolov7_reader.yaml
deleted file mode 100644
index cb87c3f8fde8bd0149189cd6a9f3437e7f4548e2..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov7/configs/yolov7_reader.yaml
+++ /dev/null
@@ -1,27 +0,0 @@
-metric: COCO
-num_classes: 80
-
-# Datset configuration
-TrainDataset:
- !COCODataSet
- image_dir: train2017
- anno_path: annotations/instances_train2017.json
- dataset_dir: dataset/coco/
-
-EvalDataset:
- !COCODataSet
- image_dir: val2017
- anno_path: annotations/instances_val2017.json
- dataset_dir: dataset/coco/
-
-worker_num: 0
-
-# preprocess reader in test
-EvalReader:
- sample_transforms:
- - Decode: {}
- - Resize: {target_size: [640, 640], keep_ratio: True}
- - Pad: {size: [640, 640], fill_value: [114., 114., 114.]}
- - NormalizeImage: {mean: [0, 0, 0], std: [1, 1, 1], is_scale: True}
- - Permute: {}
- batch_size: 1
diff --git a/example/auto_compression/pytorch_yolov7/cpp_infer/CMakeLists.txt b/example/auto_compression/pytorch_yolov7/cpp_infer/CMakeLists.txt
deleted file mode 100644
index d5307c657212bc3815353a55904672b6fa5679b4..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov7/cpp_infer/CMakeLists.txt
+++ /dev/null
@@ -1,263 +0,0 @@
-cmake_minimum_required(VERSION 3.0)
-project(cpp_inference_demo CXX C)
-option(WITH_MKL "Compile demo with MKL/OpenBlas support, default use MKL." ON)
-option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." OFF)
-option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." ON)
-option(USE_TENSORRT "Compile demo with TensorRT." OFF)
-option(WITH_ROCM "Compile demo with rocm." OFF)
-option(WITH_ONNXRUNTIME "Compile demo with ONNXRuntime" OFF)
-option(WITH_ARM "Compile demo with ARM" OFF)
-option(WITH_MIPS "Compile demo with MIPS" OFF)
-option(WITH_SW "Compile demo with SW" OFF)
-option(WITH_XPU "Compile demow ith xpu" OFF)
-option(WITH_NPU "Compile demow ith npu" OFF)
-
-if(NOT WITH_STATIC_LIB)
- add_definitions("-DPADDLE_WITH_SHARED_LIB")
-else()
- # PD_INFER_DECL is mainly used to set the dllimport/dllexport attribute in dynamic library mode.
- # Set it to empty in static library mode to avoid compilation issues.
- add_definitions("/DPD_INFER_DECL=")
-endif()
-
-macro(safe_set_static_flag)
- foreach(flag_var
- CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
- CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
- if(${flag_var} MATCHES "/MD")
- string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
- endif(${flag_var} MATCHES "/MD")
- endforeach(flag_var)
-endmacro()
-
-if(NOT DEFINED PADDLE_LIB)
- message(FATAL_ERROR "please set PADDLE_LIB with -DPADDLE_LIB=/path/paddle/lib")
-endif()
-if(NOT DEFINED DEMO_NAME)
- message(FATAL_ERROR "please set DEMO_NAME with -DDEMO_NAME=demo_name")
-endif()
-
-include_directories("${PADDLE_LIB}/")
-set(PADDLE_LIB_THIRD_PARTY_PATH "${PADDLE_LIB}/third_party/install/")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}cryptopp/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/include")
-include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/include")
-
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}cryptopp/lib")
-link_directories("${PADDLE_LIB}/paddle/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib")
-link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/lib")
-
-if (WIN32)
- add_definitions("/DGOOGLE_GLOG_DLL_DECL=")
- option(MSVC_STATIC_CRT "use static C Runtime library by default" ON)
- if (MSVC_STATIC_CRT)
- if (WITH_MKL)
- set(FLAG_OPENMP "/openmp")
- endif()
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /bigobj /MTd ${FLAG_OPENMP}")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /bigobj /MT ${FLAG_OPENMP}")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj /MTd ${FLAG_OPENMP}")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /bigobj /MT ${FLAG_OPENMP}")
- safe_set_static_flag()
- if (WITH_STATIC_LIB)
- add_definitions(-DSTATIC_LIB)
- endif()
- endif()
-else()
- if(WITH_MKL)
- set(FLAG_OPENMP "-fopenmp")
- endif()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${FLAG_OPENMP}")
-endif()
-
-if(WITH_GPU)
- if(NOT WIN32)
- include_directories("/usr/local/cuda/include")
- if(CUDA_LIB STREQUAL "")
- set(CUDA_LIB "/usr/local/cuda/lib64/" CACHE STRING "CUDA Library")
- endif()
- else()
- include_directories("C:\\Program\ Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v8.0\\include")
- if(CUDA_LIB STREQUAL "")
- set(CUDA_LIB "C:\\Program\ Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v8.0\\lib\\x64")
- endif()
- endif(NOT WIN32)
-endif()
-
-if (USE_TENSORRT AND WITH_GPU)
- set(TENSORRT_ROOT "" CACHE STRING "The root directory of TensorRT library")
- if("${TENSORRT_ROOT}" STREQUAL "")
- message(FATAL_ERROR "The TENSORRT_ROOT is empty, you must assign it a value with CMake command. Such as: -DTENSORRT_ROOT=TENSORRT_ROOT_PATH ")
- endif()
- set(TENSORRT_INCLUDE_DIR ${TENSORRT_ROOT}/include)
- set(TENSORRT_LIB_DIR ${TENSORRT_ROOT}/lib)
- file(READ ${TENSORRT_INCLUDE_DIR}/NvInfer.h TENSORRT_VERSION_FILE_CONTENTS)
- string(REGEX MATCH "define NV_TENSORRT_MAJOR +([0-9]+)" TENSORRT_MAJOR_VERSION
- "${TENSORRT_VERSION_FILE_CONTENTS}")
- if("${TENSORRT_MAJOR_VERSION}" STREQUAL "")
- file(READ ${TENSORRT_INCLUDE_DIR}/NvInferVersion.h TENSORRT_VERSION_FILE_CONTENTS)
- string(REGEX MATCH "define NV_TENSORRT_MAJOR +([0-9]+)" TENSORRT_MAJOR_VERSION
- "${TENSORRT_VERSION_FILE_CONTENTS}")
- endif()
- if("${TENSORRT_MAJOR_VERSION}" STREQUAL "")
- message(SEND_ERROR "Failed to detect TensorRT version.")
- endif()
- string(REGEX REPLACE "define NV_TENSORRT_MAJOR +([0-9]+)" "\\1"
- TENSORRT_MAJOR_VERSION "${TENSORRT_MAJOR_VERSION}")
- message(STATUS "Current TensorRT header is ${TENSORRT_INCLUDE_DIR}/NvInfer.h. "
- "Current TensorRT version is v${TENSORRT_MAJOR_VERSION}. ")
- include_directories("${TENSORRT_INCLUDE_DIR}")
- link_directories("${TENSORRT_LIB_DIR}")
-endif()
-
-if(WITH_MKL)
- set(MATH_LIB_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}mklml")
- include_directories("${MATH_LIB_PATH}/include")
- if(WIN32)
- set(MATH_LIB ${MATH_LIB_PATH}/lib/mklml${CMAKE_STATIC_LIBRARY_SUFFIX}
- ${MATH_LIB_PATH}/lib/libiomp5md${CMAKE_STATIC_LIBRARY_SUFFIX})
- else()
- set(MATH_LIB ${MATH_LIB_PATH}/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${MATH_LIB_PATH}/lib/libiomp5${CMAKE_SHARED_LIBRARY_SUFFIX})
- endif()
- set(MKLDNN_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}mkldnn")
- if(EXISTS ${MKLDNN_PATH})
- include_directories("${MKLDNN_PATH}/include")
- if(WIN32)
- set(MKLDNN_LIB ${MKLDNN_PATH}/lib/mkldnn.lib)
- else(WIN32)
- set(MKLDNN_LIB ${MKLDNN_PATH}/lib/libmkldnn.so.0)
- endif(WIN32)
- endif()
-elseif((NOT WITH_MIPS) AND (NOT WITH_SW))
- set(OPENBLAS_LIB_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}openblas")
- include_directories("${OPENBLAS_LIB_PATH}/include/openblas")
- if(WIN32)
- set(MATH_LIB ${OPENBLAS_LIB_PATH}/lib/openblas${CMAKE_STATIC_LIBRARY_SUFFIX})
- else()
- set(MATH_LIB ${OPENBLAS_LIB_PATH}/lib/libopenblas${CMAKE_STATIC_LIBRARY_SUFFIX})
- endif()
-endif()
-
-if(WITH_STATIC_LIB)
- set(DEPS ${PADDLE_LIB}/paddle/lib/libpaddle_inference${CMAKE_STATIC_LIBRARY_SUFFIX})
-else()
- if(WIN32)
- set(DEPS ${PADDLE_LIB}/paddle/lib/paddle_inference${CMAKE_STATIC_LIBRARY_SUFFIX})
- else()
- set(DEPS ${PADDLE_LIB}/paddle/lib/libpaddle_inference${CMAKE_SHARED_LIBRARY_SUFFIX})
- endif()
-endif()
-
-if (WITH_ONNXRUNTIME)
- if(WIN32)
- set(DEPS ${DEPS} ${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/onnxruntime.lib paddle2onnx)
- elseif(APPLE)
- set(DEPS ${DEPS} ${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/libonnxruntime.1.10.0.dylib paddle2onnx)
- else()
- set(DEPS ${DEPS} ${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/libonnxruntime.so.1.10.0 paddle2onnx)
- endif()
-endif()
-
-if (NOT WIN32)
- set(EXTERNAL_LIB "-lrt -ldl -lpthread")
- set(DEPS ${DEPS}
- ${MATH_LIB} ${MKLDNN_LIB}
- glog gflags protobuf xxhash cryptopp
- ${EXTERNAL_LIB})
-else()
- set(DEPS ${DEPS}
- ${MATH_LIB} ${MKLDNN_LIB}
- glog gflags_static libprotobuf xxhash cryptopp-static ${EXTERNAL_LIB})
- set(DEPS ${DEPS} shlwapi.lib)
-endif(NOT WIN32)
-
-if(WITH_GPU)
- if(NOT WIN32)
- if (USE_TENSORRT)
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/libnvinfer${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/libnvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX})
- endif()
- set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX})
- else()
- if(USE_TENSORRT)
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/nvinfer${CMAKE_STATIC_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/nvinfer_plugin${CMAKE_STATIC_LIBRARY_SUFFIX})
- if(${TENSORRT_MAJOR_VERSION} GREATER_EQUAL 7)
- set(DEPS ${DEPS} ${TENSORRT_LIB_DIR}/myelin64_1${CMAKE_STATIC_LIBRARY_SUFFIX})
- endif()
- endif()
- set(DEPS ${DEPS} ${CUDA_LIB}/cudart${CMAKE_STATIC_LIBRARY_SUFFIX} )
- set(DEPS ${DEPS} ${CUDA_LIB}/cublas${CMAKE_STATIC_LIBRARY_SUFFIX} )
- set(DEPS ${DEPS} ${CUDA_LIB}/cudnn${CMAKE_STATIC_LIBRARY_SUFFIX} )
- endif()
-endif()
-
-if(WITH_ROCM AND NOT WIN32)
- set(DEPS ${DEPS} ${ROCM_LIB}/libamdhip64${CMAKE_SHARED_LIBRARY_SUFFIX})
-endif()
-
-if(WITH_XPU AND NOT WIN32)
- set(XPU_INSTALL_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}xpu")
- set(DEPS ${DEPS} ${XPU_INSTALL_PATH}/lib/libxpuapi${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${XPU_INSTALL_PATH}/lib/libxpurt${CMAKE_SHARED_LIBRARY_SUFFIX})
-endif()
-
-if(WITH_NPU AND NOT WIN32)
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libgraph${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libge_runner${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libascendcl${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libascendcl${CMAKE_SHARED_LIBRARY_SUFFIX})
- set(DEPS ${DEPS} ${ASCEND_DIR}/ascend-toolkit/latest/fwkacllib/lib64/libacl_op_compiler${CMAKE_SHARED_LIBRARY_SUFFIX})
-endif()
-
-add_executable(${DEMO_NAME} ${DEMO_NAME}.cc)
-target_link_libraries(${DEMO_NAME} ${DEPS})
-if(WIN32)
- if(USE_TENSORRT)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${TENSORRT_LIB_DIR}/nvinfer${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- COMMAND ${CMAKE_COMMAND} -E copy ${TENSORRT_LIB_DIR}/nvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- )
- if(${TENSORRT_MAJOR_VERSION} GREATER_EQUAL 7)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${TENSORRT_LIB_DIR}/myelin64_1${CMAKE_SHARED_LIBRARY_SUFFIX}
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE})
- endif()
- endif()
- if(WITH_MKL)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${MATH_LIB_PATH}/lib/mklml.dll ${CMAKE_BINARY_DIR}/Release
- COMMAND ${CMAKE_COMMAND} -E copy ${MATH_LIB_PATH}/lib/libiomp5md.dll ${CMAKE_BINARY_DIR}/Release
- COMMAND ${CMAKE_COMMAND} -E copy ${MKLDNN_PATH}/lib/mkldnn.dll ${CMAKE_BINARY_DIR}/Release
- )
- else()
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${OPENBLAS_LIB_PATH}/lib/openblas.dll ${CMAKE_BINARY_DIR}/Release
- )
- endif()
- if(WITH_ONNXRUNTIME)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/onnxruntime.dll
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- COMMAND ${CMAKE_COMMAND} -E copy ${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/lib/paddle2onnx.dll
- ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- )
- endif()
- if(NOT WITH_STATIC_LIB)
- add_custom_command(TARGET ${DEMO_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy "${PADDLE_LIB}/paddle/lib/paddle_inference.dll" ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}
- )
- endif()
-endif()
diff --git a/example/auto_compression/pytorch_yolov7/cpp_infer/README.md b/example/auto_compression/pytorch_yolov7/cpp_infer/README.md
deleted file mode 100644
index 04c1c23bc027b228ba0f67416d9966c3b1cd1133..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov7/cpp_infer/README.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# YOLOv7 TensorRT Benchmark测试(Linux)
-
-## 环境准备
-
-- CUDA、CUDNN:确认环境中已经安装CUDA和CUDNN,并且提前获取其安装路径。
-
-- TensorRT:可通过NVIDIA官网下载[TensorRT 8.4.1.5](https://developer.nvidia.com/compute/machine-learning/tensorrt/secure/8.4.1/tars/tensorrt-8.4.1.5.linux.x86_64-gnu.cuda-11.6.cudnn8.4.tar.gz)或其他版本安装包。
-
-- Paddle Inference C++预测库:编译develop版本请参考[编译文档](https://www.paddlepaddle.org.cn/inference/user_guides/source_compile.html)。编译完成后,会在build目录下生成`paddle_inference_install_dir`文件夹,这个就是我们需要的C++预测库文件。
-
-## 编译可执行程序
-
-- (1)修改`compile.sh`中依赖库路径,主要是以下内容:
-```shell
-# Paddle Inference预测库路径
-LIB_DIR=/root/auto_compress/Paddle/build/paddle_inference_install_dir/
-# CUDNN路径
-CUDNN_LIB=/usr/lib/x86_64-linux-gnu/
-# CUDA路径
-CUDA_LIB=/usr/local/cuda/lib64
-# TensorRT安装包路径,为TRT资源包解压完成后的绝对路径,其中包含`lib`和`include`文件夹
-TENSORRT_ROOT=/root/auto_compress/trt/trt8.4/
-```
-
-## 测试
-
-- FP32
-```
-./build/trt_run --model_file yolov7_infer/model.pdmodel --params_file yolov7_infer/model.pdiparams --run_mode=trt_fp32
-```
-
-- FP16
-```
-./build/trt_run --model_file yolov7_infer/model.pdmodel --params_file yolov7_infer/model.pdiparams --run_mode=trt_fp16
-```
-
-- INT8
-```
-./build/trt_run --model_file yolov7_quant/model.pdmodel --params_file yolov7_quant/model.pdiparams --run_mode=trt_int8
-```
-
-## 性能对比
-
-| 预测库 | 模型 | 预测时延FP32
(ms) |预测时延FP16
(ms) | 预测时延INT8
(ms) |
-| :--------: | :--------: |:-------- |:--------: | :---------------------: |
-| Paddle TensorRT | YOLOv7 | 26.84ms | 7.44ms | 4.55ms |
-| TensorRT | YOLOv7 | 28.25ms | 7.23ms | 4.67ms |
-
-环境:
-- Tesla T4,TensorRT 8.4.1,CUDA 11.2
-- batch_size=1
diff --git a/example/auto_compression/pytorch_yolov7/cpp_infer/compile.sh b/example/auto_compression/pytorch_yolov7/cpp_infer/compile.sh
deleted file mode 100644
index afff924b4f63c37e2ae8906d505e046066e0a906..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov7/cpp_infer/compile.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/bash
-set +x
-set -e
-
-work_path=$(dirname $(readlink -f $0))
-
-mkdir -p build
-cd build
-rm -rf *
-
-DEMO_NAME=trt_run
-
-WITH_MKL=ON
-WITH_GPU=ON
-USE_TENSORRT=ON
-
-LIB_DIR=/root/auto_compress/Paddle/build/paddle_inference_install_dir/
-CUDNN_LIB=/usr/lib/x86_64-linux-gnu/
-CUDA_LIB=/usr/local/cuda/lib64
-TENSORRT_ROOT=/root/auto_compress/trt/trt8.4/
-
-WITH_ROCM=OFF
-ROCM_LIB=/opt/rocm/lib
-
-cmake .. -DPADDLE_LIB=${LIB_DIR} \
- -DWITH_MKL=${WITH_MKL} \
- -DDEMO_NAME=${DEMO_NAME} \
- -DWITH_GPU=${WITH_GPU} \
- -DWITH_STATIC_LIB=OFF \
- -DUSE_TENSORRT=${USE_TENSORRT} \
- -DWITH_ROCM=${WITH_ROCM} \
- -DROCM_LIB=${ROCM_LIB} \
- -DCUDNN_LIB=${CUDNN_LIB} \
- -DCUDA_LIB=${CUDA_LIB} \
- -DTENSORRT_ROOT=${TENSORRT_ROOT}
-
-make -j
diff --git a/example/auto_compression/pytorch_yolov7/eval.py b/example/auto_compression/pytorch_yolov7/eval.py
deleted file mode 100644
index 478c4e1abd50dc4a1f0697f665005bdfb1bc2b5d..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov7/eval.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import sys
-import numpy as np
-import argparse
-import paddle
-from ppdet.core.workspace import load_config, merge_config
-from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
-
-from post_process import YOLOv7PostProcess
-
-
-def argsparser():
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument(
- '--config_path',
- type=str,
- default=None,
- help="path of compression strategy config.",
- required=True)
- parser.add_argument(
- '--devices',
- type=str,
- default='gpu',
- help="which device used to compress.")
-
- return parser
-
-
-def reader_wrapper(reader, input_list):
- def gen():
- for data in reader:
- in_dict = {}
- if isinstance(input_list, list):
- for input_name in input_list:
- in_dict[input_name] = data[input_name]
- elif isinstance(input_list, dict):
- for input_name in input_list.keys():
- in_dict[input_list[input_name]] = data[input_name]
- yield in_dict
-
- return gen
-
-
-def convert_numpy_data(data, metric):
- data_all = {}
- data_all = {k: np.array(v) for k, v in data.items()}
- if isinstance(metric, VOCMetric):
- for k, v in data_all.items():
- if not isinstance(v[0], np.ndarray):
- tmp_list = []
- for t in v:
- tmp_list.append(np.array(t))
- data_all[k] = np.array(tmp_list)
- else:
- data_all = {k: np.array(v) for k, v in data.items()}
- return data_all
-
-
-def eval():
-
- place = paddle.CUDAPlace(0) if FLAGS.devices == 'gpu' else paddle.CPUPlace()
- exe = paddle.static.Executor(place)
-
- val_program, feed_target_names, fetch_targets = paddle.static.load_inference_model(
- global_config["model_dir"],
- exe,
- model_filename=global_config["model_filename"],
- params_filename=global_config["params_filename"])
- print('Loaded model from: {}'.format(global_config["model_dir"]))
-
- metric = global_config['metric']
- for batch_id, data in enumerate(val_loader):
- data_all = convert_numpy_data(data, metric)
- data_input = {}
- for k, v in data.items():
- if isinstance(global_config['input_list'], list):
- if k in global_config['input_list']:
- data_input[k] = np.array(v)
- elif isinstance(global_config['input_list'], dict):
- if k in global_config['input_list'].keys():
- data_input[global_config['input_list'][k]] = np.array(v)
- outs = exe.run(val_program,
- feed=data_input,
- fetch_list=fetch_targets,
- return_numpy=False)
- res = {}
- postprocess = YOLOv7PostProcess(
- score_threshold=0.001, nms_threshold=0.65, multi_label=True)
- res = postprocess(np.array(outs[0]), data_all['scale_factor'])
- metric.update(data_all, res)
- if batch_id % 100 == 0:
- print('Eval iter:', batch_id)
- metric.accumulate()
- metric.log()
- metric.reset()
-
-
-def main():
- global global_config
- all_config = load_slim_config(FLAGS.config_path)
- global_config = all_config["Global"]
- reader_cfg = load_config(global_config['reader_config'])
-
- dataset = reader_cfg['EvalDataset']
- global val_loader
- val_loader = create('EvalReader')(reader_cfg['EvalDataset'],
- reader_cfg['worker_num'],
- return_list=True)
- metric = None
- if reader_cfg['metric'] == 'COCO':
- clsid2catid = {v: k for k, v in dataset.catid2clsid.items()}
- anno_file = dataset.get_anno()
- metric = COCOMetric(
- anno_file=anno_file, clsid2catid=clsid2catid, IouType='bbox')
- elif reader_cfg['metric'] == 'VOC':
- metric = VOCMetric(
- label_list=dataset.get_label_list(),
- class_num=reader_cfg['num_classes'],
- map_type=reader_cfg['map_type'])
- else:
- raise ValueError("metric currently only supports COCO and VOC.")
- global_config['metric'] = metric
-
- eval()
-
-
-if __name__ == '__main__':
- paddle.enable_static()
- parser = argsparser()
- FLAGS = parser.parse_args()
-
- assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
- paddle.set_device(FLAGS.devices)
-
- main()
diff --git a/example/auto_compression/pytorch_yolov7/images/000000570688.jpg b/example/auto_compression/pytorch_yolov7/images/000000570688.jpg
deleted file mode 100644
index cb304bd56c4010c08611a30dcca58ea9140cea54..0000000000000000000000000000000000000000
Binary files a/example/auto_compression/pytorch_yolov7/images/000000570688.jpg and /dev/null differ
diff --git a/example/auto_compression/pytorch_yolov7/post_process.py b/example/auto_compression/pytorch_yolov7/post_process.py
deleted file mode 100644
index 853693daf5ac822367c0065d07ea5ef35014c336..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov7/post_process.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import numpy as np
-import cv2
-
-
-def box_area(boxes):
- """
- Args:
- boxes(np.ndarray): [N, 4]
- return: [N]
- """
- return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
-
-
-def box_iou(box1, box2):
- """
- Args:
- box1(np.ndarray): [N, 4]
- box2(np.ndarray): [M, 4]
- return: [N, M]
- """
- area1 = box_area(box1)
- area2 = box_area(box2)
- lt = np.maximum(box1[:, np.newaxis, :2], box2[:, :2])
- rb = np.minimum(box1[:, np.newaxis, 2:], box2[:, 2:])
- wh = rb - lt
- wh = np.maximum(0, wh)
- inter = wh[:, :, 0] * wh[:, :, 1]
- iou = inter / (area1[:, np.newaxis] + area2 - inter)
- return iou
-
-
-def nms(boxes, scores, iou_threshold):
- """
- Non Max Suppression numpy implementation.
- args:
- boxes(np.ndarray): [N, 4]
- scores(np.ndarray): [N, 1]
- iou_threshold(float): Threshold of IoU.
- """
- idxs = scores.argsort()
- keep = []
- while idxs.size > 0:
- max_score_index = idxs[-1]
- max_score_box = boxes[max_score_index][None, :]
- keep.append(max_score_index)
- if idxs.size == 1:
- break
- idxs = idxs[:-1]
- other_boxes = boxes[idxs]
- ious = box_iou(max_score_box, other_boxes)
- idxs = idxs[ious[0] <= iou_threshold]
-
- keep = np.array(keep)
- return keep
-
-
-class YOLOv7PostProcess(object):
- """
- Post process of YOLOv6 network.
- args:
- score_threshold(float): Threshold to filter out bounding boxes with low
- confidence score. If not provided, consider all boxes.
- nms_threshold(float): The threshold to be used in NMS.
- multi_label(bool): Whether keep multi label in boxes.
- keep_top_k(int): Number of total bboxes to be kept per image after NMS
- step. -1 means keeping all bboxes after NMS step.
- """
-
- def __init__(self,
- score_threshold=0.25,
- nms_threshold=0.5,
- multi_label=False,
- keep_top_k=300):
- self.score_threshold = score_threshold
- self.nms_threshold = nms_threshold
- self.multi_label = multi_label
- self.keep_top_k = keep_top_k
-
- def _xywh2xyxy(self, x):
- # Convert from [x, y, w, h] to [x1, y1, x2, y2]
- y = np.copy(x)
- y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
- y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
- y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
- y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
- return y
-
- def _non_max_suppression(self, prediction):
- max_wh = 4096 # (pixels) minimum and maximum box width and height
- nms_top_k = 30000
-
- cand_boxes = prediction[..., 4] > self.score_threshold # candidates
- output = [np.zeros((0, 6))] * prediction.shape[0]
-
- for batch_id, boxes in enumerate(prediction):
- # Apply constraints
- boxes = boxes[cand_boxes[batch_id]]
- if not boxes.shape[0]:
- continue
- # Compute conf (conf = obj_conf * cls_conf)
- boxes[:, 5:] *= boxes[:, 4:5]
-
- # Box (center x, center y, width, height) to (x1, y1, x2, y2)
- convert_box = self._xywh2xyxy(boxes[:, :4])
-
- # Detections matrix nx6 (xyxy, conf, cls)
- if self.multi_label:
- i, j = (boxes[:, 5:] > self.score_threshold).nonzero()
- boxes = np.concatenate(
- (convert_box[i], boxes[i, j + 5, None],
- j[:, None].astype(np.float32)),
- axis=1)
- else:
- conf = np.max(boxes[:, 5:], axis=1)
- j = np.argmax(boxes[:, 5:], axis=1)
- re = np.array(conf.reshape(-1) > self.score_threshold)
- conf = conf.reshape(-1, 1)
- j = j.reshape(-1, 1)
- boxes = np.concatenate((convert_box, conf, j), axis=1)[re]
-
- num_box = boxes.shape[0]
- if not num_box:
- continue
- elif num_box > nms_top_k:
- boxes = boxes[boxes[:, 4].argsort()[::-1][:nms_top_k]]
-
- # Batched NMS
- c = boxes[:, 5:6] * max_wh
- clean_boxes, scores = boxes[:, :4] + c, boxes[:, 4]
- keep = nms(clean_boxes, scores, self.nms_threshold)
- # limit detection box num
- if keep.shape[0] > self.keep_top_k:
- keep = keep[:self.keep_top_k]
- output[batch_id] = boxes[keep]
- return output
-
- def __call__(self, outs, scale_factor):
- preds = self._non_max_suppression(outs)
- bboxs, box_nums = [], []
- for i, pred in enumerate(preds):
- if len(pred.shape) > 2:
- pred = np.squeeze(pred)
- if len(pred.shape) == 1:
- pred = pred[np.newaxis, :]
- pred_bboxes = pred[:, :4]
- scale_factor = np.tile(scale_factor[i][::-1], (1, 2))
- pred_bboxes /= scale_factor
- bbox = np.concatenate(
- [
- pred[:, -1][:, np.newaxis], pred[:, -2][:, np.newaxis],
- pred_bboxes
- ],
- axis=-1)
- bboxs.append(bbox)
- box_num = bbox.shape[0]
- box_nums.append(box_num)
- bboxs = np.concatenate(bboxs, axis=0)
- box_nums = np.array(box_nums)
- return {'bbox': bboxs, 'bbox_num': box_nums}
diff --git a/example/auto_compression/pytorch_yolov7/run.py b/example/auto_compression/pytorch_yolov7/run.py
deleted file mode 100644
index ed73d81aaea20a37ad922d880fecd75f815337ce..0000000000000000000000000000000000000000
--- a/example/auto_compression/pytorch_yolov7/run.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import sys
-import numpy as np
-import argparse
-import paddle
-from ppdet.core.workspace import load_config, merge_config
-from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
-from paddleslim.auto_compression import AutoCompression
-
-from post_process import YOLOv7PostProcess
-
-
-def argsparser():
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument(
- '--config_path',
- type=str,
- default=None,
- help="path of compression strategy config.",
- required=True)
- parser.add_argument(
- '--save_dir',
- type=str,
- default='output',
- help="directory to save compressed model.")
- parser.add_argument(
- '--devices',
- type=str,
- default='gpu',
- help="which device used to compress.")
- parser.add_argument(
- '--eval', type=bool, default=False, help="whether to run evaluation.")
-
- return parser
-
-
-def reader_wrapper(reader, input_list):
- def gen():
- for data in reader:
- in_dict = {}
- if isinstance(input_list, list):
- for input_name in input_list:
- in_dict[input_name] = data[input_name]
- elif isinstance(input_list, dict):
- for input_name in input_list.keys():
- in_dict[input_list[input_name]] = data[input_name]
- yield in_dict
-
- return gen
-
-
-def convert_numpy_data(data, metric):
- data_all = {}
- data_all = {k: np.array(v) for k, v in data.items()}
- if isinstance(metric, VOCMetric):
- for k, v in data_all.items():
- if not isinstance(v[0], np.ndarray):
- tmp_list = []
- for t in v:
- tmp_list.append(np.array(t))
- data_all[k] = np.array(tmp_list)
- else:
- data_all = {k: np.array(v) for k, v in data.items()}
- return data_all
-
-
-def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
- metric = global_config['metric']
- for batch_id, data in enumerate(val_loader):
- data_all = convert_numpy_data(data, metric)
- data_input = {}
- for k, v in data.items():
- if isinstance(global_config['input_list'], list):
- if k in test_feed_names:
- data_input[k] = np.array(v)
- elif isinstance(global_config['input_list'], dict):
- if k in global_config['input_list'].keys():
- data_input[global_config['input_list'][k]] = np.array(v)
- outs = exe.run(compiled_test_program,
- feed=data_input,
- fetch_list=test_fetch_list,
- return_numpy=False)
- res = {}
- postprocess = YOLOv7PostProcess(
- score_threshold=0.001, nms_threshold=0.65, multi_label=True)
- res = postprocess(np.array(outs[0]), data_all['scale_factor'])
- metric.update(data_all, res)
- if batch_id % 100 == 0:
- print('Eval iter:', batch_id)
- metric.accumulate()
- metric.log()
- map_res = metric.get_results()
- metric.reset()
- return map_res['bbox'][0]
-
-
-def main():
- global global_config
- all_config = load_slim_config(FLAGS.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
- global_config = all_config["Global"]
- reader_cfg = load_config(global_config['reader_config'])
-
- train_loader = create('EvalReader')(reader_cfg['TrainDataset'],
- reader_cfg['worker_num'],
- return_list=True)
- train_loader = reader_wrapper(train_loader, global_config['input_list'])
-
- if 'Evaluation' in global_config.keys() and global_config[
- 'Evaluation'] and paddle.distributed.get_rank() == 0:
- eval_func = eval_function
- dataset = reader_cfg['EvalDataset']
- global val_loader
- _eval_batch_sampler = paddle.io.BatchSampler(
- dataset, batch_size=reader_cfg['EvalReader']['batch_size'])
- val_loader = create('EvalReader')(dataset,
- reader_cfg['worker_num'],
- batch_sampler=_eval_batch_sampler,
- return_list=True)
- metric = None
- if reader_cfg['metric'] == 'COCO':
- clsid2catid = {v: k for k, v in dataset.catid2clsid.items()}
- anno_file = dataset.get_anno()
- metric = COCOMetric(
- anno_file=anno_file, clsid2catid=clsid2catid, IouType='bbox')
- elif reader_cfg['metric'] == 'VOC':
- metric = VOCMetric(
- label_list=dataset.get_label_list(),
- class_num=reader_cfg['num_classes'],
- map_type=reader_cfg['map_type'])
- else:
- raise ValueError("metric currently only supports COCO and VOC.")
- global_config['metric'] = metric
- else:
- eval_func = None
-
- ac = AutoCompression(
- model_dir=global_config["model_dir"],
- model_filename=global_config["model_filename"],
- params_filename=global_config["params_filename"],
- save_dir=FLAGS.save_dir,
- config=all_config,
- train_dataloader=train_loader,
- eval_callback=eval_func)
- ac.compress()
-
-
-if __name__ == '__main__':
- paddle.enable_static()
- parser = argsparser()
- FLAGS = parser.parse_args()
-
- assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
- paddle.set_device(FLAGS.devices)
-
- main()
diff --git a/example/auto_compression/semantic_segmentation/README.md b/example/auto_compression/semantic_segmentation/README.md
index f01bb9045d6be6f8b83a417b7ceffc84ed4d9338..a923ec352ee5996b944b899c853f4f2e4536e97b 100644
--- a/example/auto_compression/semantic_segmentation/README.md
+++ b/example/auto_compression/semantic_segmentation/README.md
@@ -71,10 +71,10 @@ git clone https://github.com/PaddlePaddle/PaddleSlim.git
安装paddleseg
```shell
-pip install paddleseg
+pip install paddleseg==2.5.0
```
-注:安装[PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg)的目的只是为了直接使用PaddleSeg中的Dataloader组件,不涉及模型组网等。
+注:安装[PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg)的目的只是为了直接使用PaddleSeg中的Dataloader组件,不涉及模型组网等。推荐安装PaddleSeg 2.5.0, 不同版本的PaddleSeg的Dataloader返回数据的格式略有不同.
#### 3.2 准备数据集
diff --git a/example/auto_compression/semantic_segmentation/run.py b/example/auto_compression/semantic_segmentation/run.py
index 4f4d4c56fb5f4653ceb46f3a94b5ae2d7e98d3cf..a8a486c25c646731ae2e438cee93b54253cb523c 100644
--- a/example/auto_compression/semantic_segmentation/run.py
+++ b/example/auto_compression/semantic_segmentation/run.py
@@ -21,7 +21,7 @@ from paddleseg.cvlibs import Config as PaddleSegDataConfig
from paddleseg.utils import worker_init_fn
from paddleslim.auto_compression import AutoCompression
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config as load_slim_config
from paddleseg.core.infer import reverse_transform
from paddleseg.utils import metrics
@@ -38,6 +38,11 @@ def argsparser():
type=str,
default=None,
help="directory to save compressed model.")
+ parser.add_argument(
+ '--devices',
+ type=str,
+ default='gpu',
+ help="which device used to compress.")
return parser
@@ -123,7 +128,12 @@ def main(args):
config = all_config["Global"]
rank_id = paddle.distributed.get_rank()
- place = paddle.CUDAPlace(rank_id)
+ if args.devices == 'gpu':
+ place = paddle.CUDAPlace(rank_id)
+ paddle.set_device('gpu')
+ else:
+ place = paddle.CPUPlace()
+ paddle.set_device('cpu')
# step1: load dataset config and create dataloader
data_cfg = PaddleSegDataConfig(config['reader_config'])
train_dataset = data_cfg.train_dataset
diff --git a/example/auto_compression/tensorflow_mobilenet/eval.py b/example/auto_compression/tensorflow_mobilenet/eval.py
index 85e5fdaf504ce30c7ddb8d4013371da906006b7b..bf0987e3538c86b9ca278348db3a5b444cb00773 100644
--- a/example/auto_compression/tensorflow_mobilenet/eval.py
+++ b/example/auto_compression/tensorflow_mobilenet/eval.py
@@ -23,7 +23,7 @@ import paddle
import paddle.nn as nn
from paddle.io import DataLoader
from imagenet_reader import ImageNetDataset
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config as load_slim_config
def argsparser():
@@ -93,7 +93,8 @@ def eval():
def main():
global global_config
all_config = load_slim_config(args.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
+ assert "Global" in all_config, "Key 'Global' not found in config file. \n{}".format(
+ all_config)
global_config = all_config["Global"]
global data_dir
data_dir = global_config['data_dir']
diff --git a/example/auto_compression/tensorflow_mobilenet/run.py b/example/auto_compression/tensorflow_mobilenet/run.py
index 86345ec2071a95b3e630120f274cb1e6e4b99ba6..aefd2941f637d6e933bd978933e5829b211180f6 100644
--- a/example/auto_compression/tensorflow_mobilenet/run.py
+++ b/example/auto_compression/tensorflow_mobilenet/run.py
@@ -23,7 +23,7 @@ import paddle
import paddle.nn as nn
from paddle.io import DataLoader
from imagenet_reader import ImageNetDataset
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config as load_slim_config
from paddleslim.auto_compression import AutoCompression
@@ -107,7 +107,8 @@ def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
def main():
global global_config
all_config = load_slim_config(args.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
+ assert "Global" in all_config, "Key 'Global' not found in config file. \n{}".format(
+ all_config)
global_config = all_config["Global"]
global data_dir
data_dir = global_config['data_dir']
diff --git a/example/post_training_quantization/analysis.md b/example/post_training_quantization/analysis.md
new file mode 100644
index 0000000000000000000000000000000000000000..ce5e7a75eed98016fcac4845528c15e7ce1e1ab2
--- /dev/null
+++ b/example/post_training_quantization/analysis.md
@@ -0,0 +1,49 @@
+# 量化分析工具详细教程
+
+## 1. 量化分析工具功能
+1. 遍历模型所有层,依次量化该层,计算量化后精度。为所有只量化一层的模型精度排序,可视化不适合量化的层,以供量化时可选择性跳过不适合量化的层。
+2. 可视化量化效果最好和最差的层的权重和激活分布图,以供分析模型量化效果的原因。
+3. 【敬请期待】输入预期精度,直接产出符合预期精度的量化模型。
+
+## 2. paddleslim.quant.AnalysisQuant 可传入参数解析
+```yaml
+model_dir
+model_filename: None
+params_filename: None
+eval_function: None
+data_loader: None
+save_dir: 'analysis_results'
+checkpoint_name: 'analysis_checkpoint.pkl'
+num_histogram_plots: 10
+ptq_config
+```
+- model_dir: 必须传入的模型文件路径,可为文件夹名;若模型为ONNX类型,直接输入'.onnx'模型文件名称即可。
+- model_filename: 默认为None,若model_dir为文件夹名,则必须传入以'.pdmodel'结尾的模型名称,若model_dir为'.onnx'模型文件名称,则不需要传入。
+- params_filename: 默认为None,若model_dir为文件夹名,则必须传入以'.pdiparams'结尾的模型名称,若model_dir为'.onnx'模型文件名称,则不需要传入。
+- eval_function:目前不支持为None,需要传入自定义的验证函数。
+- data_loader:模型校准时使用的数据,DataLoader继承自`paddle.io.DataLoader`。可以直接使用模型套件中的DataLoader,或者根据[paddle.io.DataLoader](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/io/DataLoader_cn.html#dataloader)自定义所需要的DataLoader。
+- save_dir:分析后保存模型精度或pdf等文件的文件夹,默认为`analysis_results`。
+- checkpoint_name:由于模型可能存在大量层需要分析,因此分析过程中会中间保存结果,如果程序中断会自动加载已经分析好的结果,默认为`analysis_checkpoint.pkl`。
+- num_histogram_plots:需要可视化的直方分布图数量。可视化量化效果最好和最坏的该数量个权重和激活的分布图。默认为10。若不需要可视化直方图,设置为0即可。
+- ptq_config:可传入的离线量化中的参数,详细可参考[离线量化文档](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/quant/quant_post)。
+
+
+
+
+## 3. 量化分析工具产出内容
+
+量化分析工具会默认会产出以下目录:
+```
+analysis_results/
+├── analysis.txt
+├── best_weight_hist_result.pdf
+├── best_act_hist_result.pdf
+├── worst_weight_hist_result.pdf
+├── worst_act_hist_result.pdf
+```
+- 所有只量化一层的模型精度排序,将默认保存在 `./analysis_results/analysis.txt` 中。
+- 通过设置参数`num_histogram_plots`,可选择绘出该数量个量化效果最好和最差层的weight和activation的直方分布图,将以PDF形式保存在 `./analysis_results` 文件夹下, 分别保存为 `best_weight_hist_result.pdf`,`best_act_hist_result.pdf`,`worst_weight_hist_result.pdf` 和 `worst_act_hist_result.pdf` 中以供对比分析。
+
+
+## 3. 根据分析结果执行离线量化
+执行完量化分析工具后,可根据 `analysis.txt` 中的精度排序,在量化中去掉效果较差的层,具体操作为:在调用 `paddleslim.quant.quant_post_static` 时加入参数 `skip_tensor_list`,将需要去掉的层传入即可。
diff --git a/example/post_training_quantization/detection/analysis.py b/example/post_training_quantization/detection/analysis.py
new file mode 100644
index 0000000000000000000000000000000000000000..ba65d7291fe635cc2d2cc7eb3c37bf7c2298b84f
--- /dev/null
+++ b/example/post_training_quantization/detection/analysis.py
@@ -0,0 +1,179 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import numpy as np
+import argparse
+from tqdm import tqdm
+import paddle
+from ppdet.core.workspace import load_config, merge_config
+from ppdet.core.workspace import create
+from ppdet.metrics import COCOMetric, VOCMetric, KeyPointTopDownCOCOEval
+from keypoint_utils import keypoint_post_process
+from post_process import PPYOLOEPostProcess
+from paddleslim.quant.analysis import AnalysisQuant
+
+
+def argsparser():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '--config_path',
+ type=str,
+ default=None,
+ help="path of analysis config.",
+ required=True)
+ parser.add_argument(
+ '--devices',
+ type=str,
+ default='gpu',
+ help="which device used to compress.")
+ return parser
+
+
+def reader_wrapper(reader, input_list):
+ def gen():
+ for data in reader:
+ in_dict = {}
+ if isinstance(input_list, list):
+ for input_name in input_list:
+ in_dict[input_name] = data[input_name]
+ elif isinstance(input_list, dict):
+ for input_name in input_list.keys():
+ in_dict[input_list[input_name]] = data[input_name]
+ yield in_dict
+
+ return gen
+
+
+def convert_numpy_data(data, metric):
+ data_all = {}
+ data_all = {k: np.array(v) for k, v in data.items()}
+ if isinstance(metric, VOCMetric):
+ for k, v in data_all.items():
+ if not isinstance(v[0], np.ndarray):
+ tmp_list = []
+ for t in v:
+ tmp_list.append(np.array(t))
+ data_all[k] = np.array(tmp_list)
+ else:
+ data_all = {k: np.array(v) for k, v in data.items()}
+ return data_all
+
+
+def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
+ with tqdm(
+ total=len(val_loader),
+ bar_format='Evaluation stage, Run batch:|{bar}| {n_fmt}/{total_fmt}',
+ ncols=80) as t:
+ for batch_id, data in enumerate(val_loader):
+ data_all = convert_numpy_data(data, metric)
+ data_input = {}
+ for k, v in data.items():
+ if isinstance(config['input_list'], list):
+ if k in test_feed_names:
+ data_input[k] = np.array(v)
+ elif isinstance(config['input_list'], dict):
+ if k in config['input_list'].keys():
+ data_input[config['input_list'][k]] = np.array(v)
+ outs = exe.run(compiled_test_program,
+ feed=data_input,
+ fetch_list=test_fetch_list,
+ return_numpy=False)
+ res = {}
+ if 'arch' in config and config['arch'] == 'keypoint':
+ res = keypoint_post_process(data, data_input, exe,
+ compiled_test_program,
+ test_fetch_list, outs)
+ if 'arch' in config and config['arch'] == 'PPYOLOE':
+ postprocess = PPYOLOEPostProcess(
+ score_threshold=0.01, nms_threshold=0.6)
+ res = postprocess(np.array(outs[0]), data_all['scale_factor'])
+ else:
+ for out in outs:
+ v = np.array(out)
+ if len(v.shape) > 1:
+ res['bbox'] = v
+ else:
+ res['bbox_num'] = v
+
+ metric.update(data_all, res)
+ t.update()
+
+ metric.accumulate()
+ metric.log()
+ map_res = metric.get_results()
+ metric.reset()
+ map_key = 'keypoint' if 'arch' in config and config[
+ 'arch'] == 'keypoint' else 'bbox'
+ return map_res[map_key][0]
+
+
+def main():
+
+ global config
+ config = load_config(FLAGS.config_path)
+ ptq_config = config['PTQ']
+
+ data_loader = create('EvalReader')(config['EvalDataset'],
+ config['worker_num'],
+ return_list=True)
+ data_loader = reader_wrapper(data_loader, config['input_list'])
+
+ dataset = config['EvalDataset']
+ global val_loader
+ _eval_batch_sampler = paddle.io.BatchSampler(
+ dataset, batch_size=config['EvalReader']['batch_size'])
+ val_loader = create('EvalReader')(dataset,
+ config['worker_num'],
+ batch_sampler=_eval_batch_sampler,
+ return_list=True)
+ global metric
+ if config['metric'] == 'COCO':
+ clsid2catid = {v: k for k, v in dataset.catid2clsid.items()}
+ anno_file = dataset.get_anno()
+ metric = COCOMetric(
+ anno_file=anno_file, clsid2catid=clsid2catid, IouType='bbox')
+ elif config['metric'] == 'VOC':
+ metric = VOCMetric(
+ label_list=dataset.get_label_list(),
+ class_num=config['num_classes'],
+ map_type=config['map_type'])
+ elif config['metric'] == 'KeyPointTopDownCOCOEval':
+ anno_file = dataset.get_anno()
+ metric = KeyPointTopDownCOCOEval(anno_file,
+ len(dataset), 17, 'output_eval')
+ else:
+ raise ValueError("metric currently only supports COCO and VOC.")
+
+ analyzer = AnalysisQuant(
+ model_dir=config["model_dir"],
+ model_filename=config["model_filename"],
+ params_filename=config["params_filename"],
+ eval_function=eval_function,
+ data_loader=data_loader,
+ save_dir=config['save_dir'],
+ ptq_config=ptq_config)
+ analyzer.analysis()
+
+
+if __name__ == '__main__':
+ paddle.enable_static()
+ parser = argsparser()
+ FLAGS = parser.parse_args()
+
+ assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
+ paddle.set_device(FLAGS.devices)
+
+ main()
diff --git a/example/post_training_quantization/detection/configs/picodet_s_analysis.yaml b/example/post_training_quantization/detection/configs/picodet_s_analysis.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6c640795c44b9abae9b1bd019fb318347d1c74c9
--- /dev/null
+++ b/example/post_training_quantization/detection/configs/picodet_s_analysis.yaml
@@ -0,0 +1,47 @@
+input_list: ['image', 'scale_factor']
+model_dir: ./picodet_s_416_coco_lcnet/
+model_filename: model.pdmodel
+params_filename: model.pdiparams
+save_dir: ./analysis_results
+metric: COCO
+num_classes: 80
+
+PTQ:
+ quantizable_op_type: ["conv2d", "depthwise_conv2d"]
+ weight_quantize_type: 'abs_max'
+ activation_quantize_type: 'moving_average_abs_max'
+ is_full_quantize: False
+ batch_size: 10
+ batch_nums: 10
+
+# Datset configuration
+TrainDataset:
+ !COCODataSet
+ image_dir: train2017
+ anno_path: annotations/instances_train2017.json
+ dataset_dir: /dataset/coco/
+
+EvalDataset:
+ !COCODataSet
+ image_dir: val2017
+ anno_path: annotations/instances_val2017.json
+ dataset_dir: /dataset/coco/
+
+eval_height: &eval_height 416
+eval_width: &eval_width 416
+eval_size: &eval_size [*eval_height, *eval_width]
+
+worker_num: 0
+
+EvalReader:
+ inputs_def:
+ image_shape: [1, 3, *eval_height, *eval_width]
+ sample_transforms:
+ - Decode: {}
+ - Resize: {interp: 2, target_size: *eval_size, keep_ratio: False}
+ - NormalizeImage: {is_scale: true, mean: [0.485,0.456,0.406], std: [0.229, 0.224,0.225]}
+ - Permute: {}
+ batch_size: 32
+
+
+
diff --git a/example/post_training_quantization/detection/configs/picodet_s_ptq.yaml b/example/post_training_quantization/detection/configs/picodet_s_ptq.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..005c0d46cdb10ae19a83b572e759a194513ba445
--- /dev/null
+++ b/example/post_training_quantization/detection/configs/picodet_s_ptq.yaml
@@ -0,0 +1,38 @@
+input_list: ['image', 'scale_factor']
+model_dir: ./picodet_s_416_coco_lcnet/
+model_filename: model.pdmodel
+params_filename: model.pdiparams
+skip_tensor_list: None
+
+metric: COCO
+num_classes: 80
+
+# Datset configuration
+TrainDataset:
+ !COCODataSet
+ image_dir: train2017
+ anno_path: annotations/instances_train2017.json
+ dataset_dir: /dataset/coco/
+
+EvalDataset:
+ !COCODataSet
+ image_dir: val2017
+ anno_path: annotations/instances_val2017.json
+ dataset_dir: /dataset/coco/
+
+eval_height: &eval_height 416
+eval_width: &eval_width 416
+eval_size: &eval_size [*eval_height, *eval_width]
+
+worker_num: 0
+
+EvalReader:
+ inputs_def:
+ image_shape: [1, 3, *eval_height, *eval_width]
+ sample_transforms:
+ - Decode: {}
+ - Resize: {interp: 2, target_size: *eval_size, keep_ratio: False}
+ - NormalizeImage: {is_scale: true, mean: [0.485,0.456,0.406], std: [0.229, 0.224,0.225]}
+ - Permute: {}
+ batch_size: 32
+
diff --git a/example/auto_compression/pytorch_yolov5/eval.py b/example/post_training_quantization/detection/eval.py
similarity index 86%
rename from example/auto_compression/pytorch_yolov5/eval.py
rename to example/post_training_quantization/detection/eval.py
index 55be2feba92889bac7f19143bddffaa4c7ef632a..fc0c09ae46c644fea8ca6218d0f0da3544d59161 100644
--- a/example/auto_compression/pytorch_yolov5/eval.py
+++ b/example/post_training_quantization/detection/eval.py
@@ -19,10 +19,10 @@ import argparse
import paddle
from ppdet.core.workspace import load_config, merge_config
from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
-
-from post_process import YOLOv5PostProcess
+from ppdet.metrics import COCOMetric, VOCMetric, KeyPointTopDownCOCOEval
+from paddleslim.common import load_config as load_slim_config
+from keypoint_utils import keypoint_post_process
+from post_process import PPYOLOEPostProcess
def argsparser():
@@ -78,7 +78,7 @@ def eval():
exe = paddle.static.Executor(place)
val_program, feed_target_names, fetch_targets = paddle.static.load_inference_model(
- global_config["model_dir"],
+ global_config["model_dir"].rstrip('/'),
exe,
model_filename=global_config["model_filename"],
params_filename=global_config["params_filename"])
@@ -101,9 +101,12 @@ def eval():
fetch_list=fetch_targets,
return_numpy=False)
res = {}
- if 'arch' in global_config and global_config['arch'] == 'YOLOv5':
- postprocess = YOLOv5PostProcess(
- score_threshold=0.001, nms_threshold=0.6, multi_label=True)
+ if 'arch' in global_config and global_config['arch'] == 'keypoint':
+ res = keypoint_post_process(data, data_input, exe, val_program,
+ fetch_targets, outs)
+ if 'arch' in global_config and global_config['arch'] == 'PPYOLOE':
+ postprocess = PPYOLOEPostProcess(
+ score_threshold=0.01, nms_threshold=0.6)
res = postprocess(np.array(outs[0]), data_all['scale_factor'])
else:
for out in outs:
@@ -142,6 +145,10 @@ def main():
label_list=dataset.get_label_list(),
class_num=reader_cfg['num_classes'],
map_type=reader_cfg['map_type'])
+ elif reader_cfg['metric'] == 'KeyPointTopDownCOCOEval':
+ anno_file = dataset.get_anno()
+ metric = KeyPointTopDownCOCOEval(anno_file,
+ len(dataset), 17, 'output_eval')
else:
raise ValueError("metric currently only supports COCO and VOC.")
global_config['metric'] = metric
@@ -153,7 +160,6 @@ if __name__ == '__main__':
paddle.enable_static()
parser = argsparser()
FLAGS = parser.parse_args()
-
assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
paddle.set_device(FLAGS.devices)
diff --git a/example/post_training_quantization/detection/keypoint_utils.py b/example/post_training_quantization/detection/keypoint_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..d17095f45f5f7bdb54129656360845fcd91dc4b4
--- /dev/null
+++ b/example/post_training_quantization/detection/keypoint_utils.py
@@ -0,0 +1,307 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import numpy as np
+import cv2
+import copy
+from paddleslim.common import get_logger
+
+logger = get_logger(__name__, level=logging.INFO)
+
+__all__ = ['keypoint_post_process']
+
+
+def flip_back(output_flipped, matched_parts):
+ assert output_flipped.ndim == 4,\
+ 'output_flipped should be [batch_size, num_joints, height, width]'
+
+ output_flipped = output_flipped[:, :, :, ::-1]
+
+ for pair in matched_parts:
+ tmp = output_flipped[:, pair[0], :, :].copy()
+ output_flipped[:, pair[0], :, :] = output_flipped[:, pair[1], :, :]
+ output_flipped[:, pair[1], :, :] = tmp
+
+ return output_flipped
+
+
+def get_affine_transform(center,
+ input_size,
+ rot,
+ output_size,
+ shift=(0., 0.),
+ inv=False):
+ """Get the affine transform matrix, given the center/scale/rot/output_size.
+ Args:
+ center (np.ndarray[2, ]): Center of the bounding box (x, y).
+ input_size (np.ndarray[2, ]): Size of input feature (width, height).
+ rot (float): Rotation angle (degree).
+ output_size (np.ndarray[2, ]): Size of the destination heatmaps.
+ shift (0-100%): Shift translation ratio wrt the width/height.
+ Default (0., 0.).
+ inv (bool): Option to inverse the affine transform direction.
+ (inv=False: src->dst or inv=True: dst->src)
+ Returns:
+ np.ndarray: The transform matrix.
+ """
+ assert len(center) == 2
+ assert len(output_size) == 2
+ assert len(shift) == 2
+
+ if not isinstance(input_size, (np.ndarray, list)):
+ input_size = np.array([input_size, input_size], dtype=np.float32)
+ scale_tmp = input_size
+
+ shift = np.array(shift)
+ src_w = scale_tmp[0]
+ dst_w = output_size[0]
+ dst_h = output_size[1]
+
+ rot_rad = np.pi * rot / 180
+ src_dir = rotate_point([0., src_w * -0.5], rot_rad)
+ dst_dir = np.array([0., dst_w * -0.5])
+
+ src = np.zeros((3, 2), dtype=np.float32)
+
+ src[0, :] = center + scale_tmp * shift
+ src[1, :] = center + src_dir + scale_tmp * shift
+ src[2, :] = _get_3rd_point(src[0, :], src[1, :])
+
+ dst = np.zeros((3, 2), dtype=np.float32)
+ dst[0, :] = [dst_w * 0.5, dst_h * 0.5]
+ dst[1, :] = np.array([dst_w * 0.5, dst_h * 0.5]) + dst_dir
+ dst[2, :] = _get_3rd_point(dst[0, :], dst[1, :])
+
+ if inv:
+ trans = cv2.getAffineTransform(np.float32(dst), np.float32(src))
+ else:
+ trans = cv2.getAffineTransform(np.float32(src), np.float32(dst))
+
+ return trans
+
+
+def _get_3rd_point(a, b):
+ """To calculate the affine matrix, three pairs of points are required. This
+ function is used to get the 3rd point, given 2D points a & b.
+ The 3rd point is defined by rotating vector `a - b` by 90 degrees
+ anticlockwise, using b as the rotation center.
+ Args:
+ a (np.ndarray): point(x,y)
+ b (np.ndarray): point(x,y)
+ Returns:
+ np.ndarray: The 3rd point.
+ """
+ assert len(
+ a) == 2, 'input of _get_3rd_point should be point with length of 2'
+ assert len(
+ b) == 2, 'input of _get_3rd_point should be point with length of 2'
+ direction = a - b
+ third_pt = b + np.array([-direction[1], direction[0]], dtype=np.float32)
+
+ return third_pt
+
+
+def rotate_point(pt, angle_rad):
+ """Rotate a point by an angle.
+ Args:
+ pt (list[float]): 2 dimensional point to be rotated
+ angle_rad (float): rotation angle by radian
+ Returns:
+ list[float]: Rotated point.
+ """
+ assert len(pt) == 2
+ sn, cs = np.sin(angle_rad), np.cos(angle_rad)
+ new_x = pt[0] * cs - pt[1] * sn
+ new_y = pt[0] * sn + pt[1] * cs
+ rotated_pt = [new_x, new_y]
+
+ return rotated_pt
+
+
+def affine_transform(pt, t):
+ new_pt = np.array([pt[0], pt[1], 1.]).T
+ new_pt = np.dot(t, new_pt)
+ return new_pt[:2]
+
+
+def transform_preds(coords, center, scale, output_size):
+ target_coords = np.zeros(coords.shape)
+ trans = get_affine_transform(center, scale * 200, 0, output_size, inv=1)
+ for p in range(coords.shape[0]):
+ target_coords[p, 0:2] = affine_transform(coords[p, 0:2], trans)
+ return target_coords
+
+
+class HRNetPostProcess(object):
+ def __init__(self, use_dark=True):
+ self.use_dark = use_dark
+
+ def get_max_preds(self, heatmaps):
+ '''get predictions from score maps
+ Args:
+ heatmaps: numpy.ndarray([batch_size, num_joints, height, width])
+ Returns:
+ preds: numpy.ndarray([batch_size, num_joints, 2]), keypoints coords
+ maxvals: numpy.ndarray([batch_size, num_joints, 2]), the maximum confidence of the keypoints
+ '''
+ assert isinstance(heatmaps,
+ np.ndarray), 'heatmaps should be numpy.ndarray'
+ assert heatmaps.ndim == 4, 'batch_images should be 4-ndim'
+
+ batch_size = heatmaps.shape[0]
+ num_joints = heatmaps.shape[1]
+ width = heatmaps.shape[3]
+ heatmaps_reshaped = heatmaps.reshape((batch_size, num_joints, -1))
+ idx = np.argmax(heatmaps_reshaped, 2)
+ maxvals = np.amax(heatmaps_reshaped, 2)
+
+ maxvals = maxvals.reshape((batch_size, num_joints, 1))
+ idx = idx.reshape((batch_size, num_joints, 1))
+
+ preds = np.tile(idx, (1, 1, 2)).astype(np.float32)
+
+ preds[:, :, 0] = (preds[:, :, 0]) % width
+ preds[:, :, 1] = np.floor((preds[:, :, 1]) / width)
+
+ pred_mask = np.tile(np.greater(maxvals, 0.0), (1, 1, 2))
+ pred_mask = pred_mask.astype(np.float32)
+
+ preds *= pred_mask
+
+ return preds, maxvals
+
+ def gaussian_blur(self, heatmap, kernel):
+ border = (kernel - 1) // 2
+ batch_size = heatmap.shape[0]
+ num_joints = heatmap.shape[1]
+ height = heatmap.shape[2]
+ width = heatmap.shape[3]
+ for i in range(batch_size):
+ for j in range(num_joints):
+ origin_max = np.max(heatmap[i, j])
+ dr = np.zeros((height + 2 * border, width + 2 * border))
+ dr[border:-border, border:-border] = heatmap[i, j].copy()
+ dr = cv2.GaussianBlur(dr, (kernel, kernel), 0)
+ heatmap[i, j] = dr[border:-border, border:-border].copy()
+ heatmap[i, j] *= origin_max / np.max(heatmap[i, j])
+ return heatmap
+
+ def dark_parse(self, hm, coord):
+ heatmap_height = hm.shape[0]
+ heatmap_width = hm.shape[1]
+ px = int(coord[0])
+ py = int(coord[1])
+ if 1 < px < heatmap_width - 2 and 1 < py < heatmap_height - 2:
+ dx = 0.5 * (hm[py][px + 1] - hm[py][px - 1])
+ dy = 0.5 * (hm[py + 1][px] - hm[py - 1][px])
+ dxx = 0.25 * (hm[py][px + 2] - 2 * hm[py][px] + hm[py][px - 2])
+ dxy = 0.25 * (hm[py+1][px+1] - hm[py-1][px+1] - hm[py+1][px-1] \
+ + hm[py-1][px-1])
+ dyy = 0.25 * (
+ hm[py + 2 * 1][px] - 2 * hm[py][px] + hm[py - 2 * 1][px])
+ derivative = np.matrix([[dx], [dy]])
+ hessian = np.matrix([[dxx, dxy], [dxy, dyy]])
+ if dxx * dyy - dxy**2 != 0:
+ hessianinv = hessian.I
+ offset = -hessianinv * derivative
+ offset = np.squeeze(np.array(offset.T), axis=0)
+ coord += offset
+ return coord
+
+ def dark_postprocess(self, hm, coords, kernelsize):
+ '''
+ DARK postpocessing, Zhang et al. Distribution-Aware Coordinate
+ Representation for Human Pose Estimation (CVPR 2020).
+ '''
+ hm = self.gaussian_blur(hm, kernelsize)
+ hm = np.maximum(hm, 1e-10)
+ hm = np.log(hm)
+ for n in range(coords.shape[0]):
+ for p in range(coords.shape[1]):
+ coords[n, p] = self.dark_parse(hm[n][p], coords[n][p])
+ return coords
+
+ def get_final_preds(self, heatmaps, center, scale, kernelsize=3):
+ """
+ The highest heatvalue location with a quarter offset in the
+ direction from the highest response to the second highest response.
+ Args:
+ heatmaps (numpy.ndarray): The predicted heatmaps
+ center (numpy.ndarray): The boxes center
+ scale (numpy.ndarray): The scale factor
+ Returns:
+ preds: numpy.ndarray([batch_size, num_joints, 2]), keypoints coords
+ maxvals: numpy.ndarray([batch_size, num_joints, 1]), the maximum confidence of the keypoints
+ """
+ coords, maxvals = self.get_max_preds(heatmaps)
+
+ heatmap_height = heatmaps.shape[2]
+ heatmap_width = heatmaps.shape[3]
+
+ if self.use_dark:
+ coords = self.dark_postprocess(heatmaps, coords, kernelsize)
+ else:
+ for n in range(coords.shape[0]):
+ for p in range(coords.shape[1]):
+ hm = heatmaps[n][p]
+ px = int(math.floor(coords[n][p][0] + 0.5))
+ py = int(math.floor(coords[n][p][1] + 0.5))
+ if 1 < px < heatmap_width - 1 and 1 < py < heatmap_height - 1:
+ diff = np.array([
+ hm[py][px + 1] - hm[py][px - 1],
+ hm[py + 1][px] - hm[py - 1][px]
+ ])
+ coords[n][p] += np.sign(diff) * .25
+ preds = coords.copy()
+
+ # Transform back
+ for i in range(coords.shape[0]):
+ preds[i] = transform_preds(coords[i], center[i], scale[i],
+ [heatmap_width, heatmap_height])
+
+ return preds, maxvals
+
+ def __call__(self, output, center, scale):
+ preds, maxvals = self.get_final_preds(np.array(output), center, scale)
+ outputs = [[
+ np.concatenate(
+ (preds, maxvals), axis=-1), np.mean(
+ maxvals, axis=1)
+ ]]
+ return outputs
+
+
+def keypoint_post_process(data, data_input, exe, val_program, fetch_targets,
+ outs):
+ data_input['image'] = np.flip(data_input['image'], [3])
+ output_flipped = exe.run(val_program,
+ feed=data_input,
+ fetch_list=fetch_targets,
+ return_numpy=False)
+
+ output_flipped = np.array(output_flipped[0])
+ flip_perm = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14],
+ [15, 16]]
+ output_flipped = flip_back(output_flipped, flip_perm)
+ output_flipped[:, :, :, 1:] = copy.copy(output_flipped)[:, :, :, 0:-1]
+ hrnet_outputs = (np.array(outs[0]) + output_flipped) * 0.5
+ imshape = (
+ np.array(data['im_shape']))[:, ::-1] if 'im_shape' in data else None
+ center = np.array(data['center']) if 'center' in data else np.round(
+ imshape / 2.)
+ scale = np.array(data['scale']) if 'scale' in data else imshape / 200.
+ post_process = HRNetPostProcess()
+ outputs = post_process(hrnet_outputs, center, scale)
+ return {'keypoint': outputs}
diff --git a/example/post_training_quantization/detection/post_process.py b/example/post_training_quantization/detection/post_process.py
new file mode 100644
index 0000000000000000000000000000000000000000..eea2f019548ec288a23e37b3bd2faf24f9a98935
--- /dev/null
+++ b/example/post_training_quantization/detection/post_process.py
@@ -0,0 +1,157 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import numpy as np
+import cv2
+
+
+def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
+ """
+ Args:
+ box_scores (N, 5): boxes in corner-form and probabilities.
+ iou_threshold: intersection over union threshold.
+ top_k: keep top_k results. If k <= 0, keep all the results.
+ candidate_size: only consider the candidates with the highest scores.
+ Returns:
+ picked: a list of indexes of the kept boxes
+ """
+ scores = box_scores[:, -1]
+ boxes = box_scores[:, :-1]
+ picked = []
+ indexes = np.argsort(scores)
+ indexes = indexes[-candidate_size:]
+ while len(indexes) > 0:
+ current = indexes[-1]
+ picked.append(current)
+ if 0 < top_k == len(picked) or len(indexes) == 1:
+ break
+ current_box = boxes[current, :]
+ indexes = indexes[:-1]
+ rest_boxes = boxes[indexes, :]
+ iou = iou_of(
+ rest_boxes,
+ np.expand_dims(
+ current_box, axis=0), )
+ indexes = indexes[iou <= iou_threshold]
+
+ return box_scores[picked, :]
+
+
+def iou_of(boxes0, boxes1, eps=1e-5):
+ """Return intersection-over-union (Jaccard index) of boxes.
+ Args:
+ boxes0 (N, 4): ground truth boxes.
+ boxes1 (N or 1, 4): predicted boxes.
+ eps: a small number to avoid 0 as denominator.
+ Returns:
+ iou (N): IoU values.
+ """
+ overlap_left_top = np.maximum(boxes0[..., :2], boxes1[..., :2])
+ overlap_right_bottom = np.minimum(boxes0[..., 2:], boxes1[..., 2:])
+
+ overlap_area = area_of(overlap_left_top, overlap_right_bottom)
+ area0 = area_of(boxes0[..., :2], boxes0[..., 2:])
+ area1 = area_of(boxes1[..., :2], boxes1[..., 2:])
+ return overlap_area / (area0 + area1 - overlap_area + eps)
+
+
+def area_of(left_top, right_bottom):
+ """Compute the areas of rectangles given two corners.
+ Args:
+ left_top (N, 2): left top corner.
+ right_bottom (N, 2): right bottom corner.
+ Returns:
+ area (N): return the area.
+ """
+ hw = np.clip(right_bottom - left_top, 0.0, None)
+ return hw[..., 0] * hw[..., 1]
+
+
+class PPYOLOEPostProcess(object):
+ """
+ Args:
+ input_shape (int): network input image size
+ scale_factor (float): scale factor of ori image
+ """
+
+ def __init__(self,
+ score_threshold=0.4,
+ nms_threshold=0.5,
+ nms_top_k=10000,
+ keep_top_k=300):
+ self.score_threshold = score_threshold
+ self.nms_threshold = nms_threshold
+ self.nms_top_k = nms_top_k
+ self.keep_top_k = keep_top_k
+
+ def _non_max_suppression(self, prediction, scale_factor):
+ batch_size = prediction.shape[0]
+ out_boxes_list = []
+ box_num_list = []
+ for batch_id in range(batch_size):
+ bboxes, confidences = prediction[batch_id][..., :4], prediction[
+ batch_id][..., 4:]
+ # nms
+ picked_box_probs = []
+ picked_labels = []
+ for class_index in range(0, confidences.shape[1]):
+ probs = confidences[:, class_index]
+ mask = probs > self.score_threshold
+ probs = probs[mask]
+ if probs.shape[0] == 0:
+ continue
+ subset_boxes = bboxes[mask, :]
+ box_probs = np.concatenate(
+ [subset_boxes, probs.reshape(-1, 1)], axis=1)
+ box_probs = hard_nms(
+ box_probs,
+ iou_threshold=self.nms_threshold,
+ top_k=self.nms_top_k)
+ picked_box_probs.append(box_probs)
+ picked_labels.extend([class_index] * box_probs.shape[0])
+
+ if len(picked_box_probs) == 0:
+ out_boxes_list.append(np.empty((0, 4)))
+
+ else:
+ picked_box_probs = np.concatenate(picked_box_probs)
+ # resize output boxes
+ picked_box_probs[:, 0] /= scale_factor[batch_id][1]
+ picked_box_probs[:, 2] /= scale_factor[batch_id][1]
+ picked_box_probs[:, 1] /= scale_factor[batch_id][0]
+ picked_box_probs[:, 3] /= scale_factor[batch_id][0]
+
+ # clas score box
+ out_box = np.concatenate(
+ [
+ np.expand_dims(
+ np.array(picked_labels), axis=-1), np.expand_dims(
+ picked_box_probs[:, 4], axis=-1),
+ picked_box_probs[:, :4]
+ ],
+ axis=1)
+ if out_box.shape[0] > self.keep_top_k:
+ out_box = out_box[out_box[:, 1].argsort()[::-1]
+ [:self.keep_top_k]]
+ out_boxes_list.append(out_box)
+ box_num_list.append(out_box.shape[0])
+
+ out_boxes_list = np.concatenate(out_boxes_list, axis=0)
+ box_num_list = np.array(box_num_list)
+ return out_boxes_list, box_num_list
+
+ def __call__(self, outs, scale_factor):
+ out_boxes_list, box_num_list = self._non_max_suppression(outs,
+ scale_factor)
+ return {'bbox': out_boxes_list, 'bbox_num': box_num_list}
diff --git a/example/auto_compression/pytorch_yolov5/post_quant.py b/example/post_training_quantization/detection/post_quant.py
similarity index 75%
rename from example/auto_compression/pytorch_yolov5/post_quant.py
rename to example/post_training_quantization/detection/post_quant.py
index 8c86672761829d6541a6d3c827f5254d0eecc527..a0c010364dd1b47ce33131814fd95942da7d96b0 100644
--- a/example/auto_compression/pytorch_yolov5/post_quant.py
+++ b/example/post_training_quantization/detection/post_quant.py
@@ -19,8 +19,6 @@ import argparse
import paddle
from ppdet.core.workspace import load_config, merge_config
from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
from paddleslim.quant import quant_post_static
@@ -64,33 +62,32 @@ def reader_wrapper(reader, input_list):
def main():
- global global_config
- all_config = load_slim_config(FLAGS.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
- global_config = all_config["Global"]
- reader_cfg = load_config(global_config['reader_config'])
+ global config
+ config = load_config(FLAGS.config_path)
- train_loader = create('EvalReader')(reader_cfg['TrainDataset'],
- reader_cfg['worker_num'],
+ train_loader = create('EvalReader')(config['TrainDataset'],
+ config['worker_num'],
return_list=True)
- train_loader = reader_wrapper(train_loader, global_config['input_list'])
+ train_loader = reader_wrapper(train_loader, config['input_list'])
place = paddle.CUDAPlace(0) if FLAGS.devices == 'gpu' else paddle.CPUPlace()
exe = paddle.static.Executor(place)
quant_post_static(
executor=exe,
- model_dir=global_config["model_dir"],
+ model_dir=config["model_dir"],
quantize_model_path=FLAGS.save_dir,
data_loader=train_loader,
- model_filename=global_config["model_filename"],
- params_filename=global_config["params_filename"],
- batch_size=32,
- batch_nums=10,
+ model_filename=config["model_filename"],
+ params_filename=config["params_filename"],
+ batch_size=4,
+ batch_nums=64,
algo=FLAGS.algo,
hist_percent=0.999,
is_full_quantize=False,
bias_correction=False,
- onnx_format=False)
+ onnx_format=False,
+ skip_tensor_list=config['skip_tensor_list']
+ if 'skip_tensor_list' in config else None)
if __name__ == '__main__':
diff --git a/example/post_training_quantization/pytorch_yolo_series/README.md b/example/post_training_quantization/pytorch_yolo_series/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1df18c4a6a8a0726f4873e67aabd5ea39fa1cee1
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/README.md
@@ -0,0 +1,150 @@
+# YOLO系列离线量化示例
+
+目录:
+- [1.简介](#1简介)
+- [2.Benchmark](#2Benchmark)
+- [3.离线量化流程](#离线量化流程)
+ - [3.1 准备环境](#31-准备环境)
+ - [3.2 准备数据集](#32-准备数据集)
+ - [3.3 准备预测模型](#33-准备预测模型)
+ - [3.4 离线量化并产出模型](#34-离线量化并产出模型)
+ - [3.5 测试模型精度](#35-测试模型精度)
+ - [3.6 提高离线量化精度](#36-提高离线量化精度)
+- [4.预测部署](#4预测部署)
+- [5.FAQ](5FAQ)
+
+
+本示例将以[ultralytics/yolov5](https://github.com/ultralytics/yolov5),[meituan/YOLOv6](https://github.com/meituan/YOLOv6) 和 [WongKinYiu/yolov7](https://github.com/WongKinYiu/yolov7) YOLO系列目标检测模型为例,将PyTorch框架产出的推理模型转换为Paddle推理模型,使用离线量化功能进行压缩,并使用敏感度分析功能提升离线量化精度。离线量化产出的模型可以用PaddleInference部署,也可以导出为ONNX格式模型文件,并用TensorRT部署。
+
+
+## 2.Benchmark
+| 模型 | 策略 | 输入尺寸 | mAPval
0.5:0.95 | 预测时延FP32
(ms) |预测时延FP16
(ms) | 预测时延INT8
(ms) | 配置文件 | Inference模型 |
+| :-------- |:-------- |:--------: | :---------------------: | :----------------: | :----------------: | :---------------: | :-----------------------------: | :-----------------------------: |
+| YOLOv5s | Base模型 | 640*640 | 37.4 | 5.95ms | 2.44ms | - | - | [Model](https://paddle-slim-models.bj.bcebos.com/act/yolov5s.onnx) |
+| YOLOv5s | KL离线量化 | 640*640 | 36.0 | - | - | 1.87ms | - | - |
+| | | | | | | | | |
+| YOLOv6s | Base模型 | 640*640 | 42.4 | 9.06ms | 2.90ms | - | - | [Model](https://paddle-slim-models.bj.bcebos.com/act/yolov6s.onnx) |
+| YOLOv6s | KL离线量化(量化分析前) | 640*640 | 30.3 | - | - | 1.83ms | - | - |
+| YOLOv6s | KL离线量化(量化分析后) | 640*640 | 39.7 | - | - | - | - | [Infer Model](https://bj.bcebos.com/v1/paddle-slim-models/act/yolov6s_analyzed_ptq.tar) |
+| | | | | | | | | |
+| YOLOv7 | Base模型 | 640*640 | 51.1 | 26.84ms | 7.44ms | - | - | [Model](https://paddle-slim-models.bj.bcebos.com/act/yolov7.onnx) |
+| YOLOv7 | KL离线量化 | 640*640 | 50.2 | - | - | 4.55ms | - | - |
+
+说明:
+- mAP的指标均在COCO val2017数据集中评测得到。
+
+## 3. 离线量化流程
+
+#### 3.1 准备环境
+- PaddlePaddle >= 2.3 (可从[Paddle官网](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)下载安装)
+- PaddleSlim > 2.3版本
+- opencv-python
+
+(1)安装paddlepaddle:
+```shell
+# CPU
+pip install paddlepaddle
+# GPU
+pip install paddlepaddle-gpu
+```
+
+(2)安装paddleslim:
+```shell
+pip install paddleslim
+```
+
+#### 3.2 准备数据集
+本示例默认以COCO数据进行自动压缩实验,可以从 [MS COCO官网](https://cocodataset.org) 下载 [Train](http://images.cocodataset.org/zips/train2017.zip)、[Val](http://images.cocodataset.org/zips/val2017.zip)、[annotation](http://images.cocodataset.org/annotations/annotations_trainval2017.zip)。
+
+目录格式如下:
+```
+dataset/coco/
+├── annotations
+│ ├── instances_train2017.json
+│ ├── instances_val2017.json
+│ | ...
+├── train2017
+│ ├── 000000000009.jpg
+│ ├── 000000580008.jpg
+│ | ...
+├── val2017
+│ ├── 000000000139.jpg
+│ ├── 000000000285.jpg
+```
+
+#### 3.3 准备预测模型
+(1)准备ONNX模型:
+
+- YOLOv5:可通过[ultralytics/yolov5](https://github.com/ultralytics/yolov5) 官方的[导出教程](https://github.com/ultralytics/yolov5/issues/251)来准备ONNX模型,也可以下载准备好的[yolov5s.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov5s.onnx)。
+
+- YOLOv6:可通过[WongKinYiu/yolov7](https://github.com/WongKinYiu/yolov7)的导出脚本来准备ONNX模型,也可以直接下载我们已经准备好的[yolov7.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov7.onnx)。
+
+- YOLOv7:可通过[meituan/YOLOv6](https://github.com/meituan/YOLOv6)官方的[导出教程](https://github.com/meituan/YOLOv6/blob/main/deploy/ONNX/README.md)来准备ONNX模型,也可以下载已经准备好的[yolov6s.onnx](https://paddle-slim-models.bj.bcebos.com/act/yolov6s.onnx)。
+
+
+#### 3.4 离线量化并产出模型
+离线量化示例通过post_quant.py脚本启动,会使用接口```paddleslim.quant.quant_post_static```对模型进行量化。配置config文件中模型路径、数据路径和量化相关的参数,配置完成后便可对模型进行离线量化。具体运行命令为:
+- YOLOv5
+
+```shell
+python post_quant.py --config_path=./configs/yolov5s_ptq.yaml --save_dir=./yolov5s_ptq_out
+```
+
+- YOLOv6
+
+```shell
+python post_quant.py --config_path=./configs/yolov6s_ptq.yaml --save_dir=./yolov6s_ptq_out
+```
+
+- YOLOv7
+
+```shell
+python post_quant.py --config_path=./configs/yolov7s_ptq.yaml --save_dir=./yolov7s_ptq_out
+```
+
+
+#### 3.5 测试模型精度
+
+修改 [yolov5s_ptq.yaml](./configs/yolov5s_ptq.yaml) 中`model_dir`字段为模型存储路径,然后使用eval.py脚本得到模型的mAP:
+
+```shell
+export CUDA_VISIBLE_DEVICES=0
+python eval.py --config_path=./configs/yolov5s_ptq.yaml
+```
+
+
+#### 3.6 提高离线量化精度
+本节介绍如何使用量化分析工具提升离线量化精度。离线量化功能仅需使用少量数据,且使用简单、能快速得到量化模型,但往往会造成较大的精度损失。PaddleSlim提供量化分析工具,会使用接口```paddleslim.quant.AnalysisQuant```,可视化展示出不适合量化的层,通过跳过这些层,提高离线量化模型精度。
+
+由于YOLOv6离线量化效果较差,以YOLOv6为例,量化分析工具具体使用方法如下:
+
+```shell
+python analysis.py --config_path=./configs/yolov6s_analysis.yaml
+```
+
+如下图,经过量化分析之后,可以发现`conv2d_2.w_0`, `conv2d_11.w_0`,`conv2d_15.w_0`, `conv2d_46.w_0`, `conv2d_49.w_0` 这些层会导致较大的精度损失。
+
+
+
+
+
+
+
+对比权重直方分布图后,可以发现量化损失较小的层数值分布相对平稳,数值处于-0.25到0.25之间,而量化损失较大的层数值分布非常极端,绝大部分值趋近于0,且数值处于-0.1到0.1之间,尽管看上去都是正太分布,但大量值为0是不利于量化统计scale值的。
+
+
+
+
+
+
+经此分析,在进行离线量化时,可以跳过这些导致精度下降较多的层,可使用 [yolov6s_analyzed_ptq.yaml](./configs/yolov6s_analyzed_ptq.yaml),然后再次进行离线量化。跳过这些层后,离线量化精度上升9.4个点。
+
+```shell
+python post_quant.py --config_path=./configs/yolov6s_analyzed_ptq.yaml --save_dir=./yolov6s_analyzed_ptq_out
+```
+
+## 4.预测部署
+
+
+## 5.FAQ
+- 如果想对模型进行自动压缩,可进入[YOLO系列模型自动压缩示例](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/example/auto_compression/pytorch_yolo_series)中进行实验。
diff --git a/example/post_training_quantization/pytorch_yolo_series/analysis.py b/example/post_training_quantization/pytorch_yolo_series/analysis.py
new file mode 100644
index 0000000000000000000000000000000000000000..1c8cbcb5b9a969bb485ca2fdaf2610d7222d2ad2
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/analysis.py
@@ -0,0 +1,115 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import numpy as np
+import argparse
+import paddle
+from tqdm import tqdm
+from post_process import YOLOv6PostProcess, coco_metric
+from dataset import COCOValDataset, COCOTrainDataset
+from paddleslim.common import load_config, load_onnx_model
+from paddleslim.quant.analysis import AnalysisQuant
+
+
+def argsparser():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '--config_path',
+ type=str,
+ default=None,
+ help="path of analysis config.",
+ required=True)
+ parser.add_argument(
+ '--devices',
+ type=str,
+ default='gpu',
+ help="which device used to compress.")
+ return parser
+
+
+def eval_function(exe, compiled_test_program, test_feed_names, test_fetch_list):
+ bboxes_list, bbox_nums_list, image_id_list = [], [], []
+ with tqdm(
+ total=len(val_loader),
+ bar_format='Evaluation stage, Run batch:|{bar}| {n_fmt}/{total_fmt}',
+ ncols=80) as t:
+ for data in val_loader:
+ data_all = {k: np.array(v) for k, v in data.items()}
+ outs = exe.run(compiled_test_program,
+ feed={test_feed_names[0]: data_all['image']},
+ fetch_list=test_fetch_list,
+ return_numpy=False)
+ res = {}
+ postprocess = YOLOv6PostProcess(
+ score_threshold=0.001, nms_threshold=0.65, multi_label=True)
+ res = postprocess(np.array(outs[0]), data_all['scale_factor'])
+ bboxes_list.append(res['bbox'])
+ bbox_nums_list.append(res['bbox_num'])
+ image_id_list.append(np.array(data_all['im_id']))
+ t.update()
+ map_res = coco_metric(anno_file, bboxes_list, bbox_nums_list, image_id_list)
+ return map_res[0]
+
+
+def main():
+
+ global config
+ config = load_config(FLAGS.config_path)
+ ptq_config = config['PTQ']
+
+ input_name = 'x2paddle_image_arrays' if config[
+ 'arch'] == 'YOLOv6' else 'x2paddle_images'
+ dataset = COCOTrainDataset(
+ dataset_dir=config['dataset_dir'],
+ image_dir=config['val_image_dir'],
+ anno_path=config['val_anno_path'],
+ input_name=input_name)
+ data_loader = paddle.io.DataLoader(
+ dataset, batch_size=1, shuffle=True, drop_last=True, num_workers=0)
+
+ global val_loader
+ dataset = COCOValDataset(
+ dataset_dir=config['dataset_dir'],
+ image_dir=config['val_image_dir'],
+ anno_path=config['val_anno_path'])
+ global anno_file
+ anno_file = dataset.ann_file
+ val_loader = paddle.io.DataLoader(
+ dataset, batch_size=1, shuffle=False, drop_last=False, num_workers=0)
+
+ load_onnx_model(config["model_dir"])
+ inference_model_path = config["model_dir"].rstrip().rstrip(
+ '.onnx') + '_infer'
+ analyzer = AnalysisQuant(
+ model_dir=inference_model_path,
+ model_filename='model.pdmodel',
+ params_filename='model.pdiparams',
+ eval_function=eval_function,
+ data_loader=data_loader,
+ save_dir=config['save_dir'],
+ ptq_config=ptq_config)
+ analyzer.analysis()
+
+
+if __name__ == '__main__':
+ paddle.enable_static()
+ parser = argsparser()
+ FLAGS = parser.parse_args()
+
+ assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
+ paddle.set_device(FLAGS.devices)
+
+ main()
diff --git a/example/post_training_quantization/pytorch_yolo_series/configs/yolov5s_ptq.yaml b/example/post_training_quantization/pytorch_yolo_series/configs/yolov5s_ptq.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..eb9f792b10a4f667ce535d3f3bb47e0be6a8785f
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/configs/yolov5s_ptq.yaml
@@ -0,0 +1,8 @@
+arch: YOLOv5
+model_dir: ./yolov5s.onnx
+dataset_dir: dataset/coco/
+train_image_dir: train2017
+val_image_dir: val2017
+train_anno_path: annotations/instances_train2017.json
+val_anno_path: annotations/instances_val2017.json
+skip_tensors: None # you can set it after analysis
diff --git a/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_analysis.yaml b/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_analysis.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a99198a444cfccf90bde0f874fc90edb1a75b92e
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_analysis.yaml
@@ -0,0 +1,15 @@
+arch: YOLOv6
+model_dir: ./yolov6s.onnx
+save_dir: ./analysis_results
+dataset_dir: /dataset/coco/
+val_image_dir: val2017
+val_anno_path: annotations/instances_val2017.json
+
+PTQ:
+ quantizable_op_type: ["conv2d", "depthwise_conv2d"]
+ weight_quantize_type: 'abs_max'
+ activation_quantize_type: 'moving_average_abs_max'
+ is_full_quantize: False
+ batch_size: 10
+ batch_nums: 10
+
diff --git a/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_analyzed_ptq.yaml b/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_analyzed_ptq.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fa9585d3277937a78a168dd96af1d48b9020e17d
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_analyzed_ptq.yaml
@@ -0,0 +1,8 @@
+arch: YOLOv6
+model_dir: ./yolov6s.onnx
+dataset_dir: /dataset/coco/
+train_image_dir: train2017
+val_image_dir: val2017
+train_anno_path: annotations/instances_train2017.json
+val_anno_path: annotations/instances_val2017.json
+skip_tensor_list: ['conv2d_2.w_0', 'conv2d_15.w_0', 'conv2d_46.w_0', 'conv2d_11.w_0', 'conv2d_49.w_0']
diff --git a/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_ptq.yaml b/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_ptq.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9ec6b6a6814e813d4246ca35bae66342e2039243
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/configs/yolov6s_ptq.yaml
@@ -0,0 +1,8 @@
+arch: YOLOv6
+model_dir: ./yolov6s.onnx
+dataset_dir: /dataset/coco/
+train_image_dir: train2017
+val_image_dir: val2017
+train_anno_path: annotations/instances_train2017.json
+val_anno_path: annotations/instances_val2017.json
+skip_tensor_list: None
diff --git a/example/post_training_quantization/pytorch_yolo_series/configs/yolov7s_ptq.yaml b/example/post_training_quantization/pytorch_yolo_series/configs/yolov7s_ptq.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4d110b4e2021709823514f2595d53086c5ebee60
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/configs/yolov7s_ptq.yaml
@@ -0,0 +1,7 @@
+arch: YOLOv7
+model_dir: ./yolov7s.onnx
+dataset_dir: /dataset/coco/
+train_image_dir: train2017
+val_image_dir: val2017
+train_anno_path: annotations/instances_train2017.json
+val_anno_path: annotations/instances_val2017.json
diff --git a/example/post_training_quantization/pytorch_yolo_series/dataset.py b/example/post_training_quantization/pytorch_yolo_series/dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..326c5ecf6abebe9a8afe40116ab04c13ac1aebf1
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/dataset.py
@@ -0,0 +1,115 @@
+from pycocotools.coco import COCO
+import cv2
+import os
+import numpy as np
+import paddle
+
+
+class COCOValDataset(paddle.io.Dataset):
+ def __init__(self,
+ dataset_dir=None,
+ image_dir=None,
+ anno_path=None,
+ img_size=[640, 640],
+ input_name='x2paddle_images'):
+ self.dataset_dir = dataset_dir
+ self.image_dir = image_dir
+ self.img_size = img_size
+ self.input_name = input_name
+ self.ann_file = os.path.join(dataset_dir, anno_path)
+ self.coco = COCO(self.ann_file)
+ ori_ids = list(sorted(self.coco.imgs.keys()))
+ # check gt bbox
+ clean_ids = []
+ for idx in ori_ids:
+ ins_anno_ids = self.coco.getAnnIds(imgIds=[idx], iscrowd=False)
+ instances = self.coco.loadAnns(ins_anno_ids)
+ num_bbox = 0
+ for inst in instances:
+ if inst.get('ignore', False):
+ continue
+ if 'bbox' not in inst.keys():
+ continue
+ elif not any(np.array(inst['bbox'])):
+ continue
+ else:
+ num_bbox += 1
+ if num_bbox > 0:
+ clean_ids.append(idx)
+ self.ids = clean_ids
+
+ def __getitem__(self, idx):
+ img_id = self.ids[idx]
+ img = self._get_img_data_from_img_id(img_id)
+ img, scale_factor = self.image_preprocess(img, self.img_size)
+ return {
+ 'image': img,
+ 'im_id': np.array([img_id]),
+ 'scale_factor': scale_factor
+ }
+
+ def __len__(self):
+ return len(self.ids)
+
+ def _get_img_data_from_img_id(self, img_id):
+ img_info = self.coco.loadImgs(img_id)[0]
+ img_path = os.path.join(self.dataset_dir, self.image_dir,
+ img_info['file_name'])
+ img = cv2.imread(img_path)
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
+ return img
+
+ def _generate_scale(self, im, target_shape, keep_ratio=True):
+ """
+ Args:
+ im (np.ndarray): image (np.ndarray)
+ Returns:
+ im_scale_x: the resize ratio of X
+ im_scale_y: the resize ratio of Y
+ """
+ origin_shape = im.shape[:2]
+ if keep_ratio:
+ im_size_min = np.min(origin_shape)
+ im_size_max = np.max(origin_shape)
+ target_size_min = np.min(target_shape)
+ target_size_max = np.max(target_shape)
+ im_scale = float(target_size_min) / float(im_size_min)
+ if np.round(im_scale * im_size_max) > target_size_max:
+ im_scale = float(target_size_max) / float(im_size_max)
+ im_scale_x = im_scale
+ im_scale_y = im_scale
+ else:
+ resize_h, resize_w = target_shape
+ im_scale_y = resize_h / float(origin_shape[0])
+ im_scale_x = resize_w / float(origin_shape[1])
+ return im_scale_y, im_scale_x
+
+ def image_preprocess(self, img, target_shape):
+ # Resize image
+ im_scale_y, im_scale_x = self._generate_scale(img, target_shape)
+ img = cv2.resize(
+ img,
+ None,
+ None,
+ fx=im_scale_x,
+ fy=im_scale_y,
+ interpolation=cv2.INTER_LINEAR)
+ # Pad
+ im_h, im_w = img.shape[:2]
+ h, w = target_shape[:]
+ if h != im_h or w != im_w:
+ canvas = np.ones((h, w, 3), dtype=np.float32)
+ canvas *= np.array([114.0, 114.0, 114.0], dtype=np.float32)
+ canvas[0:im_h, 0:im_w, :] = img.astype(np.float32)
+ img = canvas
+ img = np.transpose(img / 255, [2, 0, 1])
+ scale_factor = np.array([im_scale_y, im_scale_x])
+ return img.astype(np.float32), scale_factor
+
+
+class COCOTrainDataset(COCOValDataset):
+ def __getitem__(self, idx):
+ img_id = self.ids[idx]
+ img = self._get_img_data_from_img_id(img_id)
+ img, scale_factor = self.image_preprocess(img, self.img_size)
+ return {self.input_name: img}
\ No newline at end of file
diff --git a/example/post_training_quantization/pytorch_yolo_series/eval.py b/example/post_training_quantization/pytorch_yolo_series/eval.py
new file mode 100644
index 0000000000000000000000000000000000000000..e105bb788b1483a086537f2c2ba9860707a54c99
--- /dev/null
+++ b/example/post_training_quantization/pytorch_yolo_series/eval.py
@@ -0,0 +1,101 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import numpy as np
+import argparse
+from tqdm import tqdm
+import paddle
+from paddleslim.common import load_config as load_slim_config
+from paddleslim.common import load_inference_model
+from post_process import YOLOPostProcess, coco_metric
+from dataset import COCOValDataset
+
+
+def argsparser():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '--config_path',
+ type=str,
+ default=None,
+ help="path of compression strategy config.",
+ required=True)
+ parser.add_argument(
+ '--batch_size', type=int, default=1, help="Batch size of model input.")
+ parser.add_argument(
+ '--devices',
+ type=str,
+ default='gpu',
+ help="which device used to compress.")
+
+ return parser
+
+
+def eval():
+
+ place = paddle.CUDAPlace(0) if FLAGS.devices == 'gpu' else paddle.CPUPlace()
+ exe = paddle.static.Executor(place)
+
+ val_program, feed_target_names, fetch_targets = load_inference_model(
+ config["model_dir"], exe, "model.pdmodel", "model.pdiparams")
+
+ bboxes_list, bbox_nums_list, image_id_list = [], [], []
+ with tqdm(
+ total=len(val_loader),
+ bar_format='Evaluation stage, Run batch:|{bar}| {n_fmt}/{total_fmt}',
+ ncols=80) as t:
+ for data in val_loader:
+ data_all = {k: np.array(v) for k, v in data.items()}
+ outs = exe.run(val_program,
+ feed={feed_target_names[0]: data_all['image']},
+ fetch_list=fetch_targets,
+ return_numpy=False)
+ postprocess = YOLOPostProcess(
+ score_threshold=0.001, nms_threshold=0.65, multi_label=True)
+ res = postprocess(np.array(outs[0]), data_all['scale_factor'])
+ bboxes_list.append(res['bbox'])
+ bbox_nums_list.append(res['bbox_num'])
+ image_id_list.append(np.array(data_all['im_id']))
+ t.update()
+
+ coco_metric(anno_file, bboxes_list, bbox_nums_list, image_id_list)
+
+
+def main():
+ global config
+ config = load_slim_config(FLAGS.config_path)
+
+ global val_loader
+ dataset = COCOValDataset(
+ dataset_dir=config['dataset_dir'],
+ image_dir=config['val_image_dir'],
+ anno_path=config['val_anno_path'])
+ global anno_file
+ anno_file = dataset.ann_file
+ val_loader = paddle.io.DataLoader(
+ dataset, batch_size=FLAGS.batch_size, drop_last=True)
+
+ eval()
+
+
+if __name__ == '__main__':
+ paddle.enable_static()
+ parser = argsparser()
+ FLAGS = parser.parse_args()
+
+ assert FLAGS.devices in ['cpu', 'gpu', 'xpu', 'npu']
+ paddle.set_device(FLAGS.devices)
+
+ main()
diff --git a/example/post_training_quantization/pytorch_yolo_series/images/hist_compare.png b/example/post_training_quantization/pytorch_yolo_series/images/hist_compare.png
new file mode 100644
index 0000000000000000000000000000000000000000..e895bd261126050a14254856c411b9b2cf0b7c44
Binary files /dev/null and b/example/post_training_quantization/pytorch_yolo_series/images/hist_compare.png differ
diff --git a/example/post_training_quantization/pytorch_yolo_series/images/sensitivity_rank.png b/example/post_training_quantization/pytorch_yolo_series/images/sensitivity_rank.png
new file mode 100644
index 0000000000000000000000000000000000000000..1eab297a1118f48e56d4ef496fcf5d18948016eb
Binary files /dev/null and b/example/post_training_quantization/pytorch_yolo_series/images/sensitivity_rank.png differ
diff --git a/example/auto_compression/pytorch_yolov5/post_process.py b/example/post_training_quantization/pytorch_yolo_series/post_process.py
similarity index 75%
rename from example/auto_compression/pytorch_yolov5/post_process.py
rename to example/post_training_quantization/pytorch_yolo_series/post_process.py
index 9d20926b5d51af11474ebf61a06e4ca0440c8e92..5988258b8766c5e230544b7ef721d98c92207562 100644
--- a/example/auto_compression/pytorch_yolov5/post_process.py
+++ b/example/post_training_quantization/pytorch_yolo_series/post_process.py
@@ -14,6 +14,8 @@
import numpy as np
import cv2
+import json
+import sys
def box_area(boxes):
@@ -68,9 +70,9 @@ def nms(boxes, scores, iou_threshold):
return keep
-class YOLOv5PostProcess(object):
+class YOLOPostProcess(object):
"""
- Post process of YOLOv5 network.
+ Post process of YOLO serise network.
args:
score_threshold(float): Threshold to filter out bounding boxes with low
confidence score. If not provided, consider all boxes.
@@ -157,8 +159,8 @@ class YOLOv5PostProcess(object):
if len(pred.shape) == 1:
pred = pred[np.newaxis, :]
pred_bboxes = pred[:, :4]
- scale_factor = np.tile(scale_factor[i][::-1], (1, 2))
- pred_bboxes /= scale_factor
+ scale = np.tile(scale_factor[i][::-1], (2))
+ pred_bboxes /= scale
bbox = np.concatenate(
[
pred[:, -1][:, np.newaxis], pred[:, -2][:, np.newaxis],
@@ -171,3 +173,59 @@ class YOLOv5PostProcess(object):
bboxs = np.concatenate(bboxs, axis=0)
box_nums = np.array(box_nums)
return {'bbox': bboxs, 'bbox_num': box_nums}
+
+
+def coco_metric(anno_file, bboxes_list, bbox_nums_list, image_id_list):
+ try:
+ from pycocotools.coco import COCO
+ from pycocotools.cocoeval import COCOeval
+ except:
+ print(
+ "[ERROR] Not found pycocotools, please install by `pip install pycocotools`"
+ )
+ sys.exit(1)
+
+ coco_gt = COCO(anno_file)
+ cats = coco_gt.loadCats(coco_gt.getCatIds())
+ clsid2catid = {i: cat['id'] for i, cat in enumerate(cats)}
+ results = []
+ for bboxes, bbox_nums, image_id in zip(bboxes_list, bbox_nums_list,
+ image_id_list):
+ results += _get_det_res(bboxes, bbox_nums, image_id, clsid2catid)
+
+ output = "bbox.json"
+ with open(output, 'w') as f:
+ json.dump(results, f)
+
+ coco_dt = coco_gt.loadRes(output)
+ coco_eval = COCOeval(coco_gt, coco_dt, 'bbox')
+ coco_eval.evaluate()
+ coco_eval.accumulate()
+ coco_eval.summarize()
+ return coco_eval.stats
+
+
+def _get_det_res(bboxes, bbox_nums, image_id, label_to_cat_id_map):
+ det_res = []
+ k = 0
+ for i in range(len(bbox_nums)):
+ cur_image_id = int(image_id[i][0])
+ det_nums = bbox_nums[i]
+ for j in range(det_nums):
+ dt = bboxes[k]
+ k = k + 1
+ num_id, score, xmin, ymin, xmax, ymax = dt.tolist()
+ if int(num_id) < 0:
+ continue
+ category_id = label_to_cat_id_map[int(num_id)]
+ w = xmax - xmin
+ h = ymax - ymin
+ bbox = [xmin, ymin, w, h]
+ dt_res = {
+ 'image_id': cur_image_id,
+ 'category_id': category_id,
+ 'bbox': bbox,
+ 'score': score
+ }
+ det_res.append(dt_res)
+ return det_res
diff --git a/example/auto_compression/pytorch_yolov7/post_quant.py b/example/post_training_quantization/pytorch_yolo_series/post_quant.py
similarity index 56%
rename from example/auto_compression/pytorch_yolov7/post_quant.py
rename to example/post_training_quantization/pytorch_yolo_series/post_quant.py
index 8c86672761829d6541a6d3c827f5254d0eecc527..ec4fbdbc420e518b94fd0386e86dcd610e96ba3f 100644
--- a/example/auto_compression/pytorch_yolov7/post_quant.py
+++ b/example/post_training_quantization/pytorch_yolo_series/post_quant.py
@@ -17,11 +17,9 @@ import sys
import numpy as np
import argparse
import paddle
-from ppdet.core.workspace import load_config, merge_config
-from ppdet.core.workspace import create
-from ppdet.metrics import COCOMetric, VOCMetric
-from paddleslim.auto_compression.config_helpers import load_config as load_slim_config
+from paddleslim.common import load_config, load_onnx_model
from paddleslim.quant import quant_post_static
+from dataset import COCOTrainDataset
def argsparser():
@@ -30,7 +28,7 @@ def argsparser():
'--config_path',
type=str,
default=None,
- help="path of compression strategy config.",
+ help="path of post training quantization config.",
required=True)
parser.add_argument(
'--save_dir',
@@ -48,49 +46,45 @@ def argsparser():
return parser
-def reader_wrapper(reader, input_list):
- def gen():
- for data in reader:
- in_dict = {}
- if isinstance(input_list, list):
- for input_name in input_list:
- in_dict[input_name] = data[input_name]
- elif isinstance(input_list, dict):
- for input_name in input_list.keys():
- in_dict[input_list[input_name]] = data[input_name]
- yield in_dict
-
- return gen
-
-
def main():
- global global_config
- all_config = load_slim_config(FLAGS.config_path)
- assert "Global" in all_config, f"Key 'Global' not found in config file. \n{all_config}"
- global_config = all_config["Global"]
- reader_cfg = load_config(global_config['reader_config'])
+ global config
+ config = load_config(FLAGS.config_path)
- train_loader = create('EvalReader')(reader_cfg['TrainDataset'],
- reader_cfg['worker_num'],
- return_list=True)
- train_loader = reader_wrapper(train_loader, global_config['input_list'])
+ input_name = 'x2paddle_image_arrays' if config[
+ 'arch'] == 'YOLOv6' else 'x2paddle_images'
+ dataset = COCOTrainDataset(
+ dataset_dir=config['dataset_dir'],
+ image_dir=config['val_image_dir'],
+ anno_path=config['val_anno_path'],
+ input_name=input_name)
+ train_loader = paddle.io.DataLoader(
+ dataset, batch_size=1, shuffle=True, drop_last=True, num_workers=0)
place = paddle.CUDAPlace(0) if FLAGS.devices == 'gpu' else paddle.CPUPlace()
exe = paddle.static.Executor(place)
+
+ # since the type pf model converted from pytorch is onnx,
+ # use load_onnx_model firstly and rename the model_dir
+ load_onnx_model(config["model_dir"])
+ inference_model_path = config["model_dir"].rstrip().rstrip(
+ '.onnx') + '_infer'
+
quant_post_static(
executor=exe,
- model_dir=global_config["model_dir"],
+ model_dir=inference_model_path,
quantize_model_path=FLAGS.save_dir,
data_loader=train_loader,
- model_filename=global_config["model_filename"],
- params_filename=global_config["params_filename"],
+ model_filename='model.pdmodel',
+ params_filename='model.pdiparams',
batch_size=32,
batch_nums=10,
algo=FLAGS.algo,
hist_percent=0.999,
is_full_quantize=False,
bias_correction=False,
- onnx_format=False)
+ onnx_format=True,
+ skip_tensor_list=config['skip_tensor_list']
+ if 'skip_tensor_list' in config else None)
if __name__ == '__main__':
diff --git a/paddleslim/analysis/_utils.py b/paddleslim/analysis/_utils.py
index 0b6fd1b855c02e94deb41c4ca0f5b6884996a9e7..82bedee53da83c8ce2fbf47f6cb27ee4cf080efd 100644
--- a/paddleslim/analysis/_utils.py
+++ b/paddleslim/analysis/_utils.py
@@ -135,8 +135,8 @@ def save_cls_model(model, input_shape, save_dir, data_type):
weight_bits=8,
activation_bits=8)
- model_file = os.path.join(quantize_model_path, '__model__')
- param_file = os.path.join(quantize_model_path, '__params__')
+ model_file = os.path.join(quantize_model_path, 'model.pdmodel')
+ param_file = os.path.join(quantize_model_path, 'model.pdiparams')
return model_file, param_file
diff --git a/paddleslim/analysis/latency_predictor.py b/paddleslim/analysis/latency_predictor.py
index 3c90f22bd5673f5f41688743458761ba49e2e89c..f55b413a7baac914aed3122162fe2e3565ca6051 100644
--- a/paddleslim/analysis/latency_predictor.py
+++ b/paddleslim/analysis/latency_predictor.py
@@ -95,10 +95,10 @@ class TableLatencyPredictor(LatencyPredictor):
raise NotImplementedError(
'latency predictor does NOT support running on Windows.')
elif platform.system().lower() == 'darwin':
- py_verion = platform.python_version().split('.')
+ py_version = platform.python_version().split('.')
if int(py_version[0]) != 3 or int(py_version[1]) != 9:
raise NotImplementedError(
- 'latency predictor does NOT support running on macOS when python version is not 3.9.'
+ 'Latency predictor does NOT support running on macOS when python version is not 3.9.'
)
_logger.info("pip install paddleslim-opt-tools")
diff --git a/paddleslim/auto_compression/__init__.py b/paddleslim/auto_compression/__init__.py
index 990ad37b71e76cb8044a30e64a7c4377dec274a1..cfc26259d2fa85cd80710eb61972483681525f6b 100644
--- a/paddleslim/auto_compression/__init__.py
+++ b/paddleslim/auto_compression/__init__.py
@@ -19,8 +19,14 @@ from .config_helpers import *
from .utils import *
__all__ = [
- "AutoCompression", "Quantization", "Distillation",
- "MultiTeacherDistillation", "HyperParameterOptimization", "Prune",
- "UnstructurePrune", "ProgramInfo", "TrainConfig", "save_config",
- "load_config", "predict_compressed_model"
+ "AutoCompression",
+ "Quantization",
+ "Distillation",
+ "MultiTeacherDistillation",
+ "HyperParameterOptimization",
+ "Prune",
+ "UnstructurePrune",
+ "ProgramInfo",
+ "TrainConfig",
+ "predict_compressed_model",
]
diff --git a/paddleslim/auto_compression/auto_strategy.py b/paddleslim/auto_compression/auto_strategy.py
index 451f6007579dd96a15a753b97d29b165c930f97b..eab962add5804c2b3bb1bf965e1f97b2890f0041 100644
--- a/paddleslim/auto_compression/auto_strategy.py
+++ b/paddleslim/auto_compression/auto_strategy.py
@@ -47,8 +47,10 @@ default_hpo_config = {
# default quant config, can be used by ptq&hpo and qat&distillation
default_quant_config = {
- 'quantize_op_types':
- ['conv2d', 'depthwise_conv2d', 'mul', 'matmul', 'matmul_v2'],
+ 'quantize_op_types': [
+ 'conv2d', 'depthwise_conv2d', 'conv2d_transpose', 'mul', 'matmul',
+ 'matmul_v2'
+ ],
'weight_bits': 8,
'activation_bits': 8,
"is_full_quantize": False,
diff --git a/paddleslim/auto_compression/compressor.py b/paddleslim/auto_compression/compressor.py
index 5ac38b0836d06860bd5b196def8b6d340326e098..11b80573ccbc433197e29096cbf49e649c2ab1a1 100644
--- a/paddleslim/auto_compression/compressor.py
+++ b/paddleslim/auto_compression/compressor.py
@@ -29,13 +29,15 @@ from ..quant.quanter import convert, quant_post
from ..common.recover_program import recover_inference_program
from ..common import get_logger
from ..common.patterns import get_patterns
+from ..common.load_model import load_inference_model, get_model_dir, export_onnx
+from ..common.dataloader import wrap_dataloader, get_feed_vars
+from ..common.config_helper import load_config
from ..analysis import TableLatencyPredictor
from .create_compressed_program import build_distill_program, build_quant_program, build_prune_program, remove_unused_var_nodes
from .strategy_config import TrainConfig, ProgramInfo, merge_config
from .auto_strategy import prepare_strategy, get_final_quant_config, create_strategy_config, create_train_config
-from .config_helpers import load_config, extract_strategy_config, extract_train_config
+from .config_helpers import extract_strategy_config, extract_train_config
from .utils.predict import with_variable_shape
-from .utils import get_feed_vars, wrap_dataloader, load_inference_model
_logger = get_logger(__name__, level=logging.INFO)
@@ -49,10 +51,10 @@ except Exception as e:
class AutoCompression:
def __init__(self,
model_dir,
- model_filename,
- params_filename,
- save_dir,
train_dataloader,
+ model_filename=None,
+ params_filename=None,
+ save_dir='./output',
config=None,
input_shapes=None,
target_speedup=None,
@@ -66,13 +68,13 @@ class AutoCompression:
model_dir(str): The path of inference model that will be compressed, and
the model and params that saved by ``paddle.static.save_inference_model``
are under the path.
+ train_dataloader(Python Generator, Paddle.io.DataLoader): The
+ Generator or Dataloader provides train data, and it could
+ return a batch every time.
model_filename(str): The name of model file.
params_filename(str): The name of params file.
save_dir(str): The path to save compressed model. The models in this directory will be overwrited
after calling 'compress()' function.
- train_data_loader(Python Generator, Paddle.io.DataLoader): The
- Generator or Dataloader provides train data, and it could
- return a batch every time.
input_shapes(dict|tuple|list): It is used when the model has implicit dimensions except batch size.
If it is a dict, the key is the name of input and the value is the shape.
Given the input shape of input "X" is [-1, 3, -1, -1] which means the batch size, hight
@@ -117,18 +119,8 @@ class AutoCompression:
deploy_hardware(str, optional): The hardware you want to deploy. Default: 'gpu'.
"""
self.model_dir = model_dir.rstrip('/')
-
- if model_filename == 'None':
- model_filename = None
- self.model_filename = model_filename
- if params_filename == 'None':
- params_filename = None
- self.params_filename = params_filename
-
- if params_filename is None and model_filename is not None:
- raise NotImplementedError(
- "NOT SUPPORT parameters saved in separate files. Please convert it to single binary file first."
- )
+ self.updated_model_dir, self.model_filename, self.params_filename = get_model_dir(
+ model_dir, model_filename, params_filename)
self.final_dir = save_dir
if not os.path.exists(self.final_dir):
@@ -163,8 +155,7 @@ class AutoCompression:
paddle.enable_static()
self._exe, self._places = self._prepare_envs()
- self.model_type = self._get_model_type(self._exe, self.model_dir,
- model_filename, params_filename)
+ self.model_type = self._get_model_type()
if self.train_config is not None and self.train_config.use_fleet:
fleet.init(is_collective=True)
@@ -249,8 +240,8 @@ class AutoCompression:
paddle.enable_static()
exe = paddle.static.Executor(paddle.CPUPlace())
[inference_program, feed_target_names,
- fetch_targets] = (load_inference_model(model_dir, exe, model_filename,
- params_filename))
+ fetch_targets] = load_inference_model(model_dir, exe, model_filename,
+ params_filename)
if type(input_shapes) in [list, tuple]:
assert len(
@@ -310,23 +301,26 @@ class AutoCompression:
exe = paddle.static.Executor(places)
return exe, places
- def _get_model_type(self, exe, model_dir, model_filename, params_filename):
- [inference_program, _, _]= (load_inference_model( \
- model_dir, \
- model_filename=model_filename, params_filename=params_filename,
- executor=exe))
+ def _get_model_type(self):
+ [inference_program, _, _] = (load_inference_model(
+ self.model_dir,
+ model_filename=self.model_filename,
+ params_filename=self.params_filename,
+ executor=self._exe))
_, _, model_type = get_patterns(inference_program)
if self.model_filename is None:
- new_model_filename = '__new_model__'
+ opt_model_filename = '__opt_model__'
else:
- new_model_filename = 'new_' + self.model_filename
+ opt_model_filename = 'opt_' + self.model_filename
program_bytes = inference_program._remove_training_info(
clip_extra=False).desc.serialize_to_string()
- with open(os.path.join(self.model_dir, new_model_filename), "wb") as f:
+ with open(
+ os.path.join(self.updated_model_dir, opt_model_filename),
+ "wb") as f:
f.write(program_bytes)
shutil.move(
- os.path.join(self.model_dir, new_model_filename),
- os.path.join(self.model_dir, self.model_filename))
+ os.path.join(self.updated_model_dir, opt_model_filename),
+ os.path.join(self.updated_model_dir, self.model_filename))
_logger.info(f"Detect model type: {model_type}")
return model_type
@@ -603,10 +597,17 @@ class AutoCompression:
train_config):
# start compress, including train/eval model
# TODO: add the emd loss of evaluation model.
+ if self.updated_model_dir != self.model_dir:
+ # If model is ONNX, convert it to inference model firstly.
+ load_inference_model(
+ self.model_dir,
+ model_filename=self.model_filename,
+ params_filename=self.params_filename,
+ executor=self._exe)
if strategy == 'quant_post':
quant_post(
self._exe,
- model_dir=self.model_dir,
+ model_dir=self.updated_model_dir,
quantize_model_path=os.path.join(
self.tmp_dir, 'strategy_{}'.format(str(strategy_idx + 1))),
data_loader=self.train_dataloader,
@@ -632,11 +633,17 @@ class AutoCompression:
if platform.system().lower() != 'linux':
raise NotImplementedError(
"post-quant-hpo is not support in system other than linux")
-
+ if self.updated_model_dir != self.model_dir:
+ # If model is ONNX, convert it to inference model firstly.
+ load_inference_model(
+ self.model_dir,
+ model_filename=self.model_filename,
+ params_filename=self.params_filename,
+ executor=self._exe)
post_quant_hpo.quant_post_hpo(
self._exe,
self._places,
- model_dir=self.model_dir,
+ model_dir=self.updated_model_dir,
quantize_model_path=os.path.join(
self.tmp_dir, 'strategy_{}'.format(str(strategy_idx + 1))),
train_dataloader=self.train_dataloader,
@@ -707,7 +714,10 @@ class AutoCompression:
best_metric = -1.0
total_epochs = train_config.epochs if train_config.epochs else 100
total_train_iter = 0
+ stop_training = False
for epoch_id in range(total_epochs):
+ if stop_training:
+ break
for batch_id, data in enumerate(self.train_dataloader()):
np_probs_float, = self._exe.run(train_program_info.program, \
feed=data, \
@@ -753,6 +763,10 @@ class AutoCompression:
abs(best_metric -
self.metric_before_compressed)
) / self.metric_before_compressed <= 0.005:
+ _logger.info(
+ "The error rate between the compressed model and original model is less than 5%. The training process ends."
+ )
+ stop_training = True
break
else:
_logger.info(
@@ -760,14 +774,18 @@ class AutoCompression:
format(epoch_id, metric, best_metric))
if train_config.target_metric is not None:
if metric > float(train_config.target_metric):
+ stop_training = True
+ _logger.info(
+ "The metric of compressed model has reached the target metric. The training process ends."
+ )
break
else:
_logger.warning(
"Not set eval function, so unable to test accuracy performance."
)
- if train_config.train_iter and total_train_iter >= train_config.train_iter:
- epoch_id = total_epochs
+ if (train_config.train_iter and total_train_iter >=
+ train_config.train_iter) or stop_training:
break
if 'unstructure' in self._strategy or train_config.sparse_model:
@@ -787,15 +805,19 @@ class AutoCompression:
os.remove(os.path.join(self.tmp_dir, 'best_model.pdopt'))
os.remove(os.path.join(self.tmp_dir, 'best_model.pdparams'))
- if 'qat' in strategy:
- test_program, int8_program = convert(test_program, self._places, self._quant_config, \
- scope=paddle.static.global_scope(), \
- save_int8=True)
-
model_dir = os.path.join(self.tmp_dir,
'strategy_{}'.format(str(strategy_idx + 1)))
if not os.path.exists(model_dir):
os.makedirs(model_dir)
+
+ if 'qat' in strategy:
+ test_program = convert(
+ test_program,
+ self._places,
+ self._quant_config,
+ scope=paddle.static.global_scope(),
+ save_clip_ranges_path=self.final_dir)
+
feed_vars = [
test_program.global_block().var(name)
for name in test_program_info.feed_target_names
@@ -816,3 +838,17 @@ class AutoCompression:
fetch_vars=test_program_info.fetch_targets,
executor=self._exe,
program=test_program)
+
+ def export_onnx(self,
+ model_name='quant_model.onnx',
+ deploy_backend='tensorrt'):
+ infer_model_path = os.path.join(self.final_dir, self.model_filename)
+ assert os.path.exists(
+ infer_model_path), 'Not found {}, please check it.'.format(
+ infer_model_path)
+ export_onnx(
+ self.final_dir,
+ model_filename=self.model_filename,
+ params_filename=self.params_filename,
+ save_file_path=os.path.join(self.final_dir, model_name),
+ deploy_backend=deploy_backend)
diff --git a/paddleslim/auto_compression/config_helpers.py b/paddleslim/auto_compression/config_helpers.py
index ebc5b45c83bb393e48cb005541e9f8733499f790..b1e426cc246b327a54f35ea0f0df7f5233391492 100644
--- a/paddleslim/auto_compression/config_helpers.py
+++ b/paddleslim/auto_compression/config_helpers.py
@@ -14,42 +14,7 @@
import yaml
import os
from paddleslim.auto_compression.strategy_config import *
-
-__all__ = ['save_config', 'load_config']
-
-
-def print_arguments(args, level=0):
- if level == 0:
- print('----------- Running Arguments -----------')
- for arg, value in sorted(args.items()):
- if isinstance(value, dict):
- print('\t' * level, '%s:' % arg)
- print_arguments(value, level + 1)
- else:
- print('\t' * level, '%s: %s' % (arg, value))
- if level == 0:
- print('------------------------------------------')
-
-
-def load_config(config):
- """Load configurations from yaml file into dict.
- Fields validation is skipped for loading some custom information.
- Args:
- config(str): The path of configuration file.
- Returns:
- dict: A dict storing configuration information.
- """
- if config is None:
- return None
- assert isinstance(
- config,
- str), f"config should be str but got type(config)={type(config)}"
- assert os.path.exists(config) and os.path.isfile(
- config), f"{config} not found or it is not a file."
- with open(config) as f:
- cfg = yaml.load(f, Loader=yaml.FullLoader)
- print_arguments(cfg)
- return cfg
+from ..common.config_helper import load_config
def extract_strategy_config(config):
@@ -101,12 +66,3 @@ def extract_train_config(config):
**value) if value is not None else TrainConfig()
# return default training config when it is not set
return TrainConfig()
-
-
-def save_config(config, config_path):
- """
- convert dict config to yaml.
- """
- f = open(config_path, "w")
- yaml.dump(config, f)
- f.close()
diff --git a/paddleslim/auto_compression/create_compressed_program.py b/paddleslim/auto_compression/create_compressed_program.py
index 30276bbf64b2e2e23d9e4adc19ee435c2c72ee19..8a6c7db2f5b691a2fc81643830e53bef231350ee 100644
--- a/paddleslim/auto_compression/create_compressed_program.py
+++ b/paddleslim/auto_compression/create_compressed_program.py
@@ -23,7 +23,7 @@ from ..dist import *
from ..common.recover_program import recover_inference_program, _remove_fetch_node
from ..common import get_logger
from .strategy_config import ProgramInfo
-from .utils import load_inference_model
+from ..common.load_model import load_inference_model
_logger = get_logger(__name__, level=logging.INFO)
__all__ = [
@@ -52,7 +52,8 @@ def _create_optimizer(train_config):
optimizer_builder = train_config['optimizer_builder']
assert isinstance(
optimizer_builder, dict
- ), f"Value of 'optimizer_builder' in train_config should be dict but got {type(optimizer_builder)}"
+ ), "Value of 'optimizer_builder' in train_config should be dict but got {}".format(
+ type(optimizer_builder))
if 'grad_clip' in optimizer_builder:
g_clip_params = optimizer_builder['grad_clip']
g_clip_type = g_clip_params.pop('type')
@@ -444,9 +445,8 @@ def build_prune_program(executor,
"####################channel pruning##########################")
for param in pruned_program.global_block().all_parameters():
if param.name in original_shapes:
- _logger.info(
- f"{param.name}, from {original_shapes[param.name]} to {param.shape}"
- )
+ _logger.info("{}, from {} to {}".format(
+ param.name, original_shapes[param.name], param.shape))
_logger.info(
"####################channel pruning end##########################")
train_program_info.program = pruned_program
diff --git a/paddleslim/auto_compression/strategy_config.py b/paddleslim/auto_compression/strategy_config.py
index 5226a7c843cc1d81d0bd4b3339b3e140a801b3b2..d8b3e90ce73762fd7365e9b0951e6c404f484dd2 100644
--- a/paddleslim/auto_compression/strategy_config.py
+++ b/paddleslim/auto_compression/strategy_config.py
@@ -53,7 +53,8 @@ class BaseStrategy:
class Quantization(BaseStrategy):
def __init__(self,
quantize_op_types=[
- 'conv2d', 'depthwise_conv2d', 'mul', 'matmul', 'matmul_v2'
+ 'conv2d', 'depthwise_conv2d', 'conv2d_transpose', 'mul',
+ 'matmul', 'matmul_v2'
],
weight_bits=8,
activation_bits=8,
@@ -65,6 +66,7 @@ class Quantization(BaseStrategy):
window_size=10000,
moving_rate=0.9,
for_tensorrt=False,
+ onnx_format=False,
is_full_quantize=False):
"""
Quantization Config.
@@ -80,6 +82,7 @@ class Quantization(BaseStrategy):
window_size(int): Window size for 'range_abs_max' quantization. Default: 10000.
moving_rate(float): The decay coefficient of moving average. Default: 0.9.
for_tensorrt(bool): If True, 'quantize_op_types' will be TENSORRT_OP_TYPES. Default: False.
+ onnx_format(bool): Whether to export the quantized model with format of ONNX. Default is False.
is_full_quantize(bool): If True, 'quantoze_op_types' will be TRANSFORM_PASS_OP_TYPES + QUANT_DEQUANT_PASS_OP_TYPES. Default: False.
"""
super(Quantization, self).__init__("Quantization")
@@ -95,6 +98,7 @@ class Quantization(BaseStrategy):
self.window_size = window_size
self.moving_rate = moving_rate
self.for_tensorrt = for_tensorrt
+ self.onnx_format = onnx_format
self.is_full_quantize = is_full_quantize
diff --git a/paddleslim/auto_compression/utils/__init__.py b/paddleslim/auto_compression/utils/__init__.py
index aa4f3ec07ac02436b5eaed00c781b9a6e34e70f8..e3c3a49d71823f432c810d9dccee0205d548f7ed 100644
--- a/paddleslim/auto_compression/utils/__init__.py
+++ b/paddleslim/auto_compression/utils/__init__.py
@@ -14,11 +14,5 @@
from __future__ import absolute_import
from .predict import predict_compressed_model
-from .dataloader import *
-from . import dataloader
-from .load_model import *
-from . import load_model
__all__ = ["predict_compressed_model"]
-__all__ += dataloader.__all__
-__all__ += load_model.__all__
diff --git a/paddleslim/auto_compression/utils/fake_ptq.py b/paddleslim/auto_compression/utils/fake_ptq.py
index fbecc224f663c39403f4741aa903a3cbaf5e9188..e86dd84860b869bf50903bbbf9e4126e6492084a 100644
--- a/paddleslim/auto_compression/utils/fake_ptq.py
+++ b/paddleslim/auto_compression/utils/fake_ptq.py
@@ -12,7 +12,7 @@ except:
TRANSFORM_PASS_OP_TYPES = QuantizationTransformPass._supported_quantizable_op_type
QUANT_DEQUANT_PASS_OP_TYPES = AddQuantDequantPass._supported_quantizable_op_type
-from .load_model import load_inference_model
+from ...common.load_model import load_inference_model
def post_quant_fake(executor,
diff --git a/paddleslim/auto_compression/utils/load_model.py b/paddleslim/auto_compression/utils/load_model.py
deleted file mode 100644
index bb61ab5626eca704e3becbf67a2c3711624b283b..0000000000000000000000000000000000000000
--- a/paddleslim/auto_compression/utils/load_model.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserve.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import paddle
-
-__all__ = ['load_inference_model']
-
-
-def load_inference_model(path_prefix,
- executor,
- model_filename=None,
- params_filename=None):
- if model_filename is not None and params_filename is not None:
- [inference_program, feed_target_names, fetch_targets] = (
- paddle.static.load_inference_model(
- path_prefix=path_prefix,
- executor=executor,
- model_filename=model_filename,
- params_filename=params_filename))
- else:
- model_name = '.'.join(model_filename.split('.')
- [:-1]) if model_filename is not None else 'model'
- if os.path.exists(os.path.join(path_prefix, model_name + '.pdmodel')):
- model_path_prefix = os.path.join(path_prefix, model_name)
- [inference_program, feed_target_names, fetch_targets] = (
- paddle.static.load_inference_model(
- path_prefix=model_path_prefix, executor=executor))
- else:
- [inference_program, feed_target_names, fetch_targets] = (
- paddle.static.load_inference_model(
- path_prefix=path_prefix, executor=executor))
-
- return [inference_program, feed_target_names, fetch_targets]
diff --git a/paddleslim/auto_compression/utils/predict.py b/paddleslim/auto_compression/utils/predict.py
index 01ef6a90b17280a74ef7ca54853cf20891392aad..5b8c6adb1850fd086317423bcb9e2fe97c34d4a8 100644
--- a/paddleslim/auto_compression/utils/predict.py
+++ b/paddleslim/auto_compression/utils/predict.py
@@ -4,7 +4,7 @@ import paddle
from ...analysis import TableLatencyPredictor
from .prune_model import get_sparse_model, get_prune_model
from .fake_ptq import post_quant_fake
-from .load_model import load_inference_model
+from ...common.load_model import load_inference_model
def with_variable_shape(model_dir, model_filename=None, params_filename=None):
@@ -53,7 +53,7 @@ def predict_compressed_model(executor,
latency_dict(dict): The latency latency of the model under various compression strategies.
"""
local_rank = paddle.distributed.get_rank()
- quant_model_path = f'quant_model_rank_{local_rank}_tmp'
+ quant_model_path = 'quant_model_rank_{}_tmp'.format(local_rank)
prune_model_path = f'prune_model_rank_{local_rank}_tmp'
sparse_model_path = f'sparse_model_rank_{local_rank}_tmp'
diff --git a/paddleslim/auto_compression/utils/prune_model.py b/paddleslim/auto_compression/utils/prune_model.py
index 426a1859c4419fd4bb0d4db3f8f097d5894c223b..c0da14ca9693112cf6919294f21136b86a5ea1d5 100644
--- a/paddleslim/auto_compression/utils/prune_model.py
+++ b/paddleslim/auto_compression/utils/prune_model.py
@@ -5,7 +5,7 @@ import paddle
import paddle.static as static
from ...prune import Pruner
from ...core import GraphWrapper
-from .load_model import load_inference_model
+from ...common.load_model import load_inference_model
__all__ = ["get_sparse_model", "get_prune_model"]
@@ -19,9 +19,10 @@ def get_sparse_model(executor, places, model_file, param_file, ratio,
ratio(float): The ratio to prune the model.
save_path(str): The save path of pruned model.
"""
- assert os.path.exists(model_file), f'{model_file} does not exist.'
+ assert os.path.exists(model_file), '{} does not exist.'.format(model_file)
assert os.path.exists(
- param_file) or param_file is None, f'{param_file} does not exist.'
+ param_file) or param_file is None, '{} does not exist.'.format(
+ param_file)
paddle.enable_static()
SKIP = ['image', 'feed', 'pool2d_0.tmp_0']
diff --git a/paddleslim/common/__init__.py b/paddleslim/common/__init__.py
index c3e40415b76205681fd69ce4a814e69a382d9b6c..8b1ffc02c756e8df089cb0cef37ade9421cc1a9d 100644
--- a/paddleslim/common/__init__.py
+++ b/paddleslim/common/__init__.py
@@ -25,11 +25,16 @@ from .analyze_helper import VarCollector
from . import wrapper_function
from . import recover_program
from . import patterns
+from .load_model import load_inference_model, get_model_dir, load_onnx_model, export_onnx
+from .dataloader import wrap_dataloader, get_feed_vars
+from .config_helper import load_config, save_config
__all__ = [
'EvolutionaryController', 'SAController', 'get_logger', 'ControllerServer',
'ControllerClient', 'lock', 'unlock', 'cached_reader', 'AvgrageMeter',
- 'Server', 'Client', 'RLBaseController', 'VarCollector'
+ 'Server', 'Client', 'RLBaseController', 'VarCollector', 'load_onnx_model',
+ 'load_inference_model', 'get_model_dir', 'wrap_dataloader', 'get_feed_vars',
+ 'load_config', 'save_config'
]
__all__ += wrapper_function.__all__
diff --git a/paddleslim/common/config_helper.py b/paddleslim/common/config_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..486fa9b449789f3c3d60d5e50cd3364406a9c908
--- /dev/null
+++ b/paddleslim/common/config_helper.py
@@ -0,0 +1,60 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import yaml
+import os
+
+__all__ = ['load_config', 'save_config']
+
+
+def print_arguments(args, level=0):
+ if level == 0:
+ print('----------- Running Arguments -----------')
+ for arg, value in sorted(args.items()):
+ if isinstance(value, dict):
+ print('\t' * level, '%s:' % arg)
+ print_arguments(value, level + 1)
+ else:
+ print('\t' * level, '%s: %s' % (arg, value))
+ if level == 0:
+ print('------------------------------------------')
+
+
+def load_config(config):
+ """Load configurations from yaml file into dict.
+ Fields validation is skipped for loading some custom information.
+ Args:
+ config(str): The path of configuration file.
+ Returns:
+ dict: A dict storing configuration information.
+ """
+ if config is None:
+ return None
+ assert isinstance(
+ config,
+ str), f"config should be str but got type(config)={type(config)}"
+ assert os.path.exists(config) and os.path.isfile(
+ config), f"{config} not found or it is not a file."
+ with open(config) as f:
+ cfg = yaml.load(f, Loader=yaml.FullLoader)
+ print_arguments(cfg)
+ return cfg
+
+
+def save_config(config, config_path):
+ """
+ convert dict config to yaml.
+ """
+ f = open(config_path, "w")
+ yaml.dump(config, f)
+ f.close()
diff --git a/paddleslim/auto_compression/utils/dataloader.py b/paddleslim/common/dataloader.py
similarity index 95%
rename from paddleslim/auto_compression/utils/dataloader.py
rename to paddleslim/common/dataloader.py
index f0f36716c14ba0ee99566ffb7e73f8e60838f0b0..31e375de2feee66ff88e44f66f7be8183fa4916a 100644
--- a/paddleslim/auto_compression/utils/dataloader.py
+++ b/paddleslim/common/dataloader.py
@@ -3,6 +3,7 @@ import time
import numpy as np
import paddle
from collections.abc import Iterable
+from .load_model import load_inference_model
__all__ = ["wrap_dataloader", "get_feed_vars"]
@@ -13,7 +14,7 @@ def get_feed_vars(model_dir, model_filename, params_filename):
paddle.enable_static()
exe = paddle.static.Executor(paddle.CPUPlace())
[inference_program, feed_target_names, fetch_targets] = (
- paddle.static.load_inference_model(
+ load_inference_model(
model_dir,
exe,
model_filename=model_filename,
diff --git a/paddleslim/common/load_model.py b/paddleslim/common/load_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..cc545b316982279c10e0221e954ad8ec44b33405
--- /dev/null
+++ b/paddleslim/common/load_model.py
@@ -0,0 +1,222 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserve.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import time
+import logging
+import os
+import shutil
+import sys
+import pkg_resources as pkg
+import paddle
+
+from . import get_logger
+_logger = get_logger(__name__, level=logging.INFO)
+
+__all__ = [
+ 'load_inference_model', 'get_model_dir', 'load_onnx_model', 'export_onnx'
+]
+
+
+def load_inference_model(path_prefix,
+ executor,
+ model_filename=None,
+ params_filename=None):
+ # Load onnx model to Inference model.
+ if path_prefix.endswith('.onnx'):
+ inference_program, feed_target_names, fetch_targets = load_onnx_model(
+ path_prefix)
+ return [inference_program, feed_target_names, fetch_targets]
+ # Load Inference model.
+ # TODO: clean code
+ if model_filename is not None and model_filename.endswith('.pdmodel'):
+ model_name = '.'.join(model_filename.split('.')[:-1])
+ assert os.path.exists(
+ os.path.join(path_prefix, model_name + '.pdmodel')
+ ), 'Please check {}, or fix model_filename parameter.'.format(
+ os.path.join(path_prefix, model_name + '.pdmodel'))
+ assert os.path.exists(
+ os.path.join(path_prefix, model_name + '.pdiparams')
+ ), 'Please check {}, or fix params_filename parameter.'.format(
+ os.path.join(path_prefix, model_name + '.pdiparams'))
+ model_path_prefix = os.path.join(path_prefix, model_name)
+ [inference_program, feed_target_names, fetch_targets] = (
+ paddle.static.load_inference_model(
+ path_prefix=model_path_prefix, executor=executor))
+ elif model_filename is not None and params_filename is not None:
+ [inference_program, feed_target_names, fetch_targets] = (
+ paddle.static.load_inference_model(
+ path_prefix=path_prefix,
+ executor=executor,
+ model_filename=model_filename,
+ params_filename=params_filename))
+ else:
+ model_name = '.'.join(model_filename.split('.')
+ [:-1]) if model_filename is not None else 'model'
+ if os.path.exists(os.path.join(path_prefix, model_name + '.pdmodel')):
+ model_path_prefix = os.path.join(path_prefix, model_name)
+ [inference_program, feed_target_names, fetch_targets] = (
+ paddle.static.load_inference_model(
+ path_prefix=model_path_prefix, executor=executor))
+ else:
+ [inference_program, feed_target_names, fetch_targets] = (
+ paddle.static.load_inference_model(
+ path_prefix=path_prefix, executor=executor))
+
+ return [inference_program, feed_target_names, fetch_targets]
+
+
+def get_model_dir(model_dir, model_filename, params_filename):
+ if model_dir.endswith('.onnx'):
+ updated_model_dir = model_dir.rstrip().rstrip('.onnx') + '_infer'
+ else:
+ updated_model_dir = model_dir.rstrip('/')
+
+ if model_filename == None:
+ updated_model_filename = 'model.pdmodel'
+ else:
+ updated_model_filename = model_filename
+
+ if params_filename == None:
+ updated_params_filename = 'model.pdiparams'
+ else:
+ updated_params_filename = params_filename
+
+ if params_filename is None and model_filename is not None:
+ raise NotImplementedError(
+ "NOT SUPPORT parameters saved in separate files. Please convert it to single binary file first."
+ )
+ return updated_model_dir, updated_model_filename, updated_params_filename
+
+
+def load_onnx_model(model_path, disable_feedback=False):
+ assert model_path.endswith(
+ '.onnx'
+ ), '{} does not end with .onnx suffix and cannot be loaded.'.format(
+ model_path)
+ inference_model_path = model_path.rstrip().rstrip('.onnx') + '_infer'
+ exe = paddle.static.Executor(paddle.CPUPlace())
+ if os.path.exists(os.path.join(
+ inference_model_path, 'model.pdmodel')) and os.path.exists(
+ os.path.join(inference_model_path, 'model.pdiparams')):
+ val_program, feed_target_names, fetch_targets = paddle.static.load_inference_model(
+ os.path.join(inference_model_path, 'model'), exe)
+ _logger.info('Loaded model from: {}'.format(inference_model_path))
+ return val_program, feed_target_names, fetch_targets
+ else:
+ # onnx to paddle inference model.
+ assert os.path.exists(
+ model_path), 'Not found `{}`, please check model path.'.format(
+ model_path)
+ try:
+ pkg.require('x2paddle')
+ except:
+ from pip._internal import main
+ main(['install', 'x2paddle'])
+ # check onnx installation and version
+ try:
+ pkg.require('onnx')
+ import onnx
+ version = onnx.version.version
+ v0, v1, v2 = version.split('.')
+ version_sum = int(v0) * 100 + int(v1) * 10 + int(v2)
+ if version_sum < 160:
+ _logger.error(
+ "onnx>=1.6.0 is required, please use \"pip install onnx\".")
+ except:
+ from pip._internal import main
+ main(['install', 'onnx==1.12.0'])
+
+ from x2paddle.decoder.onnx_decoder import ONNXDecoder
+ from x2paddle.op_mapper.onnx2paddle.onnx_op_mapper import ONNXOpMapper
+ from x2paddle.optimizer.optimizer import GraphOptimizer
+ from x2paddle.utils import ConverterCheck
+ time_info = int(time.time())
+ if not disable_feedback:
+ ConverterCheck(
+ task="ONNX", time_info=time_info, convert_state="Start").start()
+ # support distributed convert model
+ model_idx = paddle.distributed.get_rank(
+ ) if paddle.distributed.get_world_size() > 1 else 0
+ try:
+ _logger.info("Now translating model from onnx to paddle.")
+ model = ONNXDecoder(model_path)
+ mapper = ONNXOpMapper(model)
+ mapper.paddle_graph.build()
+ graph_opt = GraphOptimizer(source_frame="onnx")
+ graph_opt.optimize(mapper.paddle_graph)
+ _logger.info("Model optimized.")
+ onnx2paddle_out_dir = os.path.join(
+ inference_model_path, 'onnx2paddle_{}'.format(model_idx))
+ mapper.paddle_graph.gen_model(onnx2paddle_out_dir)
+ _logger.info("Successfully exported Paddle static graph model!")
+ if not disable_feedback:
+ ConverterCheck(
+ task="ONNX", time_info=time_info,
+ convert_state="Success").start()
+ except Exception as e:
+ _logger.warning(e)
+ _logger.error(
+ "x2paddle threw an exception, you can ask for help at: https://github.com/PaddlePaddle/X2Paddle/issues"
+ )
+ sys.exit(1)
+
+ if paddle.distributed.get_rank() == 0:
+ shutil.move(
+ os.path.join(onnx2paddle_out_dir, 'inference_model',
+ 'model.pdmodel'),
+ os.path.join(inference_model_path, 'model.pdmodel'))
+ shutil.move(
+ os.path.join(onnx2paddle_out_dir, 'inference_model',
+ 'model.pdiparams'),
+ os.path.join(inference_model_path, 'model.pdiparams'))
+ load_model_path = inference_model_path
+ else:
+ load_model_path = os.path.join(onnx2paddle_out_dir,
+ 'inference_model')
+
+ paddle.enable_static()
+ val_program, feed_target_names, fetch_targets = paddle.static.load_inference_model(
+ os.path.join(load_model_path, 'model'), exe)
+ _logger.info('Loaded model from: {}'.format(load_model_path))
+ # Clean up the file storage directory
+ shutil.rmtree(
+ os.path.join(inference_model_path, 'onnx2paddle_{}'.format(
+ model_idx)))
+ return val_program, feed_target_names, fetch_targets
+
+
+def export_onnx(model_dir,
+ model_filename=None,
+ params_filename=None,
+ save_file_path='output.onnx',
+ opset_version=13,
+ deploy_backend='tensorrt'):
+ if not model_filename:
+ model_filename = 'model.pdmodel'
+ if not params_filename:
+ params_filename = 'model.pdiparams'
+ try:
+ pkg.require('paddle2onnx')
+ except:
+ from pip._internal import main
+ main(['install', 'paddle2onnx==1.0.0rc3'])
+ import paddle2onnx
+ paddle2onnx.command.c_paddle_to_onnx(
+ model_file=os.path.join(model_dir, model_filename),
+ params_file=os.path.join(model_dir, params_filename),
+ save_file=save_file_path,
+ opset_version=opset_version,
+ enable_onnx_checker=True,
+ deploy_backend=deploy_backend)
+ _logger.info('Convert model to ONNX: {}'.format(save_file_path))
diff --git a/paddleslim/dygraph/prune/pruning_plan.py b/paddleslim/dygraph/prune/pruning_plan.py
index d9cd8e4a26b148e68dbcb27ca45b0668033f1807..cd669ffd5bc364b9292b413c6741b02024781070 100644
--- a/paddleslim/dygraph/prune/pruning_plan.py
+++ b/paddleslim/dygraph/prune/pruning_plan.py
@@ -220,7 +220,7 @@ class PruningPlan():
t_value = param.value().get_tensor()
value = np.array(t_value).astype("float32")
groups = _mask._op.attr('groups')
- if dims == 1 and groups is not None and groups > 1 and len(
+ if groups is not None and groups > 1 and len(
value.shape) == 4:
filter_size = value.shape[1]
except_num = np.sum(bool_mask)
@@ -230,7 +230,6 @@ class PruningPlan():
sub_layer._groups = new_groups
_logger.info("change groups from {} to {} for {}.".
format(groups, new_groups, param.name))
- continue
# The name of buffer can not contains "."
backup_name = param.name.replace(".", "_") + "_backup"
diff --git a/paddleslim/prune/prune_worker.py b/paddleslim/prune/prune_worker.py
index 25703c66db44af5363df511fd59080ac922cc317..c9c69f622e93b04804c133b8c1fa5612e186f5f6 100644
--- a/paddleslim/prune/prune_worker.py
+++ b/paddleslim/prune/prune_worker.py
@@ -522,7 +522,6 @@ class depthwise_conv2d(PruneWorker):
channel_axis = 1
if data_format == "NHWC":
channel_axis = 3
-
if var == _in_var:
assert pruned_axis == channel_axis, "The Input of conv2d can only be pruned at channel axis, but got {}".format(
pruned_axis)
@@ -533,7 +532,6 @@ class depthwise_conv2d(PruneWorker):
"repeat": repeat
}])
# kernel_number * groups will be pruned by reducing groups
- self.append_pruned_vars(_filter, 1, transforms)
self._visit_and_search(_filter, 0, transforms + [{
"repeat": repeat
}])
@@ -546,14 +544,13 @@ class depthwise_conv2d(PruneWorker):
}])
elif var == _filter:
assert pruned_axis == 0, "The filter of depthwise conv2d can only be pruned at axis 0."
- self.append_pruned_vars(_filter, 1, transforms)
+ self.append_pruned_vars(_filter, 0, transforms)
self._visit_and_search(_in_var, channel_axis, transforms)
self._visit_and_search(_out, channel_axis, transforms)
elif var == _out:
assert pruned_axis == channel_axis, "The Input of conv2d can only be pruned at channel axis, but got {}".format(
pruned_axis)
self.append_pruned_vars(_filter, 0, transforms)
- self.append_pruned_vars(_filter, 1, transforms)
self._visit_and_search(_filter, 0, transforms)
# It will not pruning number of kernels in depthwise conv2d,
# so it is not neccesary to search succeed operators.
diff --git a/paddleslim/prune/pruner.py b/paddleslim/prune/pruner.py
index 1926c8cbb03fdbd567e70f6601b4d006ded9869c..4c58c2e1de5445ccfac5e91261186a5e797e4252 100644
--- a/paddleslim/prune/pruner.py
+++ b/paddleslim/prune/pruner.py
@@ -117,7 +117,7 @@ class Pruner():
_groups = 1
if not lazy:
# update groups of conv2d
- if pruned_axis == 1:
+ if pruned_axis == 1 or pruned_axis == 0:
for op in param.outputs():
if op.type() in [
"conv2d", "conv2d_grad", "depthwise_conv2d",
@@ -132,7 +132,7 @@ class Pruner():
f"change groups of {op.type()}({param.name()}) from {op.attr('groups')} to {new_groups};"
)
op.set_attr("groups", new_groups)
- if _groups == 1:
+
origin_shape = copy.deepcopy(param.shape())
if param_shape_backup is not None:
param_shape_backup[param.name()] = origin_shape
diff --git a/paddleslim/quant/__init__.py b/paddleslim/quant/__init__.py
index 8b472e72d2acc9e5f4d26ef223ac5daa589c9265..69e5429628ca9db1d36f4bb943c836a327f41064 100644
--- a/paddleslim/quant/__init__.py
+++ b/paddleslim/quant/__init__.py
@@ -35,7 +35,7 @@ try:
except Exception as e:
_logger.warning(e)
_logger.warning(
- f"If you want to use training-aware and post-training quantization, "
- "please use Paddle >= {min_paddle_version} or develop version")
+ "If you want to use training-aware and post-training quantization, "
+ "please use Paddle >= {} or develop version".format(min_paddle_version))
from .quant_embedding import quant_embedding
diff --git a/paddleslim/quant/analysis.py b/paddleslim/quant/analysis.py
new file mode 100644
index 0000000000000000000000000000000000000000..d81e80f8eb52fa2ccbb8549a7de4a04b8a91af13
--- /dev/null
+++ b/paddleslim/quant/analysis.py
@@ -0,0 +1,312 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import pickle
+import copy
+import logging
+import matplotlib.pyplot as plt
+from matplotlib.backends.backend_pdf import PdfPages
+import numpy as np
+
+import paddle
+from paddle.fluid import core
+from paddle.fluid import framework
+from paddle.fluid.framework import IrGraph
+from paddle.fluid.executor import global_scope
+from paddle.fluid.contrib.slim.quantization import PostTrainingQuantization
+from paddle.fluid.contrib.slim.quantization.utils import _get_op_input_var_names, load_variable_data
+from .quanter import quant_post
+from ..core import GraphWrapper
+from ..common import get_logger
+from ..common import get_feed_vars, wrap_dataloader, load_inference_model, get_model_dir
+
+_logger = get_logger(__name__, level=logging.INFO)
+
+__all__ = ["AnalysisQuant"]
+
+
+class AnalysisQuant(object):
+ def __init__(self,
+ model_dir,
+ model_filename=None,
+ params_filename=None,
+ eval_function=None,
+ data_loader=None,
+ save_dir='analysis_results',
+ checkpoint_name='analysis_checkpoint.pkl',
+ num_histogram_plots=10,
+ ptq_config=None):
+ """
+ AnalysisQuant provides to analysis the sensitivity of each op in the model.
+
+ Args:
+ model_dir(str): the path of fp32 model that will be quantized, it can also be '.onnx'
+ model_filename(str, optional): the model file name of the fp32 model
+ params_filename(str, optional): the parameter file name of the fp32 model
+ eval_function(function): eval function, define by yourself to return the metric of the inference program, can be used to judge the metric of quantized model. (TODO: optional)
+ data_loader(Python Generator, Paddle.io.DataLoader, optional): the
+ Generator or Dataloader provides calibrate data, and it could
+ return a batch every time
+ save_dir(str, optional): the output dir that stores the analyzed information
+ checkpoint_name(str, optional): the name of checkpoint file that saves analyzed information and avoids break off while ananlyzing
+ ptq_config(dict, optional): the args that can initialize PostTrainingQuantization
+
+ """
+ if model_filename is None:
+ model_filename = 'model.pdmodel'
+ if params_filename is None:
+ params_filename = 'model.pdiparams'
+ self.model_dir = model_dir
+ self.model_filename = model_filename
+ self.params_filename = params_filename
+ self.histogram_bins = 1000
+ self.save_dir = save_dir
+ self.eval_function = eval_function
+ self.quant_layer_names = []
+ self.checkpoint_name = os.path.join(save_dir, checkpoint_name)
+ self.quant_layer_metrics = {}
+ self.num_histogram_plots = num_histogram_plots
+ self.ptq_config = ptq_config
+ self.batch_nums = ptq_config[
+ 'batch_nums'] if 'batch_nums' in ptq_config else 10
+
+ if not os.path.exists(self.save_dir):
+ os.mkdir(self.save_dir)
+
+ devices = paddle.device.get_device().split(':')[0]
+ self.places = paddle.device._convert_to_place(devices)
+ executor = paddle.static.Executor(self.places)
+
+ # load model
+ [program, self.feed_list, self.fetch_list]= load_inference_model( \
+ self.model_dir, \
+ executor=executor, \
+ model_filename=self.model_filename, \
+ params_filename=self.params_filename)
+
+ # create data_loader
+ self.data_loader = wrap_dataloader(data_loader, self.feed_list)
+
+ # evaluate before quant
+ # TODO: self.eval_function can be None
+ if self.eval_function is not None:
+ self.base_metric = self.eval_function(
+ executor, program, self.feed_list, self.fetch_list)
+ _logger.info('before quantized, the accuracy of the model is: {}'.
+ format(self.base_metric))
+
+ # quant and evaluate after quant (skip_list = None)
+ post_training_quantization = PostTrainingQuantization(
+ executor=executor,
+ data_loader=self.data_loader,
+ model_dir=self.model_dir,
+ model_filename=self.model_filename,
+ params_filename=self.params_filename,
+ skip_tensor_list=None,
+ algo='avg', #fastest
+ **self.ptq_config)
+ program = post_training_quantization.quantize()
+ self.quant_metric = self.eval_function(executor, program,
+ self.feed_list, self.fetch_list)
+ _logger.info('after quantized, the accuracy of the model is: {}'.format(
+ self.quant_metric))
+
+ # get quantized weight and act var name
+ self.quantized_weight_var_name = post_training_quantization._quantized_weight_var_name
+ self.quantized_act_var_name = post_training_quantization._quantized_act_var_name
+ executor.close()
+
+ # load tobe_analyized_layer from checkpoint
+ self.load_checkpoint()
+ self.tobe_analyized_layer = self.quantized_weight_var_name - set(
+ list(self.quant_layer_metrics.keys()))
+ self.tobe_analyized_layer = sorted(list(self.tobe_analyized_layer))
+
+ def analysis(self):
+ self.compute_quant_sensitivity()
+ self.sensitivity_ranklist = sorted(
+ self.quant_layer_metrics,
+ key=self.quant_layer_metrics.get,
+ reverse=False)
+
+ _logger.info('Finished computing the sensitivity of the model.')
+ for name in self.sensitivity_ranklist:
+ _logger.info("quant layer name: {}, eval metric: {}".format(
+ name, self.quant_layer_metrics[name]))
+
+ analysis_file = os.path.join(self.save_dir, "analysis.txt")
+ with open(analysis_file, "w") as analysis_ret_f:
+ for name in self.sensitivity_ranklist:
+ analysis_ret_f.write(
+ "quant layer name: {}, eval metric: {}\n".format(
+ name, self.quant_layer_metrics[name]))
+ _logger.info('Analysis file is saved in {}'.format(analysis_file))
+ self.calculate_histogram()
+
+ def save_checkpoint(self):
+ if not os.path.exists(self.save_dir):
+ os.makedirs(self.save_dir)
+ with open(self.checkpoint_name, 'wb') as f:
+ pickle.dump(self.quant_layer_metrics, f)
+ _logger.info('save checkpoint to {}'.format(self.checkpoint_name))
+
+ def load_checkpoint(self):
+ if not os.path.exists(self.checkpoint_name):
+ return False
+ with open(self.checkpoint_name, 'rb') as f:
+ self.quant_layer_metrics = pickle.load(f)
+ _logger.info('load checkpoint from {}'.format(self.checkpoint_name))
+ return True
+
+ def compute_quant_sensitivity(self):
+ '''
+ For each layer, quantize the weight op and evaluate the quantized model.
+ '''
+ for i, layer_name in enumerate(self.tobe_analyized_layer):
+ _logger.info('checking {}/{} quant model: quant layer {}'.format(
+ i + 1, len(self.tobe_analyized_layer), layer_name))
+ skip_list = copy.copy(list(self.quantized_weight_var_name))
+ skip_list.remove(layer_name)
+
+ executor = paddle.static.Executor(self.places)
+ post_training_quantization = PostTrainingQuantization(
+ executor=executor,
+ data_loader=self.data_loader,
+ model_dir=self.model_dir,
+ model_filename=self.model_filename,
+ params_filename=self.params_filename,
+ skip_tensor_list=skip_list,
+ algo='avg', #fastest
+ **self.ptq_config)
+ program = post_training_quantization.quantize()
+
+ _logger.info('Evaluating...')
+ quant_metric = self.eval_function(executor, program, self.feed_list,
+ self.fetch_list)
+ executor.close()
+ _logger.info(
+ "quant layer name: {}, eval metric: {}, the loss caused by this layer: {}".
+ format(layer_name, quant_metric, self.base_metric -
+ quant_metric))
+ self.quant_layer_metrics[layer_name] = quant_metric
+ self.save_checkpoint()
+
+ def get_act_name_by_weight(self, program, weight_names,
+ persistable_var_names):
+ act_ops_names = []
+ for op_name in weight_names:
+ for block_id in range(len(program.blocks)):
+ for op in program.blocks[block_id].ops:
+ var_name_list = _get_op_input_var_names(op)
+ if op_name in var_name_list:
+ for var_name in var_name_list:
+ if var_name not in persistable_var_names:
+ act_ops_names.append(var_name)
+ return act_ops_names
+
+ def get_hist_ops_name(self, graph, program):
+ if self.num_histogram_plots <= 0:
+ return []
+
+ best_weight_ops = self.sensitivity_ranklist[::-1][:self.
+ num_histogram_plots]
+ worst_weight_ops = self.sensitivity_ranklist[:self.num_histogram_plots]
+
+ persistable_var_names = []
+ for var in program.list_vars():
+ if var.persistable:
+ persistable_var_names.append(var.name)
+
+ best_act_ops = self.get_act_name_by_weight(program, best_weight_ops,
+ persistable_var_names)
+ worst_act_ops = self.get_act_name_by_weight(program, worst_weight_ops,
+ persistable_var_names)
+ return [best_weight_ops, best_act_ops, worst_weight_ops, worst_act_ops]
+
+ def collect_ops_histogram(self, scope, ops):
+ hist = {}
+ for var_name in ops:
+ var_tensor = load_variable_data(scope, var_name)
+ var_tensor = np.array(var_tensor)
+ min_v = float(np.min(var_tensor))
+ max_v = float(np.max(var_tensor))
+ var_tensor = var_tensor.flatten()
+ _, hist_edges = np.histogram(
+ var_tensor.copy(),
+ bins=self.histogram_bins,
+ range=(min_v, max_v))
+ hist[var_name] = [var_tensor, hist_edges]
+ return hist
+
+ def calculate_histogram(self):
+ '''
+ Sample histograms for the weight and corresponding act tensors
+ '''
+ devices = paddle.device.get_device().split(':')[0]
+ places = paddle.device._convert_to_place(devices)
+ executor = paddle.static.Executor(places)
+
+ [program, feed_list, fetch_list]= load_inference_model( \
+ self.model_dir, \
+ executor=executor, \
+ model_filename=self.model_filename, \
+ params_filename=self.params_filename)
+
+ scope = global_scope()
+
+ graph = IrGraph(core.Graph(program.desc), for_test=False)
+ ops_tobe_draw_hist = self.get_hist_ops_name(graph, program)
+ if not ops_tobe_draw_hist:
+ return
+
+ for var in program.list_vars():
+ if var.name in self.quantized_act_var_name:
+ var.persistable = True
+
+ # sample before collect histogram
+ batch_id = 0
+ for data in self.data_loader():
+ executor.run(program=program,
+ feed=data,
+ fetch_list=fetch_list,
+ return_numpy=False,
+ scope=scope)
+ batch_id += 1
+ if batch_id >= self.batch_nums:
+ break
+
+ pdf_names = [
+ 'best_weight_hist_result.pdf',
+ 'best_act_hist_result.pdf',
+ 'worst_weight_hist_result.pdf',
+ 'worst_act_hist_result.pdf',
+ ]
+ for ops, save_pdf_name in zip(ops_tobe_draw_hist, pdf_names):
+ hist_data = self.collect_ops_histogram(scope, ops)
+ self.draw_pdf(hist_data, save_pdf_name)
+
+ def draw_pdf(self, hist_data, save_pdf_name):
+ pdf_path = os.path.join(self.save_dir, save_pdf_name)
+ with PdfPages(pdf_path) as pdf:
+ for name in hist_data:
+ plt.hist(hist_data[name][0], bins=hist_data[name][1])
+ plt.xlabel(name)
+ plt.ylabel("frequency")
+ plt.title("Hist of variable {}".format(name))
+ plt.show()
+ pdf.savefig()
+ plt.close()
+ _logger.info('Histogram plot is saved in {}'.format(pdf_path))
diff --git a/paddleslim/quant/post_quant_hpo.py b/paddleslim/quant/post_quant_hpo.py
index e6bc1d9fc4d9af2ac37d1b3f2ce296c9e57a056c..dc41e48d42bd77923be1a00e76c6f71d5da24565 100755
--- a/paddleslim/quant/post_quant_hpo.py
+++ b/paddleslim/quant/post_quant_hpo.py
@@ -29,13 +29,7 @@ import shutil
import glob
from scipy.stats import wasserstein_distance
-# smac
-from ConfigSpace.hyperparameters import CategoricalHyperparameter, \
- UniformFloatHyperparameter, UniformIntegerHyperparameter
-from smac.configspace import ConfigurationSpace
-from smac.facade.smac_hpo_facade import SMAC4HPO
-from smac.scenario.scenario import Scenario
-
+import pkg_resources as pkg
from paddleslim.common import get_logger
from paddleslim.quant import quant_post
@@ -417,6 +411,18 @@ def quant_post_hpo(
None
"""
+ try:
+ pkg.require('smac')
+ except:
+ from pip._internal import main
+ main(['install', 'smac'])
+ # smac
+ from ConfigSpace.hyperparameters import CategoricalHyperparameter, \
+ UniformFloatHyperparameter, UniformIntegerHyperparameter
+ from smac.configspace import ConfigurationSpace
+ from smac.facade.smac_hpo_facade import SMAC4HPO
+ from smac.scenario.scenario import Scenario
+
global g_quant_config
g_quant_config = QuantConfig(
executor, place, model_dir, quantize_model_path, algo, hist_percent,
diff --git a/paddleslim/quant/quanter.py b/paddleslim/quant/quanter.py
index 9e07c03c6ee5c1bb657393bfbc175d72ebd558fc..9f8ed323e3ab6eb86f9a476d9895d89dddf31eca 100755
--- a/paddleslim/quant/quanter.py
+++ b/paddleslim/quant/quanter.py
@@ -16,9 +16,14 @@ import os
import copy
import json
import logging
+import collections
+import numpy as np
import paddle
+from paddle.fluid import core
+from paddle.fluid.layer_helper import LayerHelper
from paddle.fluid.framework import IrGraph
+from paddle.fluid.contrib.slim.quantization import WeightQuantization
from paddle.fluid.contrib.slim.quantization import QuantizationTransformPass
from paddle.fluid.contrib.slim.quantization import QuantizationFreezePass
from paddle.fluid.contrib.slim.quantization import ConvertToInt8Pass
@@ -27,18 +32,17 @@ from paddle.fluid.contrib.slim.quantization import PostTrainingQuantization
from paddle.fluid.contrib.slim.quantization import AddQuantDequantPass
from paddle.fluid.contrib.slim.quantization import OutScaleForTrainingPass
from paddle.fluid.contrib.slim.quantization import OutScaleForInferencePass
+from ..common import get_logger
+_logger = get_logger(__name__, level=logging.INFO)
+
try:
from paddle.fluid.contrib.slim.quantization import QuantizationTransformPassV2
from paddle.fluid.contrib.slim.quantization import QuantWeightPass
from paddle.fluid.contrib.slim.quantization import AddQuantDequantPassV2
except:
- pass
-from paddle.fluid import core
-from paddle.fluid.contrib.slim.quantization import WeightQuantization
-from paddle.fluid.layer_helper import LayerHelper
-
-from ..common import get_logger
-_logger = get_logger(__name__, level=logging.INFO)
+ _logger.warning(
+ "Some functions fail to import, please update PaddlePaddle version to 2.3+"
+ )
WEIGHT_QUANTIZATION_TYPES = [
'abs_max', 'channel_wise_abs_max', 'range_abs_max', 'moving_average_abs_max'
@@ -91,27 +95,54 @@ _quant_config_default = {
# if True, 'quantize_op_types' will be TENSORRT_OP_TYPES
'for_tensorrt': False,
# if True, 'quantoze_op_types' will be TRANSFORM_PASS_OP_TYPES + QUANT_DEQUANT_PASS_OP_TYPES
- 'is_full_quantize': False
+ 'is_full_quantize': False,
+ # if True, use onnx format to quant.
+ 'onnx_format': False,
}
-# TODO: Hard-code, remove it when Paddle 2.3.1
-class OutScaleForTrainingPassV2(OutScaleForTrainingPass):
- def __init__(self, scope=None, place=None, moving_rate=0.9):
- OutScaleForTrainingPass.__init__(
- self, scope=scope, place=place, moving_rate=moving_rate)
-
- def _scale_name(self, var_name):
+class OutScaleForInferencePassV2(object):
+ def __init__(self, scope=None):
"""
- Return the scale name for the var named `var_name`.
+ This pass is used for setting output scales of some operators.
+ These output scales may be used by tensorRT or some other inference engines.
+
+ Args:
+ scope(fluid.Scope): The scope is used to initialize these new parameters.
"""
- return "%s@scale" % (var_name)
+ self._scope = scope
+ self._teller_set = utils._out_scale_op_list
+ def apply(self, graph):
+ """
+ Get output scales from the scope and set these scales in op_descs
+ of operators in the teller_set.
-# TODO: Hard-code, remove it when Paddle 2.3.1
-class OutScaleForInferencePassV2(OutScaleForInferencePass):
- def __init__(self, scope=None):
- OutScaleForInferencePass.__init__(self, scope=scope)
+ Args:
+ graph(IrGraph): the target graph.
+ """
+ assert isinstance(graph,
+ IrGraph), 'graph must be the instance of IrGraph.'
+ collect_dict = collections.OrderedDict()
+ op_nodes = graph.all_op_nodes()
+ for op_node in op_nodes:
+ if op_node.name() in self._teller_set:
+ var_names = utils._get_op_output_var_names(op_node)
+ for var_name in var_names:
+ in_node = graph._find_node_by_name(op_node.outputs,
+ var_name)
+ if in_node.dtype() not in \
+ [core.VarDesc.VarType.FP64, core.VarDesc.VarType.FP32]:
+ continue
+
+ collect_dict[var_name] = {}
+ scale_name = self._scale_name(var_name)
+ scale_var = self._scope.find_var(scale_name)
+ assert scale_var is not None, \
+ "Can not find {} variable in the scope".format(scale_name)
+ scale_value = np.array(scale_var.get_tensor())[0]
+ collect_dict[var_name]['scale'] = float(scale_value)
+ return graph, collect_dict
def _scale_name(self, var_name):
"""
@@ -222,7 +253,6 @@ def quant_aware(program,
act_preprocess_func=None,
optimizer_func=None,
executor=None,
- onnx_format=False,
return_program=False,
draw_graph=False):
"""Add quantization and dequantization operators to "program"
@@ -236,7 +266,9 @@ def quant_aware(program,
Default: None.
scope(paddle.static.Scope): Scope records the mapping between variable names and variables,
similar to brackets in programming languages. Usually users can use
- `paddle.static.global_scope `_. When ``None`` will use `paddle.static.global_scope() `_ . Default: ``None``.
+ `paddle.static.global_scope `_.
+ When ``None`` will use `paddle.static.global_scope() `_ .
+ Default: ``None``.
for_test(bool): If the 'program' parameter is a test program, this parameter should be set to ``True``.
Otherwise, set to ``False``.Default: False
weight_quantize_func(function): Function that defines how to quantize weight. Using this
@@ -291,7 +323,8 @@ def quant_aware(program,
elif op_type in QUANT_DEQUANT_PASS_OP_TYPES:
quant_dequant_ops.append(op_type)
if len(transform_pass_ops) > 0:
- trannsform_func = 'QuantizationTransformPassV2' if onnx_format else 'QuantizationTransformPass'
+ trannsform_func = 'QuantizationTransformPassV2' if config[
+ 'onnx_format'] else 'QuantizationTransformPass'
transform_pass = eval(trannsform_func)(
scope=scope,
place=place,
@@ -313,7 +346,8 @@ def quant_aware(program,
transform_pass.apply(main_graph)
if len(quant_dequant_ops) > 0:
- qdq_func = 'AddQuantDequantPassV2' if onnx_format else 'AddQuantDequantPass'
+ qdq_func = 'AddQuantDequantPassV2' if config[
+ 'onnx_format'] else 'AddQuantDequantPass'
quant_dequant_pass = eval(qdq_func)(
scope=scope,
place=place,
@@ -323,7 +357,7 @@ def quant_aware(program,
quantizable_op_type=quant_dequant_ops)
quant_dequant_pass.apply(main_graph)
- out_scale_training_pass = OutScaleForTrainingPassV2(
+ out_scale_training_pass = OutScaleForTrainingPass(
scope=scope, place=place, moving_rate=config['moving_rate'])
out_scale_training_pass.apply(main_graph)
@@ -356,8 +390,8 @@ def quant_post_static(
data_loader=None,
model_filename=None,
params_filename=None,
- save_model_filename='__model__',
- save_params_filename='__params__',
+ save_model_filename='model.pdmodel',
+ save_params_filename='model.pdiparams',
batch_size=1,
batch_nums=None,
scope=None,
@@ -405,9 +439,9 @@ def quant_post_static(
When all parameters are saved in a single file, set it
as filename. If parameters are saved in separate files,
set it as 'None'. Default : 'None'.
- save_model_filename(str): The name of model file to save the quantized inference program. Default: '__model__'.
+ save_model_filename(str): The name of model file to save the quantized inference program. Default: 'model.pdmodel'.
save_params_filename(str): The name of file to save all related parameters.
- If it is set None, parameters will be saved in separate files. Default: '__params__'.
+ If it is set None, parameters will be saved in separate files. Default: 'model.pdiparams'.
batch_size(int, optional): The batch size of DataLoader, default is 1.
batch_nums(int, optional): If batch_nums is not None, the number of calibrate
data is 'batch_size*batch_nums'. If batch_nums is None, use all data
@@ -508,6 +542,22 @@ def quant_post_static(
quantize_model_path,
model_filename=save_model_filename,
params_filename=save_params_filename)
+ if onnx_format:
+ try:
+ collect_dict = post_training_quantization._calibration_scales
+ save_quant_table_path = os.path.join(quantize_model_path,
+ 'calibration_table.txt')
+ with open(save_quant_table_path, 'w') as txt_file:
+ for tensor_name in collect_dict.keys():
+ write_line = '{} {}'.format(
+ tensor_name, collect_dict[tensor_name]['scale']) + '\n'
+ txt_file.write(write_line)
+ _logger.info("Quantization clip ranges of tensors is save in: {}".
+ format(save_quant_table_path))
+ except:
+ _logger.warning(
+ "Unable to generate `calibration_table.txt`, please update PaddlePaddle >= 2.3.3"
+ )
# We have changed the quant_post to quant_post_static.
@@ -521,7 +571,7 @@ def convert(program,
config=None,
scope=None,
save_int8=False,
- onnx_format=False):
+ save_clip_ranges_path='./'):
"""
convert quantized and well-trained ``program`` to final quantized
``program``that can be used to save ``inference model``.
@@ -543,6 +593,7 @@ def convert(program,
save_int8: Whether to return ``program`` which model parameters'
dtype is ``int8``. This parameter can only be used to
get model size. Default: ``False``.
+ save_clip_ranges_path: If config.onnx_format=True, quantization clip ranges will be saved locally.
Returns:
Tuple : freezed program which can be used for inference.
@@ -560,11 +611,22 @@ def convert(program,
_logger.info("convert config {}".format(config))
test_graph = IrGraph(core.Graph(program.desc), for_test=True)
- if onnx_format:
+ if config['onnx_format']:
quant_weight_pass = QuantWeightPass(scope, place)
quant_weight_pass.apply(test_graph)
- else:
out_scale_infer_pass = OutScaleForInferencePassV2(scope=scope)
+ _, collect_dict = out_scale_infer_pass.apply(test_graph)
+ save_quant_table_path = os.path.join(save_clip_ranges_path,
+ 'calibration_table.txt')
+ with open(save_quant_table_path, 'w') as txt_file:
+ for tensor_name in collect_dict.keys():
+ write_line = '{} {}'.format(
+ tensor_name, collect_dict[tensor_name]['scale']) + '\n'
+ txt_file.write(write_line)
+ _logger.info("Quantization clip ranges of tensors is save in: {}".
+ format(save_quant_table_path))
+ else:
+ out_scale_infer_pass = OutScaleForInferencePass(scope=scope)
out_scale_infer_pass.apply(test_graph)
# Freeze the graph after training by adjusting the quantize
# operators' order for the inference.
diff --git a/requirements.txt b/requirements.txt
index 8ed081bad22e9e2609fd2fb94f72b4cd7e2ef81a..d558b22165383c6781270f95ff4ad9dd0d3a9914 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,6 @@
-#paddlepaddle == 1.6.0rc0
tqdm
pyzmq
matplotlib
pillow
pyyaml
scikit-learn
-smac
diff --git a/tests/act/test_act_api.py b/tests/act/test_act_api.py
index ec73d46e36b4376675958257648f587e45de7aa6..2b2a8b6c31cc51c010c7a0cee222e864602b71cc 100644
--- a/tests/act/test_act_api.py
+++ b/tests/act/test_act_api.py
@@ -8,7 +8,8 @@ import unittest
import numpy as np
from paddle.io import Dataset
from paddleslim.auto_compression import AutoCompression
-from paddleslim.auto_compression.config_helpers import load_config
+from paddleslim.common import load_config
+from paddleslim.common import load_inference_model, export_onnx
class RandomEvalDataset(Dataset):
@@ -120,5 +121,36 @@ class TestDictQATDist(ACTBase):
ac.compress()
+class TestLoadONNXModel(ACTBase):
+ def __init__(self, *args, **kwargs):
+ super(TestLoadONNXModel, self).__init__(*args, **kwargs)
+ os.system(
+ 'wget https://paddle-slim-models.bj.bcebos.com/act/yolov5s.onnx')
+ self.model_dir = 'yolov5s.onnx'
+
+ def test_compress(self):
+ place = paddle.CPUPlace()
+ exe = paddle.static.Executor(place)
+ _, _, _ = load_inference_model(
+ self.model_dir,
+ executor=exe,
+ model_filename='model.pdmodel',
+ params_filename='model.paiparams')
+ # reload model
+ _, _, _ = load_inference_model(
+ self.model_dir,
+ executor=exe,
+ model_filename='model.pdmodel',
+ params_filename='model.paiparams')
+ # convert onnx
+ export_onnx(
+ self.model_dir,
+ model_filename='model.pdmodel',
+ params_filename='model.paiparams',
+ save_file_path='output.onnx',
+ opset_version=13,
+ deploy_backend='tensorrt')
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_prune_walker.py b/tests/test_prune_walker.py
index e0375c8b6038bfd9a2db1b16f0cf7d03cc98be8a..f2f2d2fc1aa403ab15d23281da2a26a62f6a2d42 100644
--- a/tests/test_prune_walker.py
+++ b/tests/test_prune_walker.py
@@ -473,9 +473,9 @@ class TestDepthwiseConv2d(TestPruneWorker):
def set_cases(self):
weight_var = self.graph.var('conv1.w_0')
- self.cases.append((self.in_var, 1, {'conv1.w_0': [0, 1]}))
- self.cases.append((self.out_var, 1, {'conv1.w_0': [0, 1]}))
- self.cases.append((weight_var, 0, {'conv1.w_0': [1]}))
+ self.cases.append((self.in_var, 1, {'conv1.w_0': [0]}))
+ self.cases.append((self.out_var, 1, {'conv1.w_0': [0]}))
+ self.cases.append((weight_var, 0, {'conv1.w_0': [0]}))
def test_prune(self):
self.check_in_out()
diff --git a/tests/test_quant_post.py b/tests/test_quant_post.py
index 39c3a2fe08531c00cc1d42b74269c12f1ea11962..31eed36e2786f6566d26853e7b6f577fa8b2c417 100644
--- a/tests/test_quant_post.py
+++ b/tests/test_quant_post.py
@@ -132,8 +132,8 @@ class TestQuantAwareCase1(StaticCase):
quant_post_prog, feed_target_names, fetch_targets = paddle.fluid.io.load_inference_model(
dirname='./test_quant_post_inference',
executor=exe,
- model_filename='__model__',
- params_filename='__params__')
+ model_filename='model.pdmodel',
+ params_filename='model.pdiparams')
top1_2, top5_2 = test(quant_post_prog, fetch_targets)
print("before quantization: top1: {}, top5: {}".format(top1_1, top5_1))
print("after quantization: top1: {}, top5: {}".format(top1_2, top5_2))