1 //
2 // Copyright © 2017, 2019-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include <armnn/backends/SubgraphView.hpp>
7
8 #include <Graph.hpp>
9
10 #include <armnn/utility/IgnoreUnused.hpp>
11 #include <armnn/utility/NumericCast.hpp>
12 #include <armnn/utility/PolymorphicDowncast.hpp>
13
14 #include <fmt/format.h>
15 #include <utility>
16
17 namespace armnn
18 {
19
20 namespace
21 {
22
23 template <class C>
AssertIfNullsOrDuplicates(const C & container,const std::string & errorMessage)24 void AssertIfNullsOrDuplicates(const C& container, const std::string& errorMessage)
25 {
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)
29 {
30 // Ignore unused for release builds
31 IgnoreUnused(errorMessage);
32
33 // Check if the item is valid
34 ARMNN_ASSERT_MSG(i, errorMessage.c_str());
35
36 // Check if a duplicate has been found
37 ARMNN_ASSERT_MSG(duplicateSet.find(i) == duplicateSet.end(), errorMessage.c_str());
38
39 duplicateSet.insert(i);
40 });
41 }
42
43 } // anonymous namespace
44
SubgraphView(Graph & graph)45 SubgraphView::SubgraphView(Graph& graph)
46 : enable_shared_from_this()
47 , m_InputSlots{}
48 , m_OutputSlots{}
49 , m_Layers(graph.begin(), graph.end())
50 , m_IConnectableLayers(graph.begin(), graph.end())
51 {
52 ArrangeBySortOrder();
53 CheckSubgraph();
54 }
55
56 /// IConnectable Duplication to maintain backwards compatibility
SubgraphView(InputSlots && inputs,OutputSlots && outputs,Layers && layers)57 SubgraphView::SubgraphView(InputSlots&& inputs, OutputSlots&& outputs, Layers&& layers)
58 : enable_shared_from_this()
59 , m_InputSlots{InputSlots{inputs.begin(), inputs.end()}}
60 , m_IInputSlots{IInputSlots{inputs.begin(), inputs.end()}}
61 , m_OutputSlots{OutputSlots{outputs.begin(), outputs.end()}}
62 , m_IOutputSlots{IOutputSlots{outputs.begin(), outputs.end()}}
63 , m_Layers(layers)
64 , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
65 {
66 ArrangeBySortOrder();
67 CheckSubgraph();
68 }
69
70 /// IConnectable Duplication to maintain backwards compatibility
SubgraphView(SubgraphView::IConnectableLayers && layers,SubgraphView::IInputSlots && inputs,SubgraphView::IOutputSlots && outputs)71 SubgraphView::SubgraphView(SubgraphView::IConnectableLayers&& layers,
72 SubgraphView::IInputSlots&& inputs,
73 SubgraphView::IOutputSlots&& outputs)
74 : enable_shared_from_this()
75 , m_IInputSlots{inputs}
76 , m_IOutputSlots{outputs}
77 , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
78 {
79 // Cast from IConnectableLayer to Layer for backward compatibility
80 auto f = [](IConnectableLayer* value)
__anon0060705c0302(IConnectableLayer* value) 81 {
82 return PolymorphicDowncast<Layer*>(value);
83 };
84 std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
85
86 m_InputSlots.resize(inputs.size());
87 m_IInputSlots.resize(inputs.size());
88 for (unsigned int i = 0; i < inputs.size(); i++)
89 {
90 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
91 m_IInputSlots.at(i) = inputs[i];
92 }
93
94 m_OutputSlots.resize(outputs.size());
95 m_IOutputSlots.resize(outputs.size());
96 for (unsigned int i = 0; i < outputs.size(); i++)
97 {
98 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
99 m_IOutputSlots.at(i) = outputs[i];
100 }
101
102 ArrangeBySortOrder();
103 CheckSubgraph();
104 }
105
106 /// IConnectable Duplication to maintain backwards compatibility
SubgraphView(SubgraphView::IConnectableLayers && layers,SubgraphView::IInputSlots && inputs,SubgraphView::IOutputSlots && outputs,std::shared_ptr<SubgraphViewWorkingCopy> ptr)107 SubgraphView::SubgraphView(SubgraphView::IConnectableLayers&& layers,
108 SubgraphView::IInputSlots&& inputs,
109 SubgraphView::IOutputSlots&& outputs,
110 std::shared_ptr<SubgraphViewWorkingCopy> ptr)
111 : enable_shared_from_this()
112 , m_IInputSlots{inputs}
113 , m_IOutputSlots{outputs}
114 , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
115 , p_WorkingCopyImpl(std::move(ptr))
116 {
117 // Cast from IConnectableLayer to Layer for backward compatibility
118 auto f = [](IConnectableLayer* value)
__anon0060705c0402(IConnectableLayer* value) 119 {
120 return PolymorphicDowncast<Layer*>(value);
121 };
122 std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
123
124 m_InputSlots.resize(inputs.size());
125 m_IInputSlots.resize(inputs.size());
126 for (unsigned int i = 0; i < inputs.size(); i++)
127 {
128 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
129 m_IInputSlots.at(i) = inputs[i];
130 }
131
132 m_OutputSlots.resize(outputs.size());
133 m_IOutputSlots.resize(outputs.size());
134 for (unsigned int i = 0; i < outputs.size(); i++)
135 {
136 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
137 m_IOutputSlots.at(i) = outputs[i];
138 }
139
140 ArrangeBySortOrder();
141 CheckSubgraph();
142 }
143
SubgraphView(const SubgraphView & subgraph)144 SubgraphView::SubgraphView(const SubgraphView& subgraph)
145 : enable_shared_from_this()
146 , m_InputSlots(subgraph.m_InputSlots.begin(), subgraph.m_InputSlots.end())
147 , m_IInputSlots(subgraph.m_IInputSlots.begin(), subgraph.m_IInputSlots.end())
148 , m_OutputSlots(subgraph.m_OutputSlots.begin(), subgraph.m_OutputSlots.end())
149 , m_IOutputSlots(subgraph.m_IOutputSlots.begin(), subgraph.m_IOutputSlots.end())
150 , m_Layers(subgraph.m_Layers.begin(), subgraph.m_Layers.end())
151 , m_IConnectableLayers(IConnectableLayers{subgraph.m_IConnectableLayers.begin(),
152 subgraph.m_IConnectableLayers.end()})
153 {
154 ArrangeBySortOrder();
155 CheckSubgraph();
156 }
157
SubgraphView(SubgraphView && subgraph)158 SubgraphView::SubgraphView(SubgraphView&& subgraph)
159 : enable_shared_from_this()
160 , m_InputSlots(std::move(subgraph.m_InputSlots))
161 , m_IInputSlots(std::move(subgraph.m_IInputSlots))
162 , m_OutputSlots(std::move(subgraph.m_OutputSlots))
163 , m_IOutputSlots(std::move(subgraph.m_IOutputSlots))
164 , m_Layers(std::move(subgraph.m_Layers))
165 , m_IConnectableLayers(std::move(subgraph.m_IConnectableLayers))
166 {
167 ArrangeBySortOrder();
168 CheckSubgraph();
169 }
170
SubgraphView(IConnectableLayer * layer)171 SubgraphView::SubgraphView(IConnectableLayer* layer)
172 : enable_shared_from_this()
173 , m_Layers{PolymorphicDowncast<Layer*>(layer)}
174 , m_IConnectableLayers{layer}
175 {
176 unsigned int numInputSlots = layer->GetNumInputSlots();
177 m_InputSlots.resize(numInputSlots);
178 m_IInputSlots.resize(numInputSlots);
179 for (unsigned int i = 0; i < numInputSlots; i++)
180 {
181 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(&(layer->GetInputSlot(i)));
182 m_IInputSlots.at(i) = &(layer->GetInputSlot(i));
183 }
184
185 unsigned int numOutputSlots = layer->GetNumOutputSlots();
186 m_OutputSlots.resize(numOutputSlots);
187 m_IOutputSlots.resize(numOutputSlots);
188 for (unsigned int i = 0; i < numOutputSlots; i++)
189 {
190 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(&(layer->GetOutputSlot(i)));
191 m_IOutputSlots.at(i) = &(layer->GetOutputSlot(i));
192 }
193
194 CheckSubgraph();
195 }
196
operator =(SubgraphView && other)197 SubgraphView& SubgraphView::operator=(SubgraphView&& other)
198 {
199 m_InputSlots = std::move(other.m_InputSlots);
200 m_IInputSlots = std::move(other.m_IInputSlots);
201 m_OutputSlots = std::move(other.m_OutputSlots);
202 m_IOutputSlots = std::move(other.m_IOutputSlots);
203 m_Layers = std::move(other.m_Layers);
204 m_IConnectableLayers = std::move(other.m_IConnectableLayers);
205
206 CheckSubgraph();
207
208 return *this;
209 }
210
CheckSubgraph()211 void SubgraphView::CheckSubgraph()
212 {
213 // Check for invalid or duplicate input slots
214 AssertIfNullsOrDuplicates(m_InputSlots, "Sub-graphs cannot contain null or duplicate input slots");
215
216 // Check for invalid or duplicate output slots
217 AssertIfNullsOrDuplicates(m_OutputSlots, "Sub-graphs cannot contain null or duplicate output slots");
218
219 // Check for invalid or duplicate layers
220 AssertIfNullsOrDuplicates(m_Layers, "Sub-graphs cannot contain null or duplicate layers");
221
222 // Check for invalid or duplicate input slots
223 AssertIfNullsOrDuplicates(m_IInputSlots, "Sub-graphs cannot contain null or duplicate IInputSlots");
224
225 // Check for invalid or duplicate output slots
226 AssertIfNullsOrDuplicates(m_IOutputSlots, "Sub-graphs cannot contain null or duplicate IOutputSlots");
227
228 // Check for invalid or duplicate layers
229 AssertIfNullsOrDuplicates(m_IConnectableLayers,
230 "Sub-graphs cannot contain null or duplicate IConnectableLayers");
231 }
232
GetInputSlots() const233 const SubgraphView::InputSlots& SubgraphView::GetInputSlots() const
234 {
235 return m_InputSlots;
236 }
237
GetIInputSlots() const238 const SubgraphView::IInputSlots& SubgraphView::GetIInputSlots() const
239 {
240 return m_IInputSlots;
241 }
242
GetOutputSlots() const243 const SubgraphView::OutputSlots& SubgraphView::GetOutputSlots() const
244 {
245 return m_OutputSlots;
246 }
247
GetIOutputSlots() const248 const SubgraphView::IOutputSlots& SubgraphView::GetIOutputSlots() const
249 {
250 return m_IOutputSlots;
251 }
252
GetInputSlot(unsigned int index) const253 const InputSlot* SubgraphView::GetInputSlot(unsigned int index) const
254 {
255 return m_InputSlots.at(index);
256 }
257
GetIInputSlot(unsigned int index) const258 const IInputSlot* SubgraphView::GetIInputSlot(unsigned int index) const
259 {
260 return m_IInputSlots.at(index);
261 }
262
GetInputSlot(unsigned int index)263 InputSlot* SubgraphView::GetInputSlot(unsigned int index)
264 {
265 return m_InputSlots.at(index);
266 }
267
GetIInputSlot(unsigned int index)268 IInputSlot* SubgraphView::GetIInputSlot(unsigned int index)
269 {
270 return m_IInputSlots.at(index);
271 }
272
GetOutputSlot(unsigned int index) const273 const OutputSlot* SubgraphView::GetOutputSlot(unsigned int index) const
274 {
275 return m_OutputSlots.at(index);
276 }
277
GetIOutputSlot(unsigned int index) const278 const IOutputSlot* SubgraphView::GetIOutputSlot(unsigned int index) const
279 {
280 return m_IOutputSlots.at(index);
281 }
282
GetOutputSlot(unsigned int index)283 OutputSlot* SubgraphView::GetOutputSlot(unsigned int index)
284 {
285 return m_OutputSlots.at(index);
286 }
287
GetIOutputSlot(unsigned int index)288 IOutputSlot* SubgraphView::GetIOutputSlot(unsigned int index)
289 {
290 return m_IOutputSlots.at(index);
291 }
292
GetNumInputSlots() const293 unsigned int SubgraphView::GetNumInputSlots() const
294 {
295 return armnn::numeric_cast<unsigned int>(m_IInputSlots.size());
296 }
297
GetNumOutputSlots() const298 unsigned int SubgraphView::GetNumOutputSlots() const
299 {
300 return armnn::numeric_cast<unsigned int>(m_IOutputSlots.size());
301 }
302
GetLayers() const303 const SubgraphView::Layers& SubgraphView::GetLayers() const
304 {
305 return m_Layers;
306 }
307
GetIConnectableLayers() const308 const SubgraphView::IConnectableLayers& SubgraphView::GetIConnectableLayers() const
309 {
310 return m_IConnectableLayers;
311 }
312
begin()313 SubgraphView::Iterator SubgraphView::begin()
314 {
315 return m_Layers.begin();
316 }
317
end()318 SubgraphView::Iterator SubgraphView::end()
319 {
320 return m_Layers.end();
321 }
322
323 // IConnectable Duplication to maintain backwards compatibility
beginIConnectable()324 SubgraphView::IConnectableLayerIterator SubgraphView::beginIConnectable()
325 {
326 return m_IConnectableLayers.begin();
327 }
328
endIConnectable()329 SubgraphView::IConnectableLayerIterator SubgraphView::endIConnectable()
330 {
331 return m_IConnectableLayers.end();
332 }
333
begin() const334 SubgraphView::ConstIterator SubgraphView::begin() const
335 {
336 return m_Layers.begin();
337 }
338
end() const339 SubgraphView::ConstIterator SubgraphView::end() const
340 {
341 return m_Layers.end();
342 }
343
344 // IConnectable Duplication to maintain backwards compatibility
beginIConnectable() const345 SubgraphView::ConstIConnectableIterator SubgraphView::beginIConnectable() const
346 {
347 return m_IConnectableLayers.begin();
348 }
349
endIConnectable() const350 SubgraphView::ConstIConnectableIterator SubgraphView::endIConnectable() const
351 {
352 return m_IConnectableLayers.end();
353 }
354
cbegin() const355 SubgraphView::ConstIterator SubgraphView::cbegin() const
356 {
357 // Ignore deprecated call as this is internal to SubgraphView
358 ARMNN_NO_DEPRECATE_WARN_BEGIN
359 return begin();
360 ARMNN_NO_DEPRECATE_WARN_END
361 }
362
cend() const363 SubgraphView::ConstIterator SubgraphView::cend() const
364 {
365 // Ignore deprecated call as this is internal to SubgraphView
366 ARMNN_NO_DEPRECATE_WARN_BEGIN
367 return end();
368 ARMNN_NO_DEPRECATE_WARN_END
369 }
370
371 // IConnectable Duplication to maintain backwards compatibility
cbeginIConnectable() const372 SubgraphView::ConstIConnectableIterator SubgraphView::cbeginIConnectable() const
373 {
374 return beginIConnectable();
375 }
376
cendIConnectable() const377 SubgraphView::ConstIConnectableIterator SubgraphView::cendIConnectable() const
378 {
379 return endIConnectable();
380 }
381
Clear()382 void SubgraphView::Clear()
383 {
384 m_InputSlots.clear();
385 m_OutputSlots.clear();
386 m_Layers.clear();
387
388 m_IInputSlots.clear();
389 m_IOutputSlots.clear();
390 m_IConnectableLayers.clear();
391 }
392
ArrangeBySortOrder()393 void SubgraphView::ArrangeBySortOrder()
394 {
395 using LayerList = std::list<Layer*>;
396 auto compareLayerPriority = [](const LayerList::value_type& layerA, const LayerList::value_type& layerB)
397 {
398 return layerA->GetPriority() < layerB->GetPriority();
399 };
400
401 m_Layers.sort(compareLayerPriority);
402
403 using IConnectableLayersList = std::list<IConnectableLayer*>;
404 auto compareIConnectableLayerPriority = [](const IConnectableLayersList::value_type& layerA,
405 const IConnectableLayersList::value_type& layerB)
406 {
407 return PolymorphicDowncast<Layer*>(layerA)->GetPriority() <
408 PolymorphicDowncast<Layer*>(layerB)->GetPriority();
409 };
410
411 m_IConnectableLayers.sort(compareIConnectableLayerPriority);
412 }
413
414 struct SubgraphView::SubgraphViewWorkingCopy
415 {
416 public:
417
418 SubgraphViewWorkingCopy() = default;
SubgraphViewWorkingCopyarmnn::SubgraphView::SubgraphViewWorkingCopy419 SubgraphViewWorkingCopy(Graph graph, std::shared_ptr<const SubgraphView> originalSubgraphView)
420 : m_Graph(graph)
421 , m_OriginalSubgraphView(originalSubgraphView)
422 {};
423
424 Graph m_Graph;
425 std::shared_ptr<const SubgraphView> m_OriginalSubgraphView;
426
427 };
428
GetWorkingCopy() const429 SubgraphView SubgraphView::GetWorkingCopy() const
430 {
431 if (p_WorkingCopyImpl)
432 {
433 throw Exception("The SubgraphView calling GetWorkingCopy() is already a working copy. This function "
434 "should be called on original SubgraphView obtained from OptimizeSubgraphView()");
435 }
436
437 // Create a cut down SubgraphView with underlying graph containing only the relevant layers.
438 // It needs its own underlying layers so that they can be replaced safely.
439 auto ptr = std::make_shared<SubgraphViewWorkingCopy>(Graph(), shared_from_this());
440
441 std::unordered_map<const IConnectableLayer*, IConnectableLayer*> originalToClonedLayerMap;
442 std::list<armnn::IConnectableLayer*> originalSubgraphLayers = GetIConnectableLayers();
443
444 for (auto&& originalLayer : originalSubgraphLayers)
445 {
446 Layer* const layer = PolymorphicDowncast<const Layer*>(originalLayer)->Clone(ptr->m_Graph);
447 originalToClonedLayerMap.emplace(originalLayer, layer);
448 }
449
450 SubgraphView::IInputSlots workingCopyInputs;
451 // Add IInputSlots to workingCopy
452 for (auto originalSubgraphInputSlot : GetIInputSlots())
453 {
454 const IConnectableLayer& originalSubgraphLayer =
455 PolymorphicDowncast<InputSlot*>(originalSubgraphInputSlot)->GetOwningLayer();
456
457 auto* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
458
459 workingCopyInputs.push_back(&clonedLayer->GetInputSlot(originalSubgraphInputSlot->GetSlotIndex()));
460 }
461
462 for (auto originalSubgraphLayer : originalSubgraphLayers)
463 {
464 IConnectableLayer* const clonedLayer = originalToClonedLayerMap[originalSubgraphLayer];
465
466 // OutputLayers have no OutputSlots to be connected
467 if (clonedLayer->GetType() != LayerType::Output)
468 {
469 // connect all cloned layers as per original subgraph
470 for (unsigned int i = 0; i < clonedLayer->GetNumOutputSlots(); i++)
471 {
472 auto& originalOutputSlot = originalSubgraphLayer->GetOutputSlot(i);
473 auto& clonedOutputSlot = clonedLayer->GetOutputSlot(i);
474 for (unsigned int j = 0; j < originalOutputSlot.GetNumConnections(); j++)
475 {
476 // nextLayer is the layer with IInputSlot connected to IOutputSlot we are working on
477 const IConnectableLayer& nextLayerOnOriginalSubgraph =
478 originalOutputSlot.GetConnection(j)->GetOwningIConnectableLayer();
479
480 // Check the layer is in our map and so has a clonedLayer
481 if (originalToClonedLayerMap.find(&nextLayerOnOriginalSubgraph) != originalToClonedLayerMap.end())
482 {
483 auto* nextLayerOnClonedSubgraph = originalToClonedLayerMap[&nextLayerOnOriginalSubgraph];
484
485 auto index = PolymorphicDowncast<OutputSlot*>(
486 &originalOutputSlot)->GetConnection(j)->GetSlotIndex();
487
488 IInputSlot& inputSlot = nextLayerOnClonedSubgraph->GetInputSlot(index);
489
490 // Then make the connection
491 clonedOutputSlot.Connect(inputSlot);
492 }
493 }
494 // Copy the tensorInfo to the clonedOutputSlot
495 clonedOutputSlot.SetTensorInfo(originalOutputSlot.GetTensorInfo());
496 }
497 }
498 }
499
500 SubgraphView::IOutputSlots workingCopyOutputs;
501
502 // Add IOutputSlots to workingCopy
503 for (auto outputSlot : GetIOutputSlots())
504 {
505 auto outputSlotIndex = outputSlot->CalculateIndexOnOwner();
506 const IConnectableLayer& originalSubgraphLayer = outputSlot->GetOwningIConnectableLayer();
507
508 // OutputLayers have no OutputSlots to be connected
509 if (originalSubgraphLayer.GetType() != LayerType::Output)
510 {
511 IConnectableLayer* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
512
513 // Add the OutputSlot of clonedLayer to WorkingCopy OutputSlots
514 workingCopyOutputs.push_back(&clonedLayer->GetOutputSlot(outputSlotIndex));
515 }
516 }
517
518 SubgraphView::IConnectableLayers workingCopyLayers;
519 for (auto& pair : originalToClonedLayerMap)
520 {
521 workingCopyLayers.push_back(pair.second);
522 }
523
524 return {std::move(workingCopyLayers),
525 std::move(workingCopyInputs),
526 std::move(workingCopyOutputs),
527 ptr};
528 }
529
SubstituteSubgraph(SubgraphView & subgraph,IConnectableLayer * substituteLayer)530 void SubgraphView::SubstituteSubgraph(SubgraphView& subgraph, IConnectableLayer* substituteLayer)
531 {
532 ARMNN_ASSERT(substituteLayer != nullptr);
533 SubgraphView substituteSubgraph(substituteLayer);
534
535 SubstituteSubgraph(subgraph, substituteSubgraph);
536 }
537
UpdateSubgraphViewSlotPointers(SubgraphView & patternSubgraph,const SubgraphView & substituteSubgraph)538 void SubgraphView::UpdateSubgraphViewSlotPointers(SubgraphView& patternSubgraph,
539 const SubgraphView& substituteSubgraph)
540 {
541 std::vector<IInputSlot*>::iterator inputSlotPosition;
542 // search for and erase any InputSlots that appear in the WorkingCopy that match those in the PatternSubgraph
543 for (unsigned long idx = 0; idx < patternSubgraph.GetIInputSlots().size(); idx++)
544 {
545 IInputSlot *slot = patternSubgraph.GetIInputSlots()[idx];
546 inputSlotPosition = std::find(m_IInputSlots.begin(), m_IInputSlots.end(), slot);
547 if (inputSlotPosition != m_IInputSlots.end())
548 {
549 m_IInputSlots.erase(inputSlotPosition);
550
551 // while here, with correct position, add in replacement InputSlot from the substituteSubgraph
552 m_IInputSlots.insert(inputSlotPosition, substituteSubgraph.GetIInputSlots()[idx]);
553 }
554 }
555
556 std::vector<IOutputSlot*>::iterator outputSlotPosition;
557 // search for and erase any OutputSlots that appear in the WorkingCopy that match those in the PatternSubgraph
558 for (unsigned long idx = 0; idx < patternSubgraph.GetIOutputSlots().size(); idx++)
559 {
560 IOutputSlot *slot = patternSubgraph.GetIOutputSlots()[idx];
561 outputSlotPosition = std::find(m_IOutputSlots.begin(), m_IOutputSlots.end(), slot);
562 if (outputSlotPosition != m_IOutputSlots.end())
563 {
564 m_IOutputSlots.erase(outputSlotPosition);
565
566 // while here, with correct position, add in replacement OutputSlot from the substituteSubgraph
567 m_IOutputSlots.insert(outputSlotPosition, substituteSubgraph.GetIOutputSlots()[idx]);
568 }
569 }
570 }
571
SubstituteSubgraph(SubgraphView & patternSubgraph,const SubgraphView & substituteSubgraph)572 void SubgraphView::SubstituteSubgraph(SubgraphView& patternSubgraph, const SubgraphView& substituteSubgraph)
573 {
574 if (!p_WorkingCopyImpl)
575 {
576 throw NullPointerException("The SubgraphView calling SubstituteSubgraphView is not a working copy. "
577 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
578 }
579
580 auto numPatternInputs = patternSubgraph.GetIInputSlots().size();
581 auto numSubInputs = substituteSubgraph.GetIInputSlots().size();
582 if (numPatternInputs != numSubInputs)
583 {
584 throw armnn::InvalidArgumentException(
585 fmt::format("Number of InputSlots on substitute SubgraphView ({}) must equal the number of"
586 " InputSlots on pattern SubgraphView ({})",
587 numSubInputs,
588 numPatternInputs));
589 }
590
591 auto numPatternOutputs = patternSubgraph.GetIOutputSlots().size();
592 auto numSubOutputs = substituteSubgraph.GetIOutputSlots().size();
593 if (numPatternOutputs != numSubOutputs)
594 {
595 throw armnn::InvalidArgumentException(
596 fmt::format("Number of OutputSlots on substitute SubgraphView ({}) must equal the number of"
597 " OutputSlots on pattern SubgraphView ({})",
598 numSubOutputs,
599 numPatternOutputs));
600 }
601
602 // Add substitute layer to the Main graph i.e. graph in p_WorkingCopyImpl
603 auto workingCopyGraph = &p_WorkingCopyImpl->m_Graph;
604 substituteSubgraph.ForEachIConnectableLayer([workingCopyGraph](IConnectableLayer* iConnectableLayer)
605 {
606 // Search WorkingCopy Graph for substituteLayer and add if missing
607 if (std::find(std::begin(workingCopyGraph->m_Layers),
608 std::end(workingCopyGraph->m_Layers),
609 iConnectableLayer) ==
610 std::end(workingCopyGraph->m_Layers))
611 {
612 auto layer = PolymorphicDowncast<Layer*>(iConnectableLayer);
613
614 layer->Reparent(*workingCopyGraph,
615 (workingCopyGraph->m_Layers).end());
616
617 workingCopyGraph->m_LayersInOrder = false;
618 }
619 });
620
621 // Replace the old connections with connections to new layer
622 workingCopyGraph->ReplaceSubgraphConnections(patternSubgraph, substituteSubgraph);
623
624 // Update input/outputSlot pointers
625 UpdateSubgraphViewSlotPointers(patternSubgraph, substituteSubgraph);
626
627 // Delete the old layers.
628 workingCopyGraph->EraseSubgraphLayers(patternSubgraph);
629
630 // Sort
631 workingCopyGraph->TopologicalSort();
632
633 // Update SubgraphView layer pointers to match those of the internal WorkingCopy layer pointers
634 m_IConnectableLayers = IConnectableLayers{ workingCopyGraph->m_Layers.begin(),
635 workingCopyGraph->m_Layers.end() };
636 }
637
GetOriginalInputSlots() const638 const SubgraphView::IInputSlots& SubgraphView::GetOriginalInputSlots() const
639 {
640 if (!p_WorkingCopyImpl)
641 {
642 throw NullPointerException("The SubgraphView calling GetOriginalInputSlots is not a working copy. "
643 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
644 }
645 if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
646 {
647 throw NullPointerException("The working copy SubgraphView pointer to its original SubgraphView is null.");
648 }
649 return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIInputSlots();
650 }
GetOriginalOutputSlots() const651 const SubgraphView::IOutputSlots& SubgraphView::GetOriginalOutputSlots() const
652 {
653 if (!p_WorkingCopyImpl)
654 {
655 throw NullPointerException("The SubgraphView calling GetOriginalOutputSlots is not a working copy. "
656 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
657 }
658 if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
659 {
660 throw NullPointerException("The working copy SubgraphView pointer to its original SubgraphView is null.");
661 }
662 return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIOutputSlots();
663 }
664
665
666 } // namespace armnn
667