ArmNN
 20.02
SubgraphViewTests.cpp File Reference
#include <boost/test/unit_test.hpp>
#include <Graph.hpp>
#include <SubgraphView.hpp>
#include <SubgraphViewSelector.hpp>
#include <backendsCommon/CpuTensorHandle.hpp>
#include <fstream>
#include <map>
#include <queue>
#include <random>
#include <chrono>

Go to the source code of this file.

Functions

 BOOST_AUTO_TEST_CASE (SingleInputSingleOutput)
 
 BOOST_AUTO_TEST_CASE (SingleInputSingleOutputSubstituteGraph)
 
 BOOST_AUTO_TEST_CASE (MultiInputSingleOutput)
 
 BOOST_AUTO_TEST_CASE (SingleInputMultiOutput)
 
 BOOST_AUTO_TEST_CASE (MultiInputMultiOutput)
 
 BOOST_AUTO_TEST_CASE (EraseReplacedLayers)
 
 BOOST_AUTO_TEST_CASE (SubgraphForEmptyGraph)
 
 BOOST_AUTO_TEST_CASE (SubgraphForEntireGraph)
 
 BOOST_AUTO_TEST_CASE (NoSubgraphsForNoMatch)
 
 BOOST_AUTO_TEST_CASE (OneSubgraphsSelectedASingleMatch)
 
 BOOST_AUTO_TEST_CASE (MultipleLayersSelectedInTheMiddle)
 
 BOOST_AUTO_TEST_CASE (DisjointGraphs)
 
 BOOST_AUTO_TEST_CASE (IslandInTheMiddle)
 
 BOOST_AUTO_TEST_CASE (MultipleSimpleSubgraphs)
 
 BOOST_AUTO_TEST_CASE (SimpleLinearTest)
 
 BOOST_AUTO_TEST_CASE (ValidMerge)
 
 BOOST_AUTO_TEST_CASE (PropagatedDependencies)
 
 BOOST_AUTO_TEST_CASE (Random)
 
 BOOST_AUTO_TEST_CASE (SingleSubgraph)
 
 BOOST_AUTO_TEST_CASE (MultipleSubgraphs)
 
 BOOST_AUTO_TEST_CASE (SubgraphCycles)
 

Function Documentation

◆ BOOST_AUTO_TEST_CASE() [1/21]

BOOST_AUTO_TEST_CASE ( SingleInputSingleOutput  )

Definition at line 134 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), IInputSlot::GetConnection(), IOutputSlot::GetConnection(), InputSlot::GetConnection(), OutputSlot::GetConnection(), Layer::GetInputSlot(), Layer::GetOutputSlot(), and Graph::SubstituteSubgraph().

135 {
136  // Construct graph
137  Graph graph;
138 
139  Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input");
140 
141  Convolution2dDescriptor convDescriptor;
142  Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
143  Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
144 
145  Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output");
146 
147  inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
148  convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
149  convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
150 
151  // Construct sub-graph
153  CreateOutputsFrom({convLayer2}),
154  {});
155 
156  // Save sub-graph connections for comparison after substitution
157  IOutputSlot* subgraphInputConn = subgraph->GetInputSlot(0)->GetConnection();
158  IInputSlot* subgraphOutputConn = subgraph->GetOutputSlot(0)->GetConnection(0);
159 
160  // Construct dummy pre-compiled layer
161  PreCompiledDescriptor preCompiledDescriptor(1, 1);
162  Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled");
163 
164  // Substitute sub-graph with pre-compiled layer
165  graph.SubstituteSubgraph(*subgraph, preCompiledLayer);
166 
167  // Check that connections are correct after substitution
168  BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subgraphInputConn);
169  BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subgraphOutputConn);
170 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
virtual const IInputSlot * GetConnection(unsigned int index) const =0
const IOutputSlot * GetConnection() const override
Definition: Layer.hpp:199
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An output connection slot for a layer.
Definition: INetwork.hpp:37
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:396
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
virtual const IOutputSlot * GetConnection() const =0
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
This layer represents a convolution 2d operation.
A PreCompiledDescriptor for the PreCompiledLayer.
An input connection slot for a layer.
Definition: INetwork.hpp:24
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:46

◆ BOOST_AUTO_TEST_CASE() [2/21]

BOOST_AUTO_TEST_CASE ( SingleInputSingleOutputSubstituteGraph  )

Definition at line 172 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), IInputSlot::GetConnection(), IOutputSlot::GetConnection(), InputSlot::GetConnection(), OutputSlot::GetConnection(), Layer::GetInputSlot(), Layer::GetOutputSlot(), and Graph::SubstituteSubgraph().

173 {
174  // Construct graph
175  Graph graph;
176 
177  Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input");
178 
179  Convolution2dDescriptor convDescriptor;
180  Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
181  Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
182 
183  Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output");
184 
185  inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
186  convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
187  convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
188 
189  // Construct sub-graph
191  CreateOutputsFrom({convLayer2}),
192  {});
193 
194  // Save sub-graph connections for comparison after substitution
195  IOutputSlot* subgraphInputConn = subgraph->GetInputSlot(0)->GetConnection();
196  IInputSlot* subgraphOutputConn = subgraph->GetOutputSlot(0)->GetConnection(0);
197 
198  // Construct second graph with a single pre-compiled layer
199  Graph substituteGraph;
200  PreCompiledDescriptor preCompiledDescriptor(1, 1);
201  Layer* const preCompiledLayer = substituteGraph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled");
202 
203  SubgraphViewSelector::SubgraphViewPtr substituteSubgraph =
204  CreateSubgraphViewFrom(CreateInputsFrom({preCompiledLayer}),
205  CreateOutputsFrom({preCompiledLayer}),
206  {preCompiledLayer});
207  // Substitute subgraph with pre-compiled layer
208  graph.SubstituteSubgraph(*subgraph, *substituteSubgraph);
209 
210  // Check that connections are correct after substitution
211  BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subgraphInputConn);
212  BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subgraphOutputConn);
213 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
virtual const IInputSlot * GetConnection(unsigned int index) const =0
const IOutputSlot * GetConnection() const override
Definition: Layer.hpp:199
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An output connection slot for a layer.
Definition: INetwork.hpp:37
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:396
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
virtual const IOutputSlot * GetConnection() const =0
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
This layer represents a convolution 2d operation.
A PreCompiledDescriptor for the PreCompiledLayer.
An input connection slot for a layer.
Definition: INetwork.hpp:24
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:46

◆ BOOST_AUTO_TEST_CASE() [3/21]

BOOST_AUTO_TEST_CASE ( MultiInputSingleOutput  )

Definition at line 215 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), IInputSlot::GetConnection(), IOutputSlot::GetConnection(), InputSlot::GetConnection(), OutputSlot::GetConnection(), Layer::GetInputSlot(), Layer::GetOutputSlot(), and Graph::SubstituteSubgraph().

216 {
217  // Construct graph
218  Graph graph;
219 
220  Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input");
221 
222  ViewsDescriptor splitterDescriptor(2);
223  Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter");
224 
225  Convolution2dDescriptor convDescriptor;
226  Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
227  Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
228 
229  OriginsDescriptor concatDescriptor(2);
230  Layer* const concatLayer = graph.AddLayer<ConcatLayer>(concatDescriptor, "concat");
231 
232  Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output");
233 
234  inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
235  splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
236  splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0));
237  convLayer1->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
238  convLayer2->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
239  concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
240 
241  // Construct sub-graph
243  CreateOutputsFrom({concatLayer}),
244  {});
245 
246  // Save sub-graph connections for comparison after substitution
247  IOutputSlot* subgraphInputConn1 = subgraph->GetInputSlot(0)->GetConnection();
248  IOutputSlot* subgraphInputConn2 = subgraph->GetInputSlot(1)->GetConnection();
249 
250  IInputSlot* subgraphOutputConn = subgraph->GetOutputSlot(0)->GetConnection(0);
251 
252  // Construct dummy pre-compiled layer
253  PreCompiledDescriptor preCompiledDescriptor(2, 1);
254  Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled");
255 
256  // Substitute sub-graph with pre-compiled layer
257  graph.SubstituteSubgraph(*subgraph, preCompiledLayer);
258 
259  // Check that connections are correct after substitution
260  BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subgraphInputConn1);
261  BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(1).GetConnection(), subgraphInputConn2);
262 
263  BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subgraphOutputConn);
264 }
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
virtual const IInputSlot * GetConnection(unsigned int index) const =0
const IOutputSlot * GetConnection() const override
Definition: Layer.hpp:199
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An output connection slot for a layer.
Definition: INetwork.hpp:37
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:396
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
virtual const IOutputSlot * GetConnection() const =0
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
This layer represents a convolution 2d operation.
A PreCompiledDescriptor for the PreCompiledLayer.
An input connection slot for a layer.
Definition: INetwork.hpp:24
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:46

