PINTO0309 / openvino2tensorflow

This script converts the ONNX/OpenVINO IR model to Tensorflow's saved_model, tflite, h5, tfjs, tftrt(TensorRT), CoreML, EdgeTPU, ONNX and pb. PyTorch (NCHW) -> ONNX (NCHW) -> OpenVINO (NCHW) -> openvino2tensorflow -> Tensorflow/Keras (NHWC/NCHW) -> TFLite (NHWC/NCHW). And the conversion from .pb to saved_model and from saved_model to .pb and from .pb to .tflite and saved_model to .tflite and saved_model to onnx. Support for building environments with Docker. It is possible to directly access the host PC GUI and the camera to verify the operation. NVIDIA GPU (dGPU) support. Intel iHD GPU (iGPU) support.
MIT License
334 stars 40 forks source link

Movenet conversion #66

Closed lee-man closed 3 years ago

lee-man commented 3 years ago

1. OS you are using MacOS

2. OS Architecture e.g. x86_64, armv7l, aarch64, etc

3. Version of OpenVINO e.g. 2021.2.185, etc

4. Version of TensorFlow e.g. v2.4.1, tf-nightly==2.5.0.dev20210128, etc

5. Version of TensorRT e.g. TensorRT6.0 GA, etc

6. Version of TFJS e.g. 1.5.0, etc

7. Version of coremltools e.g. 4.0, etc

8. Version of ONNX e.g. v1.8.0, etc

9. Download URL for ONNX model

10. Download URL for OpenVINO IR (.bin/.xml) model

11. URL of the repository from which the transformed model was taken

12. URL or source code for simple inference testing code

here

13. Issue Details

I try to convert the Pytorch implementation of Movenet to TFLite with the correct ordering of channels. However, when I try to convert the obtained openvino model to TFLite, there's an error of incorrect input shape. I check your doc: https://github.com/PINTO0309/openvino2tensorflow#6-7-replace-weights-or-constant-values-in-const-op-and-add-transpose-or-reshape-just-before-the-operation-specified-by-layer_id , and still have no clue how to fix the problem. Could you help check it out? Thanks a lot. The following is the log:

