diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/armnn/Network.cpp | 5 | ||||
-rw-r--r-- | src/armnn/layers/ElementwiseBaseLayer.cpp | 31 | ||||
-rw-r--r-- | src/armnn/optimizations/AddBroadcastReshapeLayer.hpp | 85 | ||||
-rw-r--r-- | src/armnn/optimizations/All.hpp | 1 | ||||
-rw-r--r-- | src/armnn/test/optimizations/AddBroadcastReshapeLayerTests.cpp | 288 | ||||
-rw-r--r-- | src/armnnTfLiteParser/TfLiteParser.cpp | 124 | ||||
-rw-r--r-- | src/armnnTfLiteParser/test/LoadScopeDynamicTensor.cpp | 205 |
7 files changed, 615 insertions, 124 deletions
diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp index 17813a8983..cd5f369271 100644 --- a/src/armnn/Network.cpp +++ b/src/armnn/Network.cpp @@ -1038,11 +1038,14 @@ IOptimizedNetworkPtr Optimize(const INetwork& inNetwork, // Get the optimized graph Graph& optGraph = optNetObjPtr->GetGraph(); + // Perform AddBroadcastReshapeLayer optimisation + using namespace optimizations; + Optimizer::Pass(optGraph, MakeOptimizations(AddBroadcastReshapeLayer())); + // Infer the tensor infos for all output slots. Throws an exception on failure optGraph.InferTensorInfos(); // Perform optimisation passes - using namespace optimizations; Optimizer::Pass(optGraph, MakeOptimizations(SquashEqualPermuteSiblings(), SquashEqualTransposeSiblings(), SquashEqualReshapeSiblings(), diff --git a/src/armnn/layers/ElementwiseBaseLayer.cpp b/src/armnn/layers/ElementwiseBaseLayer.cpp index b4a3cea9e1..631e08c2ac 100644 --- a/src/armnn/layers/ElementwiseBaseLayer.cpp +++ b/src/armnn/layers/ElementwiseBaseLayer.cpp @@ -22,18 +22,29 @@ ElementwiseBaseLayer::ElementwiseBaseLayer(unsigned int numInputSlots, unsigned std::vector<TensorShape> ElementwiseBaseLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const { ARMNN_ASSERT(inputShapes.size() == 2); - auto& input0 = inputShapes[0]; - auto& input1 = inputShapes[1]; + TensorShape input0 = inputShapes[0]; + TensorShape input1 = inputShapes[1]; + + if (m_ShapeInferenceMethod == ShapeInferenceMethod::ValidateOnly) + { + ARMNN_ASSERT(input0.GetNumDimensions() == input1.GetNumDimensions()); + } + else if (m_ShapeInferenceMethod == ShapeInferenceMethod::InferAndValidate && + inputShapes[0].GetNumDimensions() < inputShapes[1].GetNumDimensions()) + { + input1 = inputShapes[0]; + input0 = inputShapes[1]; + } - // Get the max of the inputs. - ARMNN_ASSERT(input0.GetNumDimensions() == input1.GetNumDimensions()); unsigned int numDims = input0.GetNumDimensions(); - std::vector<unsigned int> dims(numDims); + unsigned int shiftedDims = input0.GetNumDimensions() - input1.GetNumDimensions(); - for (unsigned int i = 0; i < numDims; i++) + // Get the max of the inputs. + std::vector<unsigned int> dims(numDims); + for (unsigned int i = shiftedDims; i < numDims; i++) { unsigned int dim0 = input0[i]; - unsigned int dim1 = input1[i]; + unsigned int dim1 = input1[i - shiftedDims]; #if !NDEBUG // Validate inputs are broadcast compatible. @@ -44,6 +55,12 @@ std::vector<TensorShape> ElementwiseBaseLayer::InferOutputShapes(const std::vect dims[i] = std::max(dim0, dim1); } + // Fill in the rest of the shifted dimensions. + for (unsigned int i = 0; i < shiftedDims; i++) + { + dims[i] = input0[i]; + } + return std::vector<TensorShape>({ TensorShape(numDims, dims.data()) }); } diff --git a/src/armnn/optimizations/AddBroadcastReshapeLayer.hpp b/src/armnn/optimizations/AddBroadcastReshapeLayer.hpp new file mode 100644 index 0000000000..6bb53d0f12 --- /dev/null +++ b/src/armnn/optimizations/AddBroadcastReshapeLayer.hpp @@ -0,0 +1,85 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include "Optimization.hpp" + +#include <armnn/utility/IgnoreUnused.hpp> +#include <armnn/utility/PolymorphicDowncast.hpp> + +namespace armnn +{ +namespace optimizations +{ + +static const std::set<armnn::LayerType> broadcastOps { + LayerType::Addition, + LayerType::Division, + LayerType::Maximum, + LayerType::Minimum, + LayerType::Multiplication, + LayerType::Subtraction +}; + +class AddBroadcastReshapeLayerImpl +{ +public: + /// Run for every ElementwiseBaseLayer. Add Broadcast reshape layer if the inputs shape are different. + void Run(Graph& graph, Layer& layer) const + { + if (std::find(broadcastOps.begin(), broadcastOps.end(), layer.GetType()) != broadcastOps.end()) + { + layer.GetInputSlot(0).GetConnectedOutputSlot()->IsTensorInfoSet(); + layer.GetInputSlot(1).GetConnectedOutputSlot()->IsTensorInfoSet(); + + const TensorInfo &inputInfo0 = layer.GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(); + const TensorInfo &inputInfo1 = layer.GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(); + + if (inputInfo0.GetNumDimensions() == inputInfo1.GetNumDimensions()) + { + return; + } + + unsigned int reshapeSlot = 1; + TensorInfo reshapeInfo = inputInfo1; + TensorInfo inputInfo = inputInfo0; + + if (inputInfo0.GetNumDimensions() < inputInfo1.GetNumDimensions()) + { + reshapeSlot = 0; + reshapeInfo = inputInfo0; + inputInfo = inputInfo1; + } + + uint32_t numDimensions = inputInfo.GetNumDimensions(); + + std::vector<unsigned> reshapedDim; + for (unsigned int i = 0; i < reshapeInfo.GetNumDimensions(); ++i) + { + reshapedDim.push_back(reshapeInfo.GetShape()[i]); + } + + std::vector<unsigned int> reshapedDimensions(numDimensions, 1); + std::copy_backward (reshapedDim.begin(), reshapedDim.end(), reshapedDimensions.end()); + + reshapeInfo.SetShape(armnn::TensorShape{ numDimensions, reshapedDimensions.data() }); + const std::string layerName = "Reshape_for:" + layer.GetNameStr() + "-" + std::to_string(reshapeSlot); + const ReshapeDescriptor descriptor{reshapeInfo.GetShape()}; + ReshapeLayer *reshapeLayer = graph.InsertNewLayer<ReshapeLayer>(layer.GetInputSlot(reshapeSlot), + descriptor, + layerName.c_str()); + reshapeLayer->GetOutputSlot().SetTensorInfo(reshapeInfo); + } + } + +protected: + AddBroadcastReshapeLayerImpl() = default; + ~AddBroadcastReshapeLayerImpl() = default; +}; + +using AddBroadcastReshapeLayer = OptimizeForType<Layer, AddBroadcastReshapeLayerImpl>; + +} // namespace optimizations +} // namespace armnn diff --git a/src/armnn/optimizations/All.hpp b/src/armnn/optimizations/All.hpp index cb484d5a59..e89c36b834 100644 --- a/src/armnn/optimizations/All.hpp +++ b/src/armnn/optimizations/All.hpp @@ -4,6 +4,7 @@ // #pragma once +#include "AddBroadcastReshapeLayer.hpp" #include "AddDebug.hpp" #include "ConvertConstants.hpp" #include "ConvertFp32NetworkToBf16.hpp" diff --git a/src/armnn/test/optimizations/AddBroadcastReshapeLayerTests.cpp b/src/armnn/test/optimizations/AddBroadcastReshapeLayerTests.cpp new file mode 100644 index 0000000000..fe3cc31838 --- /dev/null +++ b/src/armnn/test/optimizations/AddBroadcastReshapeLayerTests.cpp @@ -0,0 +1,288 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "../GraphUtils.hpp" +#include "../TestUtils.hpp" + +#include <Optimizer.hpp> + +#include <boost/test/unit_test.hpp> + +using namespace armnn; + +BOOST_AUTO_TEST_SUITE(Optimizer) +using namespace optimizations; + +void AddBroadcastReshapeLayerOptimizerTest(const TensorInfo& info0, + const TensorInfo& info1, + const TensorInfo& outputInfo, + const std::string& reshapeLayerName, + const TensorShape& expectedReshapeShape, + const DataType expectedDataType) +{ + Graph graph; + + auto input0 = graph.AddLayer<InputLayer>(0, "input0"); + auto input1 = graph.AddLayer<InputLayer>(1, "input1"); + auto add = graph.AddLayer<AdditionLayer>("add"); + auto output = graph.AddLayer<OutputLayer>(0, "output"); + input0->GetOutputSlot().SetTensorInfo(info0); + input1->GetOutputSlot().SetTensorInfo(info1); + add->GetOutputSlot().SetTensorInfo(outputInfo); + + input0->GetOutputSlot().Connect(add->GetInputSlot(0)); + input1->GetOutputSlot().Connect(add->GetInputSlot(1)); + add->GetOutputSlot().Connect(output->GetInputSlot(0)); + + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<AdditionLayer>, + &IsLayerOfType<OutputLayer>)); + + // Run optimizer + armnn::Optimizer::Pass(graph, MakeOptimizations(AddBroadcastReshapeLayer())); + + // Broadcast reshape layer has been added to the graph correctly + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<ReshapeLayer>, + &IsLayerOfType<AdditionLayer>, + &IsLayerOfType<OutputLayer>)); + + Layer* const reshapeLayer = GetFirstLayerWithName(graph, reshapeLayerName); + BOOST_TEST(reshapeLayer); + auto addedReshapeTensorInfo = reshapeLayer->GetOutputSlot().GetTensorInfo(); + + // Tensorshape and the data type are correct + BOOST_TEST((addedReshapeTensorInfo.GetShape() == expectedReshapeShape)); + BOOST_TEST((addedReshapeTensorInfo.GetDataType() == expectedDataType)); +} + +BOOST_AUTO_TEST_CASE(AddBroadcastReshapeLayerSimpleTest) +{ + const TensorInfo info0({ 1, 2, 3, 5 }, DataType::Float32); + const TensorInfo info1({ 1 }, DataType::Float32); + AddBroadcastReshapeLayerOptimizerTest(info0, info1, info0, "Reshape_for:add-1", + TensorShape({ 1, 1, 1, 1 }), + DataType::Float32); +} + +BOOST_AUTO_TEST_CASE(AddBroadcastReshapeLayer1DTest) +{ + const TensorInfo info0({ 1, 2, 3, 5 }, DataType::Float32); + const TensorInfo info1({ 5 }, DataType::Float32); + const TensorInfo outputInfo({ 1, 1, 1, 5 }, DataType::Float32); + AddBroadcastReshapeLayerOptimizerTest(info0, info1, outputInfo, "Reshape_for:add-1", + TensorShape({ 1, 1, 1, 5 }), + DataType::Float32); +} + +BOOST_AUTO_TEST_CASE(AddBroadcastReshapeLayer2DTest) +{ + const TensorInfo info0({ 1, 2, 3, 5 }, DataType::Float32); + const TensorInfo info1({ 3, 5 }, DataType::Float32); + const TensorInfo outputInfo({ 1, 2, 3, 5 }, DataType::Float32); + AddBroadcastReshapeLayerOptimizerTest(info0, info1, outputInfo, "Reshape_for:add-1", + TensorShape({ 1, 1, 3, 5 }), + DataType::Float32); +} + +BOOST_AUTO_TEST_CASE(AddBroadcastReshapeLayer3DTest) +{ + const TensorInfo info0({ 2, 1, 1, 1 }, DataType::Float32); + const TensorInfo info1({ 3, 4, 5 }, DataType::Float32); + const TensorInfo outputInfo({ 2, 3, 4, 5 }, DataType::Float32); + AddBroadcastReshapeLayerOptimizerTest(info0, info1, outputInfo, "Reshape_for:add-1", + TensorShape({ 1, 3, 4, 5 }), + DataType::Float32); +} + +BOOST_AUTO_TEST_CASE(AddBroadcastReshapeLayer3DMergedTest) +{ + const TensorInfo info0({ 2, 3, 1, 1 }, DataType::Float32); + const TensorInfo info1({ 3, 4, 5 }, DataType::Float32); + const TensorInfo outputInfo({ 2, 3, 4, 5 }, DataType::Float32); + AddBroadcastReshapeLayerOptimizerTest(info0, info1, outputInfo, "Reshape_for:add-1", + TensorShape({ 1, 3, 4, 5 }), + DataType::Float32); +} + +BOOST_AUTO_TEST_CASE(AddBroadcastReshapeLayerSubtractionTest) +{ + Graph graph; + const TensorInfo info0({ 5 }, DataType::Float32); + const TensorInfo info1({ 1, 2, 3, 5 }, DataType::Float32); + const TensorInfo outputInfo({ 1, 2, 3, 5 }, DataType::Float32); + + auto input0 = graph.AddLayer<InputLayer>(0, "input0"); + auto input1 = graph.AddLayer<InputLayer>(1, "input1"); + auto sub = graph.AddLayer<SubtractionLayer>("sub"); + auto output = graph.AddLayer<OutputLayer>(0, "output"); + input0->GetOutputSlot().SetTensorInfo(info0); + input1->GetOutputSlot().SetTensorInfo(info1); + sub->GetOutputSlot().SetTensorInfo(outputInfo); + + input0->GetOutputSlot().Connect(sub->GetInputSlot(0)); + input1->GetOutputSlot().Connect(sub->GetInputSlot(1)); + sub->GetOutputSlot().Connect(output->GetInputSlot(0)); + + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<SubtractionLayer>, + &IsLayerOfType<OutputLayer>)); + + // Run optimizer + armnn::Optimizer::Pass(graph, MakeOptimizations(AddBroadcastReshapeLayer())); + + // Broadcast reshape layer has been added to the graph correctly + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<ReshapeLayer>, + &IsLayerOfType<SubtractionLayer>, + &IsLayerOfType<OutputLayer>)); + + Layer* const reshapeLayer = GetFirstLayerWithName(graph, "Reshape_for:sub-0"); + BOOST_TEST(reshapeLayer); + auto addedReshapeTensorInfo = reshapeLayer->GetOutputSlot().GetTensorInfo(); + + // Tensorshape and the data type are correct + BOOST_TEST((addedReshapeTensorInfo.GetShape() == TensorShape({ 1, 1, 1, 5 }))); + BOOST_TEST((addedReshapeTensorInfo.GetDataType() == DataType::Float32)); +} + +BOOST_AUTO_TEST_CASE(AddBroadcastReshapeLayerDivisionTest) +{ + Graph graph; + const TensorInfo info0({ 1, 4, 5 }, DataType::QAsymmS8); + const TensorInfo info1({ 1, 2, 4, 5 }, DataType::QAsymmS8); + const TensorInfo outputInfo({ 1, 2, 4, 5 }, DataType::QAsymmS8); + + auto input0 = graph.AddLayer<InputLayer>(0, "input0"); + auto input1 = graph.AddLayer<InputLayer>(1, "input1"); + auto div = graph.AddLayer<DivisionLayer>("div"); + auto output = graph.AddLayer<OutputLayer>(0, "output"); + input0->GetOutputSlot().SetTensorInfo(info0); + input1->GetOutputSlot().SetTensorInfo(info1); + div->GetOutputSlot().SetTensorInfo(outputInfo); + + input0->GetOutputSlot().Connect(div->GetInputSlot(0)); + input1->GetOutputSlot().Connect(div->GetInputSlot(1)); + div->GetOutputSlot().Connect(output->GetInputSlot(0)); + + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<DivisionLayer>, + &IsLayerOfType<OutputLayer>)); + + // Run optimizer + armnn::Optimizer::Pass(graph, MakeOptimizations(AddBroadcastReshapeLayer())); + + // Broadcast reshape layer has been added to the graph correctly + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<ReshapeLayer>, + &IsLayerOfType<DivisionLayer>, + &IsLayerOfType<OutputLayer>)); + + Layer* const reshapeLayer = GetFirstLayerWithName(graph, "Reshape_for:div-0"); + BOOST_TEST(reshapeLayer); + auto addedReshapeTensorInfo = reshapeLayer->GetOutputSlot().GetTensorInfo(); + + // Tensorshape and the data type are correct + BOOST_TEST((addedReshapeTensorInfo.GetShape() == TensorShape({ 1, 1, 4, 5 }))); + BOOST_TEST((addedReshapeTensorInfo.GetDataType() == DataType::QAsymmS8)); +} + +BOOST_AUTO_TEST_CASE(AddBroadcastReshapeLayerMultiplicationTest) +{ + Graph graph; + const TensorInfo info0({ 3, 5 }, DataType::QAsymmU8); + const TensorInfo info1({ 1, 2, 3, 5 }, DataType::QAsymmU8); + const TensorInfo outputInfo({ 1, 2, 3, 5 }, DataType::QAsymmU8); + + auto input0 = graph.AddLayer<InputLayer>(0, "input0"); + auto input1 = graph.AddLayer<InputLayer>(1, "input1"); + auto mul = graph.AddLayer<MultiplicationLayer>("mul"); + auto output = graph.AddLayer<OutputLayer>(0, "output"); + input0->GetOutputSlot().SetTensorInfo(info0); + input1->GetOutputSlot().SetTensorInfo(info1); + mul->GetOutputSlot().SetTensorInfo(outputInfo); + + input0->GetOutputSlot().Connect(mul->GetInputSlot(0)); + input1->GetOutputSlot().Connect(mul->GetInputSlot(1)); + mul->GetOutputSlot().Connect(output->GetInputSlot(0)); + + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<MultiplicationLayer>, + &IsLayerOfType<OutputLayer>)); + + // Run optimizer + armnn::Optimizer::Pass(graph, MakeOptimizations(AddBroadcastReshapeLayer())); + + // Broadcast reshape layer has been added to the graph correctly + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<ReshapeLayer>, + &IsLayerOfType<MultiplicationLayer>, + &IsLayerOfType<OutputLayer>)); + + Layer* const reshapeLayer = GetFirstLayerWithName(graph, "Reshape_for:mul-0"); + BOOST_TEST(reshapeLayer); + auto addedReshapeTensorInfo = reshapeLayer->GetOutputSlot().GetTensorInfo(); + + // Tensorshape and the data type are correct + BOOST_TEST((addedReshapeTensorInfo.GetShape() == TensorShape({ 1, 1, 3, 5 }))); + BOOST_TEST((addedReshapeTensorInfo.GetDataType() == DataType::QAsymmU8)); +} + +BOOST_AUTO_TEST_CASE(AddNoBroadcastReshapeLayerTest) +{ + Graph graph; + const TensorInfo info0({ 1, 1, 1, 1 }, DataType::QAsymmU8); + const TensorInfo info1({ 1, 2, 3, 5 }, DataType::QAsymmU8); + const TensorInfo outputInfo({ 1, 2, 3, 5 }, DataType::QAsymmU8); + + auto input0 = graph.AddLayer<InputLayer>(0, "input0"); + auto input1 = graph.AddLayer<InputLayer>(1, "input1"); + auto mul = graph.AddLayer<MultiplicationLayer>("mul"); + auto output = graph.AddLayer<OutputLayer>(0, "output"); + input0->GetOutputSlot().SetTensorInfo(info0); + input1->GetOutputSlot().SetTensorInfo(info1); + mul->GetOutputSlot().SetTensorInfo(outputInfo); + + input0->GetOutputSlot().Connect(mul->GetInputSlot(0)); + input1->GetOutputSlot().Connect(mul->GetInputSlot(1)); + mul->GetOutputSlot().Connect(output->GetInputSlot(0)); + + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<MultiplicationLayer>, + &IsLayerOfType<OutputLayer>)); + + // Run optimizer + armnn::Optimizer::Pass(graph, MakeOptimizations(AddBroadcastReshapeLayer())); + + // Broadcast reshape layer has not been added to the graph + BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<InputLayer>, + &IsLayerOfType<MultiplicationLayer>, + &IsLayerOfType<OutputLayer>)); + + Layer* const reshapeLayer = GetFirstLayerWithName(graph, "Reshape_for:mul-0"); + BOOST_TEST(!reshapeLayer); +} + +BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp index 109c2c2be1..6143f4af6a 100644 --- a/src/armnnTfLiteParser/TfLiteParser.cpp +++ b/src/armnnTfLiteParser/TfLiteParser.cpp @@ -443,7 +443,7 @@ armnn::TensorInfo ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr, } } -armnn::TensorInfo ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr, +armnn::TensorInfo ToTensorInfo(TfLiteParser::TensorRawPtr tensorPtr, const armnn::PermutationVector& dimensionMappings = {0, 1, 2, 3}) { auto const & dimensions = AsUnsignedVector(tensorPtr->shape); @@ -609,69 +609,6 @@ void TfLiteParser::ResetParser() m_SubgraphConnections.clear(); } -void TfLiteParser::AddBroadcastReshapeLayer(size_t subgraphIndex, - size_t operatorIndex, - IConnectableLayer *layer) -{ - CHECK_MODEL(m_Model, subgraphIndex, operatorIndex); - ARMNN_ASSERT(layer != nullptr); - - const auto & subgraphPtr = m_Model->subgraphs[subgraphIndex]; - const auto & operatorPtr = subgraphPtr->operators[operatorIndex]; - - ARMNN_ASSERT(operatorPtr->inputs.size() > 1); - - uint32_t reshapedInputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[0]); - TensorRawPtr tensorPtr = subgraphPtr->tensors[reshapedInputId].get(); - uint32_t inputId = CHECKED_NON_NEGATIVE(operatorPtr->inputs[1]); - TensorRawPtr tensorPtr1 = subgraphPtr->tensors[inputId].get(); - - armnn::TensorInfo reshapedTensorInfo = ToTensorInfo(tensorPtr); - armnn::TensorInfo inputTensorInfo = ToTensorInfo(tensorPtr1); - - uint32_t inputSlotId = 1; - uint32_t reshapeSlotId = 0; - - if (inputTensorInfo.GetNumDimensions() < reshapedTensorInfo.GetNumDimensions()) - { - uint32_t id = reshapedInputId; - reshapedInputId = inputId; - inputId = id; - - reshapedTensorInfo = ToTensorInfo(tensorPtr1); - inputTensorInfo = ToTensorInfo(tensorPtr); - - inputSlotId = 0; - reshapeSlotId = 1; - } - - uint32_t numDimensions = inputTensorInfo.GetNumDimensions(); - - std::vector<unsigned> reshapedDim; - for (unsigned int i = 0; i < reshapedTensorInfo.GetNumDimensions(); ++i) - { - reshapedDim.push_back(reshapedTensorInfo.GetShape()[i]); - } - - std::vector<unsigned int> reshapedDimensions(numDimensions, 1); - std::copy_backward (reshapedDim.begin(), reshapedDim.end(), reshapedDimensions.end()); - - reshapedTensorInfo.SetShape(armnn::TensorShape{ numDimensions, reshapedDimensions.data() }); - - std::string layerName = boost::str(boost::format("Reshape_for:%1%") % layer->GetName()); - armnn::ReshapeDescriptor desc; - desc.m_TargetShape = reshapedTensorInfo.GetShape(); - armnn::IConnectableLayer* reshapeLayer = m_Network->AddReshapeLayer(desc, layerName.c_str()); - - reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedTensorInfo); - reshapeLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(reshapeSlotId)); - - RegisterInputSlots(subgraphIndex, operatorIndex, reshapeLayer, {reshapedInputId}); - - armnn::IInputSlot* input1Slot = &(layer->GetInputSlot(inputSlotId)); - RegisterConsumerOfTensor(subgraphIndex, inputId, input1Slot); -} - INetworkPtr TfLiteParser::CreateNetworkFromBinaryFile(const char* graphFile) { ResetParser(); @@ -995,7 +932,7 @@ void TfLiteParser::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorInd // Mappings from TensorflowLite filter tensors to the ArmNN filter tensors (ArmNN weights have to be [M, I, H, W]) PermutationVector permutationVector{ 2, 3, 1, 0 }; // [H, W, I, M] -> [M, I, H, W] - + armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]); armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1], permutationVector); @@ -1353,14 +1290,7 @@ void TfLiteParser::ParseMaximum(size_t subgraphIndex, size_t operatorIndex) layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); - if (inputTensorInfo.GetNumDimensions() != input1TensorInfo.GetNumDimensions()) - { - AddBroadcastReshapeLayer(subgraphIndex, operatorIndex, layer); - } - else - { - RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); - } + RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex)); RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]}); @@ -1390,14 +1320,7 @@ void TfLiteParser::ParseMinimum(size_t subgraphIndex, size_t operatorIndex) layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); - if (inputTensorInfo.GetNumDimensions() != input1TensorInfo.GetNumDimensions()) - { - AddBroadcastReshapeLayer(subgraphIndex, operatorIndex, layer); - } - else - { - RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); - } + RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex)); RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]}); @@ -1768,14 +1691,7 @@ void TfLiteParser::ParseSub(size_t subgraphIndex, size_t operatorIndex) layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); - if (inputTensorInfo.GetNumDimensions() != input1TensorInfo.GetNumDimensions()) - { - AddBroadcastReshapeLayer(subgraphIndex, operatorIndex, layer); - } - else - { - RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); - } + RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function); @@ -1807,15 +1723,7 @@ void TfLiteParser::ParseDiv(size_t subgraphIndex, size_t operatorIndex) layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); - if (inputTensorInfo.GetNumDimensions() != input1TensorInfo.GetNumDimensions()) - { - AddBroadcastReshapeLayer(subgraphIndex, operatorIndex, layer); - } - else - { - RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); - } - + RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function); auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1846,15 +1754,7 @@ void TfLiteParser::ParseAdd(size_t subgraphIndex, size_t operatorIndex) layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); - if (inputTensorInfo.GetNumDimensions() != input1TensorInfo.GetNumDimensions()) - { - AddBroadcastReshapeLayer(subgraphIndex, operatorIndex, layer); - } - else - { - RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); - } - + RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function); auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex)); @@ -1885,15 +1785,7 @@ void TfLiteParser::ParseMul(size_t subgraphIndex, size_t operatorIndex) layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex)); - if (inputTensorInfo.GetNumDimensions() != input1TensorInfo.GetNumDimensions()) - { - AddBroadcastReshapeLayer(subgraphIndex, operatorIndex, layer); - } - else - { - RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); - } - + RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0], inputTensorIndexes[1]}); layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function); auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex)); diff --git a/src/armnnTfLiteParser/test/LoadScopeDynamicTensor.cpp b/src/armnnTfLiteParser/test/LoadScopeDynamicTensor.cpp index c4f0db7f49..89a6640e41 100644 --- a/src/armnnTfLiteParser/test/LoadScopeDynamicTensor.cpp +++ b/src/armnnTfLiteParser/test/LoadScopeDynamicTensor.cpp @@ -171,4 +171,209 @@ BOOST_FIXTURE_TEST_CASE(LoadScopeDynamicTensor2, LoadScopeDynamicTensor2Fixture) true); } +struct LoadScopeDynamicTensorBroadcastingFixture : public ParserFlatbuffersFixture +{ + explicit LoadScopeDynamicTensorBroadcastingFixture(const std::string& inputShape0, + const std::string& inputShape1, + const std::string& inputShape2, + const std::string& addShape, + const std::string& outputShape) + { + m_JsonString = R"( + { + "version": 3, + "operator_codes": [ + { + "builtin_code": "ADD", + "version": 1 + }, + { + "builtin_code": "SUB", + "version": 1 + } + ], + "subgraphs": [ + { + "tensors": [ + { + "shape": )" + inputShape0 + R"(, + "type": "FLOAT32", + "buffer": 1, + "name": "input0", + "quantization": { + "details_type": 0, + "quantized_dimension": 0 + }, + "is_variable": false + }, + { + "shape": )" + inputShape1 + R"(, + "type": "FLOAT32", + "buffer": 2, + "name": "input1", + "quantization": { + "details_type": 0, + "quantized_dimension": 0 + }, + "is_variable": false + }, + { + "shape": )" + outputShape + R"(, + "type": "FLOAT32", + "buffer": 5, + "name": "output", + "quantization": { + "details_type": 0, + "quantized_dimension": 0 + }, + "is_variable": false + }, + + { + "shape": )" + addShape + R"(, + "type": "FLOAT32", + "buffer": 4, + "name": "model/add/add", + "quantization": { + "details_type": 0, + "quantized_dimension": 0 + }, + "is_variable": false + }, + { + "shape": )" + inputShape2 + R"(, + "type": "FLOAT32", + "buffer": 3, + "name": "input2", + "quantization": { + "details_type": 0, + "quantized_dimension": 0 + }, + "is_variable": false + }, + ], + "inputs": [ + 0, + 1, + 4 + ], + "outputs": [ + 2 + ], + "operators": [ + { + "opcode_index": 0, + "inputs": [ + 0, + 1 + ], + "outputs": [ + 3 + ], + "builtin_options_type": "AddOptions", + "builtin_options": { + "fused_activation_function": "NONE" + }, + "custom_options_format": "FLEXBUFFERS" + }, + { + "opcode_index": 1, + "inputs": [ + 3, + 4 + ], + "outputs": [ + 2 + ], + "builtin_options_type": "SubOptions", + "builtin_options": { + "fused_activation_function": "NONE" + }, + "custom_options_format": "FLEXBUFFERS" + } + ], + "name": "main" + } + ], + "buffers": [ + { + }, + { + }, + { + }, + { + }, + { + }, + { + } + ] + } + )"; + Setup(); + } +}; + +struct LoadScopeDynamicTensorBroadcasting3DFixture : LoadScopeDynamicTensorBroadcastingFixture +{ + LoadScopeDynamicTensorBroadcasting3DFixture() : LoadScopeDynamicTensorBroadcastingFixture("[ 1, 2, 3, 2 ]", + "[ 2, 3, 2 ]", + "[ 2, 3, 2 ]", + "[ 1, 2, 3, 2 ]", "[]") {} +}; + +struct LoadScopeDynamicTensorBroadcasting2DFixture : LoadScopeDynamicTensorBroadcastingFixture +{ + LoadScopeDynamicTensorBroadcasting2DFixture() : LoadScopeDynamicTensorBroadcastingFixture("[ 1, 2, 3, 2 ]", + "[ 3, 2 ]", + "[ 3, 2 ]", + "[]", "[]") {} +}; + +struct LoadScopeDynamicTensorBroadcasting1DFixture : LoadScopeDynamicTensorBroadcastingFixture +{ + LoadScopeDynamicTensorBroadcasting1DFixture() : LoadScopeDynamicTensorBroadcastingFixture("[ 1, 2, 3, 2 ]", + "[ 1 ]", + "[ 1 ]", + "[]", + "[ 1, 2, 3, 2 ]") {} +}; + +BOOST_FIXTURE_TEST_CASE(LoadScopeDynamicTensorBroadcasting3D, LoadScopeDynamicTensorBroadcasting3DFixture) +{ + RunTest<4, armnn::DataType::Float32, armnn::DataType::Float32>( + 0, + { {"input0", { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f }}, + {"input1", { 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f }}, + {"input2", { 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f }} + }, + { {"output", { 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f }} }, + true); +} + +BOOST_FIXTURE_TEST_CASE(LoadScopeDynamicTensorBroadcasting2D, LoadScopeDynamicTensorBroadcasting2DFixture) +{ + RunTest<4, armnn::DataType::Float32, armnn::DataType::Float32>( + 0, + { {"input0", { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f }}, + {"input1", { 3.f, 4.f, 5.f, 6.f, 7.f, 8.f }}, + {"input2", { -1.f, -2.f, 3.f, 4.f, 5.f, 6.f }} + }, + { {"output", { 4.f, 7.f, 4.f, 5.f, 6.f, 7.f, 10.f, 13.f, 10.f, 11.f, 12.f, 13.f }} }, + true); +} + +BOOST_FIXTURE_TEST_CASE(LoadScopeDynamicTensorBroadcasting1D, LoadScopeDynamicTensorBroadcasting1DFixture) +{ + RunTest<4, armnn::DataType::Float32, armnn::DataType::Float32>( + 0, + { {"input0", { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f }}, + {"input1", { 5.f }}, + {"input2", { 1.f }} + }, + { {"output", { 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f }} }, + true); +} + BOOST_AUTO_TEST_SUITE_END() |