◆ BOOST_AUTO_TEST_CASE() [4/21]

BOOST_AUTO_TEST_CASE ( SingleInputMultiOutput  )

Definition at line 266 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), IInputSlot::GetConnection(), IOutputSlot::GetConnection(), InputSlot::GetConnection(), OutputSlot::GetConnection(), Layer::GetInputSlot(), Layer::GetOutputSlot(), and Graph::SubstituteSubgraph().

267 {
268  // Construct graph
269  Graph graph;
270 
271  Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input");
272 
273  Convolution2dDescriptor convDescriptor;
274  Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
275  Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
276  OriginsDescriptor concatDescriptor(2);
277  Layer* const concatLayer = graph.AddLayer<ConcatLayer>(concatDescriptor, "concat");
278  Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output");
279 
280  ViewsDescriptor splitterDescriptor(2);
281  Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter");
282 
283  inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
284  splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
285  splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0));
286  convLayer1->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
287  convLayer2->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
288  concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
289 
290  // Construct sub-graph
292  CreateOutputsFrom({convLayer1, convLayer2}),
293  {});
294 
295  // Save sub-graph connections for comparison after substitution
296  IOutputSlot* subgraphInputConn1 = subgraph->GetInputSlot(0)->GetConnection();
297 
298  IInputSlot* subgraphOutputConn1 = subgraph->GetOutputSlot(0)->GetConnection(0);
299  IInputSlot* subgraphOutputConn2 = subgraph->GetOutputSlot(1)->GetConnection(0);
300 
301  // Construct dummy pre-compiled layer
302  PreCompiledDescriptor preCompiledDescriptor(1, 2);
303  Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled");
304 
305  // Substitute sub-graph with pre-compiled layer
306  graph.SubstituteSubgraph(*subgraph, preCompiledLayer);
307 
308  // Check that connections are correct after substitution
309  BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subgraphInputConn1);
310 
311  BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subgraphOutputConn1);
312  BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(1).GetConnection(0), subgraphOutputConn2);
313 }
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
virtual const IInputSlot * GetConnection(unsigned int index) const =0
const IOutputSlot * GetConnection() const override
Definition: Layer.hpp:199
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An output connection slot for a layer.
Definition: INetwork.hpp:37
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:396
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
virtual const IOutputSlot * GetConnection() const =0
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
This layer represents a convolution 2d operation.
A PreCompiledDescriptor for the PreCompiledLayer.
An input connection slot for a layer.
Definition: INetwork.hpp:24
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:46

◆ BOOST_AUTO_TEST_CASE() [5/21]

BOOST_AUTO_TEST_CASE ( MultiInputMultiOutput  )

Definition at line 315 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), IInputSlot::GetConnection(), IOutputSlot::GetConnection(), InputSlot::GetConnection(), OutputSlot::GetConnection(), Layer::GetInputSlot(), Layer::GetOutputSlot(), and Graph::SubstituteSubgraph().

316 {
317  // Construct graph
318  Graph graph;
319 
320  Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input");
321 
322  ViewsDescriptor splitterDescriptor(2);
323  Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter");
324 
325  Convolution2dDescriptor convDescriptor;
326  Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
327  Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
328 
329  OriginsDescriptor concatDescriptor(2);
330  Layer* const concatLayer = graph.AddLayer<ConcatLayer>(concatDescriptor, "concat");
331 
332  Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output");
333 
334  inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
335  splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
336  splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0));
337  convLayer1->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
338  convLayer2->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
339  concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
340 
341  // Construct sub-graph
343  CreateOutputsFrom({convLayer1, convLayer2}),
344  {});
345 
346  // Save sub-graph connections for comparison after substitution
347  IOutputSlot* subgraphInputConn1 = subgraph->GetInputSlot(0)->GetConnection();
348  IOutputSlot* subgraphInputConn2 = subgraph->GetInputSlot(1)->GetConnection();
349 
350  IInputSlot* subgraphOutputConn1 = subgraph->GetOutputSlot(0)->GetConnection(0);
351  IInputSlot* subgraphOutputConn2 = subgraph->GetOutputSlot(1)->GetConnection(0);
352 
353  // Construct dummy pre-compiled layer
354  PreCompiledDescriptor preCompiledDescriptor(2, 2);
355  Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled");
356 
357  // Substitute sub-graph with pre-compiled layer
358  graph.SubstituteSubgraph(*subgraph, preCompiledLayer);
359 
360  // Check that connections are correct after substitution
361  BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subgraphInputConn1);
362  BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(1).GetConnection(), subgraphInputConn2);
363 
364  BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subgraphOutputConn1);
365  BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(1).GetConnection(0), subgraphOutputConn2);
366 }
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
virtual const IInputSlot * GetConnection(unsigned int index) const =0
const IOutputSlot * GetConnection() const override
Definition: Layer.hpp:199
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An output connection slot for a layer.
Definition: INetwork.hpp:37
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:396
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
virtual const IOutputSlot * GetConnection() const =0
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
This layer represents a convolution 2d operation.
A PreCompiledDescriptor for the PreCompiledLayer.
An input connection slot for a layer.
Definition: INetwork.hpp:24
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:46

◆ BOOST_AUTO_TEST_CASE() [6/21]

BOOST_AUTO_TEST_CASE ( EraseReplacedLayers  )

Definition at line 368 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), BOOST_AUTO_TEST_SUITE(), BOOST_AUTO_TEST_SUITE_END(), BOOST_CHECK(), CreateSubgraphViewFrom(), and Graph::SubstituteSubgraph().

369 {
370  // Construct graph
371  Graph graph;
372 
373  graph.AddLayer<InputLayer>(0, "input");
374 
375  ViewsDescriptor splitterDescriptor(2);
376  Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter");
377 
378  Convolution2dDescriptor convDescriptor;
379  Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
380  Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
381 
382  OriginsDescriptor concatDescriptor(2);
383  Layer* const concatLayer = graph.AddLayer<ConcatLayer>(concatDescriptor, "concat");
384 
385  graph.AddLayer<OutputLayer>(0, "output");
386 
387  // Construct sub-graph
389  {},
390  {splitterLayer,
391  convLayer1,
392  convLayer2,
393  concatLayer});
394 
395  // Construct dummy pre-compiled layer
396  PreCompiledDescriptor preCompiledDescriptor(0, 0);
397  Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled");
398 
399  // Save sub-graph layers for later verification
400  const SubgraphView::Layers subgraphLayers = subgraph->GetLayers();
401 
402  // Substitute sub-graph with pre-compiled layer
403  graph.SubstituteSubgraph(*subgraph, preCompiledLayer);
404 
405  // Check that the layers belonging to the sub-graph have been erased from the graph after substitution
406  BOOST_CHECK(!AreAnySubgraphLayersPresentInGraph(subgraphLayers, graph));
407 }
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::WaitingForAck)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:396
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
This layer represents a convolution 2d operation.
A PreCompiledDescriptor for the PreCompiledLayer.
std::list< Layer * > Layers

◆ BOOST_AUTO_TEST_CASE() [7/21]

BOOST_AUTO_TEST_CASE ( SubgraphForEmptyGraph  )

Definition at line 413 of file SubgraphViewTests.cpp.

References SubgraphView::GetInputSlots(), SubgraphView::GetLayers(), and SubgraphView::GetOutputSlots().

414 {
415  Graph graph;
416  SubgraphView subgraph(graph);
417 
418  BOOST_TEST(subgraph.GetInputSlots().empty());
419  BOOST_TEST(subgraph.GetOutputSlots().empty());
420  BOOST_TEST(subgraph.GetLayers().empty());
421 }
The SubgraphView class represents a subgraph of a Graph.

◆ BOOST_AUTO_TEST_CASE() [8/21]

BOOST_AUTO_TEST_CASE ( SubgraphForEntireGraph  )

Definition at line 423 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), Layer::GetInputSlot(), Graph::GetNumLayers(), and Graph::InsertNewLayer().

