//  [python]
def load_saved_model(model, saved_model_tags, input_tensor_names, output_tensor_names):  # pragma: no cover
    """Load graph_def from saved model with the default serving signature key.

    Args:
        model: Directory of the SavedModel.
        saved_model_tags: Set of tags identifying the MetaGraphDef within the
            SavedModel to analyze.
        input_tensor_names (list of string): input_tensor_names of model.
        output_tensor_names (list of string): output_tensor_names of model.

    Returns:
        graph_def: The loaded GraphDef.
        input_tensors: List of input tensors.
        output_tensors: List of output tensors.
    """
    config = tf.compat.v1.ConfigProto()
    config.use_per_session_threads = 1
    config.inter_op_parallelism_threads = 1
    if not os.listdir(os.path.join(model, "variables")):
        sess = tf.compat.v1.Session(graph=tf.Graph(), config=config)
        loader = tf.saved_model.load(model, tags=["serve"])
        if len(input_tensor_names) == 0:
            input_tensor_names = [i.name for _, i in loader.signature_def["serving_default"].inputs.items()]
        else:
            assert validate_graph_node(
                sess.graph.as_graph_def(), tensor_to_node(input_tensor_names)
            ), "tensor names {} not in the graph".format(input_tensor_names)

        if len(output_tensor_names) == 0:
            output_tensor_names = [i.name for _, i in loader.signature_def["serving_default"].outputs.items()]
        else:
            assert validate_graph_node(
                sess.graph.as_graph_def(), tensor_to_node(output_tensor_names)
            ), "tensor names {} not in the graph".format(output_tensor_names)

        return sess.graph.as_graph_def(), input_tensor_names, output_tensor_names
    else:
        from tensorflow.core.protobuf import config_pb2, meta_graph_pb2
        from tensorflow.python.eager import context
        from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2
        from tensorflow.python.grappler import tf_optimizer
        from tensorflow.python.saved_model import load, signature_constants, tag_constants
        from tensorflow.python.training import saver

        _saved_model = load.load(model, [tag_constants.SERVING])
        func = _saved_model.signatures[signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY]
        frozen_func = convert_variables_to_constants_v2(func)
        grappler_meta_graph_def = saver.export_meta_graph(
            graph_def=frozen_func.graph.as_graph_def(), graph=frozen_func.graph
        )
        if len(input_tensor_names) == 0:
            input_tensor_names = [i.name.split(":")[0] for i in frozen_func.inputs]
        if len(output_tensor_names) == 0:
            output_tensor_names = [i.name.split(":")[0] for i in frozen_func.outputs]
        # Add a collection 'train_op' so that Grappler knows the outputs.
        fetch_collection = meta_graph_pb2.CollectionDef()
        for array in frozen_func.inputs + frozen_func.outputs:
            fetch_collection.node_list.value.append(array.name)
            grappler_meta_graph_def.collection_def["train_op"].CopyFrom(fetch_collection)
        grappler_session_config = config_pb2.ConfigProto()
        rewrite_options = grappler_session_config.graph_options.rewrite_options
        rewrite_options.min_graph_nodes = -1
        opt = tf_optimizer.OptimizeGraph(grappler_session_config, grappler_meta_graph_def, graph_id=b"tf_graph")
        return opt, input_tensor_names, output_tensor_names