From d2f7323b7ddf8f811f19ba7ae9987dcc6bf672a6 Mon Sep 17 00:00:00 2001 From: Cathal Corbett Date: Fri, 10 Dec 2021 13:38:52 +0000 Subject: IVGCVSW-6252 Armnn Error: Failed to parse operator #1 within subgraph #0 error: Operator not supported * Added missing support for reshape operator in tflite parser when the target shape is dynamic and batch size is unknown * Added corresponding unit test Change-Id: I35e159c9c70440168c6092d2ad02828bb2b81cd9 Signed-off-by: Cathal Corbett --- CMakeLists.txt | 1 + src/armnnTfLiteParser/TfLiteParser.cpp | 42 ++- src/armnnTfLiteParser/test/ReshapeDynamic.cpp | 497 ++++++++++++++++++++++++++ 3 files changed, 536 insertions(+), 4 deletions(-) create mode 100644 src/armnnTfLiteParser/test/ReshapeDynamic.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 796a829ca5..551ccbf581 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -696,6 +696,7 @@ if(BUILD_UNIT_TESTS) src/armnnTfLiteParser/test/Prelu.cpp src/armnnTfLiteParser/test/Reduce.cpp src/armnnTfLiteParser/test/Reshape.cpp + src/armnnTfLiteParser/test/ReshapeDynamic.cpp src/armnnTfLiteParser/test/ResizeBilinear.cpp src/armnnTfLiteParser/test/ResizeNearestNeighbor.cpp src/armnnTfLiteParser/test/Quantize.cpp diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp index 15ca36d906..f51cf508e2 100644 --- a/src/armnnTfLiteParser/TfLiteParser.cpp +++ b/src/armnnTfLiteParser/TfLiteParser.cpp @@ -2566,13 +2566,47 @@ void TfLiteParserImpl::ParseReshape(size_t subgraphIndex, size_t operatorIndex) // Extract target shape from input auto bufferPtr = GetBuffer(m_Model, inputs[1]->buffer); auto values = reinterpret_cast(bufferPtr->data.data()); - if (!values) + if (values) { - ARMNN_THROW_PARSE_EXCEPTION("Reshape operator target shape input buffer data is null"); + for (int i = 0; i < inputs[1]->shape[0]; ++i) + { + targetShape.push_back(values[i]); + } } - for (int i=0; i < inputs[1]->shape[0]; ++i) + else { - targetShape.push_back(values[i]); + try + { + // We attempt to infer during Runtime. + TensorShape reshapeShapes = ToTensorInfo(inputs[1]).GetShape(); + // The parser only supports shape (batch, -1) or (-1) for non-constant shape input. + if (reshapeShapes[0] > 2) + { + throw ParseException(fmt::format("Invalid input shape '{}' in Reshape layer '{}' {}. " + "When inferring during runtime, the parser only supports " + "shape (batch, -1) or (-1) for target shape input.", + reshapeShapes[0], + layerName, + CHECK_LOCATION().AsString())); + } + + const int32_t numInputElements = inputTensorInfo.GetNumElements(); + const int32_t inputTensorShape = inputTensorInfo.GetShape()[0]; + if (reshapeShapes[0] == 1) + { + targetShape = {numInputElements}; + } + else if (reshapeShapes[0] == 2) + { + targetShape = {inputTensorShape, numInputElements / inputTensorShape}; + } + } + catch (const std::exception& exc) + { + ARMNN_THROW_PARSE_EXCEPTION("Failed attempt to infer during runtime the target shape input for " + "Reshape operation. Reshape operator target shape input buffer data " + "is null. " << exc.what()); + } } } else diff --git a/src/armnnTfLiteParser/test/ReshapeDynamic.cpp b/src/armnnTfLiteParser/test/ReshapeDynamic.cpp new file mode 100644 index 0000000000..31e23620c7 --- /dev/null +++ b/src/armnnTfLiteParser/test/ReshapeDynamic.cpp @@ -0,0 +1,497 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "ParserFlatbuffersFixture.hpp" + + +TEST_SUITE("TensorflowLiteParser_Reshape_Dynamic") +{ +struct ReshapeDynamicFixture1 : public ParserFlatbuffersFixture +{ + explicit ReshapeDynamicFixture1() + { + m_JsonString = R"( +{ + "version": 3, + "operator_codes": [ + { + "deprecated_builtin_code": 77, + "version": 1, + "builtin_code": "ADD" + }, + { + "deprecated_builtin_code": 22, + "version": 1, + "builtin_code": "ADD" + } + ], + "subgraphs": [ + { + "tensors": [ + { + "shape": [ + 2, + 5 + ], + "type": "FLOAT32", + "buffer": 1, + "name": "input_33", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false, + "shape_signature": [ + -1, + 10 + ] + }, + { + "shape": [ + 2 + ], + "type": "INT32", + "buffer": 2, + "name": "functional_15/tf_op_layer_Shape_9/Shape_9", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false + }, + { + "shape": [ + 2, + 5 + ], + "type": "FLOAT32", + "buffer": 3, + "name": "Identity", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false, + "shape_signature": [ + -1, + 5 + ] + } + ], + "inputs": [ + 0 + ], + "outputs": [ + 2 + ], + "operators": [ + { + "opcode_index": 0, + "inputs": [ + 0 + ], + "outputs": [ + 1 + ], + "builtin_options_type": "ShapeOptions", + "builtin_options": { + "out_type": "INT32" + }, + "custom_options_format": "FLEXBUFFERS" + }, + { + "opcode_index": 1, + "inputs": [ + 0, + 1 + ], + "outputs": [ + 2 + ], + "builtin_options_type": "NONE", + "custom_options_format": "FLEXBUFFERS" + } + ], + "name": "main" + } + ], + "description": "MLIR Converted.", + "buffers": [ + { + }, + { + }, + { + }, + { + }, + { + "data": [ + 49, + 46, + 49, + 48, + 46, + 48, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ], + "metadata": [ + { + "name": "min_runtime_version", + "buffer": 4 + } + ] +} +)"; + + } +}; + +// ParseReshape test case: reshapeShapes[0] == 2 +TEST_CASE_FIXTURE(ReshapeDynamicFixture1, "ParseReshapeDynamic1") +{ + SetupSingleInputSingleOutput("input_33", "Identity"); + RunTest<2, armnn::DataType::Float32>(0, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }); + + CHECK((m_Parser->GetNetworkOutputBindingInfo(0, "Identity").second.GetShape() + == armnn::TensorShape({2,5}))); +} + +struct ReshapeDynamicFixture2 : public ParserFlatbuffersFixture +{ + explicit ReshapeDynamicFixture2() + { + m_JsonString = R"( +{ + "version": 3, + "operator_codes": [ + { + "deprecated_builtin_code": 77, + "version": 1, + "builtin_code": "ADD" + }, + { + "deprecated_builtin_code": 22, + "version": 1, + "builtin_code": "ADD" + } + ], + "subgraphs": [ + { + "tensors": [ + { + "shape": [ + -1, + 10 + ], + "type": "FLOAT32", + "buffer": 1, + "name": "input_33", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false, + "shape_signature": [ + 2, + 5 + ] + }, + { + "shape": [ + 1 + ], + "type": "INT32", + "buffer": 2, + "name": "functional_15/tf_op_layer_Shape_9/Shape_9", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false + }, + { + "shape": [ + 10 + ], + "type": "FLOAT32", + "buffer": 3, + "name": "Identity", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false, + "shape_signature": [ + -1, + 10 + ] + } + ], + "inputs": [ + 0 + ], + "outputs": [ + 2 + ], + "operators": [ + { + "opcode_index": 0, + "inputs": [ + 0 + ], + "outputs": [ + 1 + ], + "builtin_options_type": "ShapeOptions", + "builtin_options": { + "out_type": "INT32" + }, + "custom_options_format": "FLEXBUFFERS" + }, + { + "opcode_index": 1, + "inputs": [ + 0, + 1 + ], + "outputs": [ + 2 + ], + "builtin_options_type": "NONE", + "custom_options_format": "FLEXBUFFERS" + } + ], + "name": "main" + } + ], + "description": "MLIR Converted.", + "buffers": [ + { + }, + { + }, + { + }, + { + }, + { + "data": [ + 49, + 46, + 49, + 48, + 46, + 48, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ], + "metadata": [ + { + "name": "min_runtime_version", + "buffer": 4 + } + ] +} +)"; + + } +}; + +// ParseReshape test case: reshapeShapes[0] == 1 +TEST_CASE_FIXTURE(ReshapeDynamicFixture2, "ParseReshapeDynamic2") +{ + SetupSingleInputSingleOutput("input_33", "Identity"); + RunTest<1, armnn::DataType::Float32>(0, + { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }, + { 1, 2, 3, 4, 5, 6, 7, 8 ,9, 10 }); + CHECK((m_Parser->GetNetworkOutputBindingInfo(0, "Identity").second.GetShape() + == armnn::TensorShape({10}))); +} + +struct ReshapeDynamicFixture3 : public ParserFlatbuffersFixture +{ + explicit ReshapeDynamicFixture3() + { + m_JsonString = R"( +{ + "version": 3, + "operator_codes": [ + { + "deprecated_builtin_code": 77, + "version": 1, + "builtin_code": "ADD" + }, + { + "deprecated_builtin_code": 22, + "version": 1, + "builtin_code": "ADD" + } + ], + "subgraphs": [ + { + "tensors": [ + { + "shape": [ + 1, + 9 + ], + "type": "FLOAT32", + "buffer": 1, + "name": "input_33", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false, + "shape_signature": [ + -1, + 9 + ] + }, + { + "shape": [ + 3 + ], + "type": "INT32", + "buffer": 2, + "name": "functional_15/tf_op_layer_Shape_9/Shape_9", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false + }, + { + "shape": [ + 1, + 9 + ], + "type": "FLOAT32", + "buffer": 3, + "name": "Identity", + "quantization": { + "details_type": "NONE", + "quantized_dimension": 0 + }, + "is_variable": false, + "shape_signature": [ + -1, + 9 + ] + } + ], + "inputs": [ + 0 + ], + "outputs": [ + 2 + ], + "operators": [ + { + "opcode_index": 0, + "inputs": [ + 0 + ], + "outputs": [ + 1 + ], + "builtin_options_type": "ShapeOptions", + "builtin_options": { + "out_type": "INT32" + }, + "custom_options_format": "FLEXBUFFERS" + }, + { + "opcode_index": 1, + "inputs": [ + 0, + 1 + ], + "outputs": [ + 2 + ], + "builtin_options_type": "NONE", + "custom_options_format": "FLEXBUFFERS" + } + ], + "name": "main" + } + ], + "description": "MLIR Converted.", + "buffers": [ + { + }, + { + }, + { + }, + { + }, + { + "data": [ + 49, + 46, + 49, + 48, + 46, + 48, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ], + "metadata": [ + { + "name": "min_runtime_version", + "buffer": 4 + } + ] +} +)"; + + } +}; + +// ParseReshape test case: reshapeShapes[0] > 2 +TEST_CASE_FIXTURE(ReshapeDynamicFixture3, "ParseReshapeDynamic3") +{ + CHECK_THROWS_AS(SetupSingleInputSingleOutput("input_33", "Identity"), armnn::ParseException); +} + +} -- cgit v1.2.1