From 314e8f14a40727bafdb5d77e489c4e565a50eee4 Mon Sep 17 00:00:00 2001 From: Klas Magnusson Date: Tue, 14 Mar 2023 12:17:11 +0100 Subject: [PATCH 1/2] Fix None shape error when one input to ConcatV2 has a shape. I tried to convert a network where one of the inputs to a concatenation along dimension -1 had shape None. The other input did however have a shape. The conversion failed because the code only looked att the shape of the first input to determine what positive axis value to use in the concatenation. If the order of the inputs had been reversed, the conversion would have worked. I have now changed the code to look at the shapes of both input nodes. With the new code, I can convert the network. I have also verified that the resulting onnx-file works. Signed-off-by: Klas Magnusson --- tf2onnx/onnx_opset/tensor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tf2onnx/onnx_opset/tensor.py b/tf2onnx/onnx_opset/tensor.py index 044a253d4..1650506e2 100644 --- a/tf2onnx/onnx_opset/tensor.py +++ b/tf2onnx/onnx_opset/tensor.py @@ -297,8 +297,13 @@ def version_1(cls, ctx, node, **kwargs): ctx.remove_input(node, node.input[-1], len(node.input) - 1) if axis_val < 0: # onnxruntime does not support -1 axis, but TF supports. - input_shape = ctx.get_shape(node.input[0]) - utils.make_sure(input_shape is not None, "shape of {} is None".format(node.input[0])) + input_shape = None + for node_input in node.input: + input_shape = ctx.get_shape(node_input) + if input_shape is not None: + break + utils.make_sure(input_shape is not None, + "the shapes of the following inputs are None: {}".format(', '.join(node.input))) axis_val = len(input_shape) + axis_val node.set_attr("axis", axis_val) From 8f5f1d909f2a4858a49aaaef3b36d57f9bacb356 Mon Sep 17 00:00:00 2001 From: Klas Magnusson Date: Wed, 12 Apr 2023 11:30:55 +0200 Subject: [PATCH 2/2] Test of negative axis concatenation where the first input has none shape. In the test, a tensor with none shape is created by applying the slice operator to another tensor. The slice size is obtained by adding two tensors and therefore the size of the sliced tensor cannot be inferred and is set to None. A tensor with a known shape is then concatenated to the tensor with none shape along the -1 axis. Previously, it was not possible to convert a network with this structure, but I fixed that bug in my previous commit. The problem occurred only when the first input had none shape and when the concatenation axis was -1. Signed-off-by: Klas Magnusson --- tests/test_backend.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_backend.py b/tests/test_backend.py index eebdf51ec..ac30073af 100755 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -1647,6 +1647,23 @@ def func(x1, x2, x3): return tf.identity(x_, name=_TFOUTPUT) self._run_test_case(func, [_OUTPUT], {_INPUT: x_val1, _INPUT1: x_val2, "input3:0": x_val3}) + def test_concat_negative_axis_none_shape(self): + x_val = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], dtype=np.float32).reshape((2, 3)) + y_val = np.array([7.0, 8.0, 9.0, 10.0, 11.0, 12.0], dtype=np.float32).reshape((2, 3)) + s1_val = np.array([1, 1], dtype=np.int32) + s2_val = np.array([1, 1], dtype=np.int32) + def func(): + x = tf_placeholder(tf.float32, [2, 3], name=_TFINPUT) + y = tf_placeholder(tf.float32, [2, 3], name=_TFINPUT1) + s1 = tf_placeholder(tf.int32, [2], name="input3") + s2 = tf_placeholder(tf.int32, [2], name="input4") + s = tf.add(s1, s2) + x_with_none_shape = tf.slice(x, [0, 0], s) + t = tf.concat([x_with_none_shape, y], -1) + return tf.identity(t, name=_TFOUTPUT) + self._run_test_case(func, [_OUTPUT], {_INPUT: x_val, _INPUT1: y_val, "input3:0": s1_val, "input4:0": s2_val}, + as_session=True, premade_placeholders=True) + def test_concat_const_string(self): x_val1 = np.array([["Hello world", "abc"], ["def", "♦♥♠♣"]], dtype=str) const_val = np.array([["Hello there", "wxyz"], ["", "π"]], dtype=str)