From bbd4061da3094e1eec61fcdb6297f626ff025ba2 Mon Sep 17 00:00:00 2001 From: saoste01 Date: Tue, 28 Aug 2018 15:41:51 +0100 Subject: IVGCVSW-1779: Updating TF Parser to include the RealDiv operator Change-Id: I4b193d9119f5aaf41081335df043352953364c87 --- src/armnnTfParser/TfParser.cpp | 60 +++++++++++-- src/armnnTfParser/TfParser.hpp | 2 + src/armnnTfParser/test/RealDiv.cpp | 169 +++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+), 8 deletions(-) create mode 100644 src/armnnTfParser/test/RealDiv.cpp (limited to 'src/armnnTfParser') diff --git a/src/armnnTfParser/TfParser.cpp b/src/armnnTfParser/TfParser.cpp index 5bc2ad7d18..2d873c9b4d 100644 --- a/src/armnnTfParser/TfParser.cpp +++ b/src/armnnTfParser/TfParser.cpp @@ -266,8 +266,8 @@ TensorInfo PrepareReshape(const TensorInfo& input, const std::vector& t } // We need the input0Slot to guide the reshape for input1Slot. -IOutputSlot* BroadcastForAddandMul(IOutputSlot* input0Slot, IOutputSlot* input1Slot, bool isNHWC, INetwork& m_Network, - const tensorflow::NodeDef& nodeDef) +IOutputSlot* AddBroadcastReshapeLayer(IOutputSlot* input0Slot, IOutputSlot* input1Slot, bool isNHWC, + INetwork& m_Network, const tensorflow::NodeDef& nodeDef) { const TensorInfo& input1Info = input1Slot->GetTensorInfo(); const TensorInfo inputTensorInfo = input0Slot->GetTensorInfo(); @@ -354,6 +354,7 @@ const std::map TfParser::ms_Ope { "MatMul", &TfParser::ParseMatMul }, { "Mul", &TfParser::ParseMul }, { "Placeholder", &TfParser::ParsePlaceholder }, + { "RealDiv", &TfParser::ParseRealDiv }, { "Relu", &TfParser::ParseRelu }, { "Relu6", &TfParser::ParseRelu6 }, { "Reshape", &TfParser::ParseReshape }, @@ -1893,6 +1894,12 @@ ParsedTfOperationPtr TfParser::ParsePlaceholder(const tensorflow::NodeDef& nodeD return std::make_unique(this, nodeDef, layer); } +ParsedTfOperationPtr TfParser::ParseRealDiv(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef) +{ + boost::ignore_unused(graphDef); + return AddRealDivLayer(nodeDef); +} + ParsedTfOperationPtr TfParser::ParseRelu(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef) { @@ -2135,20 +2142,20 @@ ParsedTfOperationPtr TfParser::AddAdditionLayer(const tensorflow::NodeDef& nodeD const std::string dataFormat = ReadMandatoryNodeStringAttribute(nodeDef, "data_format"); CHECK_DATA_FORMAT(nodeDef, dataFormat, "BiasAdd"); - input1Slot = BroadcastForAddandMul(input0Slot, input1Slot, dataFormat == "NHWC", *m_Network, nodeDef); + input1Slot = AddBroadcastReshapeLayer(input0Slot, input1Slot, dataFormat == "NHWC", *m_Network, nodeDef); } else { if (input0Info.GetNumDimensions() == 1) { const bool isNHWC = true; - input0Slot = BroadcastForAddandMul(input1Slot, input0Slot, isNHWC, *m_Network, nodeDef); + input0Slot = AddBroadcastReshapeLayer(input1Slot, input0Slot, isNHWC, *m_Network, nodeDef); } if (input1Info.GetNumDimensions() == 1) { const bool isNHWC = true; - input1Slot = BroadcastForAddandMul(input0Slot, input1Slot, isNHWC, *m_Network, nodeDef); + input1Slot = AddBroadcastReshapeLayer(input0Slot, input1Slot, isNHWC, *m_Network, nodeDef); } } @@ -2169,6 +2176,44 @@ ParsedTfOperationPtr TfParser::AddAdditionLayer(const tensorflow::NodeDef& nodeD return std::make_unique(this, nodeDef, layer); } +ParsedTfOperationPtr TfParser::AddRealDivLayer(const tensorflow::NodeDef& nodeDef) +{ + std::vector inputs = GetInputParsedTfOperationsChecked(nodeDef, 2); + + IConnectableLayer* const layer = m_Network->AddDivisionLayer(nodeDef.name().c_str()); + IOutputSlot* input0Slot = &inputs[0].m_IndexedValue->ResolveArmnnOutputSlot(inputs[0].m_Index); + IOutputSlot* input1Slot = &inputs[1].m_IndexedValue->ResolveArmnnOutputSlot(inputs[1].m_Index); + + auto const input0NumDims = input0Slot->GetTensorInfo().GetNumDimensions(); + auto const input1NumDims = input1Slot->GetTensorInfo().GetNumDimensions(); + + + if (input0NumDims < input1NumDims) + { + const bool isNHWC = true; + input0Slot = AddBroadcastReshapeLayer(input1Slot, input0Slot, isNHWC, *m_Network, nodeDef); + } + if (input1NumDims < input0NumDims) + { + const bool isNHWC = true; + input1Slot = AddBroadcastReshapeLayer(input0Slot, input1Slot, isNHWC, *m_Network, nodeDef); + } + + input0Slot->Connect(layer->GetInputSlot(0)); + input1Slot->Connect(layer->GetInputSlot(1)); + + if (input0NumDims < input1NumDims) + { + layer->GetOutputSlot(0).SetTensorInfo(input1Slot->GetTensorInfo()); + } + else + { + layer->GetOutputSlot(0).SetTensorInfo(input0Slot->GetTensorInfo()); + + } + return std::make_unique(this, nodeDef, layer); +} + IConnectableLayer* TfParser::AddMultiplicationLayer(const tensorflow::NodeDef& nodeDef) { std::vector inputs = GetInputParsedTfOperationsChecked(nodeDef, 2); @@ -2183,12 +2228,12 @@ IConnectableLayer* TfParser::AddMultiplicationLayer(const tensorflow::NodeDef& n if (input0NumDims < input1NumDims) { const bool isNHWC = true; - input0Slot = BroadcastForAddandMul(input1Slot, input0Slot, isNHWC, *m_Network, nodeDef); + input0Slot = AddBroadcastReshapeLayer(input1Slot, input0Slot, isNHWC, *m_Network, nodeDef); } if (input1NumDims < input0NumDims) { const bool isNHWC = true; - input1Slot = BroadcastForAddandMul(input0Slot, input1Slot, isNHWC, *m_Network, nodeDef); + input1Slot = AddBroadcastReshapeLayer(input0Slot, input1Slot, isNHWC, *m_Network, nodeDef); } input0Slot->Connect(layer->GetInputSlot(0)); @@ -2205,7 +2250,6 @@ IConnectableLayer* TfParser::AddMultiplicationLayer(const tensorflow::NodeDef& n return layer; } - IConnectableLayer* TfParser::AddFullyConnectedLayer(const tensorflow::NodeDef& matMulNodeDef, const tensorflow::NodeDef* addNodeDef, const char* armnnLayerName) { diff --git a/src/armnnTfParser/TfParser.hpp b/src/armnnTfParser/TfParser.hpp index 75cd3a5bd0..534714cbee 100644 --- a/src/armnnTfParser/TfParser.hpp +++ b/src/armnnTfParser/TfParser.hpp @@ -136,6 +136,7 @@ private: ParsedTfOperationPtr ParseMatMul(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); ParsedTfOperationPtr ParseMul(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); ParsedTfOperationPtr ParsePlaceholder(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); + ParsedTfOperationPtr ParseRealDiv(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); ParsedTfOperationPtr ParseRelu(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); ParsedTfOperationPtr ParseRelu6(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); ParsedTfOperationPtr ParseReshape(const tensorflow::NodeDef& nodeDef, const tensorflow::GraphDef& graphDef); @@ -153,6 +154,7 @@ private: ParsedTfOperationPtr ParseMaximum(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); private: armnn::IConnectableLayer* AddMultiplicationLayer(const tensorflow::NodeDef& nodeDef); diff --git a/src/armnnTfParser/test/RealDiv.cpp b/src/armnnTfParser/test/RealDiv.cpp new file mode 100644 index 0000000000..9151cf63ef --- /dev/null +++ b/src/armnnTfParser/test/RealDiv.cpp @@ -0,0 +1,169 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#include +#include "armnnTfParser/ITfParser.hpp" +#include "ParserPrototxtFixture.hpp" + +BOOST_AUTO_TEST_SUITE(TensorflowParser) + +struct DivisionFixture : public armnnUtils::ParserPrototxtFixture +{ + DivisionFixture() + { + m_Prototext = "node { \n" + " name: \"graphInput\" \n" + " op: \"Placeholder\" \n" + " attr { \n" + " key: \"dtype\" \n" + " value { \n" + " type: DT_FLOAT \n" + " } \n" + " } \n" + " attr { \n" + " key: \"shape\" \n" + " value { \n" + " shape { \n" + " } \n" + " } \n" + " } \n" + " } \n" + " node { \n" + " name: \"softmax1\" \n" + " op: \"Softmax\" \n" + " input: \"graphInput\" \n" + " attr { \n" + " key: \"T\" \n" + " value { \n" + " type: DT_FLOAT \n" + " } \n" + " } \n" + " }\n" + " node {\n" + " name: \"softmax2\"\n" + " op : \"Softmax\"\n" + " input: \"graphInput\"\n" + " attr { \n" + " key: \"T\" \n" + " value { \n" + " type: DT_FLOAT \n" + " } \n" + " } \n" + " }\n" + " node {\n" + " name: \"division\"\n" + " op : \"RealDiv\"\n" + " input: \"softmax1\"\n" + " input: \"softmax2\"\n" + " attr { \n" + " key: \"T\" \n" + " value { \n" + " type: DT_FLOAT \n" + " } \n" + " } \n" + " }\n"; + + SetupSingleInputSingleOutput({ 4, 1 }, "graphInput", "division"); + } +}; + +BOOST_FIXTURE_TEST_CASE(ParseDivision, DivisionFixture) +{ + RunTest<2>({ 2, 1.0f, 3, 1 }, { 1, 1.0f, 1, 1}); +} + +struct DivisionBroadcastFixture : public armnnUtils::ParserPrototxtFixture +{ + DivisionBroadcastFixture(const armnn::TensorShape& inputShape0, const armnn::TensorShape& inputShape1) + { + 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: "RealDiv" + input: "input0" + input: "input1" + attr { + key: "T" + value { + type: DT_FLOAT + } + } + } + )"; + + Setup({ { "input0", inputShape0 }, + { "input1", inputShape1 } }, + { "output" }); + } +}; +struct DivisionBroadcastFixture4D1D : public DivisionBroadcastFixture +{ + DivisionBroadcastFixture4D1D() : DivisionBroadcastFixture({ 1, 2, 2, 3 }, { 1 }) {} +}; + +BOOST_FIXTURE_TEST_CASE(ParseDivisionBroadcast4D1D, DivisionBroadcastFixture4D1D) +{ + RunTest<4>({ { "input0", { 0.0f, 100.0f, 2.0f, + 3.0f, 250.0f, 15.0f, + 33.0f, 60.0f, 5.0f, + 35.0f, 10.0f, 55.0f } }, + { "input1", { 5.0f } } }, + { { "output", { 0, 20.0f, 0.4f, + 0.6f, 50.0f, 3.0f, + 6.6f, 12.0f, 1.0f, + 7.0f, 2.0f, 11.0f } } }); +} + +BOOST_FIXTURE_TEST_CASE(ParseDivideByZeroBroadcast4D1D, DivisionBroadcastFixture4D1D) +{ + float Inf = std::numeric_limits::infinity(); + float NaN = std::numeric_limits::quiet_NaN(); + + RunTest<4>({ { "input0", { 0.0f, -100.0f, 2.0f, + 3.0f, -250.0f, 15.0f, + 33.0f, -0, 5.0f, + 35.0f, -10.0f, 55.0f } }, + { "input1", { 0 } } }, + { { "output", { NaN, -Inf, Inf, + Inf, -Inf, Inf, + Inf, NaN, Inf, + Inf, -Inf, Inf } } }); +} + +BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.1