424 {
425  Graph graph;
426 
427  auto output = graph.AddLayer<OutputLayer>(0, "output");
428  auto mid0 = graph.InsertNewLayer<ActivationLayer>(output->GetInputSlot(0),
430  "mid0");
431  auto mid1 = graph.InsertNewLayer<ActivationLayer>(mid0->GetInputSlot(0),
433  "mid1");
434  graph.InsertNewLayer<InputLayer>(mid1->GetInputSlot(0), 0, "input");
435 
436  SubgraphView subgraph(graph);
437 
438  BOOST_TEST(subgraph.GetInputSlots().empty());
439  BOOST_TEST(subgraph.GetOutputSlots().empty());
440  BOOST_TEST(subgraph.GetLayers().size() == graph.GetNumLayers());
441 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
This layer represents an activation operation with the specified activation function.
The SubgraphView class represents a subgraph of a Graph.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
size_t GetNumLayers() const
Definition: Graph.hpp:187
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition: Graph.hpp:409

◆ BOOST_AUTO_TEST_CASE() [9/21]

BOOST_AUTO_TEST_CASE ( NoSubgraphsForNoMatch  )

Definition at line 443 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), Graph::InsertNewLayer(), and SubgraphViewSelector::SelectSubgraphs().

444 {
445  Graph graph;
446 
447  auto output = graph.AddLayer<OutputLayer>(0, "output");
448  graph.InsertNewLayer<InputLayer>(output->GetInputSlot(0), 0, "input");
449 
451  SubgraphViewSelector::SelectSubgraphs(graph, [](const Layer &) { return false; });
452 
453  BOOST_TEST(subgraphs.empty());
454 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
std::vector< SubgraphViewPtr > Subgraphs
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition: Graph.hpp:409

◆ BOOST_AUTO_TEST_CASE() [10/21]

BOOST_AUTO_TEST_CASE ( OneSubgraphsSelectedASingleMatch  )

Definition at line 456 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), Layer::GetNameStr(), Graph::InsertNewLayer(), and SubgraphViewSelector::SelectSubgraphs().

457 {
458  Graph graph;
459 
460  auto output = graph.AddLayer<OutputLayer>(0, "output");
461  graph.InsertNewLayer<InputLayer>(output->GetInputSlot(0), 0, "input");
462 
464  SubgraphViewSelector::SelectSubgraphs(
465  graph,
466  // select the output layer only
467  [](const Layer & l)
468  {
469  bool isOutput = l.GetNameStr().compare("output") == 0;
470  return isOutput;
471  });
472 
473  BOOST_TEST(subgraphs.size() == 1);
474  if (subgraphs.size() == 1)
475  {
476  auto expected = CreateSubgraphViewFrom(CreateInputsFrom({output}),
477  // outputs of 'output' will be empty
478  CreateOutputsFrom({output}),
479  {output});
480 
481  CompareSubgraphViews(subgraphs[0], expected);
482  }
483 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
const std::string & GetNameStr() const
Definition: Layer.hpp:216
std::vector< SubgraphViewPtr > Subgraphs
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition: Graph.hpp:409

◆ BOOST_AUTO_TEST_CASE() [11/21]

BOOST_AUTO_TEST_CASE ( MultipleLayersSelectedInTheMiddle  )

Definition at line 485 of file SubgraphViewTests.cpp.

References armnn::Activation, Graph::AddLayer(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), Layer::GetInputSlot(), Layer::GetType(), Graph::InsertNewLayer(), and SubgraphViewSelector::SelectSubgraphs().

486 {
487  Graph graph;
488 
489  auto output = graph.AddLayer<OutputLayer>(0, "output");
490  auto mid0 = graph.InsertNewLayer<ActivationLayer>(output->GetInputSlot(0),
492  "mid0");
493  auto mid1 = graph.InsertNewLayer<ActivationLayer>(mid0->GetInputSlot(0),
495  "mid1");
496  graph.InsertNewLayer<InputLayer>(mid1->GetInputSlot(0), 0, "input");
497 
499  SubgraphViewSelector::SelectSubgraphs(
500  graph,
501  // select the middle layers only
502  [](const Layer & l)
503  {
504  bool toSelect = (l.GetType() == LayerType::Activation);
505  return toSelect;
506  });
507 
508  BOOST_TEST(subgraphs.size() == 1);
509  if (subgraphs.size() == 1)
510  {
511  auto expected = CreateSubgraphViewFrom(CreateInputsFrom({mid1}),
512  CreateOutputsFrom({mid0}),
513  {mid1, mid0});
514 
515  CompareSubgraphViews(subgraphs[0], expected);
516  }
517 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
This layer represents an activation operation with the specified activation function.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
float Activation(float in, ActivationFunction function, float a, float b)
Definition: Activation.cpp:13
std::vector< SubgraphViewPtr > Subgraphs
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
LayerType GetType() const
Definition: Layer.hpp:259
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition: Graph.hpp:409

◆ BOOST_AUTO_TEST_CASE() [12/21]

BOOST_AUTO_TEST_CASE ( DisjointGraphs  )

Definition at line 519 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), CreateSubgraphViewFrom(), Layer::GetInputSlot(), Graph::InsertNewLayer(), and SubgraphViewSelector::SelectSubgraphs().

520 {
521  // The input graph has two disjoint sections and all layers are selected.
522  // This should result in two subgraphs being produced.
523  Graph graph;
524 
525  // the graph is constructed in reverse order
526  auto o0 = graph.AddLayer<OutputLayer>(0, "output0");
527  auto n0 = graph.InsertNewLayer<ActivationLayer>(o0->GetInputSlot(0), ActivationDescriptor{}, "intermediate0");
528  auto i0 = graph.InsertNewLayer<InputLayer>(n0->GetInputSlot(0), 0, "input0");
529 
530  auto o1 = graph.AddLayer<OutputLayer>(1, "output1");
531  auto n1 = graph.InsertNewLayer<ActivationLayer>(o1->GetInputSlot(0), ActivationDescriptor{}, "intermediate1");
532  auto i1 = graph.InsertNewLayer<InputLayer>(n1->GetInputSlot(0), 1, "input1");
533 
535  SubgraphViewSelector::SelectSubgraphs(graph,
536  // select the middle layers only
537  [](const Layer&) {
538  return true;
539  });
540 
541  // expected results to test against
542  auto expected1 = CreateSubgraphViewFrom({}, {}, { o0, n0, i0 });
543  auto expected2 = CreateSubgraphViewFrom({}, {}, { o1, n1, i1 });
544  BOOST_TEST(subgraphs.size() == 2);
545  if (subgraphs.size() == 2)
546  {
547  BOOST_TEST((subgraphs[0] != nullptr));
548  BOOST_TEST((subgraphs[1] != nullptr));
549  if (subgraphs[0].get() != nullptr && subgraphs[1].get() != nullptr)
550  {
551  if (std::find(subgraphs[0]->GetLayers().begin(), subgraphs[0]->GetLayers().end(), i0) !=
552  subgraphs[0]->GetLayers().end())
553  {
554  CompareSubgraphViews(subgraphs[0], expected1);
555  CompareSubgraphViews(subgraphs[1], expected2);
556  }
557  else
558  {
559  CompareSubgraphViews(subgraphs[0], expected2);
560  CompareSubgraphViews(subgraphs[1], expected1);
561  }
562  }
563  }
564 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
This layer represents an activation operation with the specified activation function.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
std::vector< SubgraphViewPtr > Subgraphs
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition: Graph.hpp:409

◆ BOOST_AUTO_TEST_CASE() [13/21]

BOOST_AUTO_TEST_CASE ( IslandInTheMiddle  )

Definition at line 566 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), Layer::GetInputSlot(), Layer::GetName(), Layer::GetOutputSlot(), Graph::InsertNewLayer(), and SubgraphViewSelector::SelectSubgraphs().

567 {
568  // This case represent the scenario when a non-selected X1 node placed in the middle
569  // of the selected M* nodes.
570  // This checks that we don't merge M6 and M3 and create a dependency loop.
571  /*
572  M0
573  / \
574  M1 M4
575  | |
576  M2 X1 < the island in the middle !
577  | |
578  M3 M5
579  \ /
580  M6
581  */
582  Graph graph;
583 
584  OriginsDescriptor concatDescriptor(2);
585  auto m6 = graph.AddLayer<ConcatLayer>(concatDescriptor, "m6");
586  auto m3 = graph.InsertNewLayer<ActivationLayer>(m6->GetInputSlot(0),
588  "m3");
589  auto m2 = graph.InsertNewLayer<ActivationLayer>(m3->GetInputSlot(0),
591  "m2");
592  auto m1 = graph.InsertNewLayer<ActivationLayer>(m2->GetInputSlot(0),
594  "m1");
595  auto m0 = graph.InsertNewLayer<InputLayer>(m1->GetInputSlot(0), 0, "m0");
596 
597  auto m5 = graph.InsertNewLayer<ActivationLayer>(m6->GetInputSlot(1),
599  "m5");
600  auto x1 = graph.InsertNewLayer<ActivationLayer>(m5->GetInputSlot(0),
602  "x1");
603  auto m4 = graph.InsertNewLayer<ActivationLayer>(x1->GetInputSlot(0),
605  "m4");
606 
607  // Connect the other branch to the input layer
608  m0->GetOutputSlot(0).Connect(m4->GetInputSlot(0));
609 
610  // All selected 'M*' layers will be of Activation type
612  SubgraphViewSelector::SelectSubgraphs(
613  graph,
614  // select the middle layers only
615  [](const Layer& l)
616  {
617  bool toSelect = std::string(l.GetName())[0] == 'm';
618  return toSelect;
619  });
620 
621  // expected results to test against
622  auto largerSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({ m0 }),
623  CreateOutputsFrom({ m3, m4 }),
624  { m0, m1, m2, m3, m4 });
625 
626  auto smallerSubgraph =
627  CreateSubgraphViewFrom(std::vector<InputSlot*>{ &m5->GetInputSlot(0), & m6->GetInputSlot(0) },
628  std::vector<OutputSlot*>{},
629  { m5, m6 });
630 
631  BOOST_TEST(subgraphs.size() == 2);
632  if (subgraphs.size() == 2)
633  {
634  // we need to have valid subgraph pointers here
635  BOOST_TEST((subgraphs[0] != nullptr));
636  BOOST_TEST((subgraphs[1] != nullptr));
637 
638  if (subgraphs[0].get() != nullptr && subgraphs[1].get() != nullptr)
639  {
640  // sort the subgraphs by layer size, so it is simpler to test
641  std::sort(subgraphs.begin(), subgraphs.end(),
643  {
644  return (lhs->GetLayers().size() < rhs->GetLayers().size());
645  }
646  );
647 
648  BOOST_TEST(subgraphs[0]->GetLayers().size() == 2);
649  BOOST_TEST(subgraphs[1]->GetLayers().size() == 5);
650 
651  CompareSubgraphViews(subgraphs[0], smallerSubgraph);
652  CompareSubgraphViews(subgraphs[1], largerSubgraph);
653  }
654  }
655 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
This layer represents an activation operation with the specified activation function.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
std::vector< SubgraphViewPtr > Subgraphs
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:305
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition: Graph.hpp:409

◆ BOOST_AUTO_TEST_CASE() [14/21]

BOOST_AUTO_TEST_CASE ( MultipleSimpleSubgraphs  )

Definition at line 657 of file SubgraphViewTests.cpp.

References armnn::Activation, Graph::AddLayer(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), Layer::GetInputSlot(), Layer::GetType(), Graph::InsertNewLayer(), and SubgraphViewSelector::SelectSubgraphs().

658 {
659  // This test case represents the scenario when we have two distinct subgraphs
660  // in a simple linear network. The selected nodes are the M* and the
661  // non-selected ones are the X*
662  //
663  // X1 -> M1 -> M2 -> X2 -> M3 -> X3
664  //
665  // The expected results is two subgraphs, one with {M1, M2} and another one
666  // with {M3}
667  //
668  Graph graph;
669 
670  // the graph is constructed in reverse order
671  auto x3 = graph.AddLayer<OutputLayer>(0, "output");
672  auto m3 = graph.InsertNewLayer<ActivationLayer>(x3->GetInputSlot(0),
674  "m3");
675  auto x2 = graph.InsertNewLayer<Convolution2dLayer>(m3->GetInputSlot(0),
677  "x2");
678  auto m2 = graph.InsertNewLayer<ActivationLayer>(x2->GetInputSlot(0),
680  "m2");
681  auto m1 = graph.InsertNewLayer<ActivationLayer>(m2->GetInputSlot(0),
683  "m1");
684  graph.InsertNewLayer<InputLayer>(m1->GetInputSlot(0), 0, "x1");
685 
686  // All selected 'M*' layers will be of Activation type
688  SubgraphViewSelector::SelectSubgraphs(
689  graph,
690  // select the middle layers only
691  [](const Layer & l)
692  {
693  bool toSelect = (l.GetType() == LayerType::Activation);
694  return toSelect;
695  });
696 
697  // expected results to test against
698  auto largerSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({m1}),
699  CreateOutputsFrom({m2}),
700  {m1, m2});
701 
702  auto smallerSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({m3}),
703  CreateOutputsFrom({m3}),
704  {m3});
705 
706  BOOST_TEST(subgraphs.size() == 2);
707  if (subgraphs.size() == 2)
708  {
709  // we need to have valid subgraph pointers here
710  BOOST_TEST((subgraphs[0] != nullptr));
711  BOOST_TEST((subgraphs[1] != nullptr));
712 
713  if (subgraphs[0].get() != nullptr && subgraphs[1].get() != nullptr)
714  {
715  // sort the subgraphs by layer size, so it is simpler to test
716  std::sort(subgraphs.begin(), subgraphs.end(),
718  {
719  return (lhs->GetLayers().size() < rhs->GetLayers().size());
720  }
721  );
722 
723  BOOST_TEST(subgraphs[0]->GetLayers().size() == 1);
724  BOOST_TEST(subgraphs[1]->GetLayers().size() == 2);
725 
726  CompareSubgraphViews(subgraphs[0], smallerSubgraph);
727  CompareSubgraphViews(subgraphs[1], largerSubgraph);
728  }
729  }
730 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
This layer represents an activation operation with the specified activation function.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
float Activation(float in, ActivationFunction function, float a, float b)
Definition: Activation.cpp:13
std::vector< SubgraphViewPtr > Subgraphs
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
LayerType GetType() const
Definition: Layer.hpp:259
This layer represents a convolution 2d operation.
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition: Graph.hpp:409

