14 #include <fmt/format.h>
24 void AssertIfNullsOrDuplicates(
const C& container,
const std::string& errorMessage)
26 using T =
typename C::value_type;
27 std::unordered_set<T> duplicateSet;
28 std::for_each(container.begin(), container.end(), [&duplicateSet, &errorMessage](
const T& i)
33 throw armnn::GraphValidationException(errorMessage.c_str());
37 if (duplicateSet.find(i) != duplicateSet.end())
39 throw armnn::GraphValidationException(errorMessage.c_str());
42 duplicateSet.insert(i);
48 SubgraphView::SubgraphView(
Graph& graph)
49 : enable_shared_from_this()
52 , m_Layers(graph.begin(), graph.end())
53 , m_IConnectableLayers(graph.begin(), graph.end())
61 : enable_shared_from_this()
62 , m_InputSlots{
InputSlots{inputs.begin(), inputs.end()}}
63 , m_IInputSlots{IInputSlots{inputs.begin(), inputs.end()}}
64 , m_OutputSlots{OutputSlots{outputs.begin(), outputs.end()}}
65 , m_IOutputSlots{IOutputSlots{outputs.begin(), outputs.end()}}
67 , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
77 : enable_shared_from_this()
78 , m_IInputSlots{inputs}
79 , m_IOutputSlots{outputs}
80 , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
83 auto f = [](IConnectableLayer* value)
85 return PolymorphicDowncast<Layer*>(value);
87 std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
89 m_InputSlots.resize(inputs.size());
90 m_IInputSlots.resize(inputs.size());
91 for (
unsigned int i = 0; i < inputs.size(); i++)
93 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
94 m_IInputSlots.at(i) = inputs[i];
97 m_OutputSlots.resize(outputs.size());
98 m_IOutputSlots.resize(outputs.size());
99 for (
unsigned int i = 0; i < outputs.size(); i++)
101 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
102 m_IOutputSlots.at(i) = outputs[i];
105 ArrangeBySortOrder();
113 std::shared_ptr<SubgraphViewWorkingCopy> ptr)
114 : enable_shared_from_this()
115 , m_IInputSlots{inputs}
116 , m_IOutputSlots{outputs}
117 , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
118 , p_WorkingCopyImpl(std::move(ptr))
121 auto f = [](IConnectableLayer* value)
123 return PolymorphicDowncast<Layer*>(value);
125 std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
127 m_InputSlots.resize(inputs.size());
128 m_IInputSlots.resize(inputs.size());
129 for (
unsigned int i = 0; i < inputs.size(); i++)
131 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
132 m_IInputSlots.at(i) = inputs[i];
135 m_OutputSlots.resize(outputs.size());
136 m_IOutputSlots.resize(outputs.size());
137 for (
unsigned int i = 0; i < outputs.size(); i++)
139 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
140 m_IOutputSlots.at(i) = outputs[i];
143 ArrangeBySortOrder();
148 : enable_shared_from_this()
149 , m_InputSlots(subgraph.m_InputSlots.begin(), subgraph.m_InputSlots.end())
150 , m_IInputSlots(subgraph.m_IInputSlots.begin(), subgraph.m_IInputSlots.end())
151 , m_OutputSlots(subgraph.m_OutputSlots.begin(), subgraph.m_OutputSlots.end())
152 , m_IOutputSlots(subgraph.m_IOutputSlots.begin(), subgraph.m_IOutputSlots.end())
153 , m_Layers(subgraph.m_Layers.begin(), subgraph.m_Layers.end())
155 subgraph.m_IConnectableLayers.end()})
157 ArrangeBySortOrder();
162 : enable_shared_from_this()
163 , m_InputSlots(
std::move(subgraph.m_InputSlots))
164 , m_IInputSlots(
std::move(subgraph.m_IInputSlots))
165 , m_OutputSlots(
std::move(subgraph.m_OutputSlots))
166 , m_IOutputSlots(
std::move(subgraph.m_IOutputSlots))
167 , m_Layers(
std::move(subgraph.m_Layers))
168 , m_IConnectableLayers(
std::move(subgraph.m_IConnectableLayers))
170 ArrangeBySortOrder();
175 : enable_shared_from_this()
176 , m_Layers{PolymorphicDowncast<Layer*>(layer)}
177 , m_IConnectableLayers{layer}
179 unsigned int numInputSlots = layer->GetNumInputSlots();
180 m_InputSlots.resize(numInputSlots);
181 m_IInputSlots.resize(numInputSlots);
182 for (
unsigned int i = 0; i < numInputSlots; i++)
184 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(&(layer->GetInputSlot(i)));
185 m_IInputSlots.at(i) = &(layer->GetInputSlot(i));
188 unsigned int numOutputSlots = layer->GetNumOutputSlots();
189 m_OutputSlots.resize(numOutputSlots);
190 m_IOutputSlots.resize(numOutputSlots);
191 for (
unsigned int i = 0; i < numOutputSlots; i++)
193 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(&(layer->GetOutputSlot(i)));
194 m_IOutputSlots.at(i) = &(layer->GetOutputSlot(i));
202 m_InputSlots = std::move(other.m_InputSlots);
203 m_IInputSlots = std::move(other.m_IInputSlots);
204 m_OutputSlots = std::move(other.m_OutputSlots);
205 m_IOutputSlots = std::move(other.m_IOutputSlots);
206 m_Layers = std::move(other.m_Layers);
207 m_IConnectableLayers = std::move(other.m_IConnectableLayers);
214 void SubgraphView::CheckSubgraph()
217 AssertIfNullsOrDuplicates(m_InputSlots,
"Sub-graphs cannot contain null or duplicate input slots");
220 AssertIfNullsOrDuplicates(m_OutputSlots,
"Sub-graphs cannot contain null or duplicate output slots");
223 AssertIfNullsOrDuplicates(m_Layers,
"Sub-graphs cannot contain null or duplicate layers");
226 AssertIfNullsOrDuplicates(m_IInputSlots,
"Sub-graphs cannot contain null or duplicate IInputSlots");
229 AssertIfNullsOrDuplicates(m_IOutputSlots,
"Sub-graphs cannot contain null or duplicate IOutputSlots");
232 AssertIfNullsOrDuplicates(m_IConnectableLayers,
233 "Sub-graphs cannot contain null or duplicate IConnectableLayers");
238 return m_IInputSlots;
243 return m_IOutputSlots;
248 return m_IInputSlots.at(index);
253 return m_IInputSlots.at(index);
258 return m_IOutputSlots.at(index);
263 return m_OutputSlots.at(index);
268 return m_IOutputSlots.at(index);
273 return armnn::numeric_cast<unsigned int>(m_IInputSlots.size());
278 return armnn::numeric_cast<unsigned int>(m_IOutputSlots.size());
283 return m_IConnectableLayers;
288 return m_IConnectableLayers.begin();
293 return m_IConnectableLayers.end();
299 return m_IConnectableLayers.begin();
304 return m_IConnectableLayers.end();
309 return m_IConnectableLayers.begin();
314 return m_IConnectableLayers.end();
320 return m_IConnectableLayers.begin();
325 return m_IConnectableLayers.end();
351 m_InputSlots.clear();
352 m_OutputSlots.clear();
355 m_IInputSlots.clear();
356 m_IOutputSlots.clear();
357 m_IConnectableLayers.clear();
360 void SubgraphView::ArrangeBySortOrder()
362 using LayerList = std::list<Layer*>;
363 auto compareLayerPriority = [](
const LayerList::value_type& layerA,
const LayerList::value_type& layerB)
365 return layerA->GetPriority() < layerB->GetPriority();
368 m_Layers.sort(compareLayerPriority);
370 using IConnectableLayersList = std::list<IConnectableLayer*>;
371 auto compareIConnectableLayerPriority = [](
const IConnectableLayersList::value_type& layerA,
372 const IConnectableLayersList::value_type& layerB)
374 return PolymorphicDowncast<Layer*>(layerA)->GetPriority() <
375 PolymorphicDowncast<Layer*>(layerB)->GetPriority();
378 m_IConnectableLayers.sort(compareIConnectableLayerPriority);
381 struct SubgraphView::SubgraphViewWorkingCopy
385 SubgraphViewWorkingCopy() =
default;
386 SubgraphViewWorkingCopy(Graph graph, std::shared_ptr<const SubgraphView> originalSubgraphView)
388 , m_OriginalSubgraphView(originalSubgraphView)
392 std::shared_ptr<const SubgraphView> m_OriginalSubgraphView;
398 if (p_WorkingCopyImpl)
400 throw Exception(
"The SubgraphView calling GetWorkingCopy() is already a working copy. This function "
401 "should be called on original SubgraphView obtained from OptimizeSubgraphView()");
406 auto ptr = std::make_shared<SubgraphViewWorkingCopy>(
Graph(), shared_from_this());
408 std::unordered_map<const IConnectableLayer*, IConnectableLayer*> originalToClonedLayerMap;
411 for (
auto&& originalLayer : originalSubgraphLayers)
413 Layer*
const layer = PolymorphicDowncast<const Layer*>(originalLayer)->
Clone(ptr->m_Graph);
414 originalToClonedLayerMap.emplace(originalLayer, layer);
422 PolymorphicDowncast<InputSlot*>(originalSubgraphInputSlot)->GetOwningLayer();
424 auto* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
426 workingCopyInputs.push_back(&clonedLayer->GetInputSlot(originalSubgraphInputSlot->GetSlotIndex()));
429 for (
auto originalSubgraphLayer : originalSubgraphLayers)
431 IConnectableLayer*
const clonedLayer = originalToClonedLayerMap[originalSubgraphLayer];
439 auto& originalOutputSlot = originalSubgraphLayer->
GetOutputSlot(i);
441 for (
unsigned int j = 0; j < originalOutputSlot.GetNumConnections(); j++)
445 originalOutputSlot.GetConnection(j)->GetOwningIConnectableLayer();
448 if (originalToClonedLayerMap.find(&nextLayerOnOriginalSubgraph) != originalToClonedLayerMap.end())
450 auto* nextLayerOnClonedSubgraph = originalToClonedLayerMap[&nextLayerOnOriginalSubgraph];
452 auto index = PolymorphicDowncast<OutputSlot*>(
453 &originalOutputSlot)->GetConnection(j)->GetSlotIndex();
455 IInputSlot& inputSlot = nextLayerOnClonedSubgraph->GetInputSlot(index);
458 clonedOutputSlot.Connect(inputSlot);
462 clonedOutputSlot.
SetTensorInfo(originalOutputSlot.GetTensorInfo());
472 auto outputSlotIndex = outputSlot->CalculateIndexOnOwner();
473 const IConnectableLayer& originalSubgraphLayer = outputSlot->GetOwningIConnectableLayer();
478 IConnectableLayer* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
481 workingCopyOutputs.push_back(&clonedLayer->
GetOutputSlot(outputSlotIndex));
486 for (
auto& pair : originalToClonedLayerMap)
488 workingCopyLayers.push_back(pair.second);
491 return {std::move(workingCopyLayers),
492 std::move(workingCopyInputs),
493 std::move(workingCopyOutputs),
506 void SubgraphView::UpdateSubgraphViewSlotPointers(
SubgraphView& patternSubgraph,
509 std::vector<IInputSlot*>::iterator inputSlotPosition;
511 for (
unsigned long idx = 0; idx < patternSubgraph.
GetIInputSlots().size(); idx++)
514 inputSlotPosition = std::find(m_IInputSlots.begin(), m_IInputSlots.end(), slot);
515 if (inputSlotPosition != m_IInputSlots.end())
517 m_IInputSlots.erase(inputSlotPosition);
520 m_IInputSlots.insert(inputSlotPosition, substituteSubgraph.
GetIInputSlots()[idx]);
524 std::vector<IOutputSlot*>::iterator outputSlotPosition;
526 for (
unsigned long idx = 0; idx < patternSubgraph.
GetIOutputSlots().size(); idx++)
529 outputSlotPosition = std::find(m_IOutputSlots.begin(), m_IOutputSlots.end(), slot);
530 if (outputSlotPosition != m_IOutputSlots.end())
532 m_IOutputSlots.erase(outputSlotPosition);
535 m_IOutputSlots.insert(outputSlotPosition, substituteSubgraph.
GetIOutputSlots()[idx]);
542 if (!p_WorkingCopyImpl)
544 throw NullPointerException(
"The SubgraphView calling SubstituteSubgraphView is not a working copy. "
545 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
550 if (numPatternInputs != numSubInputs)
553 fmt::format(
"Number of InputSlots on substitute SubgraphView ({}) must equal the number of"
554 " InputSlots on pattern SubgraphView ({})",
561 if (numPatternOutputs != numSubOutputs)
564 fmt::format(
"Number of OutputSlots on substitute SubgraphView ({}) must equal the number of"
565 " OutputSlots on pattern SubgraphView ({})",
571 auto workingCopyGraph = &p_WorkingCopyImpl->m_Graph;
575 if (std::find(std::begin(workingCopyGraph->m_Layers),
576 std::end(workingCopyGraph->m_Layers),
577 iConnectableLayer) ==
578 std::end(workingCopyGraph->m_Layers))
580 auto layer = PolymorphicDowncast<Layer*>(iConnectableLayer);
582 layer->Reparent(*workingCopyGraph,
583 (workingCopyGraph->m_Layers).end());
585 workingCopyGraph->m_LayersInOrder = false;
590 workingCopyGraph->ReplaceSubgraphConnections(patternSubgraph, substituteSubgraph);
593 UpdateSubgraphViewSlotPointers(patternSubgraph, substituteSubgraph);
596 workingCopyGraph->EraseSubgraphLayers(patternSubgraph);
599 workingCopyGraph->TopologicalSort();
603 workingCopyGraph->m_Layers.end() };
608 if (!p_WorkingCopyImpl)
610 throw NullPointerException(
"The SubgraphView calling GetOriginalInputSlots is not a working copy. "
611 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
613 if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
615 throw NullPointerException(
"The working copy SubgraphView pointer to its original SubgraphView is null.");
617 return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIInputSlots();
621 if (!p_WorkingCopyImpl)
623 throw NullPointerException(
"The SubgraphView calling GetOriginalOutputSlots is not a working copy. "
624 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
626 if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
628 throw NullPointerException(
"The working copy SubgraphView pointer to its original SubgraphView is null.");
630 return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIOutputSlots();