20 #include <boost/test/unit_test.hpp> 79 std::vector<armnn::Layer*> order;
111 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
112 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
113 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
114 BOOST_TEST(
CheckOrder(graph, layerC, layerD));
130 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
131 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
132 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
133 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
134 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
152 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
153 BOOST_TEST(
CheckOrder(graph, layerA, layerF));
154 BOOST_TEST(
CheckOrder(graph, layerF, layerC));
155 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
156 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
157 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
165 std::vector<armnn::Layer*> order;
197 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
198 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
199 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
200 BOOST_TEST(
CheckOrder(graph, layerC, layerD));
216 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
217 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
218 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
219 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
220 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
239 BOOST_TEST(
CheckOrder(graph, layerA, layerF));
240 BOOST_TEST(
CheckOrder(graph, layerF, layerB));
241 BOOST_TEST(
CheckOrder(graph, layerF, layerC));
242 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
243 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
244 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
249 using Edge = std::pair<const armnn::Layer*, const armnn::Layer*>;
252 static std::vector<Edge> GetEdgeList(
const armnn::Graph& graph)
254 std::vector<Edge> edges;
256 for (
auto&& srcLayer: graph)
258 const unsigned int numOutputSlots = srcLayer->GetNumOutputSlots();
259 for (
unsigned int s = 0; s < numOutputSlots; ++s)
263 for (
unsigned int c = 0; c < numConnections; ++c)
265 auto inputSlot = armnn::PolymorphicDowncast<const armnn::InputSlot*>(outputSlot.
GetConnection(c));
266 edges.emplace_back(srcLayer, &inputSlot->GetOwningLayer());
276 std::vector<Edge> origEdges = GetEdgeList(origGraph);
277 std::vector<Edge> newEdges = GetEdgeList(graph);
281 std::vector<Edge> sortedNewEdges = newEdges;
282 std::sort(sortedNewEdges.begin(), sortedNewEdges.end());
284 auto last = std::unique(sortedNewEdges.begin(), sortedNewEdges.end());
285 BOOST_CHECK_MESSAGE(last == sortedNewEdges.end(),
"New graph contains duplicate edges!");
289 while (!newEdges.empty())
291 const Edge edge = std::move(newEdges.back());
295 int originalEdge = -1;
296 for (
unsigned int i = 0; i < origEdges.size(); i++)
298 const Edge& origEdge = origEdges[i];
299 if (origEdge.first->GetNameStr() == edge.first->GetNameStr() &&
300 origEdge.second->GetNameStr() == edge.second->GetNameStr())
306 if (originalEdge != -1)
311 BOOST_TEST(srcLayer);
312 BOOST_TEST(dstLayer);
315 if (srcLayer && dstLayer)
321 origEdges.erase(origEdges.begin() + originalEdge);
330 if (srcLayer ==
nullptr || dstLayer ==
nullptr)
332 BOOST_ERROR(
"At least one of the two ends of a new edge (" << edge.first <<
", " << edge.second <<
") " 333 "introduced after adding copy layers to a graph " 334 "correspond to a layer not known to the graph");
342 if (srcLayerInOrigGraph == dstLayerInOrigGraph)
344 BOOST_ERROR(
"A new edge (" 345 << edge.first->GetName()
347 << edge.second->GetName()
348 <<
") introduced after adding copy " 349 "layers to a graph is invalid. One of the ends should be present in the original " 350 "graph and the other should not, but " 351 << (srcLayerInOrigGraph ?
"both are" :
"none are"));
355 const armnn::Layer* copyLayer = srcLayerInOrigGraph ? dstLayer : srcLayer;
356 const armnn::Layer* nonCopyLayer = srcLayerInOrigGraph ? srcLayer : dstLayer;
359 std::vector<Edge> adjEdges;
360 auto it = newEdges.begin();
361 while (it != newEdges.end())
364 if (copyLayer == (srcLayerInOrigGraph ? newEdge.first : newEdge.second))
366 adjEdges.push_back(newEdge);
369 it = newEdges.erase(it);
377 if (adjEdges.empty())
379 BOOST_ERROR(
"An edge connecting a layer and a copy layer exists, (" << edge.first <<
", " <<
380 edge.second <<
"), but no other edges connecting the copy layer '" << copyLayer->
GetName()
381 <<
"' to other layers could be found");
386 for (
const Edge& adjEdge : adjEdges)
389 const armnn::Layer* adjLayer = srcLayerInOrigGraph ? adjEdge.second : adjEdge.first;
393 BOOST_ERROR(
"An edge (" << adjEdge.first <<
", " << adjEdge.second <<
") is adjacent to an edge " 394 "connecting a layer and a copy layer, (" << edge.first <<
", " << edge.second <<
"), " 395 "but the non-copy layer in the former does not correspond to a layer");
404 const armnn::Layer* origEdgeSrc = srcLayerInOrigGraph ? nonCopyLayer : adjLayer;
405 const armnn::Layer* origEdgeDst = srcLayerInOrigGraph ? adjLayer : nonCopyLayer;
407 auto origEdgeIter = origEdges.begin();
408 for (; origEdgeIter != origEdges.end(); origEdgeIter++)
410 if (origEdgeIter->first->GetNameStr() == origEdgeSrc->
GetNameStr() &&
411 origEdgeIter->second->GetNameStr() == origEdgeDst->
GetNameStr())
417 if (origEdgeIter != origEdges.end())
419 origEdges.erase(origEdgeIter);
423 BOOST_ERROR(
"An edge (" << adjEdge.first <<
", " << adjEdge.second <<
") is adjacent to an " 424 "edge connecting a layer and a copy layer, (" << edge.first <<
", " << edge.second <<
425 "), but there is no edge connecting the layers in the original graph");
432 BOOST_TEST(origEdges.empty(),
"Not all of the edges in the original graph correspond to paths in the new graph");
435 struct CopyLayersFixture
441 void InitialiseTestGraph()
443 using namespace armnn;
446 Layer*
const inputLayer = AddLayer<InputLayer>(0,
"input");
450 Layer*
const convLayer1 = AddLayer<Convolution2dLayer>(convolutionDefaults,
"conv1");
455 Layer*
const convLayer2 = AddLayer<Convolution2dLayer>(convolutionDefaults,
"conv2");
461 Layer*
const concatLayer = AddLayer<ConcatLayer>(concatDefaults,
"concat");
468 Layer*
const actLayer = AddLayer<ActivationLayer>(activationDefaults,
"act");
474 Layer*
const softmaxLayer = AddLayer<SoftmaxLayer>(softmaxDefaults,
"softmax");
479 Layer*
const outputLayer = AddLayer<OutputLayer>(0,
"output");
497 std::map<armnn::BackendId, std::unique_ptr<armnn::IBackendInternal>> m_Backends;
502 template <
typename LayerType,
typename... Args>
507 for (
auto slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
509 slot->SetTensorInfo(m_TensorDesc);
518 InitialiseTestGraph();
520 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
522 TestGraphAfterAddingCopyLayers(m_Graph, origGraph);
527 InitialiseTestGraph();
528 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
531 const std::vector<Edge> edges = GetEdgeList(m_Graph);
532 for (
int i = 0; i < 4; ++i)
534 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
535 const std::vector<Edge> otherEdges = GetEdgeList(m_Graph);
536 BOOST_TEST((edges == otherEdges));
569 std::vector<Edge> edges = GetEdgeList(graph);
570 BOOST_CHECK(edges.size() == 6u);
571 std::sort(edges.begin(), edges.end());
572 auto last = std::unique(edges.begin(), edges.end());
573 BOOST_CHECK_MESSAGE(last == edges.end(),
"Found duplicated edges after AddCompatibilityLayers()");
BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
Iterator begin()
Returns iterator pointing to the beginning of the list. Lowercase for range-based for loops...
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
void SetEdgeStrategy(unsigned int connectionIndex, EdgeStrategy strategy)
No strategy has been defined. Used internally to verify integrity of optimizations.
CPU Execution: Reference C++ kernels.
armnn::Layer * GetFirstLayerWithName(armnn::Graph &graph, const std::string &name)
bool CheckOrder(const armnn::Graph &graph, const armnn::Layer *first, const armnn::Layer *second)
Checks that first comes before second in the order.
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
A Convolution2dDescriptor for the Convolution2dLayer.
Source backends tensor data can be exported to destination backend tensor without copy...
int Connect(InputSlot &destination)
bool GraphHasNamedLayer(const armnn::Graph &graph, const std::string &name)
This layer represents an activation operation with the specified activation function.
Copyright (c) 2020 ARM Limited.
void SetBackendId(const BackendId &id)
virtual const IInputSlot * GetConnection(unsigned int index) const =0
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
A layer user-provided data can be bound to (e.g. inputs, outputs).
An output connection slot for a layer.
An OriginsDescriptor for the ConcatLayer.
const std::string & GetNameStr() const
GPU Execution: OpenCL: ArmCompute.
BOOST_AUTO_TEST_CASE(ClassGraph)
An ActivationDescriptor for the ActivationLayer.
const BackendId & GetBackendId() const
This layer represents an addition operation.
BOOST_AUTO_TEST_SUITE_END()
CPU Execution: NEON: ArmCompute.
void SetTensorInfo(const TensorInfo &tensorInfo) override
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
virtual unsigned int GetNumConnections() const =0
const char * GetName() const override
Returns the name of the layer.
Graph & TopologicalSort()
Sorts layers in topological order and return this.
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
A SoftmaxDescriptor for the SoftmaxLayer.
void AddCompatibilityLayers(std::map< BackendId, std::unique_ptr< class IBackendInternal >> &backends, TensorHandleFactoryRegistry ®istry)
Modifies the graph in-place, removing edges connecting layers using different compute devices...
BOOST_FIXTURE_TEST_CASE(AddCopyLayers, CopyLayersFixture)