◆ BOOST_AUTO_TEST_CASE() [15/21]

BOOST_AUTO_TEST_CASE ( SimpleLinearTest  )

Definition at line 732 of file SubgraphViewTests.cpp.

References armnn::Activation, armnn::Addition, Graph::AddLayer(), armnn::BOOST_AUTO_TEST_CASE(), BOOST_CHECK(), armnn::Concat, OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), Layer::GetInputSlot(), Layer::GetOutputSlot(), Layer::GetType(), SubgraphViewSelector::SelectSubgraphs(), and armnn::Splitter.

733 {
734  //X1 -> M1 -> M2 -> X2
735  //Where the input slots of M1 and the output slots of M2 are to be the sub graph boundaries.
736  Graph graph;
737 
738  ActivationDescriptor activationDefaults;
739 
740  auto layerX1 = graph.AddLayer<InputLayer>(0, "layerX1");
741  auto layerX2 = graph.AddLayer<OutputLayer>(0, "layerX2");
742  auto layerM1 = graph.AddLayer<ActivationLayer>(activationDefaults, "layerM1");
743  auto layerM2 = graph.AddLayer<ActivationLayer>(activationDefaults, "layerM2");
744 
745  // X1
746  // |
747  // M1
748  // |
749  // M2
750  // |
751  // X2
752 
753  layerX1->GetOutputSlot(0).Connect(layerM1->GetInputSlot(0));
754  layerM1->GetOutputSlot(0).Connect(layerM2->GetInputSlot(0));
755  layerM2->GetOutputSlot(0).Connect(layerX2->GetInputSlot(0));
756 
758  SubgraphViewSelector::SelectSubgraphs(
759  graph,
760  // select the activation layers M1 and M2
761  [](const Layer & l)
762  {
763  bool toSelect = (l.GetType() == LayerType::Activation);
764  return toSelect;
765  });
766 
767  BOOST_CHECK(subgraphs.size() == 1);
768  if(subgraphs.size() == 1)
769  {
770  auto expected = CreateSubgraphViewFrom(CreateInputsFrom({layerM1}),
771  CreateOutputsFrom({layerM2}),
772  {layerM1, layerM2});
773 
774  CompareSubgraphViews(subgraphs[0], expected);
775  }
776 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
This layer represents an activation operation with the specified activation function.
BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::WaitingForAck)
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
float Activation(float in, ActivationFunction function, float a, float b)
Definition: Activation.cpp:13
std::vector< SubgraphViewPtr > Subgraphs
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
LayerType GetType() const
Definition: Layer.hpp:259
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312

