Files
wehub-resource-sync 2aaeece67c
Codestyle Check / Lint (push) Has been cancelled
Codestyle Check / Check bypass (push) Has been cancelled
Pipelines-Test / Pipelines-Test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:14 +08:00

209 lines
9.2 KiB
Python

# coding:utf-8
# 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 math
import os
import sys
import threading
from multiprocessing import cpu_count
import paddle
from ..utils.env import PADDLE_INFERENCE_MODEL_SUFFIX, PADDLE_INFERENCE_WEIGHTS_SUFFIX
from ..utils.log import logger
class Predictor:
def __init__(self, model_path, precision, device):
self._model_path = model_path
self._default_static_model_path = "auto_static"
self._precision = precision
self._cpu_thread = 8
self._config = None
self._device = device
self._num_threads = math.ceil(cpu_count() / 2)
self._output_num = 1
paddle.set_device(device)
self._create_predictor()
self._lock = threading.Lock()
def _get_default_static_model_path(self):
# The model path had the static_model_path
static_model_path = os.path.join(
self._model_path, self._default_static_model_path, f"inference{PADDLE_INFERENCE_MODEL_SUFFIX}"
)
if os.path.exists(static_model_path):
return os.path.join(self._model_path, self._default_static_model_path, "inference")
for file_name in os.listdir(self._model_path):
# FIXME(wawltor) The path maybe not correct
if file_name.count(PADDLE_INFERENCE_MODEL_SUFFIX):
return os.path.join(self._model_path, file_name[: -len(PADDLE_INFERENCE_MODEL_SUFFIX)])
return None
def _is_int8_model(self, model_path):
paddle.set_device("cpu")
model = paddle.jit.load(model_path)
program = model.program()
for block in program.blocks:
for i, op in enumerate(block.ops):
if op.type.count("quantize"):
paddle.set_device(self._device)
return True
paddle.set_device(self._device)
return False
def _create_predictor(self):
# Get the model parameter path and model config path
static_model_path = self._get_default_static_model_path()
# Convert the Draph Model to Static Model
if static_model_path is None:
raise RuntimeError("The model path do not include the inference model, please check!")
is_int8_model = self._is_int8_model(static_model_path)
# Load the inference model and maybe we will convert the onnx model
# Judge the predictor type for the inference
if self._precision == "int8" and not is_int8_model:
self._precision = "fp32"
if is_int8_model:
self._precision = "int8"
self._predictor_type = self._check_predictor_type()
if self._predictor_type == "paddle_inference":
self._prepare_paddle_mode(static_model_path)
else:
self._prepare_onnx_mode(static_model_path)
def _check_predictor_type(self):
predictor_type = "paddle_inference"
device = paddle.get_device()
if self._precision == "int8" or device == "xpu" or device == "cpu":
predictor_type = "paddle_inference"
else:
if device.count("gpu") and self._precision == "fp16":
try:
import onnx # noqa F401
import onnxruntime as ort # noqa F401
import paddle2onnx # noqa F401
from onnxconverter_common import float16 # noqa F401
predictor_type = "onnxruntime"
except Exception:
logger.error(
"The inference precision is change to 'fp32', please install the dependencies that required for 'fp16' inference, you could use the commands as fololws:\n"
" ****** pip uninstall onnxruntime ******\n"
" ****** pip install onnxruntime-gpu onnx onnxconverter-common ******"
)
sys.exit(-1)
return predictor_type
def _prepare_paddle_mode(self, static_model_path):
"""
Construct the input data and predictor in the PaddlePaddele static mode.
"""
self._config = paddle.inference.Config(
static_model_path + PADDLE_INFERENCE_MODEL_SUFFIX,
static_model_path + PADDLE_INFERENCE_WEIGHTS_SUFFIX,
)
self._config.disable_glog_info()
if paddle.get_device() == "cpu":
self._config.disable_gpu()
self._config.enable_mkldnn()
self._config.enable_memory_optim()
if self._precision == "int8":
self._config.enable_mkldnn_bfloat16()
elif self._precision == "fp16":
self._config.enable_mkldnn_int8()
else:
self._config.enable_use_gpu(100, int(self._device.split(":")[-1]))
if self._precision == "int8":
# FIXME(wawltor) The paddlenlp serving support the int8 model
logger.warning("The PaddleNLP serving do not support the INT8 model, we will support later!")
sys.exit(-1)
self._config.switch_use_feed_fetch_ops(False)
self._config.set_cpu_math_library_num_threads(self._num_threads)
self._config.delete_pass("embedding_eltwise_layernorm_fuse_pass")
self._predictor = paddle.inference.create_predictor(self._config)
self._input_handles = [self._predictor.get_input_handle(name) for name in self._predictor.get_input_names()]
self._output_handles = [self._predictor.get_output_handle(name) for name in self._predictor.get_output_names()]
self._output_num = len(self._output_handles)
def _prepare_onnx_mode(self, static_model_path):
import onnx
import onnxruntime as ort
import paddle2onnx
from onnxconverter_common import float16
onnx_dir = os.path.join(self._model_path, "onnx")
if not os.path.exists(onnx_dir):
os.mkdir(onnx_dir)
float_onnx_file = os.path.join(onnx_dir, "model.onnx")
if not os.path.exists(float_onnx_file):
model_path = static_model_path + PADDLE_INFERENCE_MODEL_SUFFIX
params_file = static_model_path + ".pdiparams"
onnx_model = paddle2onnx.command.c_paddle_to_onnx(
model_file=model_path, params_file=params_file, opset_version=13, enable_onnx_checker=True
)
with open(float_onnx_file, "wb") as f:
f.write(onnx_model)
fp16_model_file = os.path.join(onnx_dir, "fp16_model.onnx")
if not os.path.exists(fp16_model_file):
onnx_model = onnx.load_model(float_onnx_file)
trans_model = float16.convert_float_to_float16(onnx_model, keep_io_types=True)
onnx.save_model(trans_model, fp16_model_file)
providers = ["CUDAExecutionProvider"]
sess_options = ort.SessionOptions()
sess_options.inter_op_num_threads = self._num_threads
device_id = int(self._device.split(":")[-1])
self._predictor = ort.InferenceSession(
fp16_model_file,
sess_options=sess_options,
providers=providers,
provider_options=[{"device_id": device_id}],
)
self._output_num = len(self._predictor.get_outputs())
assert "CUDAExecutionProvider" in self._predictor.get_providers(), (
"The environment for GPU inference is not set properly. "
"A possible cause is that you had installed both onnxruntime and onnxruntime-gpu. "
"Please run the following commands to reinstall: \n "
"1) pip uninstall -y onnxruntime onnxruntime-gpu \n 2) pip install onnxruntime-gpu"
)
def _convert_dygraph_to_static(self, model_instance, input_spec):
"""
Convert the dygraph model to static model.
"""
assert (
model_instance is not None
), "The dygraph model must be created before converting the dygraph model to static model."
assert (
input_spec is not None
), "The input spec must be created before converting the dygraph model to static model."
logger.info(
"Converting to the static inference model will cost a little time, please do not break this process."
)
try:
static_model = paddle.jit.to_static(model_instance, input_spec=input_spec)
save_path = os.path.join(self._model_path, self._default_static_model_path, "inference")
paddle.jit.save(static_model, save_path)
logger.info("The static inference model save in the path:{}".format(save_path))
except Exception:
logger.warning(
"Fail convert to inference model, please create the issue for the developers,"
"the issue link: https://github.com/PaddlePaddle/PaddleNLP/issues"
)
sys.exit(-1)