diff options
author | Francis Murtagh <francis.murtagh@arm.com> | 2022-12-21 09:10:04 +0000 |
---|---|---|
committer | Francis Murtagh <francis.murtagh@arm.com> | 2023-01-12 11:11:28 +0000 |
commit | 01f72693d39ed966ad06adadc8aac141bc395659 (patch) | |
tree | d619d2c112bff714d38025b57370aa4095935e36 /src/armnn | |
parent | 05b6a3e5946a3f58b6f5b0caface9153a1c2b364 (diff) | |
download | armnn-01f72693d39ed966ad06adadc8aac141bc395659.tar.gz |
IVGCVSW-7418 Allow working copy SubgraphView to get Original Slots
* API to remove need for workaround so backend users can get slots
* OutputSlots outside the SubgraphView needed to obtain TensorInfo
* Fix a few Copyright headers
* Add shared_ptr back to original subgraph view using
std::enable_shared_from_this
Signed-off-by: Francis Murtagh <francis.murtagh@arm.com>
Change-Id: I033a00d6fc4020619d406ac06a156b7e380a426a
Diffstat (limited to 'src/armnn')
-rw-r--r-- | src/armnn/Graph.cpp | 2 | ||||
-rw-r--r-- | src/armnn/SubgraphView.cpp | 56 | ||||
-rw-r--r-- | src/armnn/SubgraphViewSelector.cpp | 5 | ||||
-rw-r--r-- | src/armnn/SubgraphViewSelector.hpp | 5 | ||||
-rw-r--r-- | src/armnn/test/SubgraphViewTests.cpp | 138 |
5 files changed, 171 insertions, 35 deletions
diff --git a/src/armnn/Graph.cpp b/src/armnn/Graph.cpp index e5d123830c..6943076ada 100644 --- a/src/armnn/Graph.cpp +++ b/src/armnn/Graph.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // diff --git a/src/armnn/SubgraphView.cpp b/src/armnn/SubgraphView.cpp index b48529c523..fef6390bf2 100644 --- a/src/armnn/SubgraphView.cpp +++ b/src/armnn/SubgraphView.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017, 2019-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -42,7 +42,8 @@ void AssertIfNullsOrDuplicates(const C& container, const std::string& errorMessa } // anonymous namespace SubgraphView::SubgraphView(Graph& graph) - : m_InputSlots{} + : enable_shared_from_this() + , m_InputSlots{} , m_OutputSlots{} , m_Layers(graph.begin(), graph.end()) , m_IConnectableLayers(graph.begin(), graph.end()) @@ -53,7 +54,8 @@ SubgraphView::SubgraphView(Graph& graph) /// IConnectable Duplication to maintain backwards compatibility SubgraphView::SubgraphView(InputSlots&& inputs, OutputSlots&& outputs, Layers&& layers) - : m_InputSlots{InputSlots{inputs.begin(), inputs.end()}} + : enable_shared_from_this() + , m_InputSlots{InputSlots{inputs.begin(), inputs.end()}} , m_IInputSlots{IInputSlots{inputs.begin(), inputs.end()}} , m_OutputSlots{OutputSlots{outputs.begin(), outputs.end()}} , m_IOutputSlots{IOutputSlots{outputs.begin(), outputs.end()}} @@ -68,7 +70,8 @@ SubgraphView::SubgraphView(InputSlots&& inputs, OutputSlots&& outputs, Layers&& SubgraphView::SubgraphView(SubgraphView::IConnectableLayers&& layers, SubgraphView::IInputSlots&& inputs, SubgraphView::IOutputSlots&& outputs) - : m_IInputSlots{inputs} + : enable_shared_from_this() + , m_IInputSlots{inputs} , m_IOutputSlots{outputs} , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()}) { @@ -104,7 +107,8 @@ SubgraphView::SubgraphView(SubgraphView::IConnectableLayers&& layers, SubgraphView::IInputSlots&& inputs, SubgraphView::IOutputSlots&& outputs, std::shared_ptr<SubgraphViewWorkingCopy> ptr) - : m_IInputSlots{inputs} + : enable_shared_from_this() + , m_IInputSlots{inputs} , m_IOutputSlots{outputs} , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()}) , p_WorkingCopyImpl(std::move(ptr)) @@ -137,7 +141,8 @@ SubgraphView::SubgraphView(SubgraphView::IConnectableLayers&& layers, } SubgraphView::SubgraphView(const SubgraphView& subgraph) - : m_InputSlots(subgraph.m_InputSlots.begin(), subgraph.m_InputSlots.end()) + : enable_shared_from_this() + , m_InputSlots(subgraph.m_InputSlots.begin(), subgraph.m_InputSlots.end()) , m_IInputSlots(subgraph.m_IInputSlots.begin(), subgraph.m_IInputSlots.end()) , m_OutputSlots(subgraph.m_OutputSlots.begin(), subgraph.m_OutputSlots.end()) , m_IOutputSlots(subgraph.m_IOutputSlots.begin(), subgraph.m_IOutputSlots.end()) @@ -150,7 +155,8 @@ SubgraphView::SubgraphView(const SubgraphView& subgraph) } SubgraphView::SubgraphView(SubgraphView&& subgraph) - : m_InputSlots(std::move(subgraph.m_InputSlots)) + : enable_shared_from_this() + , m_InputSlots(std::move(subgraph.m_InputSlots)) , m_IInputSlots(std::move(subgraph.m_IInputSlots)) , m_OutputSlots(std::move(subgraph.m_OutputSlots)) , m_IOutputSlots(std::move(subgraph.m_IOutputSlots)) @@ -162,7 +168,8 @@ SubgraphView::SubgraphView(SubgraphView&& subgraph) } SubgraphView::SubgraphView(IConnectableLayer* layer) - : m_Layers{PolymorphicDowncast<Layer*>(layer)} + : enable_shared_from_this() + , m_Layers{PolymorphicDowncast<Layer*>(layer)} , m_IConnectableLayers{layer} { unsigned int numInputSlots = layer->GetNumInputSlots(); @@ -408,11 +415,13 @@ struct SubgraphView::SubgraphViewWorkingCopy public: SubgraphViewWorkingCopy() = default; - SubgraphViewWorkingCopy(Graph graph) + SubgraphViewWorkingCopy(Graph graph, std::shared_ptr<const SubgraphView> originalSubgraphView) : m_Graph(graph) + , m_OriginalSubgraphView(originalSubgraphView) {}; Graph m_Graph; + std::shared_ptr<const SubgraphView> m_OriginalSubgraphView; }; @@ -426,7 +435,7 @@ SubgraphView SubgraphView::GetWorkingCopy() const // Create a cut down SubgraphView with underlying graph containing only the relevant layers. // It needs its own underlying layers so that they can be replaced safely. - auto ptr = std::make_shared<SubgraphViewWorkingCopy>(Graph()); + auto ptr = std::make_shared<SubgraphViewWorkingCopy>(Graph(), shared_from_this()); std::unordered_map<const IConnectableLayer*, IConnectableLayer*> originalToClonedLayerMap; std::list<armnn::IConnectableLayer*> originalSubgraphLayers = GetIConnectableLayers(); @@ -607,5 +616,32 @@ void SubgraphView::SubstituteSubgraph(SubgraphView& patternSubgraph, const Subgr workingCopyGraph->m_Layers.end() }; } +const SubgraphView::IInputSlots& SubgraphView::GetOriginalInputSlots() const +{ + if (!p_WorkingCopyImpl) + { + throw NullPointerException("The SubgraphView calling GetOriginalInputSlots is not a working copy. " + "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()"); + } + if (!p_WorkingCopyImpl->m_OriginalSubgraphView) + { + throw NullPointerException("The working copy SubgraphView pointer to its original SubgraphView is null."); + } + return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIInputSlots(); +} +const SubgraphView::IOutputSlots& SubgraphView::GetOriginalOutputSlots() const +{ + if (!p_WorkingCopyImpl) + { + throw NullPointerException("The SubgraphView calling GetOriginalOutputSlots is not a working copy. " + "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()"); + } + if (!p_WorkingCopyImpl->m_OriginalSubgraphView) + { + throw NullPointerException("The working copy SubgraphView pointer to its original SubgraphView is null."); + } + return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIOutputSlots(); +} + } // namespace armnn diff --git a/src/armnn/SubgraphViewSelector.cpp b/src/armnn/SubgraphViewSelector.cpp index b632149924..9fa8252790 100644 --- a/src/armnn/SubgraphViewSelector.cpp +++ b/src/armnn/SubgraphViewSelector.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017, 2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -524,7 +524,8 @@ SubgraphViewSelector::SelectSubgraphs(SubgraphView& subgraph, const LayerSelecto // Sort subgraphs list into deterministic order, not relying on pointer values which may be different on each // execution. This makes debugging the optimised graph much easier as subsequent stages can also be // deterministic. - std::sort(result.begin(), result.end(), [](const SubgraphViewPtr& a, const SubgraphViewPtr& b) + std::sort(result.begin(), result.end(), [](const SubgraphView::SubgraphViewPtr& a, + const SubgraphView::SubgraphViewPtr& b) { return a->GetIConnectableLayers().front()->GetGuid() < b->GetIConnectableLayers().front()->GetGuid(); }); diff --git a/src/armnn/SubgraphViewSelector.hpp b/src/armnn/SubgraphViewSelector.hpp index 0a05bc259e..4808a99fb9 100644 --- a/src/armnn/SubgraphViewSelector.hpp +++ b/src/armnn/SubgraphViewSelector.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017, 2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once @@ -21,8 +21,7 @@ class Graph; class SubgraphViewSelector final { public: - using SubgraphViewPtr = std::unique_ptr<SubgraphView>; - using Subgraphs = std::vector<SubgraphViewPtr>; + using Subgraphs = std::vector<SubgraphView::SubgraphViewPtr>; using LayerSelectorFunction = std::function<bool(const Layer&)>; /// Selects subgraphs from a graph based on the selector function and the algorithm. diff --git a/src/armnn/test/SubgraphViewTests.cpp b/src/armnn/test/SubgraphViewTests.cpp index 9bb5e69bbb..48f4a7fc01 100644 --- a/src/armnn/test/SubgraphViewTests.cpp +++ b/src/armnn/test/SubgraphViewTests.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2017, 2019-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -119,14 +119,14 @@ SubgraphView::IOutputSlots CreateIOutputsFrom(const std::vector<armnn::IConnecta // this takes the inputs, outputs and layers as a copy and the move these copies into the // resulting subgraph, so the pass by value is intentional // -SubgraphViewSelector::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots&& inputs, +SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots&& inputs, SubgraphView::OutputSlots&& outputs, SubgraphView::Layers&& layers) { return std::make_unique<SubgraphView>(std::move(inputs), std::move(outputs), std::move(layers)); } -SubgraphViewSelector::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::IConnectableLayers&& layers, +SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::IConnectableLayers&& layers, SubgraphView::IInputSlots&& inputs, SubgraphView::IOutputSlots&& outputs) { @@ -147,8 +147,8 @@ void CompareVectors(const std::vector<T>& result, const std::vector<T>& expected CHECK(std::equal(result.begin(), result.end(), expected.begin(), expected.end())); } -void CompareSubgraphViews(SubgraphViewSelector::SubgraphViewPtr& result, - SubgraphViewSelector::SubgraphViewPtr& expected) +void CompareSubgraphViews(SubgraphView::SubgraphViewPtr& result, + SubgraphView::SubgraphViewPtr& expected) { // expect both to be valid subgraphs CHECK((result.get() != nullptr)); @@ -256,7 +256,7 @@ TEST_CASE("SubgraphViewSlots") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({}, + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({}, CreateIInputsFrom({convLayer1}, {1, 2}), CreateIOutputsFrom({convLayer2})); @@ -293,7 +293,7 @@ TEST_CASE("SubgraphViewConstructors") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({inputLayer, convLayer1, convLayer2, outputLayer}, CreateIInputsFrom({convLayer1}), CreateIOutputsFrom({convLayer2})); @@ -354,7 +354,7 @@ TEST_CASE("SingleInputSingleOutput") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({}, CreateIInputsFrom({convLayer1}, {1}), CreateIOutputsFrom({convLayer2})); @@ -396,7 +396,7 @@ TEST_CASE("SingleInputSingleOutputAddPrecompiledLayerSubstituteSubgraph1") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}), + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}), CreateOutputsFrom({convLayer2}), {}); @@ -440,7 +440,7 @@ TEST_CASE("SingleInputSingleOutputAddPrecompiledLayerSubstituteSubgraph2") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}), + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}), CreateOutputsFrom({convLayer2}), {}); @@ -485,7 +485,7 @@ TEST_CASE("SingleInputSingleOutputSubstituteGraph") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}), CreateOutputsFrom({convLayer2}), {}); @@ -499,7 +499,7 @@ TEST_CASE("SingleInputSingleOutputSubstituteGraph") PreCompiledDescriptor preCompiledDescriptor(1, 1); Layer* const preCompiledLayer = substituteGraph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled"); - SubgraphViewSelector::SubgraphViewPtr substituteSubgraph = + SubgraphView::SubgraphViewPtr substituteSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({preCompiledLayer}), CreateOutputsFrom({preCompiledLayer}), {preCompiledLayer}); @@ -587,7 +587,7 @@ TEST_CASE("SingleInputMultiOutput") concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({splitterLayer}), CreateOutputsFrom({convLayer1, convLayer2}), {}); @@ -639,7 +639,7 @@ TEST_CASE("MultiInputMultiOutput") concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1, convLayer2}, {1}), CreateOutputsFrom({convLayer1, convLayer2}), {}); @@ -686,7 +686,7 @@ TEST_CASE("EraseReplacedIConnectableLayers") graph.AddLayer<OutputLayer>(0, "output"); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({splitterLayer, + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({splitterLayer, convLayer1, convLayer2, concatLayer}, @@ -1514,7 +1514,7 @@ TEST_CASE("Random") for (Layer* layer : graph) { size_t i = 0; - for (std::unique_ptr<SubgraphView>& subgraph : subgraphs) + for (auto& subgraph : subgraphs) { std::string name = std::to_string(i++); if (std::find(subgraph->cbeginIConnectable(), subgraph->cendIConnectable(), layer) @@ -1551,7 +1551,7 @@ TEST_CASE("Random") // Check the dependencies between subgraphs to make sure that the algorithm has produced a valid result. // Starting from each of the input slots of each subgraph, recurse up the graph and ensure that we never // encounter a layer that belongs to the subgraph that we started from. - for (std::unique_ptr<SubgraphView>& subgraph : subgraphs) + for (auto& subgraph : subgraphs) { for (IInputSlot* inSlot : subgraph->GetIInputSlots()) { @@ -2092,6 +2092,106 @@ TEST_CASE("SubgraphViewPartialWorkingCopySubstituteSubgraph") CHECK(std::string((*workingCopy.beginIConnectable())->GetName()) == "Activation2"); } +// Workaround function used to get the original OutputSlot connected to the InputSlot of a SubgraphView +// As working copy SubgraphViews do not have connections on boundary it finds the corresponding InputSlot +// on the Original SubgraphView and then returns the OutputSlot connected to it. +// Using this function to test against the simpler API: SubgraphView::GetOriginalInputSlots(). +const IOutputSlot* GetConnection(IInputSlot* inputSlot, + const SubgraphView& workingCopy, + const SubgraphView& original) +{ + const IOutputSlot* res = inputSlot->GetConnection(); + if (res) + { + return res; + } + + const SubgraphView::IInputSlots& workingCopyInputSlots = workingCopy.GetIInputSlots(); + const SubgraphView::IInputSlots& originalInputSlots = original.GetIInputSlots(); + for (SubgraphView::InputSlots::size_type i = 0; i < workingCopyInputSlots.size(); i++) + { + if (workingCopyInputSlots[i] == inputSlot) + { + return originalInputSlots[i]->GetConnection(); + } + } + return nullptr; +} + +// Workaround function used to get the original InputSlot connected to the OutputSlot of a SubgraphView +// As working copy SubgraphViews do not have connections on boundary it finds the corresponding OutputSlot +// on the Original SubgraphView and then returns the InputSlot connected to it using index parameter. +// Using this function to test against the simpler API: SubgraphView::GetOriginalOutputSlots(). +const IInputSlot* GetConnection(IOutputSlot* outputSlot, + unsigned int index, + const SubgraphView& workingCopy, + const SubgraphView& original) +{ + const IInputSlot* res; + // Check within range + if (index < outputSlot->GetNumConnections() && outputSlot->GetNumConnections() > 0) + { + res = outputSlot->GetConnection(index); + return res; + } + + const SubgraphView::IOutputSlots& workingCopyOutputSlots = workingCopy.GetIOutputSlots(); + const SubgraphView::IOutputSlots& originalOutputSlots = original.GetIOutputSlots(); + for (SubgraphView::OutputSlots::size_type i = 0; i < workingCopyOutputSlots.size(); i++) + { + if (workingCopyOutputSlots[i] == outputSlot) + { + // Check within range + if (index < originalOutputSlots[i]->GetNumConnections() && originalOutputSlots[i]->GetNumConnections() > 0) + { + return originalOutputSlots[i]->GetConnection(index); + } + } + } + return nullptr; +} + +SubgraphView CheckOutOfScopeWorkingCopy() +{ + Graph graph; + + auto input = graph.AddLayer<InputLayer>(0, "Input"); + auto activation = graph.AddLayer<ActivationLayer>(ActivationDescriptor{}, "Activation"); + auto output = graph.AddLayer<OutputLayer>(1, "Output"); + + input->GetOutputSlot(0).Connect(activation->GetInputSlot(0)); + activation->GetOutputSlot(0).Connect(output->GetInputSlot(0)); + + //Add in out of order + auto shared = CreateSubgraphViewFrom({activation}, + {&activation->GetInputSlot(0)}, + {&activation->GetOutputSlot(0)}); + + auto workingCopy = shared->GetWorkingCopy(); + + // Check InputSlots are same as original + auto boundaryOutputSlot = GetConnection(workingCopy.GetIInputSlots()[0], workingCopy, *shared); + CHECK(boundaryOutputSlot); + + auto inputSlots = workingCopy.GetOriginalInputSlots(); + CHECK(inputSlots[0]->GetConnection() == boundaryOutputSlot); + + // Check OutputSlots are same as original + auto boundaryInputSlot = GetConnection(workingCopy.GetIOutputSlots()[0], 0U, workingCopy, *shared); + CHECK(boundaryInputSlot); + + auto outputSlots = workingCopy.GetOriginalOutputSlots(); + CHECK(outputSlots[0]->GetConnection(0) == boundaryInputSlot); + + return workingCopy; +} + +TEST_CASE("SubgraphViewWorkingCopyOriginalSlots") +{ + auto result = CheckOutOfScopeWorkingCopy(); + auto outputSlots = result.GetOriginalOutputSlots(); +} + TEST_CASE("SubgraphViewWorkingCopyOptimizationViews") { Graph graph; @@ -2394,7 +2494,7 @@ TEST_CASE("MultipleOutputSlotsSubstituteGraph") } // pattern subgraph creation - SubgraphViewSelector::SubgraphViewPtr subgraph = + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({convCopyLayer}, {&convCopyLayer->GetInputSlot(0)}, {&convCopyLayer->GetOutputSlot(0)}); @@ -2491,7 +2591,7 @@ TEST_CASE("MultipleInputMultipleOutputSlots_SubstituteGraph") // pattern subgraph creation IConnectableLayer* constCopyLayer = &addCopyLayer->GetInputSlot(0).GetConnection()->GetOwningIConnectableLayer(); - SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({addCopyLayer, constCopyLayer}, + SubgraphView::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({addCopyLayer, constCopyLayer}, {&addCopyLayer->GetInputSlot(0)}, {&addCopyLayer->GetOutputSlot(0)}); |