◆ BOOST_AUTO_TEST_CASE() [16/21]

BOOST_AUTO_TEST_CASE ( ValidMerge  )

Definition at line 953 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), Layer::GetInputSlot(), Layer::GetName(), Layer::GetOutputSlot(), and SubgraphViewSelector::SelectSubgraphs().

954 {
955  // Checks that a node that has multiple choices for merge candidates (M3 in this case) correctly merges with the
956  // one that it can (M0), and doesn't merge with the ones it can't (X2 and M2).
957  //
958  // X1
959  // |
960  // M1
961  // / \'
962  // X2 M2 M0
963  // \ | /
964  // M3
965  //
966  Graph graph;
967 
968  ActivationDescriptor activationDefaults;
969  OriginsDescriptor concatDescriptor(3);
970 
971  auto x1 = graph.AddLayer<InputLayer>(0, "x1");
972  auto x2 = graph.AddLayer<ActivationLayer>(activationDefaults, "x2");
973  auto m0 = graph.AddLayer<InputLayer>(1, "m0");
974  auto m1 = graph.AddLayer<ActivationLayer>(activationDefaults, "m1");
975  auto m2 = graph.AddLayer<ActivationLayer>(activationDefaults, "m2");
976  auto m3 = graph.AddLayer<ConcatLayer>(concatDescriptor, "m3");
977 
978  x1->GetOutputSlot(0).Connect(m1->GetInputSlot(0));
979  m1->GetOutputSlot(0).Connect(x2->GetInputSlot(0));
980  m1->GetOutputSlot(0).Connect(m2->GetInputSlot(0));
981  x2->GetOutputSlot(0).Connect(m3->GetInputSlot(0));
982  m2->GetOutputSlot(0).Connect(m3->GetInputSlot(1));
983  m0->GetOutputSlot(0).Connect(m3->GetInputSlot(2));
984 
985  SubgraphViewSelector::Subgraphs subgraphs = SubgraphViewSelector::SelectSubgraphs(
986  graph,
987  [](const Layer& l) {
988  return std::string(l.GetName())[0] == 'm';
989  });
990 
991  // expected results to test against
992  auto expectedSubgraph0 =
994  CreateInputsFrom({ m1 }),
995  std::vector<OutputSlot*>{ &m1->GetOutputSlot(0), &m2->GetOutputSlot(0) },
996  { m1, m2 });
997 
998  auto expectedSubgraph1 = CreateSubgraphViewFrom(
999  std::vector<InputSlot*>{ &m3->GetInputSlot(0), & m3->GetInputSlot(1) },
1000  CreateOutputsFrom({ }),
1001  { m0, m3 });
1002 
1003  BOOST_TEST(subgraphs.size() == 2);
1004  if (subgraphs.size() == 2)
1005  {
1006  // we need to have valid subgraph pointers here
1007  BOOST_TEST((subgraphs[0] != nullptr));
1008  BOOST_TEST((subgraphs[1] != nullptr));
1009 
1010  if (subgraphs[0].get() != nullptr && subgraphs[1].get() != nullptr)
1011  {
1012  if (subgraphs[0]->GetInputSlots().size() == 1)
1013  {
1014  CompareSubgraphViews(subgraphs[0], expectedSubgraph0);
1015  CompareSubgraphViews(subgraphs[1], expectedSubgraph1);
1016  }
1017  else
1018  {
1019  CompareSubgraphViews(subgraphs[0], expectedSubgraph1);
1020  CompareSubgraphViews(subgraphs[1], expectedSubgraph0);
1021  }
1022  }
1023  }
1024 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
This layer represents an activation operation with the specified activation function.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
std::vector< SubgraphViewPtr > Subgraphs
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:305

◆ BOOST_AUTO_TEST_CASE() [17/21]

BOOST_AUTO_TEST_CASE ( PropagatedDependencies  )

Definition at line 1026 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), Layer::GetInputSlot(), Layer::GetName(), Layer::GetOutputSlot(), Graph::InsertNewLayer(), and SubgraphViewSelector::SelectSubgraphs().

1027 {
1028  // Version of IslandInTheMiddle with longer chain
1029  // to make sure antecedents are propagated.
1030  /*
1031  M0
1032  / \
1033  M1 M4
1034  | |
1035  M2 X1 < the island in the middle !
1036  | |
1037  | M10
1038  | |
1039  | X2 < another island in the middle !
1040  | |
1041  M3 M5
1042  \ /
1043  M6
1044  */
1045  Graph graph;
1046 
1047  OriginsDescriptor concatDescriptor(2);
1048  auto m6 = graph.AddLayer<ConcatLayer>(concatDescriptor, "m6");
1049  auto m3 = graph.InsertNewLayer<ActivationLayer>(m6->GetInputSlot(0),
1051  "m3");
1052  auto m2 = graph.InsertNewLayer<ActivationLayer>(m3->GetInputSlot(0),
1054  "m2");
1055  auto m1 = graph.InsertNewLayer<ActivationLayer>(m2->GetInputSlot(0),
1057  "m1");
1058  auto m0 = graph.InsertNewLayer<InputLayer>(m1->GetInputSlot(0), 0, "m0");
1059 
1060  auto m5 = graph.InsertNewLayer<ActivationLayer>(m6->GetInputSlot(1),
1062  "m5");
1063  auto x2 = graph.InsertNewLayer<ActivationLayer>(m5->GetInputSlot(0), ActivationDescriptor{}, "x2");
1064  auto m10 = graph.InsertNewLayer<ActivationLayer>(x2->GetInputSlot(0), ActivationDescriptor{}, "m10");
1065  auto x1 = graph.InsertNewLayer<ActivationLayer>(m10->GetInputSlot(0),
1067  "x1");
1068  auto m4 = graph.InsertNewLayer<ActivationLayer>(x1->GetInputSlot(0),
1070  "m4");
1071 
1072  // Connect the other branch to the input layer
1073  m0->GetOutputSlot(0).Connect(m4->GetInputSlot(0));
1074 
1075  // All selected 'M*' layers will be of Activation type
1077  SubgraphViewSelector::SelectSubgraphs(
1078  graph,
1079  // select the middle layers only
1080  [](const Layer& l)
1081  {
1082  bool toSelect = std::string(l.GetName())[0] == 'm';
1083  return toSelect;
1084  });
1085 
1086  // expected results to test against
1087  auto largerSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({ m0 }),
1088  CreateOutputsFrom({ m3, m4 }),
1089  { m0, m1, m2, m3, m4 });
1090 
1091  auto mediumSubgraph = CreateSubgraphViewFrom(std::vector<InputSlot*>{ &m5->GetInputSlot(0), &m6->GetInputSlot(0) },
1092  std::vector<OutputSlot*>{}, { m5, m6 });
1093 
1094  auto smallerSubgraph =
1095  CreateSubgraphViewFrom(CreateInputsFrom({ m10 }), CreateOutputsFrom({ m10 }), { m10 });
1096 
1097  BOOST_TEST(subgraphs.size() == 3);
1098  if (subgraphs.size() == 3)
1099  {
1100  // we need to have valid subgraph pointers here
1101  BOOST_TEST((subgraphs[0] != nullptr));
1102  BOOST_TEST((subgraphs[1] != nullptr));
1103  BOOST_TEST((subgraphs[2] != nullptr));
1104 
1105  if (subgraphs[0].get() != nullptr && subgraphs[1].get() != nullptr && subgraphs[2].get() != nullptr)
1106  {
1107  // sort the subgraphs by layer size, so it is simpler to test
1108  std::sort(subgraphs.begin(), subgraphs.end(),
1110  {
1111  return (lhs->GetLayers().size() < rhs->GetLayers().size());
1112  }
1113  );
1114 
1115  CompareSubgraphViews(subgraphs[0], smallerSubgraph);
1116  CompareSubgraphViews(subgraphs[1], mediumSubgraph);
1117  CompareSubgraphViews(subgraphs[2], largerSubgraph);
1118  }
1119  }
1120 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
This layer represents an activation operation with the specified activation function.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
std::vector< SubgraphViewPtr > Subgraphs
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:305
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition: Graph.hpp:409

◆ BOOST_AUTO_TEST_CASE() [18/21]

BOOST_AUTO_TEST_CASE ( Random  )