ERROR: Cannot reshape a tensor with 48 elements to shape [17,2] (34 elements) for '{{node tf.reshape_4/Reshape}} = Reshape[T=DT_FLOAT, Tshape=DT_INT32](Placeholder, tf.reshape_4/Reshape/shape)' with input shapes: [48], [2] and with input tensors computed as partial shapes: input[1] = [17,2].
ERROR: model_path  : openvino/movenet_opt.xml
ERROR: weights_path: openvino/movenet_opt.bin
ERROR: layer_id    : 471
ERROR: input_layer0 layer_id=469: KerasTensor(type_spec=TensorSpec(shape=(48,), dtype=tf.float32, name=None), name='tf.__operators__.getitem_1/strided_slice:0', description="created by layer 'tf.__operators__.getitem_1'")
ERROR: input_layer1 layer_id=470: Const(ndarray).shape  (2,)
array([17,  2])
ERROR: The trace log is below.
Traceback (most recent call last):
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py", line 206, in wrapper
    return target(*args, **kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py", line 195, in reshape
    result = gen_array_ops.reshape(tensor, shape, name)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/ops/gen_array_ops.py", line 8392, in reshape
    return reshape_eager_fallback(
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/ops/gen_array_ops.py", line 8413, in reshape_eager_fallback
    _attr_T, (tensor,) = _execute.args_to_matching_eager([tensor], ctx, [])
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/eager/execute.py", line 273, in args_to_matching_eager
    tensor = ops.convert_to_tensor(
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/profiler/trace.py", line 163, in wrapped
    return func(*args, **kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/ops.py", line 1566, in convert_to_tensor
    ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 339, in _constant_tensor_conversion_function
    return constant(v, dtype=dtype, name=name)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 264, in constant
    return _constant_impl(value, dtype, shape, name, verify_shape=False,
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 276, in _constant_impl
    return _constant_eager_impl(ctx, value, dtype, shape, verify_shape)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 301, in _constant_eager_impl
    t = convert_to_eager_tensor(value, ctx, dtype)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 98, in convert_to_eager_tensor
    return ops.EagerTensor(value, ctx.device_name, dtype)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/keras/engine/keras_tensor.py", line 254, in __array__
    raise TypeError(
TypeError: Cannot convert a symbolic Keras input/output to a numpy array. This error may indicate that you're trying to pass a symbolic value to a NumPy call, which is not supported. Or, you may be trying to pass Keras symbolic inputs/outputs to a TF API that does not register dispatching, preventing Keras from automatically converting the API call to a lambda layer in the Functional Model.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/ops.py", line 1880, in _create_c_op
    c_op = pywrap_tf_session.TF_FinishOperation(op_desc)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Cannot reshape a tensor with 48 elements to shape [17,2] (34 elements) for '{{node tf.reshape_4/Reshape}} = Reshape[T=DT_FLOAT, Tshape=DT_INT32](Placeholder, tf.reshape_4/Reshape/shape)' with input shapes: [48], [2] and with input tensors computed as partial shapes: input[1] = [17,2].

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/mli/opt/anaconda3/bin/openvino2tensorflow", line 2533, in convert
    tf_layers_dict[layer_id] = tf.reshape(op1, shape)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py", line 210, in wrapper
    result = dispatch(wrapper, args, kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py", line 126, in dispatch
    result = dispatcher.handle(op, args, kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/keras/layers/core.py", line 1486, in handle
    return TFOpLambda(op)(*args, **kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py", line 969, in __call__
    return self._functional_construction_call(inputs, args, kwargs,
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py", line 1107, in _functional_construction_call
    outputs = self._keras_tensor_symbolic_call(
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py", line 840, in _keras_tensor_symbolic_call
    return self._infer_output_signature(inputs, args, kwargs, input_masks)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py", line 880, in _infer_output_signature
    outputs = call_fn(inputs, *args, **kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/keras/layers/core.py", line 1363, in _call_wrapper
    return self._call_wrapper(*args, **kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/keras/layers/core.py", line 1395, in _call_wrapper
    result = self.function(*args, **kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py", line 206, in wrapper
    return target(*args, **kwargs)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py", line 195, in reshape
    result = gen_array_ops.reshape(tensor, shape, name)
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/ops/gen_array_ops.py", line 8397, in reshape
    _, _, _op, _outputs = _op_def_library._apply_op_helper(
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/op_def_library.py", line 748, in _apply_op_helper
    op = g._create_op_internal(op_type_name, inputs, dtypes=None,
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/func_graph.py", line 599, in _create_op_internal
    return super(FuncGraph, self)._create_op_internal(  # pylint: disable=protected-access
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/ops.py", line 3557, in _create_op_internal
    ret = Operation(
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/ops.py", line 2041, in __init__
    self._c_op = _create_c_op(self._graph, node_def, inputs,
  File "/Users/mli/opt/anaconda3/lib/python3.8/site-packages/tensorflow/python/framework/ops.py", line 1883, in _create_c_op
    raise ValueError(str(e))
ValueError: Cannot reshape a tensor with 48 elements to shape [17,2] (34 elements) for '{{node tf.reshape_4/Reshape}} = Reshape[T=DT_FLOAT, Tshape=DT_INT32](Placeholder, tf.reshape_4/Reshape/shape)' with input shapes: [48], [2] and with input tensors computed as partial shapes: input[1] = [17,2].

And I attached the corresponding model files here. openvino.zip

Best wishes, Min

lee-man commented 3 years ago

Also, in Google's official Movenet model, the Conv + ReLU6, and Conv +ReLU are fused together. Also the upsampling op: ResizeBilinear is used. Do you have any idea to use these specific ops when we convert the PyTorch model to TFLite for better performance? Thanks! The model definition of Pytorch Movenet is included here: https://github.com/lee-man/movenet-pytorch/blob/main/movenet/models/movenet.py

PINTO0309 commented 3 years ago

The custom model you have created is quite complex because it contains many layers of Transpose, Reshape, Gather, etc... that are less than 4D after the middle of the model. Therefore, it is not possible to mechanically convert NCHW format to NHWC format programmatically.

If the layer contains less than 4D shape changes, you will need to customize the tool's behavior.

python3 openvino2tensorflow_special_custom.py \
--model_path movenet_opt.xml \
--output_saved_model --output_pb \
--output_no_quant_float32_tflite \
--weight_replacement_config replace.json

I followed through to the final layer to make sure it was converted correctly, but I have not checked to see if the inference works correctly. I was only trying to show you that the conversion would be successful. If the inference results do not meet your expectations, please adjust the resources I have attached here yourself.

Also, in Google's official Movenet model, the Conv + ReLU6, and Conv +ReLU are fused together. Also the upsampling op: ResizeBilinear is used. Do you have any idea to use these specific ops when we convert the PyTorch model to TFLite for better performance?

I have no idea what your concern is. Sorry. :crying_cat_face:

model_float32 tflite pic

Let me ask you one last question. Why did you implement it in PyTorch and not in TensorFlow? The cost is too high. :sweat_smile:

lee-man commented 3 years ago

@PINTO0309 Thanks for your quick response! I really appreciate it and will check it later.

I have no idea what your concern is. Sorry. 😿

I thought that the Conv layer and ReLU will not be fused together. It's my fault.

Let me ask you one last question. Why did you implement it in PyTorch and not in TensorFlow? The cost is too high. 😅

Actually, my first step is trying to reimplement the Movenet structure using PyTorch and train it on my own dataset. However, it turned out that the performance is not that satisfactory. So I decided to reimplement the inference part and try to make it the same as the original one. Indeed the cost is too high as you said.

Min