未验证 提交 e8e77ebe 编写于 作者: L lidanqing 提交者: GitHub

Add quant2 int8 lstm model test (#35887) (#35912)

Co-authored-by: Njoanna.wozna.intel <joanna.wozna@intel.com>
上级 c67cf85d
...@@ -93,7 +93,8 @@ class Quant2Int8MkldnnPass(object): ...@@ -93,7 +93,8 @@ class Quant2Int8MkldnnPass(object):
graph = self._dequantize_weights(graph) graph = self._dequantize_weights(graph)
graph = self._optimize_fp32_graph(graph) graph = self._optimize_fp32_graph(graph)
graph = self._compute_weight_scales(graph) graph = self._compute_weight_scales(graph)
graph = self._update_relu_output_scales(graph) # This function causes nondeterministic quantization behavior
# graph = self._update_relu_output_scales(graph)
graph = self._propagate_scales(graph) graph = self._propagate_scales(graph)
graph = self._quantize_fp32_graph(graph) graph = self._quantize_fp32_graph(graph)
graph = self._final_optimizations(graph) graph = self._final_optimizations(graph)
......
...@@ -92,17 +92,14 @@ function(inference_quant2_int8_nlp_test target quant_model_dir fp32_model_dir da ...@@ -92,17 +92,14 @@ function(inference_quant2_int8_nlp_test target quant_model_dir fp32_model_dir da
--ops_to_quantize ${ops_to_quantize}) --ops_to_quantize ${ops_to_quantize})
endfunction() endfunction()
function(inference_quant2_int8_lstm_model_test target fp32_model dataset_path) function(inference_quant2_int8_lstm_model_test target fp32_model quant_model dataset_path)
py_test(${target} SRCS "${CMAKE_CURRENT_SOURCE_DIR}/quant2_int8_lstm_model.py" py_test(${target} SRCS "${CMAKE_CURRENT_SOURCE_DIR}/quant2_int8_lstm_model.py"
ENVS FLAGS_OMP_NUM_THREADS=${CPU_NUM_THREADS_ON_CI}
OMP_NUM_THREADS=${CPU_NUM_THREADS_ON_CI}
FLAGS_use_mkldnn=true
ARGS --fp32_model ${fp32_model} ARGS --fp32_model ${fp32_model}
--quant_model ${quant_model}
--infer_data ${dataset_path} --infer_data ${dataset_path}
--num_threads 4 --num_threads 1
--mkldnn_cache_capacity 100 --mkldnn_cache_capacity 100
--warmup_iter 100 --warmup_iter 100
--warmup_batch_size 1
--acc_diff_threshold 0.11) --acc_diff_threshold 0.11)
endfunction() endfunction()
...@@ -293,11 +290,10 @@ if(LINUX AND WITH_MKLDNN) ...@@ -293,11 +290,10 @@ if(LINUX AND WITH_MKLDNN)
# PTQ int8 lstm model # PTQ int8 lstm model
set(LSTM_DATA_ARCHIVE "unittest_model_data/quant_lstm_input_data.tar.gz") set(LSTM_DATA_ARCHIVE "unittest_model_data/quant_lstm_input_data.tar.gz")
set(QUANT2_INT8_LSTM_SAVE_PATH "${QUANT_INSTALL_DIR}/lstm_quant2")
download_quant_data(${QUANT2_INT8_LSTM_SAVE_PATH} ${LSTM_DATA_ARCHIVE} add84c754e9b792fea1fbd728d134ab7) download_quant_data(${QUANT2_INT8_LSTM_SAVE_PATH} ${LSTM_DATA_ARCHIVE} add84c754e9b792fea1fbd728d134ab7)
set(QUANT2_FP32_LSTM_MODEL_ARCHIVE "lstm_fp32_model.tar.gz") set(QUANT2_FP32_LSTM_MODEL_ARCHIVE "lstm_fp32_model.tar.gz")
download_lstm_model(${QUANT2_INT8_LSTM_SAVE_PATH} ${QUANT2_FP32_LSTM_MODEL_ARCHIVE} eecd9f44d69a84acc1cf2235c4b8b743) download_lstm_model(${QUANT2_INT8_LSTM_SAVE_PATH} ${QUANT2_FP32_LSTM_MODEL_ARCHIVE} eecd9f44d69a84acc1cf2235c4b8b743)
inference_quant2_int8_lstm_model_test(test_quant2_int8_lstm_mkldnn ${QUANT2_INT8_LSTM_SAVE_PATH}/lstm_fp32_model ${QUANT2_INT8_LSTM_SAVE_PATH}/quant_lstm_input_data) inference_quant2_int8_lstm_model_test(test_quant2_int8_lstm_mkldnn ${QUANT2_INT8_LSTM_SAVE_PATH}/lstm_fp32_model ${QUANT2_LSTM_MODEL_DIR}/lstm_quant ${QUANT2_INT8_LSTM_SAVE_PATH}/quant_lstm_input_data)
endif() endif()
......
...@@ -20,30 +20,28 @@ import time ...@@ -20,30 +20,28 @@ import time
import unittest import unittest
from paddle import fluid from paddle import fluid
from paddle.fluid.core import AnalysisConfig, create_paddle_predictor from paddle.fluid.core import AnalysisConfig, create_paddle_predictor
from save_quant_model import transform_and_save_int8_model
def parse_args(): def parse_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
'--fp32_model', type=str, default='', help='A path to a FP32 model.') '--fp32_model', type=str, default='', help='A path to a FP32 model.')
parser.add_argument('--infer_data', type=str, default='', help='Data file.')
parser.add_argument( parser.add_argument(
'--num_threads', type=int, default=1, help='Number of threads.') '--quant_model', type=str, default='', help='A path to a quant model.')
parser.add_argument('--infer_data', type=str, default='', help='Data file.')
parser.add_argument( parser.add_argument(
'--warmup_iter', '--warmup_iter',
type=int, type=int,
default=1, default=1,
help='Number of the first iterations to skip in performance statistics.') help='Number of the first iterations to skip in performance statistics.')
parser.add_argument(
'--warmup_batch_size',
type=int,
default=1,
help='Number of batches to use in PTQ warmup. Default: 1.')
parser.add_argument( parser.add_argument(
'--acc_diff_threshold', '--acc_diff_threshold',
type=float, type=float,
default=0.01, default=0.01,
help='Accepted accuracy difference threshold.') help='Accepted accuracy difference threshold.')
parser.add_argument(
'--num_threads', type=int, default=1, help='Number of threads.')
parser.add_argument( parser.add_argument(
'--mkldnn_cache_capacity', '--mkldnn_cache_capacity',
type=int, type=int,
...@@ -56,7 +54,7 @@ def parse_args(): ...@@ -56,7 +54,7 @@ def parse_args():
class TestLstmModelPTQ(unittest.TestCase): class TestLstmModelPTQ(unittest.TestCase):
def get_warmup_tensor(self, data_path, place, warmup_batch_size): def get_warmup_tensor(self, data_path, place):
data = [] data = []
with open(data_path, 'rb') as in_f: with open(data_path, 'rb') as in_f:
while True: while True:
...@@ -87,30 +85,31 @@ class TestLstmModelPTQ(unittest.TestCase): ...@@ -87,30 +85,31 @@ class TestLstmModelPTQ(unittest.TestCase):
infer_label.shape = label.shape infer_label.shape = label.shape
infer_label.dtype = fluid.core.PaddleDType.INT32 infer_label.dtype = fluid.core.PaddleDType.INT32
data.append([infer_data, infer_label]) data.append([infer_data, infer_label])
warmup_data = data[:warmup_batch_size] warmup_data = data[:1]
inputs = data[warmup_batch_size:] inputs = data[1:]
return warmup_data, inputs return warmup_data, inputs
def set_config(self, def set_config(self,
model_path, model_path,
num_threads, num_threads,
mkldnn_cache_capacity, mkldnn_cache_capacity,
warmup_batch_size,
warmup_data=None, warmup_data=None,
enable_int8=False): use_analysis=False,
enable_ptq=False):
config = AnalysisConfig(model_path) config = AnalysisConfig(model_path)
config.set_cpu_math_library_num_threads(num_threads)
if use_analysis:
config.disable_gpu() config.disable_gpu()
config.switch_use_feed_fetch_ops(True) config.switch_use_feed_fetch_ops(True)
config.switch_ir_optim(True) config.switch_ir_optim(True)
config.set_cpu_math_library_num_threads(num_threads)
# This pass to work properly, must be added before fc_fuse_pass
config.pass_builder().insert_pass(5, "fc_lstm_fuse_pass")
config.enable_mkldnn() config.enable_mkldnn()
config.set_mkldnn_cache_capacity(mkldnn_cache_capacity) config.set_mkldnn_cache_capacity(mkldnn_cache_capacity)
if enable_int8: if enable_ptq:
# This pass to work properly, must be added before fc_fuse_pass
config.pass_builder().insert_pass(5, "fc_lstm_fuse_pass")
config.enable_quantizer() config.enable_quantizer()
config.quantizer_config().set_quant_data(warmup_data) config.quantizer_config().set_quant_data(warmup_data)
config.quantizer_config().set_quant_batch_size(warmup_batch_size) config.quantizer_config().set_quant_batch_size(1)
return config return config
def run_program(self, def run_program(self,
...@@ -119,15 +118,13 @@ class TestLstmModelPTQ(unittest.TestCase): ...@@ -119,15 +118,13 @@ class TestLstmModelPTQ(unittest.TestCase):
num_threads, num_threads,
mkldnn_cache_capacity, mkldnn_cache_capacity,
warmup_iter, warmup_iter,
warmup_batch_size, use_analysis=False,
enable_ptq_int8=False): enable_ptq=False):
place = fluid.CPUPlace() place = fluid.CPUPlace()
warmup_data, inputs = self.get_warmup_tensor(data_path, place, warmup_data, inputs = self.get_warmup_tensor(data_path, place)
warmup_batch_size)
warmup_data = [item[0] for item in warmup_data] warmup_data = [item[0] for item in warmup_data]
config = self.set_config(model_path, num_threads, mkldnn_cache_capacity, config = self.set_config(model_path, num_threads, mkldnn_cache_capacity,
warmup_batch_size, warmup_data, warmup_data, use_analysis, enable_ptq)
enable_ptq_int8)
predictor = create_paddle_predictor(config) predictor = create_paddle_predictor(config)
data = [item[0] for item in inputs] data = [item[0] for item in inputs]
...@@ -183,34 +180,47 @@ class TestLstmModelPTQ(unittest.TestCase): ...@@ -183,34 +180,47 @@ class TestLstmModelPTQ(unittest.TestCase):
fp32_model = test_case_args.fp32_model fp32_model = test_case_args.fp32_model
assert fp32_model, 'The FP32 model path cannot be empty. Please, use the --fp32_model option.' assert fp32_model, 'The FP32 model path cannot be empty. Please, use the --fp32_model option.'
quant_model = test_case_args.quant_model
assert quant_model, 'The quant model path cannot be empty. Please, use the --quant_model option.'
infer_data = test_case_args.infer_data infer_data = test_case_args.infer_data
assert infer_data, 'The dataset path cannot be empty. Please, use the --infer_data option.' assert infer_data, 'The dataset path cannot be empty. Please, use the --infer_data option.'
num_threads = test_case_args.num_threads num_threads = test_case_args.num_threads
mkldnn_cache_capacity = test_case_args.mkldnn_cache_capacity mkldnn_cache_capacity = test_case_args.mkldnn_cache_capacity
warmup_iter = test_case_args.warmup_iter warmup_iter = test_case_args.warmup_iter
warmup_batch_size = test_case_args.warmup_batch_size
acc_diff_threshold = test_case_args.acc_diff_threshold acc_diff_threshold = test_case_args.acc_diff_threshold
(fp32_hx_acc, fp32_ctc_acc, fp32_fps) = self.run_program( (fp32_hx_acc, fp32_ctc_acc, fp32_fps) = self.run_program(
fp32_model, infer_data, num_threads, mkldnn_cache_capacity, fp32_model, infer_data, num_threads, mkldnn_cache_capacity,
warmup_iter, warmup_batch_size, False) warmup_iter, False, False)
(int8_hx_acc, int8_ctc_acc, int8_fps) = self.run_program( (int8_hx_acc, int8_ctc_acc, int8_fps) = self.run_program(
fp32_model, infer_data, num_threads, mkldnn_cache_capacity, fp32_model, infer_data, num_threads, mkldnn_cache_capacity,
warmup_iter, warmup_batch_size, True) warmup_iter, True, True)
quant_model_save_path = quant_model + "_int8"
# transform model to quant2
transform_and_save_int8_model(quant_model, quant_model_save_path,
"fusion_lstm,concat")
print("FP32: fps {0}, hx_acc {1}, ctc_acc {2}.".format( (quant_hx_acc, quant_ctc_acc, quant_fps) = self.run_program(
quant_model_save_path, infer_data, num_threads,
mkldnn_cache_capacity, warmup_iter, True, False)
print("FP32: fps {0}, hx_acc {1}, ctc_acc {2}".format(
fp32_fps, fp32_hx_acc, fp32_ctc_acc)) fp32_fps, fp32_hx_acc, fp32_ctc_acc))
print("PTQ INT8: fps {0}, hx_acc {1}, ctc_acc {2}.".format( print("PTQ_INT8: fps {0}, hx_acc {1}, ctc_acc {2}".format(
int8_fps, int8_hx_acc, int8_ctc_acc)) int8_fps, int8_hx_acc, int8_ctc_acc))
print("QUANT2_INT8: fps {0}, hx_acc {1}, ctc_acc {2}".format(
quant_fps, quant_hx_acc, quant_ctc_acc))
sys.stdout.flush() sys.stdout.flush()
hx_delta_value = fp32_hx_acc - int8_hx_acc self.assertLess(fp32_hx_acc - int8_hx_acc, acc_diff_threshold)
ctc_delta_value = fp32_ctc_acc - int8_ctc_acc self.assertLess(fp32_ctc_acc - int8_ctc_acc, acc_diff_threshold)
self.assertLess(hx_delta_value, acc_diff_threshold) self.assertLess(fp32_hx_acc - quant_hx_acc, acc_diff_threshold)
self.assertLess(ctc_delta_value, acc_diff_threshold) self.assertLess(fp32_ctc_acc - quant_ctc_acc, acc_diff_threshold)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -16,11 +16,6 @@ import unittest ...@@ -16,11 +16,6 @@ import unittest
import os import os
import sys import sys
import argparse import argparse
import logging
import struct
import six
import numpy as np
import time
import paddle import paddle
import paddle.fluid as fluid import paddle.fluid as fluid
from paddle.fluid.framework import IrGraph from paddle.fluid.framework import IrGraph
...@@ -62,7 +57,11 @@ def parse_args(): ...@@ -62,7 +57,11 @@ def parse_args():
return test_args, sys.argv[:1] + args return test_args, sys.argv[:1] + args
def transform_and_save_int8_model(original_path, save_path): def transform_and_save_int8_model(original_path,
save_path,
ops_to_quantize='',
op_ids_to_skip='',
debug=False):
place = fluid.CPUPlace() place = fluid.CPUPlace()
exe = fluid.Executor(place) exe = fluid.Executor(place)
inference_scope = fluid.executor.global_scope() inference_scope = fluid.executor.global_scope()
...@@ -75,24 +74,26 @@ def transform_and_save_int8_model(original_path, save_path): ...@@ -75,24 +74,26 @@ def transform_and_save_int8_model(original_path, save_path):
fetch_targets] = fluid.io.load_inference_model(original_path, exe, fetch_targets] = fluid.io.load_inference_model(original_path, exe,
'model', 'params') 'model', 'params')
ops_to_quantize = set() ops_to_quantize_set = set()
if len(test_args.ops_to_quantize) > 0: print(ops_to_quantize)
ops_to_quantize = set(test_args.ops_to_quantize.split(',')) if len(ops_to_quantize) > 0:
ops_to_quantize_set = set(ops_to_quantize.split(','))
op_ids_to_skip = set([-1]) op_ids_to_skip_set = set([-1])
if len(test_args.op_ids_to_skip) > 0: print(op_ids_to_skip)
op_ids_to_skip = set(map(int, test_args.op_ids_to_skip.split(','))) if len(op_ids_to_skip) > 0:
op_ids_to_skip_set = set(map(int, op_ids_to_skip.split(',')))
graph = IrGraph(core.Graph(inference_program.desc), for_test=True) graph = IrGraph(core.Graph(inference_program.desc), for_test=True)
if (test_args.debug): if (debug):
graph.draw('.', 'quant_orig', graph.all_op_nodes()) graph.draw('.', 'quant_orig', graph.all_op_nodes())
transform_to_mkldnn_int8_pass = Quant2Int8MkldnnPass( transform_to_mkldnn_int8_pass = Quant2Int8MkldnnPass(
ops_to_quantize, ops_to_quantize_set,
_op_ids_to_skip=op_ids_to_skip, _op_ids_to_skip=op_ids_to_skip_set,
_scope=inference_scope, _scope=inference_scope,
_place=place, _place=place,
_core=core, _core=core,
_debug=test_args.debug) _debug=debug)
graph = transform_to_mkldnn_int8_pass.apply(graph) graph = transform_to_mkldnn_int8_pass.apply(graph)
inference_program = graph.to_program() inference_program = graph.to_program()
with fluid.scope_guard(inference_scope): with fluid.scope_guard(inference_scope):
...@@ -106,5 +107,6 @@ def transform_and_save_int8_model(original_path, save_path): ...@@ -106,5 +107,6 @@ def transform_and_save_int8_model(original_path, save_path):
if __name__ == '__main__': if __name__ == '__main__':
global test_args global test_args
test_args, remaining_args = parse_args() test_args, remaining_args = parse_args()
transform_and_save_int8_model(test_args.quant_model_path, transform_and_save_int8_model(
test_args.int8_model_save_path) test_args.quant_model_path, test_args.int8_model_save_path,
test_args.ops_to_quantize, test_args.op_ids_to_skip, test_args.debug)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册