Definition at line 1122 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), BOOST_AUTO_TEST_SUITE(), BOOST_AUTO_TEST_SUITE_END(), BOOST_CHECK(), OutputSlot::Connect(), armnn::Constant, armnn::debug, InputSlot::GetConnectedOutputSlot(), Layer::GetInputSlots(), Layer::GetName(), Layer::GetNumOutputSlots(), Layer::GetOutputSlot(), armnn::Input, SubgraphViewSelector::SelectSubgraphs(), and Graph::SerializeToDot().

1123 {
1124  // Creates random networks, splits them into subgraphs and checks the resulting subgraphs obey the required
1125  // dependency rules. We can easily generate very large networks which helps cover corner cases the other
1126  // small, manually crafted tests have missed. We can also use this to measure performance on large networks.
1127  constexpr bool debug = false; // Enable this to dump dot files and performance timings.
1128 
1129  std::mt19937 randomGenerator;
1130 
1131  // Helper function to get a random number in [0, maxExclusive)
1132  auto GetRandom = [&randomGenerator](auto maxExclusive) {
1133  // Note we could use uniform_int_distribution here, but that gives inconsistent results across platforms
1134  // which makes it harder to reproduce results.
1135  // It appears that uniform_real_distribution is consistent across MSVC and gcc so we use that and round it.
1136  std::uniform_real_distribution<float> uniform(0.0f, 1.0f);
1137  return static_cast<decltype(maxExclusive)>(uniform(randomGenerator) * static_cast<float>(maxExclusive));
1138  };
1139  // Helper function to get a bool that has probability 'trueProb' of being true.
1140  auto GetRandomFlag = [&randomGenerator](float trueProb) {
1141  std::uniform_real_distribution<float> uniform(0.0f, 1.0f);
1142  return uniform(randomGenerator) < trueProb;
1143  };
1144 
1145  constexpr uint32_t numTests = 100;
1146  for (uint32_t testIdx = 0; testIdx < numTests; ++testIdx)
1147  {
1148  randomGenerator.seed(testIdx); // Set a deterministic seed for reproducibility.
1149 
1150  // Create random graph
1151  Graph graph;
1152  {
1153  // First add the layers, without any connections. The following random constants determine the number of
1154  // each layer to add, along with the chance that each layer will be 'supported' (i.e. selected for
1155  // inclusion in the resulting subgraphs).
1156  uint32_t numInputs = 1 + GetRandom(4u);
1157  uint32_t numConstants = 1 + GetRandom(4u);
1158  uint32_t numOutputs = 1 + GetRandom(4u);
1159  uint32_t numConcats = 0 + GetRandom(500u);
1160  uint32_t numSplits = 0 + GetRandom(500u);
1161  float supportedProb = 0.7f;
1162 
1163  for (uint32_t i = 0; i < numInputs; ++i)
1164  {
1165  std::string name = "input" + std::to_string(i) + (GetRandomFlag(supportedProb) ? "S" : "N");
1166  graph.AddLayer<InputLayer>(static_cast<LayerBindingId>(i), name.c_str());
1167  }
1168  for (uint32_t i = 0; i < numConstants; ++i)
1169  {
1170  std::string name = "constant" + std::to_string(i) + (GetRandomFlag(supportedProb) ? "S" : "N");
1171  graph.AddLayer<ConstantLayer>(name.c_str());
1172  }
1173  for (uint32_t i = 0; i < numOutputs; ++i)
1174  {
1175  std::string name = "output" + std::to_string(i) + (GetRandomFlag(supportedProb) ? "S" : "N");
1176  graph.AddLayer<OutputLayer>(static_cast<LayerBindingId>(i), name.c_str());
1177  }
1178  for (uint32_t i = 0; i < numConcats; ++i)
1179  {
1180  std::string name = "concat" + std::to_string(i) + (GetRandomFlag(supportedProb) ? "S" : "N");
1181  uint32_t numInputs = 1 + GetRandom(3u);
1182  OriginsDescriptor concatDesc(numInputs);
1183  graph.AddLayer<ConcatLayer>(concatDesc, name.c_str());
1184  }
1185  for (uint32_t i = 0; i < numSplits; ++i)
1186  {
1187  std::string name = "split" + std::to_string(i) + (GetRandomFlag(supportedProb) ? "S" : "N");
1188  uint32_t numOutputs = 1 + GetRandom(3u);
1189  ViewsDescriptor splitDesc(numOutputs);
1190  graph.AddLayer<SplitterLayer>(splitDesc, name.c_str());
1191  }
1192 
1193  // Associate each layer with a "depth" parameter. This is used when creating connections to ensure
1194  // that we don't have any loops, by only connecting to layers with a lower "depth".
1195  // This can be thought of as distance from the "top" of the graph (assuming the graph flows top-to-bottom).
1196  // Unfortunately this approach ends up producing very "wide" graphs,
1197  // which probably isn't very representative of 'real' networks.
1198  uint32_t maxLayerDepth = 5 + GetRandom(2000u);
1199  std::map<Layer*, uint32_t> layerDepths;
1200  std::map<uint32_t, std::vector<Layer*>> layersAtDepth;
1201  for (Layer* layer : graph)
1202  {
1203  uint32_t depth;
1204  if (layer->GetType() == LayerType::Input || layer->GetType() == LayerType::Constant)
1205  {
1206  // There needs to be at least one input-like layer above everything else, otherwise would be
1207  // nothing for them to connect to!
1208  depth = 0;
1209  }
1210  else
1211  {
1212  // Other layers are randomly assigned to later depths.
1213  depth = 1 + GetRandom(maxLayerDepth);
1214  }
1215  layerDepths[layer] = depth;
1216  layersAtDepth[depth].push_back(layer);
1217  }
1218 
1219  // Connect layers to each other. Every input slot of every layer must be connected, but it doesn't
1220  // matter if an output slot goes unused.
1221  for (Layer* layer : graph)
1222  {
1223  for (uint32_t inputSlotIdx = 0; inputSlotIdx < layer->GetNumInputSlots(); ++inputSlotIdx)
1224  {
1225  InputSlot& inputSlot = layer->GetInputSlot(inputSlotIdx);
1226  uint32_t maxLayerDepthToConnectTo = layerDepths[layer]; // This prevents a connection causing a loop
1227  // Finding a layer to connect to may take multiple attempts, so keep trying until it works.
1228  while (inputSlot.GetConnectedOutputSlot() == nullptr)
1229  {
1230  uint32_t layerDepth = GetRandom(maxLayerDepthToConnectTo);
1231  const std::vector<Layer*>& layersToChooseFrom = layersAtDepth[layerDepth];
1232  if (layersToChooseFrom.size() == 0)
1233  {
1234  continue;
1235  }
1236  Layer* layerToConnectWith = layersToChooseFrom[GetRandom(layersToChooseFrom.size())];
1237  if (layerToConnectWith->GetNumOutputSlots() == 0)
1238  {
1239  continue;
1240  }
1241  uint32_t outputSlotIdx = GetRandom(layerToConnectWith->GetNumOutputSlots());
1242  layerToConnectWith->GetOutputSlot(outputSlotIdx).Connect(inputSlot);
1243  }
1244  }
1245  }
1246  }
1247 
1248  if (debug)
1249  {
1250  std::ofstream f("INPUT_" + std::to_string(testIdx) + ".dot");
1251  graph.SerializeToDot(f);
1252  }
1253 
1254  // Run the splitting algorithm, selecting all nodes ending in an 'S' (as randomly assigned above).
1255  auto startTime = std::chrono::high_resolution_clock::now();
1256 
1258  SubgraphViewSelector::SelectSubgraphs(graph,
1259  [](const Layer& l) { return std::string(l.GetName()).back() == 'S'; });
1260 
1261  auto endTime = std::chrono::high_resolution_clock::now();
1262  auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime);
1263  if (debug)
1264  {
1265  std::cout << "Test " << testIdx << ": " << duration.count() << " microseconds" << std::endl;
1266  }
1267 
1268  // Build a map of which subgraph is assigned to each layer.
1269  // This helps some of the following code.
1270  std::map<Layer*, SubgraphView*> layerToSubgraph;
1271  for (Layer* layer : graph)
1272  {
1273  size_t i = 0;
1274  for (std::unique_ptr<SubgraphView>& subgraph : subgraphs)
1275  {
1276  std::string name = std::to_string(i++);
1277  if (std::find(subgraph->begin(), subgraph->end(), layer) != subgraph->end())
1278  {
1279  layerToSubgraph[layer] = subgraph.get();
1280  break;
1281  }
1282  }
1283  }
1284 
1285  if (debug)
1286  {
1287  // Before dumping the dot file, set each Layer's BackendId property so that the dot file
1288  // shows the resulting subgraph assignments.
1289  for (Layer* layer : graph)
1290  {
1291  std::string name = "NotAssigned";
1292  auto subgraphIt = layerToSubgraph.find(layer);
1293  if (subgraphIt != layerToSubgraph.end())
1294  {
1295  auto subgraphIdx = std::distance(subgraphs.begin(),
1296  std::find_if(subgraphs.begin(), subgraphs.end(),
1297  [&](auto& s) { return s.get() == subgraphIt->second; }));
1298  name = std::to_string(subgraphIdx);
1299  }
1300  layer->SetBackendId(armnn::BackendId(name));
1301  }
1302 
1303  std::ofstream f("GRAPH_" + std::to_string(testIdx) + ".dot");
1304  graph.SerializeToDot(f);
1305  }
1306 
1307  // Check the dependencies between subgraphs to make sure that the algorithm has produced a valid result.
1308  // Starting from each of the input slots of each subgraph, recurse up the graph and ensure that we never
1309  // encounter a layer that belongs to the subgraph that we started from.
1310  for (std::unique_ptr<SubgraphView>& subgraph : subgraphs)
1311  {
1312  for (InputSlot* inputSlot : subgraph->GetInputSlots())
1313  {
1314  std::queue<Layer*> toProcess;
1315  toProcess.push(&inputSlot->GetConnectedOutputSlot()->GetOwningLayer());
1316  while (toProcess.size() > 0)
1317  {
1318  Layer* l = toProcess.front();
1319  toProcess.pop();
1320 
1321  BOOST_CHECK(layerToSubgraph[l] != subgraph.get());
1322 
1323  for (const InputSlot& is : l->GetInputSlots())
1324  {
1325  toProcess.push(&is.GetConnectedOutputSlot()->GetOwningLayer());
1326  }
1327  }
1328  }
1329  }
1330  }
1331 }
A layer that the constant data can be bound to.
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
Layer & GetOwningLayer() const
Definition: Layer.hpp:115
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
const std::vector< InputSlot > & GetInputSlots() const
Definition: Layer.hpp:231
unsigned int GetNumOutputSlots() const override
Returns the number of connectable output slots.
Definition: Layer.hpp:308
BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::WaitingForAck)
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:171
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
std::vector< SubgraphViewPtr > Subgraphs
const OutputSlot * GetConnectedOutputSlot() const
Definition: Layer.hpp:55
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:305

