Example #1
0
    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))
Example #2
0
    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]))
Example #3
0
    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))
Example #4
0
    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
Example #5
0
  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