19 #include <boost/cast.hpp> 20 #include <boost/test/unit_test.hpp> 29 auto firstPos = std::find(order.begin(), order.end(), first);
30 auto secondPos = std::find(firstPos, order.end(), second);
32 return (secondPos != order.end());
92 std::vector<armnn::Layer*> order;
124 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
125 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
126 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
127 BOOST_TEST(
CheckOrder(graph, layerC, layerD));
143 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
144 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
145 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
146 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
147 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
165 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
166 BOOST_TEST(
CheckOrder(graph, layerA, layerF));
167 BOOST_TEST(
CheckOrder(graph, layerF, layerC));
168 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
169 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
170 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
178 std::vector<armnn::Layer*> order;
210 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
211 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
212 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
213 BOOST_TEST(
CheckOrder(graph, layerC, layerD));
229 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
230 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
231 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
232 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
233 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
252 BOOST_TEST(
CheckOrder(graph, layerA, layerF));
253 BOOST_TEST(
CheckOrder(graph, layerF, layerB));
254 BOOST_TEST(
CheckOrder(graph, layerF, layerC));
255 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
256 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
257 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
262 using Edge = std::pair<const armnn::Layer*, const armnn::Layer*>;
265 static std::vector<Edge> GetEdgeList(
const armnn::Graph& graph)
267 std::vector<Edge> edges;
269 for (
auto&& srcLayer: graph)
271 const unsigned int numOutputSlots = srcLayer->GetNumOutputSlots();
272 for (
unsigned int s = 0; s < numOutputSlots; ++s)
276 for (
unsigned int c = 0; c < numConnections; ++c)
278 auto inputSlot = armnn::PolymorphicDowncast<const armnn::InputSlot*>(outputSlot.
GetConnection(c));
279 edges.emplace_back(srcLayer, &inputSlot->GetOwningLayer());
289 std::vector<Edge> origEdges = GetEdgeList(origGraph);
290 std::vector<Edge> newEdges = GetEdgeList(graph);
294 std::vector<Edge> sortedNewEdges = newEdges;
295 std::sort(sortedNewEdges.begin(), sortedNewEdges.end());
297 auto last = std::unique(sortedNewEdges.begin(), sortedNewEdges.end());
298 BOOST_CHECK_MESSAGE(last == sortedNewEdges.end(),
"New graph contains duplicate edges!");
302 while (!newEdges.empty())
304 const Edge edge = std::move(newEdges.back());
308 int originalEdge = -1;
309 for (
unsigned int i = 0; i < origEdges.size(); i++)
311 const Edge& origEdge = origEdges[i];
312 if (origEdge.first->GetNameStr() == edge.first->GetNameStr() &&
313 origEdge.second->GetNameStr() == edge.second->GetNameStr())
319 if (originalEdge != -1)
324 BOOST_TEST(srcLayer);
325 BOOST_TEST(dstLayer);
328 if (srcLayer && dstLayer)
334 origEdges.erase(origEdges.begin() + originalEdge);
343 if (srcLayer ==
nullptr || dstLayer ==
nullptr)
345 BOOST_ERROR(
"At least one of the two ends of a new edge (" << edge.first <<
", " << edge.second <<
") " 346 "introduced after adding copy layers to a graph " 347 "correspond to a layer not known to the graph");
355 if (srcLayerInOrigGraph == dstLayerInOrigGraph)
357 BOOST_ERROR(
"A new edge (" 358 << edge.first->GetName()
360 << edge.second->GetName()
361 <<
") introduced after adding copy " 362 "layers to a graph is invalid. One of the ends should be present in the original " 363 "graph and the other should not, but " 364 << (srcLayerInOrigGraph ?
"both are" :
"none are"));
368 const armnn::Layer* copyLayer = srcLayerInOrigGraph ? dstLayer : srcLayer;
369 const armnn::Layer* nonCopyLayer = srcLayerInOrigGraph ? srcLayer : dstLayer;
372 std::vector<Edge> adjEdges;
373 auto it = newEdges.begin();
374 while (it != newEdges.end())
377 if (copyLayer == (srcLayerInOrigGraph ? newEdge.first : newEdge.second))
379 adjEdges.push_back(newEdge);
382 it = newEdges.erase(it);
390 if (adjEdges.empty())
392 BOOST_ERROR(
"An edge connecting a layer and a copy layer exists, (" << edge.first <<
", " <<
393 edge.second <<
"), but no other edges connecting the copy layer '" << copyLayer->
GetName()
394 <<
"' to other layers could be found");
399 for (
const Edge& adjEdge : adjEdges)
402 const armnn::Layer* adjLayer = srcLayerInOrigGraph ? adjEdge.second : adjEdge.first;
406 BOOST_ERROR(
"An edge (" << adjEdge.first <<
", " << adjEdge.second <<
") is adjacent to an edge " 407 "connecting a layer and a copy layer, (" << edge.first <<
", " << edge.second <<
"), " 408 "but the non-copy layer in the former does not correspond to a layer");
417 const armnn::Layer* origEdgeSrc = srcLayerInOrigGraph ? nonCopyLayer : adjLayer;
418 const armnn::Layer* origEdgeDst = srcLayerInOrigGraph ? adjLayer : nonCopyLayer;
420 auto origEdgeIter = origEdges.begin();
421 for (; origEdgeIter != origEdges.end(); origEdgeIter++)
423 if (origEdgeIter->first->GetNameStr() == origEdgeSrc->
GetNameStr() &&
424 origEdgeIter->second->GetNameStr() == origEdgeDst->
GetNameStr())
430 if (origEdgeIter != origEdges.end())
432 origEdges.erase(origEdgeIter);
436 BOOST_ERROR(
"An edge (" << adjEdge.first <<
", " << adjEdge.second <<
") is adjacent to an " 437 "edge connecting a layer and a copy layer, (" << edge.first <<
", " << edge.second <<
438 "), but there is no edge connecting the layers in the original graph");
445 BOOST_TEST(origEdges.empty(),
"Not all of the edges in the original graph correspond to paths in the new graph");
448 struct CopyLayersFixture
454 void InitialiseTestGraph()
456 using namespace armnn;
459 Layer*
const inputLayer = AddLayer<InputLayer>(0,
"input");
463 Layer*
const convLayer1 = AddLayer<Convolution2dLayer>(convolutionDefaults,
"conv1");
468 Layer*
const convLayer2 = AddLayer<Convolution2dLayer>(convolutionDefaults,
"conv2");
474 Layer*
const concatLayer = AddLayer<ConcatLayer>(concatDefaults,
"concat");
481 Layer*
const actLayer = AddLayer<ActivationLayer>(activationDefaults,
"act");
487 Layer*
const softmaxLayer = AddLayer<SoftmaxLayer>(softmaxDefaults,
"softmax");
492 Layer*
const outputLayer = AddLayer<OutputLayer>(0,
"output");
510 std::map<armnn::BackendId, std::unique_ptr<armnn::IBackendInternal>> m_Backends;
515 template <
typename LayerType,
typename... Args>
520 for (
auto slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
522 slot->SetTensorInfo(m_TensorDesc);
531 InitialiseTestGraph();
533 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
535 TestGraphAfterAddingCopyLayers(m_Graph, origGraph);
540 InitialiseTestGraph();
541 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
544 const std::vector<Edge> edges = GetEdgeList(m_Graph);
545 for (
int i = 0; i < 4; ++i)
547 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
548 const std::vector<Edge> otherEdges = GetEdgeList(m_Graph);
549 BOOST_TEST((edges == otherEdges));
582 std::vector<Edge> edges = GetEdgeList(graph);
584 std::sort(edges.begin(), edges.end());
585 auto last = std::unique(edges.begin(), edges.end());
586 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
BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::WaitingForAck)
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
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
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
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)