◆ BOOST_AUTO_TEST_CASE() [19/21]

BOOST_AUTO_TEST_CASE ( SingleSubgraph  )

Definition at line 1337 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), Layer::GetBackendId(), IInputSlot::GetConnection(), IOutputSlot::GetConnection(), InputSlot::GetConnection(), OutputSlot::GetConnection(), Layer::GetInputSlot(), Layer::GetOutputSlot(), armnn::GpuAcc, armnn::numeric_cast(), SubgraphViewSelector::SelectSubgraphs(), Layer::SetBackendId(), and Graph::SubstituteSubgraph().

1338 {
1339  // This test case represents the scenario when we have one subgraph
1340  // in which two layers have GpuAcc backend assigned
1341 
1342  //Construct graph
1343  Graph graph;
1344 
1345  Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input");
1346 
1347  Convolution2dDescriptor convDescriptor;
1348  Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
1349  convLayer1->SetBackendId(Compute::GpuAcc);
1350 
1351  Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
1352  convLayer2->SetBackendId(Compute::GpuAcc);
1353 
1354  Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output");
1355 
1356  inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
1357  convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
1358  convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1359 
1360  // GpuAcc sub graph selector
1362  SubgraphViewSelector::SelectSubgraphs(
1363  graph,
1364  // select the GpuAcc layers only
1365  [](const Layer & l){
1366  bool toSelect = (l.GetBackendId() == Compute::GpuAcc);
1367  return toSelect;
1368  });
1369 
1370  BOOST_TEST(subgraphs.size() == 1);
1371  if(subgraphs.size() == 1)
1372  {
1373  BOOST_TEST((subgraphs[0] != nullptr));
1374 
1375  if (subgraphs[0].get() != nullptr)
1376  {
1377  unsigned int numInputSlots = boost::numeric_cast<unsigned int>(subgraphs[0]->GetInputSlots().size());
1378  unsigned int numOutputSlots = boost::numeric_cast<unsigned int>(subgraphs[0]->GetOutputSlots().size());
1379 
1380  BOOST_TEST((numInputSlots == 1));
1381  BOOST_TEST((numOutputSlots == 1));
1382 
1383  // Save sub-graph connections for comparison after substitution
1384  IOutputSlot* subgraphInputConn1 = subgraphs[0]->GetInputSlot(0)->GetConnection();
1385  IInputSlot* subgraphOutputConn1 = subgraphs[0]->GetOutputSlot(0)->GetConnection(0);
1386 
1387  // Construct dummy pre-compiled layer
1388  PreCompiledDescriptor preCompiledDescriptor(numInputSlots, numOutputSlots);
1389  Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled");
1390 
1391  // Substitute sub-graph with pre-compiled layer
1392  graph.SubstituteSubgraph(*subgraphs[0], preCompiledLayer);
1393 
1394  // Check that connections are correct after substitution
1395  BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subgraphInputConn1);
1396 
1397  BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subgraphOutputConn1);
1398  }
1399  }
1400 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
void SetBackendId(const BackendId &id)
Definition: Layer.hpp:264
virtual const IInputSlot * GetConnection(unsigned int index) const =0
const IOutputSlot * GetConnection() const override
Definition: Layer.hpp:199
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An output connection slot for a layer.
Definition: INetwork.hpp:37
std::vector< SubgraphViewPtr > Subgraphs
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:33
const BackendId & GetBackendId() const
Definition: Layer.hpp:263
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:396
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
virtual const IOutputSlot * GetConnection() const =0
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
This layer represents a convolution 2d operation.
A PreCompiledDescriptor for the PreCompiledLayer.
An input connection slot for a layer.
Definition: INetwork.hpp:24
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:46

◆ BOOST_AUTO_TEST_CASE() [20/21]

BOOST_AUTO_TEST_CASE ( MultipleSubgraphs  )

Definition at line 1402 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), OutputSlot::Connect(), armnn::CpuAcc, Layer::GetBackendId(), IInputSlot::GetConnection(), IOutputSlot::GetConnection(), InputSlot::GetConnection(), OutputSlot::GetConnection(), Layer::GetInputSlot(), Layer::GetOutputSlot(), armnn::numeric_cast(), SubgraphViewSelector::SelectSubgraphs(), Layer::SetBackendId(), and Graph::SubstituteSubgraph().

