def from_session(cls, sess, input_tensors, output_tensors): """Creates a TFLiteConverter class from a TensorFlow Session. Args: sess: TensorFlow Session. input_tensors: List of input tensors. Type and shape are computed using `foo.shape` and `foo.dtype`. output_tensors: List of output tensors (only .name is used from this). Returns: TFLiteConverter class. """ graph_def = _freeze_graph(sess, input_tensors, output_tensors) return cls(graph_def, input_tensors, output_tensors, experimental_debug_info_func=_build_debug_info_func( sess.graph))
def from_saved_model(cls, saved_model_dir, input_arrays=None, input_shapes=None, output_arrays=None, tag_set=None, signature_key=None): """Creates a TFLiteConverter class from a SavedModel. Args: saved_model_dir: SavedModel directory to convert. input_arrays: List of input tensors to freeze graph with. Uses input arrays from SignatureDef when none are provided. (default None) input_shapes: Dict of strings representing input tensor names to list of integers representing input shapes (e.g., {"foo" : [1, 16, 16, 3]}). Automatically determined when input shapes is None (e.g., {"foo" : None}). (default None) output_arrays: List of output tensors to freeze graph with. Uses output arrays from SignatureDef when none are provided. (default None) tag_set: Set of tags identifying the MetaGraphDef within the SavedModel to analyze. All tags in the tag set must be present. (default set("serve")) signature_key: Key identifying SignatureDef containing inputs and outputs. (default DEFAULT_SERVING_SIGNATURE_DEF_KEY) Returns: TFLiteConverter class. """ if tag_set is None: tag_set = set([_tag_constants.SERVING]) if signature_key is None: signature_key = _signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY result = _freeze_saved_model(saved_model_dir, input_arrays, input_shapes, output_arrays, tag_set, signature_key) return cls(graph_def=result[0], input_tensors=result[1], output_tensors=result[2], experimental_debug_info_func=_build_debug_info_func( result[3]))
def from_keras_model_file(cls, model_file, input_arrays=None, input_shapes=None, output_arrays=None, custom_objects=None): """Creates a TFLiteConverter class from a tf.keras model file. Args: model_file: Full filepath of HDF5 file containing the tf.keras model. input_arrays: List of input tensors to freeze graph with. Uses input arrays from SignatureDef when none are provided. (default None) input_shapes: Dict of strings representing input tensor names to list of integers representing input shapes (e.g., {"foo" : [1, 16, 16, 3]}). Automatically determined when input shapes is None (e.g., {"foo" : None}). (default None) output_arrays: List of output tensors to freeze graph with. Uses output arrays from SignatureDef when none are provided. (default None) custom_objects: Dict mapping names (strings) to custom classes or functions to be considered during model deserialization. (default None) Returns: TFLiteConverter class. """ # Handles Keras when Eager mode is enabled. if context.executing_eagerly(): if input_arrays or output_arrays: raise ValueError( "`input_arrays` and `output_arrays` are unsupported " "with Eager mode. If your model requires any of these " "parameters, please use disable_eager_execution().") _keras.backend.set_learning_phase(False) keras_model = _keras.models.load_model(model_file, custom_objects) function = _saving_utils.trace_model_call(keras_model) concrete_func = function.get_concrete_function() frozen_func = _convert_to_constants.convert_variables_to_constants_v2( concrete_func, lower_control_flow=False) _set_tensor_shapes(frozen_func.inputs, input_shapes) return cls(frozen_func.graph.as_graph_def(), frozen_func.inputs, frozen_func.outputs, experimental_debug_info_func=_build_debug_info_func( frozen_func.graph)) # Handles Keras when Eager mode is disabled. _keras.backend.clear_session() _keras.backend.set_learning_phase(False) keras_model = _keras.models.load_model(model_file, custom_objects) sess = _keras.backend.get_session() # Get input and output tensors. if input_arrays: input_tensors = _get_tensors_from_tensor_names( sess.graph, input_arrays) else: input_tensors = keras_model.inputs if output_arrays: output_tensors = _get_tensors_from_tensor_names( sess.graph, output_arrays) else: output_tensors = keras_model.outputs _set_tensor_shapes(input_tensors, input_shapes) graph_def = _freeze_graph(sess, input_tensors, output_tensors) return cls(graph_def, input_tensors, output_tensors, experimental_debug_info_func=_build_debug_info_func( sess.graph))
def convert(self): """Converts a TensorFlow GraphDef based on instance variables. Returns: The converted data in serialized format. Raises: ValueError: Multiple concrete functions are specified. Input shape is not specified. Invalid quantization parameters. """ # TODO(b/130297984): Add support for converting multiple function. if len(self._funcs) != 1: raise ValueError( "This converter can only convert a single " "ConcreteFunction. Converting multiple functions is " "under development.") frozen_func = _convert_to_constants.convert_variables_to_constants_v2( self._funcs[0], lower_control_flow=False) input_tensors = [ tensor for tensor in frozen_func.inputs if tensor.dtype != _dtypes.resource ] output_tensors = frozen_func.outputs # Run a Grappler pass. graph_def = frozen_func.graph.as_graph_def() graph_def = _run_graph_optimizations(graph_def, input_tensors, output_tensors, config=self._grappler_config(), graph=frozen_func.graph) # Checks dimensions in input tensor. for tensor in input_tensors: # Note that shape_list might be empty for scalar shapes. shape_list = tensor.shape.as_list() if None in shape_list[1:]: raise ValueError( "None is only supported in the 1st dimension. Tensor '{0}' has " "invalid shape '{1}'.".format(_get_tensor_name(tensor), shape_list)) elif shape_list and shape_list[0] is None: # Set the batch size to 1 if undefined. shape = tensor.shape.as_list() shape[0] = 1 tensor.set_shape(shape) self._validate_quantization() self._validate_representative_dataset() self._debug_info = _get_debug_info( _build_debug_info_func(self._funcs[0].graph), graph_def) converter_kwargs = self._get_base_converter_args() # Converts model. result = _toco_convert_impl(input_data=graph_def, input_tensors=input_tensors, output_tensors=output_tensors, **converter_kwargs) if self._is_calibration_quantize(): result = self._calibrate_quantize_model(result, constants.FLOAT, constants.FLOAT) return result
def convert(self): """Converts a TensorFlow GraphDef based on instance variables. Returns: The converted data in serialized format. Raises: ValueError: Multiple concrete functions are specified. Input shape is not specified. Invalid quantization parameters. """ # TODO(b/130297984): Add support for converting multiple function. if len(self._funcs) != 1: raise ValueError("This converter can only convert a single " "ConcreteFunction. Converting multiple functions is " "under development.") # graph_def is used here to preserve the node bug information frozen_func, graph_def = ( _convert_to_constants.convert_variables_to_constants_v2_as_graph( self._funcs[0], lower_control_flow=False)) input_tensors = [ tensor for tensor in frozen_func.inputs if tensor.dtype != _dtypes.resource ] output_tensors = frozen_func.outputs # Run a Grappler pass. graph_def = _run_graph_optimizations( graph_def, input_tensors, output_tensors, config=self._grappler_config(), graph=frozen_func.graph) # Checks dimensions in input tensor. for tensor in input_tensors: # Note that shape_list might be empty for scalar shapes. shape_list = tensor.shape.as_list() if None in shape_list[1:]: raise ValueError( "None is only supported in the 1st dimension. Tensor '{0}' has " "invalid shape '{1}'.".format(_get_tensor_name(tensor), shape_list)) elif shape_list and shape_list[0] is None: # Set the batch size to 1 if undefined. shape = tensor.shape.as_list() shape[0] = 1 tensor.set_shape(shape) self._validate_quantization() self._validate_representative_dataset() if self._trackable_obj is None: self._debug_info = _get_debug_info( _build_debug_info_func(self._funcs[0].graph), graph_def) else: self._debug_info = _get_debug_info( _convert_debug_info_func(self._trackable_obj.graph_debug_info), graph_def) converter_kwargs = self._get_base_converter_args() if not self.experimental_new_converter: logging.warning( "Please consider switching to use new converter by setting " "experimental_new_converter to true. " "Old converter (TOCO) is deprecated and flow will be switched on " "by default to use new converter soon.") else: logging.info("Using experimental converter: If you encountered a problem " "please file a bug. You can opt-out " "by setting experimental_new_converter=False") # Converts model. result = _toco_convert_impl( input_data=graph_def, input_tensors=input_tensors, output_tensors=output_tensors, **converter_kwargs) if self._is_calibration_quantize(): result = self._calibrate_quantize_model( result, constants.FLOAT, constants.FLOAT, self.experimental_new_quantizer) return result