diff --git a/doc/images/wechat_group_1.jpeg b/doc/images/wechat_group_1.jpeg index 069ebd42e06e56d7d33c575e36fc953a2e4c0488..7368e20ae84784adf1c96c4f9c12f08cada169ec 100644 Binary files a/doc/images/wechat_group_1.jpeg and b/doc/images/wechat_group_1.jpeg differ diff --git a/python/paddle_serving_app/local_predict.py b/python/paddle_serving_app/local_predict.py index 105c5c9afedd157eea3b51ec54ffd2d30890c2e7..5f922a28f849866fcd08a29b63c70a986d064c68 100644 --- a/python/paddle_serving_app/local_predict.py +++ b/python/paddle_serving_app/local_predict.py @@ -23,10 +23,13 @@ from .proto import general_model_config_pb2 as m_config import paddle.inference as paddle_infer import logging import glob +from paddle_serving_server.pipeline.error_catch import ErrorCatch, CustomException, CustomExceptionCode, ParamChecker, ParamVerify +check_dynamic_shape_info=ParamVerify.check_dynamic_shape_info logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger("LocalPredictor") logger.setLevel(logging.INFO) +from paddle_serving_server.util import kill_stop_process_by_pid precision_map = { 'int8': paddle_infer.PrecisionType.Int8, @@ -157,12 +160,12 @@ class LocalPredictor(object): "use_trt:{}, use_lite:{}, use_xpu:{}, precision:{}, use_calib:{}, " "use_mkldnn:{}, mkldnn_cache_capacity:{}, mkldnn_op_list:{}, " "mkldnn_bf16_op_list:{}, use_feed_fetch_ops:{}, " - "use_ascend_cl:{}, min_subgraph_size:{}, dynamic_shape_info:{}".format( - model_path, use_gpu, gpu_id, use_profile, thread_num, mem_optim, - ir_optim, use_trt, use_lite, use_xpu, precision, use_calib, - use_mkldnn, mkldnn_cache_capacity, mkldnn_op_list, - mkldnn_bf16_op_list, use_feed_fetch_ops, use_ascend_cl, - min_subgraph_size, dynamic_shape_info)) + "use_ascend_cl:{}, min_subgraph_size:{}, dynamic_shape_info:{}". + format(model_path, use_gpu, gpu_id, use_profile, thread_num, + mem_optim, ir_optim, use_trt, use_lite, use_xpu, precision, + use_calib, use_mkldnn, mkldnn_cache_capacity, mkldnn_op_list, + mkldnn_bf16_op_list, use_feed_fetch_ops, use_ascend_cl, + min_subgraph_size, dynamic_shape_info)) self.feed_names_ = [var.alias_name for var in model_conf.feed_var] self.fetch_names_ = [var.alias_name for var in model_conf.fetch_var] @@ -223,11 +226,20 @@ class LocalPredictor(object): use_static=False, use_calib_mode=use_calib) + @ErrorCatch + @ParamChecker + def dynamic_shape_info_helper(dynamic_shape_info:lambda dynamic_shape_info: check_dynamic_shape_info(dynamic_shape_info)): + pass + _, resp = dynamic_shape_info_helper(dynamic_shape_info) + if resp.err_no != CustomExceptionCode.OK.value: + print("dynamic_shape_info configure error, it should contain [min_input_shape', 'max_input_shape', 'opt_input_shape' {}".format(resp.err_msg)) + kill_stop_process_by_pid("kill", os.getpgid(os.getpid())) + if len(dynamic_shape_info): - config.set_trt_dynamic_shape_info( - dynamic_shape_info['min_input_shape'], - dynamic_shape_info['max_input_shape'], - dynamic_shape_info['opt_input_shape']) + config.set_trt_dynamic_shape_info( + dynamic_shape_info['min_input_shape'], + dynamic_shape_info['max_input_shape'], + dynamic_shape_info['opt_input_shape']) # set lite if use_lite: config.enable_lite_engine( @@ -269,7 +281,18 @@ class LocalPredictor(object): if mkldnn_bf16_op_list is not None: config.set_bfloat16_op(mkldnn_bf16_op_list) - self.predictor = paddle_infer.create_predictor(config) + @ErrorCatch + def create_predictor_check(config): + predictor = paddle_infer.create_predictor(config) + return predictor + predictor, resp = create_predictor_check(config) + if resp.err_no != CustomExceptionCode.OK.value: + logger.critical( + "failed to create predictor: {}".format(resp.err_msg), + exc_info=False) + print("failed to create predictor: {}".format(resp.err_msg)) + kill_stop_process_by_pid("kill", os.getpgid(os.getpid())) + self.predictor = predictor def predict(self, feed=None, fetch=None, batch=False, log_id=0): """ @@ -315,7 +338,8 @@ class LocalPredictor(object): # Assemble the input data of paddle predictor, and filter invalid inputs. input_names = self.predictor.get_input_names() for name in input_names: - if isinstance(feed[name], list): + if isinstance(feed[name], list) and not isinstance(feed[name][0], + str): feed[name] = np.array(feed[name]).reshape(self.feed_shapes_[ name]) if self.feed_types_[name] == 0: @@ -342,6 +366,9 @@ class LocalPredictor(object): feed[name] = feed[name].astype("complex64") elif self.feed_types_[name] == 11: feed[name] = feed[name].astype("complex128") + elif isinstance(feed[name], list) and isinstance(feed[name][0], + str): + pass else: raise ValueError("local predictor receives wrong data type") diff --git a/python/paddle_serving_client/io/__init__.py b/python/paddle_serving_client/io/__init__.py index 970ab144ada1d2e3e6a18b72ae9a40db289eef14..a601d9a3881005bb9c1e64e80a41d211189a34a6 100644 --- a/python/paddle_serving_client/io/__init__.py +++ b/python/paddle_serving_client/io/__init__.py @@ -211,8 +211,10 @@ def save_model(server_model_folder, new_params_path = os.path.join(server_model_folder, params_filename) with open(new_model_path, "wb") as new_model_file: - new_model_file.write(main_program._remove_training_info(False).desc.serialize_to_string()) - + new_model_file.write( + main_program._remove_training_info(False) + .desc.serialize_to_string()) + paddle.static.save_vars( executor=executor, dirname=server_model_folder, @@ -231,7 +233,8 @@ def save_model(server_model_folder, key = CipherUtils.gen_key_to_file(128, "key") params = fluid.io.save_persistables( executor=executor, dirname=None, main_program=main_program) - model = main_program._remove_training_info(False).desc.serialize_to_string() + model = main_program._remove_training_info( + False).desc.serialize_to_string() if not os.path.exists(server_model_folder): os.makedirs(server_model_folder) os.chdir(server_model_folder) @@ -248,15 +251,20 @@ def save_model(server_model_folder, fetch_alias = target_var_names else: fetch_alias = fetch_alias_names.split(',') - if len(feed_alias) != len(feed_var_dict.keys()) or len(fetch_alias) != len(target_var_names): - raise ValueError("please check the input --feed_alias_names and --fetch_alias_names, should be same size with feed_vars and fetch_vars") + if len(feed_alias) != len(feed_var_dict.keys()) or len(fetch_alias) != len( + target_var_names): + raise ValueError( + "please check the input --feed_alias_names and --fetch_alias_names, should be same size with feed_vars and fetch_vars" + ) for i, key in enumerate(feed_var_dict): feed_var = model_conf.FeedVar() feed_var.alias_name = feed_alias[i] feed_var.name = feed_var_dict[key].name feed_var.feed_type = var_type_conversion(feed_var_dict[key].dtype) - feed_var.is_lod_tensor = feed_var_dict[key].lod_level >= 1 + feed_var.is_lod_tensor = feed_var_dict[ + key].lod_level >= 1 if feed_var_dict[ + key].lod_level is not None else False if feed_var.is_lod_tensor: feed_var.shape.extend([-1]) else: @@ -331,7 +339,8 @@ def inference_model_to_serving(dirname, fetch_dict = {x.name: x for x in fetch_targets} save_model(serving_server, serving_client, feed_dict, fetch_dict, inference_program, encryption, key_len, encrypt_conf, - model_filename, params_filename, show_proto, feed_alias_names, fetch_alias_names) + model_filename, params_filename, show_proto, feed_alias_names, + fetch_alias_names) feed_names = feed_dict.keys() fetch_names = fetch_dict.keys() return feed_names, fetch_names diff --git a/python/pipeline/channel.py b/python/pipeline/channel.py index 9ef1c09c48d4c851faf16c2621a0fa1dc561c201..8df5a6259f8a2b3c7048771c73e7d802b94ba8b7 100644 --- a/python/pipeline/channel.py +++ b/python/pipeline/channel.py @@ -34,6 +34,7 @@ from .error_catch import CustomExceptionCode as ChannelDataErrcode _LOGGER = logging.getLogger(__name__) + class ChannelDataType(enum.Enum): """ Channel data type @@ -167,7 +168,8 @@ class ChannelData(object): elif isinstance(npdata, dict): # batch_size = 1 for _, value in npdata.items(): - if not isinstance(value, np.ndarray): + if not isinstance(value, np.ndarray) and not (isinstance( + value, list) and isinstance(value[0], str)): error_code = ChannelDataErrcode.TYPE_ERROR.value error_info = "Failed to check data: the value " \ "of data must be np.ndarray, but get {}.".format( diff --git a/python/pipeline/error_catch.py b/python/pipeline/error_catch.py index 4860e8ab8eb522c6c2bcfcf5aaf54176f774a70a..52beedbef80300c5022f7845bf4aafd50156bde1 100644 --- a/python/pipeline/error_catch.py +++ b/python/pipeline/error_catch.py @@ -227,5 +227,17 @@ class ParamVerify(object): if key not in right_fetch_list: return False return True + + @staticmethod + def check_dynamic_shape_info(dynamic_shape_info): + if not isinstance(dynamic_shape_info, dict): + return False + if len(dynamic_shape_info) == 0: + return True + shape_info_keys = ["min_input_shape", "max_input_shape", "opt_input_shape"] + if all(key in dynamic_shape_info for key in shape_info_keys): + return True + else: + return False ErrorCatch = ErrorCatch() diff --git a/python/pipeline/operator.py b/python/pipeline/operator.py index cd3b54d90290cbca4a3c151ef7521b09f15e739f..9407717a49f54efc982b098ca9dc9008f9713c53 100644 --- a/python/pipeline/operator.py +++ b/python/pipeline/operator.py @@ -46,6 +46,7 @@ from .util import NameGenerator from .profiler import UnsafeTimeProfiler as TimeProfiler from . import local_service_handler from .pipeline_client import PipelineClient as PPClient +from paddle_serving_server.util import kill_stop_process_by_pid _LOGGER = logging.getLogger(__name__) _op_name_gen = NameGenerator("Op") @@ -1328,7 +1329,12 @@ class Op(object): # init ops profiler = None - try: + @ErrorCatch + def check_helper(self, is_thread_op, model_config, workdir, + thread_num, device_type, devices, mem_optim, ir_optim, + precision, use_mkldnn, mkldnn_cache_capacity, mkldnn_op_list, + mkldnn_bf16_op_list, min_subgraph_size, dynamic_shape_info): + if is_thread_op == False and self.client_type == "local_predictor": self.service_handler = local_service_handler.LocalServiceHandler( model_config=model_config, @@ -1354,12 +1360,21 @@ class Op(object): concurrency_idx) # check all ops initialized successfully. profiler = self._initialize(is_thread_op, concurrency_idx) + return profiler - except Exception as e: + profiler, resp = check_helper(self, is_thread_op, model_config, workdir, + thread_num, device_type, devices, mem_optim, ir_optim, + precision, use_mkldnn, mkldnn_cache_capacity, mkldnn_op_list, + mkldnn_bf16_op_list, min_subgraph_size, dynamic_shape_info) + + if resp.err_no != CustomExceptionCode.OK.value: _LOGGER.critical( - "{} failed to init op: {}".format(op_info_prefix, e), - exc_info=True) - os._exit(-1) + "{} failed to init op: {}".format(op_info_prefix, resp.err_msg), + exc_info=False) + + print("{} failed to init op: {}".format(op_info_prefix, resp.err_msg)) + kill_stop_process_by_pid("kill", os.getpgid(os.getpid())) + _LOGGER.info("{} Succ init".format(op_info_prefix)) batch_generator = self._auto_batching_generator(