1403 {
1404  // This test case represents the scenario when we have two subgraphs
1405  // in which two layers have CpuAcc backend assigned
1406 
1407  //Construct graph
1408  Graph graph;
1409 
1410  Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input");
1411 
1412  ViewsDescriptor splitterDescriptor(2);
1413  Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter");
1414  splitterLayer->SetBackendId(Compute::CpuAcc);
1415 
1416  Convolution2dDescriptor convDescriptor;
1417  Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
1418  Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
1419 
1420  OriginsDescriptor concatDescriptor(2);
1421  Layer* const pConcatLayer = graph.AddLayer<ConcatLayer>(concatDescriptor, "concat");
1422  pConcatLayer->SetBackendId(Compute::CpuAcc);
1423 
1424  Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output");
1425 
1426  inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
1427  splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
1428  splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0));
1429  convLayer1->GetOutputSlot(0).Connect(pConcatLayer->GetInputSlot(0));
1430  convLayer2->GetOutputSlot(0).Connect(pConcatLayer->GetInputSlot(1));
1431  pConcatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1432 
1433  // CpuAcc sub graph selector
1435  SubgraphViewSelector::SelectSubgraphs(
1436  graph,
1437  // select the CpuAcc layers only
1438  [](const Layer & l){
1439  bool toSelect = (l.GetBackendId() == Compute::CpuAcc);
1440  return toSelect;
1441  });
1442 
1443  BOOST_TEST(subgraphs.size() == 2);
1444  if(subgraphs.size() == 2)
1445  {
1446  BOOST_TEST((subgraphs[0] != nullptr));
1447  BOOST_TEST((subgraphs[1] != nullptr));
1448 
1449  if (subgraphs[0].get() != nullptr && subgraphs[1].get() != nullptr)
1450  {
1451  //Sort subgraphs by their inputSlot size.
1452  std::sort(subgraphs.begin(), subgraphs.end(),
1454  {
1455  return (lhs->GetInputSlots().size() < rhs->GetInputSlots().size());
1456  }
1457  );
1458 
1459  unsigned int numInputSlots1 = boost::numeric_cast<unsigned int>(subgraphs[0]->GetInputSlots().size());
1460  unsigned int numOutputSlots1 = boost::numeric_cast<unsigned int>(subgraphs[0]->GetOutputSlots().size());
1461 
1462  unsigned int numInputSlots2 = boost::numeric_cast<unsigned int>(subgraphs[1]->GetInputSlots().size());
1463  unsigned int numOutputSlots2 = boost::numeric_cast<unsigned int>(subgraphs[1]->GetOutputSlots().size());
1464 
1465  // Save sub-graph connections for comparison after substitution
1466  IOutputSlot* subgraph1InputConn = subgraphs[0]->GetInputSlot(0)->GetConnection();
1467  IInputSlot* subgraph1OutputConn1 = subgraphs[0]->GetOutputSlot(0)->GetConnection(0);
1468  IInputSlot* subgraph1OutputConn2 = subgraphs[0]->GetOutputSlot(1)->GetConnection(0);
1469 
1470  // Save sub-graph connections for comparison after substitution
1471  IOutputSlot* subgraph2InputConn1 = subgraphs[1]->GetInputSlot(0)->GetConnection();
1472  IOutputSlot* subgraph2InputConn2 = subgraphs[1]->GetInputSlot(1)->GetConnection();
1473  IInputSlot* subgraph2OutputConn = subgraphs[1]->GetOutputSlot(0)->GetConnection(0);
1474 
1475  PreCompiledDescriptor preCompiledDescriptor1(numInputSlots1, numOutputSlots1);
1476  Layer* const preCompiledLayer1 = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor1, "pre-compiled1");
1477 
1478  PreCompiledDescriptor preCompiledDescriptor2(numInputSlots2, numOutputSlots2);
1479  Layer* const preCompiledLayer2 = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor2, "pre-compiled2");
1480 
1481  // Substitute sub-graph with pre-compiled layer
1482  graph.SubstituteSubgraph(*subgraphs[0], preCompiledLayer1);
1483  graph.SubstituteSubgraph(*subgraphs[1], preCompiledLayer2);
1484 
1485  // Check that connections are correct after substitution
1486  BOOST_CHECK_EQUAL(preCompiledLayer1->GetInputSlot(0).GetConnection(), subgraph1InputConn);
1487  BOOST_CHECK_EQUAL(preCompiledLayer1->GetOutputSlot(0).GetConnection(0), subgraph1OutputConn1);
1488  BOOST_CHECK_EQUAL(preCompiledLayer1->GetOutputSlot(1).GetConnection(0), subgraph1OutputConn2);
1489 
1490  BOOST_CHECK_EQUAL(preCompiledLayer2->GetInputSlot(0).GetConnection(), subgraph2InputConn1);
1491  BOOST_CHECK_EQUAL(preCompiledLayer2->GetInputSlot(1).GetConnection(), subgraph2InputConn2);
1492  BOOST_CHECK_EQUAL(preCompiledLayer2->GetOutputSlot(0).GetConnection(0), subgraph2OutputConn);
1493  }
1494  }
1495 }
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
void SetBackendId(const BackendId &id)
Definition: Layer.hpp:264
virtual const IInputSlot * GetConnection(unsigned int index) const =0
const IOutputSlot * GetConnection() const override
Definition: Layer.hpp:199
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
An output connection slot for a layer.
Definition: INetwork.hpp:37
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
std::vector< SubgraphViewPtr > Subgraphs
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:33
const BackendId & GetBackendId() const
Definition: Layer.hpp:263
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:396
std::unique_ptr< SubgraphView > SubgraphViewPtr
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
virtual const IOutputSlot * GetConnection() const =0
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
This layer represents a convolution 2d operation.
A PreCompiledDescriptor for the PreCompiledLayer.
An input connection slot for a layer.
Definition: INetwork.hpp:24
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:46

◆ BOOST_AUTO_TEST_CASE() [21/21]

BOOST_AUTO_TEST_CASE ( SubgraphCycles  )

Definition at line 1497 of file SubgraphViewTests.cpp.

References Graph::AddLayer(), BOOST_AUTO_TEST_SUITE_END(), OutputSlot::Connect(), CreateInputsFrom(), CreateOutputsFrom(), CreateSubgraphViewFrom(), Layer::GetInputSlot(), Layer::GetNameStr(), Layer::GetOutputSlot(), and SubgraphViewSelector::SelectSubgraphs().

1498 {
1499  // This case represent the scenario when a naive split could lead to a cyclic dependency between two subgraphs
1500  //
1501  // X0 -> M0 -> X1 -> M2 -> X2
1502  // X0 -> M0 -> M1 -> M2 -> X2
1503  //
1504  /*
1505  X0
1506  |
1507  |
1508  M0
1509  / |
1510  / |
1511  X1 M1
1512  \ /
1513  M2
1514  |
1515  X2
1516  */
1517  // The expected result for this is that M0,M1 will be part of one subgraph and M2 in another and the
1518  // input and output slots in the subgraphs will be set accordingly.
1519  //
1520  Graph graph;
1521 
1522  OriginsDescriptor originsDescriptor(2);
1523  auto x0 = graph.AddLayer<InputLayer>(0, "x0");
1524  auto m0 = graph.AddLayer<ActivationLayer>(ActivationDescriptor{}, "m0");
1525  auto x1 = graph.AddLayer<ActivationLayer>(ActivationDescriptor{}, "x1");
1526  auto m1 = graph.AddLayer<ActivationLayer>(ActivationDescriptor{}, "m1");
1527  auto m2 = graph.AddLayer<AdditionLayer>("m2");
1528  auto x2 = graph.AddLayer<ActivationLayer>(ActivationDescriptor{}, "x2");
1529 
1530  x0->GetOutputSlot(0).Connect(m0->GetInputSlot(0));
1531  m0->GetOutputSlot(0).Connect(x1->GetInputSlot(0));
1532  m0->GetOutputSlot(0).Connect(m1->GetInputSlot(0));
1533  x1->GetOutputSlot(0).Connect(m2->GetInputSlot(0));
1534  m1->GetOutputSlot(0).Connect(m2->GetInputSlot(1));
1535  m2->GetOutputSlot(0).Connect(x2->GetInputSlot(0));
1536 
1537  // All selected 'M*' layers will be have 'm' in the name
1539  SubgraphViewSelector::SelectSubgraphs(
1540  graph,
1541  // select the middle layers only
1542  [](const Layer & l)
1543  {
1544  bool toSelect = (l.GetNameStr().find('m') != std::string::npos);
1545  return toSelect;
1546  });
1547 
1548  // expected results to test against
1549  auto inputSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({m0}),
1550  CreateOutputsFrom({m0, m1}),
1551  {m0, m1});
1552 
1553  auto outputSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({m2}),
1554  CreateOutputsFrom({m2}),
1555  {m2});
1556 
1557  BOOST_TEST(subgraphs.size() == 2);
1558  if (subgraphs.size() == 2)
1559  {
1560  // we need to have valid subgraph pointers here
1561  BOOST_TEST((subgraphs[0] != nullptr));
1562  BOOST_TEST((subgraphs[1] != nullptr));
1563 
1564  if (subgraphs[0].get() != nullptr && subgraphs[1].get() != nullptr)
1565  {
1566  // sort the subgraphs by layer size, so it is simpler to test
1567  std::sort(subgraphs.begin(), subgraphs.end(),
1569  {
1570  return (lhs->GetLayers().size() < rhs->GetLayers().size());
1571  }
1572  );
1573 
1574  // one subgraph needs to be size=1 and the other one is 4
1575  BOOST_TEST(subgraphs[0]->GetLayers().size() == 1);
1576  BOOST_TEST(subgraphs[1]->GetLayers().size() == 2);
1577 
1578  CompareSubgraphViews(subgraphs[0], outputSubgraph);
1579  CompareSubgraphViews(subgraphs[1], inputSubgraph);
1580  }
1581  }
1582 }
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:397
int Connect(InputSlot &destination)
Definition: Layer.cpp:79
This layer represents an activation operation with the specified activation function.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:310
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
const std::string & GetNameStr() const
Definition: Layer.hpp:216
std::vector< SubgraphViewPtr > Subgraphs
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
This layer represents an addition operation.
std::unique_ptr< SubgraphView > SubgraphViewPtr
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312