diff options
author | Nattapat Chaimanowong <nattapat.chaimanowong@arm.com> | 2018-12-04 13:47:02 +0000 |
---|---|---|
committer | nattapat.chaimanowong <nattapat.chaimanowong@arm.com> | 2018-12-04 14:43:18 +0000 |
commit | 24df822711e14cd3099a926272d863ed139ed4d7 (patch) | |
tree | 28a6165db8b64247ad8ceb63a0b3aeb5ccc60779 | |
parent | 20e58806b94636f579c5e8b0ca91ab771b6310e6 (diff) | |
download | armnn-24df822711e14cd3099a926272d863ed139ed4d7.tar.gz |
IVGCVSW-2251 Add support for Minimum operator in TfParser
Change-Id: Ib84e5bde39d706c5125e0f84577195fc61107a4a
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/armnnTfParser/TfParser.cpp | 55 | ||||
-rw-r--r-- | src/armnnTfParser/TfParser.hpp | 1 | ||||
-rw-r--r-- | src/armnnTfParser/test/Minimum.cpp | 165 |
4 files changed, 222 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 197989aea7..73f926937c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,6 +392,7 @@ if(BUILD_UNIT_TESTS) src/armnnTfParser/test/LocalResponseNormalization.cpp src/armnnTfParser/test/Maximum.cpp src/armnnTfParser/test/MaximumForLeakyRelu.cpp + src/armnnTfParser/test/Minimum.cpp src/armnnTfParser/test/Multiplication.cpp src/armnnTfParser/test/MultiOutput.cpp src/armnnTfParser/test/PassThru.cpp diff --git a/src/armnnTfParser/TfParser.cpp b/src/armnnTfParser/TfParser.cpp index abf4d3f5c9..09769ecf6e 100644 --- a/src/armnnTfParser/TfParser.cpp +++ b/src/armnnTfParser/TfParser.cpp @@ -369,6 +369,7 @@ const std::map<std::string, TfParser::OperationParsingFunction> TfParser::ms_Ope { "MaxPool", &TfParser::ParseMaxPool }, { "AvgPool", &TfParser::ParseAvgPool }, { "Maximum", &TfParser::ParseMaximum }, + { "Minimum", &TfParser::ParseMinimum }, }; ITfParser* ITfParser::CreateRaw() @@ -1424,6 +1425,60 @@ ParsedTfOperationPtr TfParser::ParseMaximum(const tensorflow::NodeDef& nodeDef, } } +ParsedTfOperationPtr TfParser::ParseMinimum(const tensorflow::NodeDef& nodeDef, + const tensorflow::GraphDef& graphDef) +{ + std::vector<OutputOfParsedTfOperation> inputs = GetInputParsedTfOperationsChecked(nodeDef, 2); + + IOutputSlot* input0Slot = &inputs[0].m_IndexedValue->ResolveArmnnOutputSlot(inputs[0].m_Index); + IOutputSlot* input1Slot = &inputs[1].m_IndexedValue->ResolveArmnnOutputSlot(inputs[1].m_Index); + const unsigned int input0Dim = input0Slot->GetTensorInfo().GetNumDimensions(); + const unsigned int input1Dim = input1Slot->GetTensorInfo().GetNumDimensions(); + + if (input0Dim != input1Dim) + { + // broadcasting where input0 and input1 have different number of dimensions + // is only supported for 1D and 4D tensors pair + if (input0Dim == 1 && input1Dim == 4) + { + input0Slot = AddBroadcastReshapeLayer(input1Slot, input0Slot, true, *m_Network, nodeDef); + } + else if (input0Dim == 4 && input1Dim == 1) + { + input1Slot = AddBroadcastReshapeLayer(input0Slot, input1Slot, true, *m_Network, nodeDef); + } + else + { + throw ParseException( + boost::str( + boost::format("Unsupported broadcast configuration for Minimum operation %1% %2%") + % nodeDef.name() + % CHECK_LOCATION().AsString())); + } + } + + IConnectableLayer* const layer = m_Network->AddMinimumLayer(nodeDef.name().c_str()); + + input0Slot->Connect(layer->GetInputSlot(0)); + input1Slot->Connect(layer->GetInputSlot(1)); + + TensorInfo outputInfo = input0Slot->GetTensorInfo(); + std::vector<unsigned int> outputShape; + + const TensorShape& input0Shape = input0Slot->GetTensorInfo().GetShape(); + const TensorShape& input1Shape = input1Slot->GetTensorInfo().GetShape(); + + for (unsigned int i = 0; i < input0Shape.GetNumDimensions(); i++) + { + outputShape.push_back(std::max(input0Shape[i], input1Shape[i])); + } + + outputInfo.SetShape(TensorShape(input0Shape.GetNumDimensions(), outputShape.data())); + layer->GetOutputSlot(0).SetTensorInfo(outputInfo); + + return std::make_unique<SingleLayerParsedTfOperation>(this, nodeDef, layer); +} + ParsedTfOperationPtr TfParser::ParseConcat(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef) { diff --git a/src/armnnTfParser/TfParser.hpp b/src/armnnTfParser/TfParser.hpp index f57ea0518e..7abf783c38 100644 --- a/src/armnnTfParser/TfParser.hpp +++ b/src/armnnTfParser/TfParser.hpp @@ -152,6 +152,7 @@ private: ParsedTfOperationPtr ParsePooling2d(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef, armnn::PoolingAlgorithm pooltype); ParsedTfOperationPtr ParseMaximum(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); + ParsedTfOperationPtr ParseMinimum(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); ParsedTfOperationPtr AddActivationLayer(const tensorflow::NodeDef& nodeDef, armnn::ActivationDescriptor& desc); ParsedTfOperationPtr AddAdditionLayer(const tensorflow::NodeDef& nodeDef, bool isBiasAdd = false); ParsedTfOperationPtr AddRealDivLayer(const tensorflow::NodeDef& nodeDef); diff --git a/src/armnnTfParser/test/Minimum.cpp b/src/armnnTfParser/test/Minimum.cpp new file mode 100644 index 0000000000..feb86a17d6 --- /dev/null +++ b/src/armnnTfParser/test/Minimum.cpp @@ -0,0 +1,165 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include <boost/test/unit_test.hpp> +#include "armnnTfParser/ITfParser.hpp" +#include "ParserPrototxtFixture.hpp" + +BOOST_AUTO_TEST_SUITE(TensorflowParser) + +struct MinimumFixture : public armnnUtils::ParserPrototxtFixture<armnnTfParser::ITfParser> +{ + MinimumFixture() + { + m_Prototext = R"( + node { + name: "input0" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "shape" + value { + shape { + } + } + } + } + node { + name: "input1" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "shape" + value { + shape { + } + } + } + } + node { + name: "output" + op: "Minimum" + input: "input0" + input: "input1" + attr { + key: "T" + value { + type: DT_FLOAT + } + } + } + )"; + } +}; + +BOOST_FIXTURE_TEST_CASE(ParseMininumUnsupportedBroadcast, MinimumFixture) +{ + BOOST_REQUIRE_THROW(Setup({ { "input0", {2, 3} }, + { "input1", {1, 2, 2, 3} } }, + { "output" }), + armnn::ParseException); +} + +struct MinimumFixtureAutoSetup : public MinimumFixture +{ + MinimumFixtureAutoSetup(const armnn::TensorShape& input0Shape, + const armnn::TensorShape& input1Shape) + : MinimumFixture() + { + Setup({ { "input0", input0Shape }, + { "input1", input1Shape } }, + { "output" }); + } +}; + +struct MinimumFixture4D : public MinimumFixtureAutoSetup +{ + MinimumFixture4D() + : MinimumFixtureAutoSetup({1, 2, 2, 3}, {1, 2, 2, 3}) {} +}; + +BOOST_FIXTURE_TEST_CASE(ParseMinimum4D, MinimumFixture4D) +{ + RunTest<4>({ { "input0", { 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f } }, + { "input1", { 0.0f, 0.0f, 0.0f, + 5.0f, 5.0f, 5.0f, + 7.0f, 7.0f, 7.0f, + 9.0f, 9.0f, 9.0f } } }, + { { "output", { 0.0f, 0.0f, 0.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 7.0f, + 9.0f, 9.0f, 9.0f } } }); +} + +struct MinimumBroadcastFixture4D : public MinimumFixtureAutoSetup +{ + MinimumBroadcastFixture4D() + : MinimumFixtureAutoSetup({1, 1, 2, 1}, {1, 2, 1, 3}) {} +}; + +BOOST_FIXTURE_TEST_CASE(ParseMinimumBroadcast4D, MinimumBroadcastFixture4D) +{ + RunTest<4>({ { "input0", { 2.0f, + 4.0f } }, + { "input1", { 1.0f, 2.0f, 3.0f, + 4.0f, 5.0f, 6.0f } } }, + { { "output", { 1.0f, 2.0f, 2.0f, + 1.0f, 2.0f, 3.0f, + 2.0f, 2.0f, 2.0f, + 4.0f, 4.0f, 4.0f } } }); +} + +struct MinimumBroadcastFixture4D1D : public MinimumFixtureAutoSetup +{ + MinimumBroadcastFixture4D1D() + : MinimumFixtureAutoSetup({1, 2, 2, 3}, {1}) {} +}; + +BOOST_FIXTURE_TEST_CASE(ParseMinimumBroadcast4D1D, MinimumBroadcastFixture4D1D) +{ + RunTest<4>({ { "input0", { 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f } }, + { "input1", { 5.0f } } }, + { { "output", { 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 5.0f, 5.0f, 5.0f, + 5.0f, 5.0f, 5.0f } } }); +} + +struct MinimumBroadcastFixture1D4D : public MinimumFixtureAutoSetup +{ + MinimumBroadcastFixture1D4D() + : MinimumFixtureAutoSetup({3}, {1, 2, 2, 3}) {} +}; + +BOOST_FIXTURE_TEST_CASE(ParseMinimumBroadcast1D4D, MinimumBroadcastFixture1D4D) +{ + RunTest<4>({ { "input0", { 5.0f, 6.0f, 7.0f } }, + { "input1", { 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f } } }, + { { "output", { 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 5.0f, 6.0f, 7.0f, + 5.0f, 6.0f, 7.0f } } }); +} + +BOOST_AUTO_TEST_SUITE_END() |